github.com/infraboard/keyauth@v0.8.1/common/password/generator.go (about) 1 package password 2 3 import ( 4 "crypto/rand" 5 "math/big" 6 "strings" 7 ) 8 9 // Generator is what generates the password 10 type Generator struct { 11 *Config 12 } 13 14 // New returns a new generator 15 func New(config *Config) *Generator { 16 if config == nil { 17 config = &DefaultConfig 18 } 19 20 if !config.IncludeSymbols && 21 !config.IncludeUppercaseLetters && 22 !config.IncludeLowercaseLetters && 23 !config.IncludeNumbers && 24 config.CharacterSet == "" { 25 config = &DefaultConfig 26 } 27 28 if config.Length == 0 { 29 config.Length = LengthStrong 30 } 31 32 if config.CharacterSet == "" { 33 config.CharacterSet = buildCharacterSet(config) 34 } 35 36 return &Generator{Config: config} 37 } 38 39 func buildCharacterSet(config *Config) string { 40 var characterSet string 41 if config.IncludeLowercaseLetters { 42 characterSet += DefaultLetterSet 43 if config.ExcludeSimilarCharacters { 44 characterSet = removeCharacters(characterSet, DefaultLetterAmbiguousSet) 45 } 46 } 47 48 if config.IncludeUppercaseLetters { 49 characterSet += strings.ToUpper(DefaultLetterSet) 50 if config.ExcludeSimilarCharacters { 51 characterSet = removeCharacters(characterSet, strings.ToUpper(DefaultLetterAmbiguousSet)) 52 } 53 } 54 55 if config.IncludeNumbers { 56 characterSet += DefaultNumberSet 57 if config.ExcludeSimilarCharacters { 58 characterSet = removeCharacters(characterSet, DefaultNumberAmbiguousSet) 59 } 60 } 61 62 if config.IncludeSymbols { 63 characterSet += DefaultSymbolSet 64 if config.ExcludeAmbiguousCharacters { 65 characterSet = removeCharacters(characterSet, DefaultSymbolAmbiguousSet) 66 } 67 } 68 69 return characterSet 70 } 71 72 func removeCharacters(str, characters string) string { 73 return strings.Map(func(r rune) rune { 74 if !strings.ContainsRune(characters, r) { 75 return r 76 } 77 return -1 78 }, str) 79 } 80 81 // NewWithDefault returns a new generator with the default 82 // config 83 func NewWithDefault() *Generator { 84 return New(&DefaultConfig) 85 } 86 87 // Generate generates one password with length set in the 88 // config 89 func (g Generator) Generate() (*string, error) { 90 var generated string 91 characterSet := strings.Split(g.Config.CharacterSet, "") 92 max := big.NewInt(int64(len(characterSet))) 93 94 for i := 0; i < g.Config.Length; i++ { 95 val, err := rand.Int(rand.Reader, max) 96 if err != nil { 97 return nil, err 98 } 99 generated += characterSet[val.Int64()] 100 } 101 return &generated, nil 102 } 103 104 // GenerateMany generates multiple passwords with length set 105 // in the config 106 func (g Generator) GenerateMany(amount int) ([]string, error) { 107 var generated []string 108 for i := 0; i < amount; i++ { 109 str, err := g.Generate() 110 if err != nil { 111 return nil, err 112 } 113 114 generated = append(generated, *str) 115 } 116 return generated, nil 117 } 118 119 // GenerateWithLength generate one password with set length 120 func (g Generator) GenerateWithLength(length int) (*string, error) { 121 var generated string 122 characterSet := strings.Split(g.Config.CharacterSet, "") 123 max := big.NewInt(int64(len(characterSet))) 124 for i := 0; i < length; i++ { 125 val, err := rand.Int(rand.Reader, max) 126 if err != nil { 127 return nil, err 128 } 129 generated += characterSet[val.Int64()] 130 } 131 return &generated, nil 132 } 133 134 // GenerateManyWithLength generates multiple passwords with set length 135 func (g Generator) GenerateManyWithLength(amount, length int) ([]string, error) { 136 var generated []string 137 for i := 0; i < amount; i++ { 138 str, err := g.GenerateWithLength(length) 139 if err != nil { 140 return nil, err 141 } 142 generated = append(generated, *str) 143 } 144 return generated, nil 145 }