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 }