112 lines
2.3 KiB
Go
112 lines
2.3 KiB
Go
package pwgen
|
|
|
|
import (
|
|
"errors"
|
|
)
|
|
|
|
const (
|
|
DefaultLength = 20
|
|
DefaultSpecialsAlphabet = `!?~@#$%^&*()-+={}[]\/{}|<>`
|
|
)
|
|
|
|
var ErrLengthOverflow = errors.New("length overflow")
|
|
|
|
type generationOptionFunc func(options *options)
|
|
|
|
func (f generationOptionFunc) ApplyToOptions(options *options) {
|
|
f(options)
|
|
}
|
|
|
|
func WithLength(length uint) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
options.Length = length
|
|
})
|
|
}
|
|
|
|
func WithLetters(letters uint) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
options.Letters = letters
|
|
})
|
|
}
|
|
|
|
func WithUppercase(uppercase uint) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
options.Uppercase = uppercase
|
|
})
|
|
}
|
|
|
|
func WithLowercase(lowercase uint) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
options.Lowercase = lowercase
|
|
})
|
|
}
|
|
|
|
func WithDigits(digits uint) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
options.Digits = digits
|
|
})
|
|
}
|
|
|
|
func WithSpecials(specials uint) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
options.Specials = specials
|
|
})
|
|
}
|
|
|
|
func WithSpecialsAlphabet(specialsAlphabet string) GenerationOption {
|
|
return generationOptionFunc(func(options *options) {
|
|
if specialsAlphabet == "" {
|
|
specialsAlphabet = DefaultSpecialsAlphabet
|
|
}
|
|
options.SpecialsAlphabet = specialsAlphabet
|
|
})
|
|
}
|
|
|
|
func defaultOptions(opts ...GenerationOption) *options {
|
|
o := &options{
|
|
Length: DefaultLength,
|
|
Letters: 0,
|
|
Digits: 3,
|
|
Uppercase: 3,
|
|
Lowercase: 3,
|
|
Specials: 3,
|
|
SpecialsAlphabet: DefaultSpecialsAlphabet,
|
|
}
|
|
|
|
for i := range opts {
|
|
opts[i].ApplyToOptions(o)
|
|
}
|
|
|
|
return o
|
|
}
|
|
|
|
type options struct {
|
|
Length uint
|
|
Letters uint
|
|
Digits uint
|
|
Uppercase uint
|
|
Lowercase uint
|
|
Specials uint
|
|
SpecialsAlphabet string
|
|
}
|
|
|
|
func (o options) effectiveLength() (uint, error) {
|
|
var length uint
|
|
|
|
for _, i := range []uint{o.Digits, o.Lowercase, o.Uppercase, o.Specials} {
|
|
if length+i < length {
|
|
return 0, ErrLengthOverflow
|
|
}
|
|
length += i
|
|
}
|
|
|
|
if upperAndLower := o.Lowercase + o.Uppercase; upperAndLower < o.Letters {
|
|
length += o.Letters - upperAndLower
|
|
}
|
|
|
|
if length > o.Length {
|
|
return length, nil
|
|
}
|
|
|
|
return o.Length, nil
|
|
}
|