package pwgen import ( "math/rand" "time" ) var ( _ Generator = (*DefaultGenerator)(nil) Default = NewDefaultGenerator(nil) lowerCase = alphabet('a', 'z') upperCase = alphabet('A', 'Z') letters = merge(lowerCase, upperCase) digits = alphabet('0', '9') ) func Generate(opts ...GenerationOption) (string, error) { return Default.Generate(opts...) } func MustGenerate(opts ...GenerationOption) string { if pw, err := Generate(opts...); err != nil { panic(err) } else { return pw } } func NewDefaultGenerator(prng Int32n) DefaultGenerator { if prng == nil { prng = rand.New(rand.NewSource(time.Now().UnixNano())) } return DefaultGenerator{ PRNG: prng, } } type DefaultGenerator struct { PRNG Int32n } func (d DefaultGenerator) Generate(opts ...GenerationOption) (string, error) { compiledOptions := defaultOptions(opts...) fullAlphabet := merge(lowerCase, upperCase, digits, []rune(compiledOptions.SpecialsAlphabet)) effectiveLength, err := compiledOptions.effectiveLength() if err != nil { return "", err } generated := make([]rune, 0, effectiveLength) for i := uint(0); i < compiledOptions.Lowercase; i++ { generated = append(generated, runeFor(lowerCase, d.PRNG)) } for i := uint(0); i < compiledOptions.Uppercase; i++ { generated = append(generated, runeFor(upperCase, d.PRNG)) } for i := uint(0); i < compiledOptions.Digits; i++ { generated = append(generated, runeFor(digits, d.PRNG)) } for i := uint(0); i < compiledOptions.Specials; i++ { generated = append(generated, runeFor([]rune(compiledOptions.SpecialsAlphabet), d.PRNG)) } for i := compiledOptions.Lowercase + compiledOptions.Uppercase; i < compiledOptions.Letters; i++ { generated = append(generated, runeFor(letters, d.PRNG)) } for i := uint(len(generated)); i < effectiveLength; i++ { generated = append(generated, runeFor(fullAlphabet, d.PRNG)) } return string(shuffle(generated, d.PRNG)), nil }