-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpassword.go
138 lines (129 loc) · 3.28 KB
/
password.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
131
132
133
134
135
136
137
138
package password
import (
"crypto/rand"
"math/big"
)
type Charset int
const (
Uppercase Charset = 1 << iota // 1 << 0 which is 00000001
Lowercase // 1 << 1 which is 00000010
Numbers // 1 << 2 which is 00000100
Unreserved // 1 << 3 which is 00001000
Reserved // 1 << 4 which is 00010000
SimpleSymbols // 1 << 5 which is 00100000
Symbols // 1 << 6 which is 01000000
AlphaNum = Uppercase | Lowercase | Numbers
Default = Uppercase | Lowercase | Numbers | SimpleSymbols
)
var (
uppercase = []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZ`)
len_uppercase = len(uppercase)
lowercase = []byte(`abcdefghijklmnopqrstuvwxyz`)
len_lowercase = len(lowercase)
numbers = []byte(`0123456789`)
len_numbers = len(numbers)
unreserved = []byte(`-._~`) // ref: https://perishablepress.com/stop-using-unsafe-characters-in-urls/
len_unreserved = len(unreserved)
reserved = []byte(`!#$&'()*+,/:;=?@[]`)
len_reserved = len(reserved)
simple_symbols = []byte(`!()*.;_~`) // ref: https://github.com/golang/go/blob/release-branch.go1.15/src/net/url/url.go#L1158-L1186 , missing: Unreserved | Reserved - #/?[]':+@,-=$&
len_simple_symbols = len(simple_symbols)
symbols = []byte(`!"#$%&'()*+,-./:;<=>?@^[\]_{|}~` + "`")
len_symbols = len(symbols)
)
func Generate(n int) string {
if n <= 2 {
return GenerateForCharset(n, AlphaNum)
}
return GenerateForCharset(1, AlphaNum) + GenerateForCharset(n-2, Default) + GenerateForCharset(1, AlphaNum)
}
func GenerateForCharset(n int, chset Charset) string {
buf := make([]byte, n)
count := 0
if chset&Uppercase != 0 {
count += len_uppercase
}
if chset&Lowercase != 0 {
count += len_lowercase
}
if chset&Numbers != 0 {
count += len_numbers
}
if chset&Unreserved != 0 {
count += len_unreserved
}
if chset&Reserved != 0 {
count += len_reserved
}
if chset&SimpleSymbols != 0 {
count += len_simple_symbols
}
if chset&Symbols != 0 {
count += len_symbols
}
max := big.NewInt(int64(count))
for i := 0; i < n; i++ {
r, err := rand.Int(rand.Reader, max)
if err != nil {
panic(err)
}
idx := int(r.Int64())
if chset&Uppercase != 0 {
if idx < len_uppercase {
buf[i] = uppercase[idx]
continue
} else {
idx -= len_uppercase
}
}
if chset&Lowercase != 0 {
if idx < len_lowercase {
buf[i] = lowercase[idx]
continue
} else {
idx -= len_lowercase
}
}
if chset&Numbers != 0 {
if idx < len_numbers {
buf[i] = numbers[idx]
continue
} else {
idx -= len_numbers
}
}
if chset&Unreserved != 0 {
if idx < len_unreserved {
buf[i] = unreserved[idx]
continue
} else {
idx -= len_unreserved
}
}
if chset&Reserved != 0 {
if idx < len_reserved {
buf[i] = reserved[idx]
continue
} else {
idx -= len_reserved
}
}
if chset&SimpleSymbols != 0 {
if idx < len_simple_symbols {
buf[i] = simple_symbols[idx]
continue
} else {
idx -= len_simple_symbols
}
}
if chset&Symbols != 0 {
if idx < len_symbols {
buf[i] = symbols[idx]
continue
} else {
idx -= len_symbols
}
}
}
return string(buf)
}