blob: b7cdb65f901a72af15db4ba7e1168291c7b43ec9 [file] [log] [blame]
iomodo48c837e2021-02-19 01:17:07 +04001package model
2
3import (
4 "net/mail"
5 "regexp"
6 "strings"
7 "unicode"
8
9 "github.com/pkg/errors"
10)
11
12const (
13 userNameMaxLength = 64
14 userNameMinLength = 1
15 userEmailMaxLength = 128
16)
17
18// User contains the details about the user.
iomodo48c837e2021-02-19 01:17:07 +040019type User struct {
20 ID string `json:"id"`
21 CreateAt int64 `json:"create_at,omitempty"`
22 UpdateAt int64 `json:"update_at,omitempty"`
23 DeleteAt int64 `json:"delete_at"`
24 Username string `json:"username"`
25 Password string `json:"password,omitempty"`
26 Email string `json:"email"`
27 EmailVerified bool `json:"email_verified,omitempty"`
28 FirstName string `json:"first_name"`
29 LastName string `json:"last_name"`
30 LastPasswordUpdate int64 `json:"last_password_update,omitempty"`
31}
32
33// IsValid validates the user and returns an error if it isn't configured
34// correctly.
35func (u *User) IsValid() error {
36 if !isValidID(u.ID) {
37 return invalidUserError("id", "")
38 }
39
40 if u.CreateAt == 0 {
41 return invalidUserError("create_at", u.ID)
42 }
43
44 if u.UpdateAt == 0 {
45 return invalidUserError("update_at", u.ID)
46 }
47
48 if !isValidUsername(u.Username) {
49 return invalidUserError("username", u.ID)
50 }
51
52 if !isValidEmail(u.Email) {
53 return invalidUserError("email", u.ID)
54 }
55
56 return nil
57}
58
59func isValidID(value string) bool {
60 if len(value) != 26 {
61 return false
62 }
63
64 for _, r := range value {
65 if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
66 return false
67 }
68 }
69
70 return true
71}
72
73func invalidUserError(fieldName string, userID string) error {
74 return errors.Errorf("Invalid User field: %s; id: %s", fieldName, userID)
75}
76
77func isValidUsername(s string) bool {
78 if len(s) < userNameMinLength || len(s) > userNameMaxLength {
79 return false
80 }
81
82 validUsernameChars := regexp.MustCompile(`^[a-z0-9\.\-_]+$`)
83 if !validUsernameChars.MatchString(s) {
84 return false
85 }
86
87 return true
88}
89
90func isValidEmail(email string) bool {
91 if len(email) > userEmailMaxLength || email == "" {
92 return false
93 }
94 if !isLower(email) {
95 return false
96 }
97
98 if addr, err := mail.ParseAddress(email); err != nil {
99 return false
100 } else if addr.Name != "" {
101 // mail.ParseAddress accepts input of the form "Billy Bob <billy@example.com>" which we don't allow
102 return false
103 }
104
105 return true
106}
107
108func isLower(s string) bool {
109 return strings.ToLower(s) == s
110}