Skip to content

Commit 21f395f

Browse files
authored
Merge pull request #27 from myrunes/dev-securityhotfix
remove sensible data from user response models
2 parents 119e225 + a75f033 commit 21f395f

File tree

2 files changed

+1064
-1051
lines changed

2 files changed

+1064
-1051
lines changed

internal/objects/user.go

Lines changed: 132 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,132 @@
1-
package objects
2-
3-
import (
4-
"errors"
5-
"regexp"
6-
"strings"
7-
"time"
8-
9-
"github.com/myrunes/backend/internal/auth"
10-
"github.com/myrunes/backend/internal/static"
11-
12-
"github.com/bwmarrin/snowflake"
13-
)
14-
15-
// userIDNode is the node to generate user snowflake IDs.
16-
var userIDNode, _ = snowflake.NewNode(static.NodeIDUsers)
17-
18-
// allowedUNameChars is a regular expression which matches
19-
// on user name strings which are valid.
20-
var allowedUNameChars = regexp.MustCompile(`[\w_\-]+`)
21-
22-
var (
23-
ErrInvalidUsername = errors.New("invalid username")
24-
)
25-
26-
// User wraps a general user object.
27-
type User struct {
28-
UID snowflake.ID `json:"uid"`
29-
Username string `json:"username"`
30-
MailAddress string `json:"mailaddress"`
31-
DisplayName string `json:"displayname"`
32-
PassHash []byte `json:"passhash,omitempty"`
33-
LastLogin time.Time `json:"lastlogin"`
34-
Created time.Time `json:"created"`
35-
Favorites []string `json:"favorites"`
36-
PageOrder map[string][]snowflake.ID `json:"pageorder"`
37-
HasOldPassword bool `json:"hasoldpw,omitempty"`
38-
}
39-
40-
// NewUser creates a new User object with the given
41-
// username and password which will be hashed using
42-
// the passed authModdleware and then saved to the
43-
// user object.
44-
func NewUser(username, password string, authMiddleware auth.AuthMiddleware) (*User, error) {
45-
now := time.Now()
46-
passHash, err := authMiddleware.CreateHash(password)
47-
if err != nil {
48-
return nil, err
49-
}
50-
51-
user := &User{
52-
Created: now,
53-
LastLogin: now,
54-
PassHash: []byte(passHash),
55-
UID: userIDNode.Generate(),
56-
Username: strings.ToLower(username),
57-
DisplayName: username,
58-
Favorites: []string{},
59-
}
60-
61-
return user, nil
62-
}
63-
64-
// Update sets mutable user data to the
65-
// current user object from the given
66-
// newUser object properties.
67-
// If login is set to true, lastLogin
68-
// will be set to the current time.
69-
func (u *User) Update(newUser *User, login bool) {
70-
if login {
71-
u.LastLogin = time.Now()
72-
}
73-
74-
if newUser == nil {
75-
return
76-
}
77-
78-
if newUser.DisplayName != "" {
79-
u.DisplayName = newUser.DisplayName
80-
}
81-
82-
if newUser.Favorites != nil {
83-
u.Favorites = newUser.Favorites
84-
}
85-
86-
if newUser.Username != "" {
87-
u.Username = newUser.Username
88-
}
89-
90-
if newUser.PassHash != nil && len(newUser.PassHash) > 0 {
91-
u.PassHash = newUser.PassHash
92-
}
93-
94-
if newUser.PageOrder != nil {
95-
u.PageOrder = newUser.PageOrder
96-
}
97-
98-
if newUser.MailAddress != "" {
99-
if newUser.MailAddress == "__RESET__" {
100-
u.MailAddress = ""
101-
} else {
102-
u.MailAddress = newUser.MailAddress
103-
}
104-
}
105-
}
106-
107-
// Validate checks if the user object
108-
// is built by specification.
109-
// If the validation fails, the failure
110-
// will be returned as error object.
111-
func (u *User) Validate(acceptEmptyUsername bool) error {
112-
if (!acceptEmptyUsername && len(u.Username) < 3) ||
113-
len(allowedUNameChars.FindAllString(u.Username, -1)) > 1 {
114-
115-
return ErrInvalidUsername
116-
}
117-
118-
return nil
119-
}
1+
package objects
2+
3+
import (
4+
"errors"
5+
"regexp"
6+
"strings"
7+
"time"
8+
9+
"github.com/myrunes/backend/internal/auth"
10+
"github.com/myrunes/backend/internal/static"
11+
12+
"github.com/bwmarrin/snowflake"
13+
)
14+
15+
// userIDNode is the node to generate user snowflake IDs.
16+
var userIDNode, _ = snowflake.NewNode(static.NodeIDUsers)
17+
18+
// allowedUNameChars is a regular expression which matches
19+
// on user name strings which are valid.
20+
var allowedUNameChars = regexp.MustCompile(`[\w_\-]+`)
21+
22+
var (
23+
ErrInvalidUsername = errors.New("invalid username")
24+
)
25+
26+
// User wraps a general user object.
27+
type User struct {
28+
UID snowflake.ID `json:"uid"`
29+
Username string `json:"username"`
30+
MailAddress string `json:"mailaddress,omitempty"`
31+
DisplayName string `json:"displayname"`
32+
LastLogin time.Time `json:"lastlogin,omitempty"`
33+
Created time.Time `json:"created"`
34+
Favorites []string `json:"favorites,omitempty"`
35+
PageOrder map[string][]snowflake.ID `json:"pageorder,omitempty"`
36+
HasOldPassword bool `json:"hasoldpw,omitempty"`
37+
38+
PassHash []byte `json:"-"`
39+
}
40+
41+
// NewUser creates a new User object with the given
42+
// username and password which will be hashed using
43+
// the passed authModdleware and then saved to the
44+
// user object.
45+
func NewUser(username, password string, authMiddleware auth.AuthMiddleware) (*User, error) {
46+
now := time.Now()
47+
passHash, err := authMiddleware.CreateHash(password)
48+
if err != nil {
49+
return nil, err
50+
}
51+
52+
user := &User{
53+
Created: now,
54+
LastLogin: now,
55+
PassHash: []byte(passHash),
56+
UID: userIDNode.Generate(),
57+
Username: strings.ToLower(username),
58+
DisplayName: username,
59+
Favorites: []string{},
60+
}
61+
62+
return user, nil
63+
}
64+
65+
// Update sets mutable user data to the
66+
// current user object from the given
67+
// newUser object properties.
68+
// If login is set to true, lastLogin
69+
// will be set to the current time.
70+
func (u *User) Update(newUser *User, login bool) {
71+
if login {
72+
u.LastLogin = time.Now()
73+
}
74+
75+
if newUser == nil {
76+
return
77+
}
78+
79+
if newUser.DisplayName != "" {
80+
u.DisplayName = newUser.DisplayName
81+
}
82+
83+
if newUser.Favorites != nil {
84+
u.Favorites = newUser.Favorites
85+
}
86+
87+
if newUser.Username != "" {
88+
u.Username = newUser.Username
89+
}
90+
91+
if newUser.PassHash != nil && len(newUser.PassHash) > 0 {
92+
u.PassHash = newUser.PassHash
93+
}
94+
95+
if newUser.PageOrder != nil {
96+
u.PageOrder = newUser.PageOrder
97+
}
98+
99+
if newUser.MailAddress != "" {
100+
if newUser.MailAddress == "__RESET__" {
101+
u.MailAddress = ""
102+
} else {
103+
u.MailAddress = newUser.MailAddress
104+
}
105+
}
106+
}
107+
108+
// Validate checks if the user object
109+
// is built by specification.
110+
// If the validation fails, the failure
111+
// will be returned as error object.
112+
func (u *User) Validate(acceptEmptyUsername bool) error {
113+
if (!acceptEmptyUsername && len(u.Username) < 3) ||
114+
len(allowedUNameChars.FindAllString(u.Username, -1)) > 1 {
115+
116+
return ErrInvalidUsername
117+
}
118+
119+
return nil
120+
}
121+
122+
// Sanitize creates a new User object from
123+
// the current User object which only contains
124+
// information which shall be publicly visible.
125+
func (u *User) Sanitize() *User {
126+
return &User{
127+
UID: u.UID,
128+
Created: u.Created,
129+
DisplayName: u.DisplayName,
130+
Username: u.Username,
131+
}
132+
}

0 commit comments

Comments
 (0)