package pwgenerator import ( "crypto/rand" "math/big" insecureRand "math/rand" "sort" "strings" ) // newCryptoShuffler returns a new cryptoShuffler. func newCryptoShuffler() *cryptoShuffler { return new(cryptoShuffler) } /* GetCharset returns a CharSet from a set of characters. chars can be one of []rune, []byte, []string, or string. */ func GetCharset(chars interface{}) (charset CharSet, err error) { switch t := chars.(type) { case []rune: charset = CharSet(string(t)) case []byte: charset = CharSet(string(t)) case []string: s := strings.Join(t, "") charset = CharSet(s) case string: charset = CharSet(t) default: err = ErrBadType return } return } // sortDedupe sorts a slice of runes and deduplicates them. func sortDedupe(charset *CharSet) { var vals map[Char]bool = make(map[Char]bool) var sorted CharSet var idx int // This inherently dedupes. for _, i := range *charset { vals[i] = true } // This handles sorting. sorted = make(CharSet, len(vals)) // First we need a slice (again). for k := range vals { sorted[idx] = k idx++ } // And now we can sort... sort.Sort(&sorted) // And replace the original charset with the sorted, deduplicated one. *charset = sorted 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) { // Avoid a panic on max being 0 per rand.Int. if max == 0 { max = 1 } var max64 int64 = int64(max) var cryptoInt *big.Int = big.NewInt(max64) var randInt64 int64 if cryptoInt, err = rand.Int(rand.Reader, cryptoInt); err != nil { return } randInt64 = cryptoInt.Int64() randInt = int(randInt64) return } // passwordShuffle shuffles a password's characters ordering so we don't have the condition satisfiers in the beginning. func passwordShuffle(passwd *string) { var r *insecureRand.Rand = insecureRand.New(newCryptoShuffler()) r.Shuffle( len(*passwd), func(i, j int) { var chars []rune = []rune(*passwd) chars[i], chars[j] = chars[j], chars[i] *passwd = string(chars) }, ) return }