Skip to content

Commit 3d1edfd

Browse files
committed
wip(api,cli): refactor models.User
1 parent 7bc5f1a commit 3d1edfd

File tree

6 files changed

+113
-159
lines changed

6 files changed

+113
-159
lines changed

api/services/auth.go

Lines changed: 9 additions & 8 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 passwordDigest, _ := hash.Do(req.Password); passwordDigest != "" {
291+
changes.Password = passwordDigest
291292
}
292293
}
293294

@@ -309,12 +310,12 @@ func (s *service) AuthLocalUser(ctx context.Context, req *requests.AuthLocalUser
309310
User: user.Username,
310311
Name: user.Name,
311312
Email: user.Email,
312-
RecoveryEmail: user.RecoveryEmail,
313+
RecoveryEmail: user.Preferences.SecurityEmail,
313314
MFA: user.MFA.Enabled,
314315
Tenant: tenantID,
315316
Role: role,
316317
Token: token,
317-
MaxNamespaces: user.MaxNamespaces,
318+
MaxNamespaces: user.Preferences.MaxNamespaces,
318319
}
319320

320321
return res, 0, "", nil
@@ -393,12 +394,12 @@ func (s *service) CreateUserToken(ctx context.Context, req *requests.CreateUserT
393394
User: user.Username,
394395
Name: user.Name,
395396
Email: user.Email,
396-
RecoveryEmail: user.RecoveryEmail,
397+
RecoveryEmail: user.Preferences.SecurityEmail,
397398
MFA: user.MFA.Enabled,
398399
Tenant: tenantID,
399400
Role: role,
400401
Token: token,
401-
MaxNamespaces: user.MaxNamespaces,
402+
MaxNamespaces: user.Preferences.MaxNamespaces,
402403
}, nil
403404
}
404405

api/services/namespace.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ func (s *service) CreateNamespace(ctx context.Context, req *requests.NamespaceCr
3232

3333
// When MaxNamespaces is less than zero, it means that the user has no limit
3434
// of namespaces. If the value is zero, it means he has no right to create a new namespace
35-
if user.MaxNamespaces == 0 {
36-
return nil, NewErrNamespaceCreationIsForbidden(user.MaxNamespaces, nil)
37-
} else if user.MaxNamespaces > 0 {
35+
if user.Preferences.MaxNamespaces == 0 {
36+
return nil, NewErrNamespaceCreationIsForbidden(user.Preferences.MaxNamespaces, nil)
37+
} else if user.Preferences.MaxNamespaces > 0 {
3838
info, err := s.store.UserGetInfo(ctx, req.UserID)
3939
switch {
4040
case err != nil:
4141
return nil, err
42-
case len(info.OwnedNamespaces) >= user.MaxNamespaces:
43-
return nil, NewErrNamespaceLimitReached(user.MaxNamespaces, nil)
42+
case len(info.OwnedNamespaces) >= user.Preferences.MaxNamespaces:
43+
return nil, NewErrNamespaceLimitReached(user.Preferences.MaxNamespaces, nil)
4444
}
4545
}
4646

api/services/setup.go

Lines changed: 14 additions & 23 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
)
@@ -30,36 +31,26 @@ func (s *service) Setup(ctx context.Context, req requests.Setup) error {
3031
return NewErrSetupForbidden(err)
3132
}
3233

33-
data := models.UserData{
34-
Name: req.Name,
35-
Email: req.Email,
36-
Username: req.Username,
37-
RecoveryEmail: "",
38-
}
39-
40-
if ok, err := s.validator.Struct(data); !ok || err != nil {
41-
return NewErrUserInvalid(nil, err)
42-
}
43-
44-
password, err := models.HashUserPassword(req.Password)
34+
passwordDigest, err := hash.Do(req.Password)
4535
if err != nil {
4636
return NewErrUserPasswordInvalid(err)
4737
}
4838

49-
if ok, err := s.validator.Struct(password); !ok || err != nil {
50-
return NewErrUserPasswordInvalid(err)
51-
}
52-
5339
user := &models.User{
54-
Origin: models.UserOriginLocal,
55-
UserData: data,
56-
Password: password,
40+
Origin: models.UserOriginLocal,
41+
Name: req.Name,
42+
Email: req.Email,
43+
Username: req.Username,
44+
PasswordDigest: passwordDigest,
5745
// NOTE: user's created from the setup screen doesn't need to be confirmed.
58-
Status: models.UserStatusConfirmed,
59-
CreatedAt: clock.Now(),
60-
MaxNamespaces: -1,
46+
Status: models.UserStatusConfirmed,
47+
CreatedAt: clock.Now(),
6148
Preferences: models.UserPreferences{
62-
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
49+
PreferredNamespace: "",
50+
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
51+
SecurityEmail: "",
52+
MaxNamespaces: -1,
53+
EmailMarketing: false,
6354
},
6455
}
6556

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+
passwordDigest, _ := hash.Do(req.Password)
55+
changes.Password = passwordDigest
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+
passwordDigest, 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: passwordDigest}); err != nil {
8384
return NewErrUserUpdate(user, err)
8485
}
8586

cli/services/users.go

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,19 @@ package services
33
import (
44
"context"
55
"slices"
6+
"strings"
67

78
"github.com/shellhub-io/shellhub/cli/pkg/inputs"
8-
"github.com/shellhub-io/shellhub/pkg/clock"
9+
"github.com/shellhub-io/shellhub/pkg/hash"
910
"github.com/shellhub-io/shellhub/pkg/models"
11+
"golang.org/x/text/cases"
12+
"golang.org/x/text/language"
1013
)
1114

1215
// UserCreate adds a new user based on the provided user's data. This method validates data and
1316
// checks for conflicts.
1417
func (s *service) UserCreate(ctx context.Context, input *inputs.UserCreate) (*models.User, error) {
15-
// TODO: convert username and email to lower case.
16-
userData := models.UserData{
17-
Name: input.Username,
18-
Email: input.Email,
19-
Username: input.Username,
20-
}
21-
22-
// TODO: validate this at cmd layer
23-
if ok, err := s.validator.Struct(userData); !ok || err != nil {
24-
return nil, ErrUserDataInvalid
25-
}
26-
27-
if conflicts, has, _ := s.store.UserConflicts(ctx, &models.UserConflicts{Email: userData.Email, Username: userData.Username}); has {
18+
if conflicts, has, err := s.store.UserConflicts(ctx, &models.UserConflicts{Email: input.Email}); err != nil || has {
2819
containsEmail := slices.Contains(conflicts, "email")
2920
containsUsername := slices.Contains(conflicts, "username")
3021

@@ -40,34 +31,32 @@ func (s *service) UserCreate(ctx context.Context, input *inputs.UserCreate) (*mo
4031
}
4132
}
4233

43-
password, err := models.HashUserPassword(input.Password)
34+
passwordDigest, err := hash.Do(input.Password)
4435
if err != nil {
4536
return nil, ErrUserPasswordInvalid
4637
}
4738

48-
// TODO: validate this at cmd layer
49-
if ok, err := s.validator.Struct(password); !ok || err != nil {
50-
return nil, ErrUserPasswordInvalid
51-
}
52-
5339
user := &models.User{
54-
Origin: models.UserOriginLocal,
55-
UserData: userData,
56-
Password: password,
57-
Status: models.UserStatusConfirmed,
58-
CreatedAt: clock.Now(),
59-
MaxNamespaces: MaxNumberNamespacesCommunity,
40+
Origin: models.UserOriginLocal,
41+
ExternalID: "",
42+
Status: models.UserStatusConfirmed,
43+
Name: cases.Title(language.AmericanEnglish).String(strings.ToLower(input.Username)),
44+
Email: strings.ToLower(input.Email),
45+
Username: strings.ToLower(input.Username),
46+
PasswordDigest: passwordDigest,
6047
Preferences: models.UserPreferences{
61-
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
48+
PreferredNamespace: "",
49+
AuthMethods: []models.UserAuthMethod{models.UserAuthMethodLocal},
50+
SecurityEmail: "",
51+
MaxNamespaces: -1,
52+
EmailMarketing: false,
6253
},
6354
}
6455

6556
if _, err := s.store.UserCreate(ctx, user); err != nil {
6657
return nil, ErrCreateNewUser
6758
}
6859

69-
s.store.SystemSet(ctx, "setup", true) //nolint:errcheck
70-
7160
return user, nil
7261
}
7362

@@ -117,17 +106,12 @@ func (s *service) UserUpdate(ctx context.Context, input *inputs.UserUpdate) erro
117106
return ErrUserNotFound
118107
}
119108

120-
password, err := models.HashUserPassword(input.Password)
109+
passwordDigest, err := hash.Do(input.Password)
121110
if err != nil {
122111
return ErrUserPasswordInvalid
123112
}
124113

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 {
114+
if err := s.store.UserUpdate(ctx, user.ID, &models.UserChanges{Password: passwordDigest}); err != nil {
131115
return ErrFailedUpdateUser
132116
}
133117

0 commit comments

Comments
 (0)