-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathname.go
More file actions
130 lines (117 loc) · 3.79 KB
/
name.go
File metadata and controls
130 lines (117 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package codersdk
import (
"fmt"
"regexp"
"strings"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/coderd/util/namesgenerator"
)
var (
UsernameValidRegex = regexp.MustCompile("^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$")
usernameReplace = regexp.MustCompile("[^a-zA-Z0-9-]*")
templateVersionName = regexp.MustCompile(`^[a-zA-Z0-9]+(?:[_.-]{1}[a-zA-Z0-9]+)*$`)
templateDisplayName = regexp.MustCompile(`^[^\s](.*[^\s])?$`)
)
// UsernameFrom returns a best-effort username from the provided string.
//
// It first attempts to validate the incoming string, which will
// be returned if it is valid. It then will attempt to extract
// the username from an email address. If no success happens during
// these steps, a random username will be returned.
func UsernameFrom(str string) string {
if valid := NameValid(str); valid == nil {
return str
}
emailAt := strings.LastIndex(str, "@")
if emailAt >= 0 {
str = str[:emailAt]
}
str = usernameReplace.ReplaceAllString(str, "")
if valid := NameValid(str); valid == nil {
return str
}
return namesgenerator.NameDigitWith("-")
}
// NameValid returns whether the input string is a valid name.
// It is a generic validator for any name (user, workspace, template, role name, etc.).
func NameValid(str string) error {
if len(str) > 32 {
return xerrors.New("must be <= 32 characters")
}
if len(str) < 1 {
return xerrors.New("must be >= 1 character")
}
// Avoid conflicts with routes like /templates/new and /groups/create.
if str == "new" || str == "create" {
return xerrors.Errorf("cannot use %q as a name", str)
}
matched := UsernameValidRegex.MatchString(str)
if !matched {
return xerrors.New("must be alphanumeric with hyphens")
}
return nil
}
// TemplateVersionNameValid returns whether the input string is a valid template version name.
func TemplateVersionNameValid(str string) error {
if len(str) > 64 {
return xerrors.New("must be <= 64 characters")
}
matched := templateVersionName.MatchString(str)
if !matched {
return xerrors.New("must be alphanumeric with underscores and dots")
}
return nil
}
// DisplayNameValid returns whether the input string is a valid template display name.
func DisplayNameValid(str string) error {
if len(str) == 0 {
return nil // empty display_name is correct
}
if len(str) > 64 {
return xerrors.New("must be <= 64 characters")
}
matched := templateDisplayName.MatchString(str)
if !matched {
return xerrors.New("must be alphanumeric with spaces")
}
return nil
}
// UserRealNameValid returns whether the input string is a valid real user name.
func UserRealNameValid(str string) error {
if len(str) > 128 {
return xerrors.New("must be <= 128 characters")
}
if strings.TrimSpace(str) != str {
return xerrors.New("must not have leading or trailing whitespace")
}
return nil
}
// GroupNameValid returns whether the input string is a valid group name.
func GroupNameValid(str string) error {
// We want to support longer names for groups to allow users to sync their
// group names with their identity providers without manual mapping. Related
// to: https://github.com/coder/coder/issues/15184
limit := 255
if len(str) > limit {
return xerrors.New(fmt.Sprintf("must be <= %d characters", limit))
}
// Avoid conflicts with routes like /groups/new and /groups/create.
if str == "new" || str == "create" {
return xerrors.Errorf("cannot use %q as a name", str)
}
matched := UsernameValidRegex.MatchString(str)
if !matched {
return xerrors.New("must be alphanumeric with hyphens")
}
return nil
}
// NormalizeUserRealName normalizes a user name such that it will pass
// validation by UserRealNameValid. This is done to avoid blocking
// little Bobby Whitespace from using Coder.
func NormalizeRealUsername(str string) string {
s := strings.TrimSpace(str)
if len(s) > 128 {
s = s[:128]
}
return s
}