Skip to content

Commit c9e7e8c

Browse files
committed
refactor(pkg,api,cli): remove UserPassword struct
1 parent a77afb9 commit c9e7e8c

File tree

5 files changed

+32
-65
lines changed

5 files changed

+32
-65
lines changed

api/services/auth.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/shellhub-io/shellhub/pkg/api/jwttoken"
2121
"github.com/shellhub-io/shellhub/pkg/api/requests"
2222
"github.com/shellhub-io/shellhub/pkg/clock"
23+
"github.com/shellhub-io/shellhub/pkg/hash"
2324
"github.com/shellhub-io/shellhub/pkg/models"
2425
"github.com/shellhub-io/shellhub/pkg/uuid"
2526
log "github.com/sirupsen/logrus"
@@ -226,7 +227,7 @@ func (s *service) AuthLocalUser(ctx context.Context, req *requests.AuthLocalUser
226227
return nil, lockout, "", NewErrAuthUnathorized(nil)
227228
}
228229

229-
if !user.Password.Compare(req.Password) {
230+
if !hash.CompareWith(req.Password, user.PasswordDigest) {
230231
lockout, _, err := s.cache.StoreLoginAttempt(ctx, sourceIP, user.ID)
231232
if err != nil {
232233
log.WithError(err).
@@ -285,9 +286,9 @@ func (s *service) AuthLocalUser(ctx context.Context, req *requests.AuthLocalUser
285286

286287
// Updates last_login and the hash algorithm to bcrypt if still using SHA256
287288
changes := &models.UserChanges{LastLogin: clock.Now(), PreferredNamespace: &tenantID}
288-
if !strings.HasPrefix(user.Password.Hash, "$") {
289-
if neo, _ := models.HashUserPassword(req.Password); neo.Hash != "" {
290-
changes.Password = neo.Hash
289+
if !strings.HasPrefix(user.PasswordDigest, "$") {
290+
if pwdDigest, _ := hash.Do(req.Password); pwdDigest != "" {
291+
changes.Password = pwdDigest
291292
}
292293
}
293294

api/services/setup.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/shellhub-io/shellhub/pkg/api/authorizer"
1515
"github.com/shellhub-io/shellhub/pkg/api/requests"
1616
"github.com/shellhub-io/shellhub/pkg/clock"
17+
"github.com/shellhub-io/shellhub/pkg/hash"
1718
"github.com/shellhub-io/shellhub/pkg/models"
1819
"github.com/shellhub-io/shellhub/pkg/uuid"
1920
)
@@ -41,19 +42,19 @@ func (s *service) Setup(ctx context.Context, req requests.Setup) error {
4142
return NewErrUserInvalid(nil, err)
4243
}
4344

44-
password, err := models.HashUserPassword(req.Password)
45+
pwdDigest, err := hash.Do(req.Password)
4546
if err != nil {
4647
return NewErrUserPasswordInvalid(err)
4748
}
4849

49-
if ok, err := s.validator.Struct(password); !ok || err != nil {
50+
if ok, err := s.validator.Struct(pwdDigest); !ok || err != nil {
5051
return NewErrUserPasswordInvalid(err)
5152
}
5253

5354
user := &models.User{
54-
Origin: models.UserOriginLocal,
55-
UserData: data,
56-
Password: password,
55+
Origin: models.UserOriginLocal,
56+
UserData: data,
57+
PasswordDigest: pwdDigest,
5758
// NOTE: user's created from the setup screen doesn't need to be confirmed.
5859
Status: models.UserStatusConfirmed,
5960
CreatedAt: clock.Now(),

api/services/user.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"strings"
66

77
"github.com/shellhub-io/shellhub/pkg/api/requests"
8+
"github.com/shellhub-io/shellhub/pkg/hash"
89
"github.com/shellhub-io/shellhub/pkg/models"
910
)
1011

@@ -46,12 +47,12 @@ func (s *service) UpdateUser(ctx context.Context, req *requests.UpdateUser) ([]s
4647

4748
if req.Password != "" {
4849
// TODO: test
49-
if !user.Password.Compare(req.CurrentPassword) {
50+
if !hash.CompareWith(req.CurrentPassword, user.PasswordDigest) {
5051
return []string{}, NewErrUserPasswordNotMatch(nil)
5152
}
5253

53-
neo, _ := models.HashUserPassword(req.Password)
54-
changes.Password = neo.Hash
54+
pwdDigest, _ := hash.Do(req.Password)
55+
changes.Password = pwdDigest
5556
}
5657

5758
if err := s.store.UserUpdate(ctx, req.UserID, changes); err != nil {
@@ -70,16 +71,16 @@ func (s *service) UpdatePasswordUser(ctx context.Context, id, currentPassword, n
7071
return NewErrUserNotFound(id, err)
7172
}
7273

73-
if !user.Password.Compare(currentPassword) {
74+
if !hash.CompareWith(currentPassword, user.PasswordDigest) {
7475
return NewErrUserPasswordNotMatch(nil)
7576
}
7677

77-
neo, err := models.HashUserPassword(newPassword)
78+
pwdDigest, err := hash.Do(newPassword)
7879
if err != nil {
7980
return NewErrUserPasswordInvalid(err)
8081
}
8182

82-
if err := s.store.UserUpdate(ctx, id, &models.UserChanges{Password: neo.Hash}); err != nil {
83+
if err := s.store.UserUpdate(ctx, id, &models.UserChanges{Password: pwdDigest}); err != nil {
8384
return NewErrUserUpdate(user, err)
8485
}
8586

cli/services/users.go

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/shellhub-io/shellhub/cli/pkg/inputs"
88
"github.com/shellhub-io/shellhub/pkg/clock"
9+
"github.com/shellhub-io/shellhub/pkg/hash"
910
"github.com/shellhub-io/shellhub/pkg/models"
1011
)
1112

@@ -40,23 +41,18 @@ func (s *service) UserCreate(ctx context.Context, input *inputs.UserCreate) (*mo
4041
}
4142
}
4243

43-
password, err := models.HashUserPassword(input.Password)
44+
pwdDigest, err := hash.Do(input.Password)
4445
if err != nil {
4546
return nil, ErrUserPasswordInvalid
4647
}
4748

48-
// TODO: validate this at cmd layer
49-
if ok, err := s.validator.Struct(password); !ok || err != nil {
50-
return nil, ErrUserPasswordInvalid
51-
}
52-
5349
user := &models.User{
54-
Origin: models.UserOriginLocal,
55-
UserData: userData,
56-
Password: password,
57-
Status: models.UserStatusConfirmed,
58-
CreatedAt: clock.Now(),
59-
MaxNamespaces: MaxNumberNamespacesCommunity,
50+
Origin: models.UserOriginLocal,
51+
UserData: userData,
52+
PasswordDigest: pwdDigest,
53+
Status: models.UserStatusConfirmed,
54+
CreatedAt: clock.Now(),
55+
MaxNamespaces: MaxNumberNamespacesCommunity,
6056
Preferences: models.UserPreferences{
6157
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
6258
},
@@ -117,17 +113,12 @@ func (s *service) UserUpdate(ctx context.Context, input *inputs.UserUpdate) erro
117113
return ErrUserNotFound
118114
}
119115

120-
password, err := models.HashUserPassword(input.Password)
116+
pwdDigest, err := hash.Do(input.Password)
121117
if err != nil {
122118
return ErrUserPasswordInvalid
123119
}
124120

125-
// TODO: validate this at cmd layer
126-
if ok, err := s.validator.Struct(password); !ok || err != nil {
127-
return ErrUserPasswordInvalid
128-
}
129-
130-
if err := s.store.UserUpdate(ctx, user.ID, &models.UserChanges{Password: password.Hash}); err != nil {
121+
if err := s.store.UserUpdate(ctx, user.ID, &models.UserChanges{Password: pwdDigest}); err != nil {
131122
return ErrFailedUpdateUser
132123
}
133124

pkg/models/user.go

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package models
33
import (
44
"time"
55

6-
"github.com/shellhub-io/shellhub/pkg/hash"
76
"github.com/shellhub-io/shellhub/pkg/validator"
87
)
98

@@ -72,13 +71,16 @@ type User struct {
7271
LastLogin time.Time `json:"last_login" bson:"last_login"`
7372
EmailMarketing bool `json:"email_marketing" bson:"email_marketing"`
7473
UserData `bson:",inline"`
74+
75+
// PasswordDigest stores the hashed password.
76+
PasswordDigest string `json:"-"`
77+
7578
// MFA contains attributes related to a user's MFA settings. Use [UserMFA.Enabled] to
7679
// check if MFA is active for the user.
7780
//
7881
// NOTE: MFA is available as a cloud-only feature and must be ignored in community.
7982
MFA UserMFA `json:"mfa" bson:"mfa"`
8083
Preferences UserPreferences `json:"preferences" bson:"preferences"`
81-
Password UserPassword `bson:",inline"`
8284
}
8385

8486
type UserData struct {
@@ -110,35 +112,6 @@ type UserPreferences struct {
110112
AuthMethods []UserAuthMethod `json:"auth_methods" bson:"auth_methods"`
111113
}
112114

113-
type UserPassword struct {
114-
// Plain contains the plain text password.
115-
Plain string `json:"password" bson:"-" validate:"required,password"`
116-
// Hash contains the hashed pasword from plain text.
117-
Hash string `json:"-" bson:"password"`
118-
}
119-
120-
// HashUserPassword receives a plain password and hash it, returning
121-
// a [UserPassword].
122-
func HashUserPassword(plain string) (UserPassword, error) {
123-
p := UserPassword{
124-
Plain: plain,
125-
}
126-
127-
var err error
128-
p.Hash, err = hash.Do(p.Plain)
129-
130-
return p, err
131-
}
132-
133-
// Compare reports whether a plain password matches with hash.
134-
//
135-
// For compatibility purposes, it can compare using both SHA256 and bcrypt algorithms.
136-
// Hashes starting with "$" are assumed to be a bcrypt hash; otherwise, they are treated as
137-
// SHA256 hashes.
138-
func (p *UserPassword) Compare(plain string) bool {
139-
return hash.CompareWith(plain, p.Hash)
140-
}
141-
142115
// UserAuthIdentifier is an username or email used to authenticate.
143116
type UserAuthIdentifier string
144117

0 commit comments

Comments
 (0)