go-pwgen/options.go

113 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
}