-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathuser.go
130 lines (113 loc) · 3.64 KB
/
user.go
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
// Copyright 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package names
import (
"fmt"
"regexp"
)
const (
UserTagKind = "user"
LocalUserDomain = "local"
)
var (
// TODO this does not allow single character usernames or
// domains. Is that deliberate?
// https://github.com/juju/names/issues/54
validUserNameSnippet = "[a-zA-Z0-9][a-zA-Z0-9.+-]*[a-zA-Z0-9]"
validUserSnippet = fmt.Sprintf("(?:%s(?:@%s)?)", validUserNameSnippet, validUserNameSnippet)
validName = regexp.MustCompile(fmt.Sprintf("^(?P<name>%s)(?:@(?P<domain>%s))?$", validUserNameSnippet, validUserNameSnippet))
validUserName = regexp.MustCompile("^" + validUserNameSnippet + "$")
)
// IsValidUser returns whether id is a valid user id.
// Valid users may or may not be qualified with an
// @domain suffix. Examples of valid users include
// bob, bob@local, bob@somewhere-else, 0-a-f@123.
func IsValidUser(id string) bool {
return validName.MatchString(id)
}
// IsValidUserName returns whether the given
// name is a valid name part of a user. That is,
// usernames with a domain suffix will return
// false.
func IsValidUserName(name string) bool {
return validUserName.MatchString(name)
}
// IsValidUserDomain returns whether the given user
// domain is valid.
func IsValidUserDomain(domain string) bool {
return validUserName.MatchString(domain)
}
// UserTag represents a user that may be stored locally
// or associated with some external domain.
type UserTag struct {
name string
domain string
}
func (t UserTag) Kind() string { return UserTagKind }
func (t UserTag) String() string { return UserTagKind + "-" + t.Id() }
// Id implements Tag.Id. Local users will always have
// an Id value without any domain.
func (t UserTag) Id() string {
if t.domain == "" || t.domain == LocalUserDomain {
return t.name
}
return t.name + "@" + t.domain
}
// Name returns the name part of the user name
// without its associated domain.
func (t UserTag) Name() string { return t.name }
// IsLocal returns true if the tag represents a local user.
// Users without an explicit domain are considered local.
func (t UserTag) IsLocal() bool {
return t.Domain() == LocalUserDomain || t.Domain() == ""
}
// Domain returns the user domain. Users in the local database
// are from the LocalDomain. Other users are considered 'remote' users.
func (t UserTag) Domain() string {
return t.domain
}
// WithDomain returns a copy of the user tag with the
// domain changed to the given argument.
// The domain must satisfy IsValidUserDomain
// or this function will panic.
func (t UserTag) WithDomain(domain string) UserTag {
if !IsValidUserDomain(domain) {
panic(fmt.Sprintf("invalid user domain %q", domain))
}
return UserTag{
name: t.name,
domain: domain,
}
}
// NewUserTag returns the tag for the user with the given name.
// It panics if the user name does not satisfy IsValidUser.
func NewUserTag(userName string) UserTag {
parts := validName.FindStringSubmatch(userName)
if len(parts) != 3 {
panic(fmt.Sprintf("invalid user tag %q", userName))
}
domain := parts[2]
if domain == LocalUserDomain {
domain = ""
}
return UserTag{name: parts[1], domain: domain}
}
// NewLocalUserTag returns the tag for a local user with the given name.
func NewLocalUserTag(name string) UserTag {
if !IsValidUserName(name) {
panic(fmt.Sprintf("invalid user name %q", name))
}
return UserTag{name: name}
}
// ParseUserTag parses a user tag string.
func ParseUserTag(tag string) (UserTag, error) {
t, err := ParseTag(tag)
if err != nil {
return UserTag{}, err
}
ut, ok := t.(UserTag)
if !ok {
return UserTag{}, invalidTagError(tag, UserTagKind)
}
return ut, nil
}