args... still needs charset minimums (how?)
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
package pwgenerator
|
||||
|
||||
// Defaults.
|
||||
const (
|
||||
DefCount uint = 1
|
||||
DefMaxLen uint = 256
|
||||
DefMinLin uint = 1
|
||||
)
|
||||
|
||||
// Pre-defined charsets.
|
||||
var (
|
||||
// upper contains the characters from 0x41 to 0x5a ([A-Z]).
|
||||
|
||||
@@ -5,5 +5,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBadType error = errors.New("cannot typeswitch; unsupported type")
|
||||
ErrBadType error = errors.New("cannot typeswitch; unsupported type")
|
||||
ErrTooSmall error = errors.New("password max length too short for specified required chars")
|
||||
ErrSwitchedLenLimits error = errors.New("the max password length is shorter than the minimum password length")
|
||||
)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package pwgenerator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
"sort"
|
||||
)
|
||||
|
||||
@@ -31,3 +34,26 @@ func sortDedupe(charset *CharSet) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
saferRandInt uses crypto/rand instead of math/rand to get a random number.
|
||||
|
||||
While this is cryptographically safer, I guarantee it's a much bigger pain to do.
|
||||
*/
|
||||
func saferRandInt(max int) (randInt int, err error) {
|
||||
|
||||
var max64 int64 = int64(max)
|
||||
var cryptoInt *big.Int = big.NewInt(max64)
|
||||
var cryptoReader *bytes.Buffer = new(bytes.Buffer)
|
||||
var randInt64 int64
|
||||
|
||||
if cryptoInt, err = rand.Int(cryptoReader, cryptoInt); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
randInt64 = cryptoInt.Int64()
|
||||
|
||||
randInt = int(randInt64)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,6 +18,20 @@ func (c *CharSet) Less(i, j int) (isBefore bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// RandChar returns a random character from a CharSet.
|
||||
func (c *CharSet) RandChar() (char Char, err error) {
|
||||
|
||||
var selectIdx int
|
||||
|
||||
if selectIdx, err = saferRandInt(len(*c) - 1); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
char = (*c)[selectIdx]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// String returns a string from a CharSet.
|
||||
func (c *CharSet) String() (s string) {
|
||||
|
||||
|
||||
@@ -2,12 +2,86 @@ package pwgenerator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"r00t2.io/goutils/multierr"
|
||||
)
|
||||
|
||||
// Generate generates a list of passwords for a GenOpts.
|
||||
func (o *GenOpts) Generate() (passwords []string, err error) {
|
||||
|
||||
// TODO
|
||||
var passwds []string = make([]string, o.Count)
|
||||
var charset CharSet = o.Chars()
|
||||
var errs *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
if o.Count == 0 {
|
||||
o.Count = DefCount
|
||||
}
|
||||
if o.LengthMax == 0 {
|
||||
o.LengthMax = DefMaxLen
|
||||
}
|
||||
|
||||
for idx, _ := range passwds {
|
||||
if passwds[idx], err = o.generatePassword(charset); err != nil {
|
||||
errs.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
passwords = passwds
|
||||
|
||||
if !errs.IsEmpty() {
|
||||
err = errs
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// generatePassword generates a single password from CharSet c.
|
||||
func (o *GenOpts) generatePassword(c CharSet) (password string, err error) {
|
||||
|
||||
var maxMin uint
|
||||
var trueMinLen uint
|
||||
var passLenGap uint
|
||||
var passLen int
|
||||
var passAlloc []rune
|
||||
|
||||
// Sanity checks/error conditions.
|
||||
maxMin = o.CountUpper + o.CountLower + o.CountSymbols + o.CountExtended
|
||||
if maxMin > o.LengthMax {
|
||||
err = ErrTooSmall
|
||||
return
|
||||
}
|
||||
if o.LengthMin > o.LengthMax {
|
||||
err = ErrSwitchedLenLimits
|
||||
return
|
||||
}
|
||||
|
||||
// Defaults.
|
||||
trueMinLen = o.LengthMin
|
||||
if trueMinLen == 0 {
|
||||
trueMinLen = DefMinLin
|
||||
}
|
||||
|
||||
// Get a fixed password length...
|
||||
passLenGap = o.LengthMax - trueMinLen
|
||||
if passLen, err = saferRandInt(int(passLenGap)); err != nil {
|
||||
return
|
||||
}
|
||||
passLen = passLen + int(trueMinLen) // (We need to re-add; it was subtracted above to get a zero-shifted number for start in saferRandInt.)
|
||||
// And make the rune slice of that length.
|
||||
passAlloc = make([]rune, passLen)
|
||||
|
||||
for _, idx := range passAlloc {
|
||||
var char Char
|
||||
|
||||
if char, err = c.RandChar(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
passAlloc[idx] = rune(char)
|
||||
}
|
||||
|
||||
password = string(passAlloc)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -35,6 +109,8 @@ func (o *GenOpts) Chars() (chars CharSet) {
|
||||
chars = append(chars, extendedSymbols...)
|
||||
}
|
||||
|
||||
// TODO: Count* fields
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user