go-pwgen/pwgen.go

80 lines
2 KiB
Go

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
}