blob: 4ed6cc813f3527f6e0bba76bcf9b752762a4f75a [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.
19// This struct's serializer methods are auto-generated. If a new field is added/removed,
20// please run make gen-serialized.
21type User struct {
22 ID string `json:"id"`
23 CreateAt int64 `json:"create_at,omitempty"`
24 UpdateAt int64 `json:"update_at,omitempty"`
25 DeleteAt int64 `json:"delete_at"`
26 Username string `json:"username"`
27 Password string `json:"password,omitempty"`
28 Email string `json:"email"`
29 EmailVerified bool `json:"email_verified,omitempty"`
30 FirstName string `json:"first_name"`
31 LastName string `json:"last_name"`
32 LastPasswordUpdate int64 `json:"last_password_update,omitempty"`
33}
34
35// IsValid validates the user and returns an error if it isn't configured
36// correctly.
37func (u *User) IsValid() error {
38 if !isValidID(u.ID) {
39 return invalidUserError("id", "")
40 }
41
42 if u.CreateAt == 0 {
43 return invalidUserError("create_at", u.ID)
44 }
45
46 if u.UpdateAt == 0 {
47 return invalidUserError("update_at", u.ID)
48 }
49
50 if !isValidUsername(u.Username) {
51 return invalidUserError("username", u.ID)
52 }
53
54 if !isValidEmail(u.Email) {
55 return invalidUserError("email", u.ID)
56 }
57
58 return nil
59}
60
61func isValidID(value string) bool {
62 if len(value) != 26 {
63 return false
64 }
65
66 for _, r := range value {
67 if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
68 return false
69 }
70 }
71
72 return true
73}
74
75func invalidUserError(fieldName string, userID string) error {
76 return errors.Errorf("Invalid User field: %s; id: %s", fieldName, userID)
77}
78
79func isValidUsername(s string) bool {
80 if len(s) < userNameMinLength || len(s) > userNameMaxLength {
81 return false
82 }
83
84 validUsernameChars := regexp.MustCompile(`^[a-z0-9\.\-_]+$`)
85 if !validUsernameChars.MatchString(s) {
86 return false
87 }
88
89 return true
90}
91
92func isValidEmail(email string) bool {
93 if len(email) > userEmailMaxLength || email == "" {
94 return false
95 }
96 if !isLower(email) {
97 return false
98 }
99
100 if addr, err := mail.ParseAddress(email); err != nil {
101 return false
102 } else if addr.Name != "" {
103 // mail.ParseAddress accepts input of the form "Billy Bob <billy@example.com>" which we don't allow
104 return false
105 }
106
107 return true
108}
109
110func isLower(s string) bool {
111 return strings.ToLower(s) == s
112}