/
generator.go
145 lines (125 loc) · 3.34 KB
/
generator.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
139
140
141
142
143
144
145
package password
import (
"crypto/rand"
"math/big"
"strings"
)
// Generator is what generates the password
type Generator struct {
*Config
}
// New returns a new generator
func New(config *Config) *Generator {
if config == nil {
config = &DefaultConfig
}
if !config.IncludeSymbols &&
!config.IncludeUppercaseLetters &&
!config.IncludeLowercaseLetters &&
!config.IncludeNumbers &&
config.CharacterSet == "" {
config = &DefaultConfig
}
if config.Length == 0 {
config.Length = LengthStrong
}
if config.CharacterSet == "" {
config.CharacterSet = buildCharacterSet(config)
}
return &Generator{Config: config}
}
func buildCharacterSet(config *Config) string {
var characterSet string
if config.IncludeLowercaseLetters {
characterSet += DefaultLetterSet
if config.ExcludeSimilarCharacters {
characterSet = removeCharacters(characterSet, DefaultLetterAmbiguousSet)
}
}
if config.IncludeUppercaseLetters {
characterSet += strings.ToUpper(DefaultLetterSet)
if config.ExcludeSimilarCharacters {
characterSet = removeCharacters(characterSet, strings.ToUpper(DefaultLetterAmbiguousSet))
}
}
if config.IncludeNumbers {
characterSet += DefaultNumberSet
if config.ExcludeSimilarCharacters {
characterSet = removeCharacters(characterSet, DefaultNumberAmbiguousSet)
}
}
if config.IncludeSymbols {
characterSet += DefaultSymbolSet
if config.ExcludeAmbiguousCharacters {
characterSet = removeCharacters(characterSet, DefaultSymbolAmbiguousSet)
}
}
return characterSet
}
func removeCharacters(str, characters string) string {
return strings.Map(func(r rune) rune {
if !strings.ContainsRune(characters, r) {
return r
}
return -1
}, str)
}
// NewWithDefault returns a new generator with the default
// config
func NewWithDefault() *Generator {
return New(&DefaultConfig)
}
// Generate generates one password with length set in the
// config
func (g Generator) Generate() (*string, error) {
var generated string
characterSet := strings.Split(g.Config.CharacterSet, "")
max := big.NewInt(int64(len(characterSet)))
for i := 0; i < g.Config.Length; i++ {
val, err := rand.Int(rand.Reader, max)
if err != nil {
return nil, err
}
generated += characterSet[val.Int64()]
}
return &generated, nil
}
// GenerateMany generates multiple passwords with length set
// in the config
func (g Generator) GenerateMany(amount int) ([]string, error) {
var generated []string
for i := 0; i < amount; i++ {
str, err := g.Generate()
if err != nil {
return nil, err
}
generated = append(generated, *str)
}
return generated, nil
}
// GenerateWithLength generate one password with set length
func (g Generator) GenerateWithLength(length int) (*string, error) {
var generated string
characterSet := strings.Split(g.Config.CharacterSet, "")
max := big.NewInt(int64(len(characterSet)))
for i := 0; i < length; i++ {
val, err := rand.Int(rand.Reader, max)
if err != nil {
return nil, err
}
generated += characterSet[val.Int64()]
}
return &generated, nil
}
// GenerateManyWithLength generates multiple passwords with set length
func (g Generator) GenerateManyWithLength(amount, length int) ([]string, error) {
var generated []string
for i := 0; i < amount; i++ {
str, err := g.GenerateWithLength(length)
if err != nil {
return nil, err
}
generated = append(generated, *str)
}
return generated, nil
}