9e2d6932f6
This adds the "airshipctl document" tree of commands, as well as one of its leaf commands, "generate masterpassphrase". Change-Id: I2365ebe67b38ebbbe4873c6e1beb6407f0e000eb
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
package secret
|
|
|
|
import (
|
|
"math/rand"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
defaultLength = 24
|
|
|
|
asciiLowers = "abcdefghijklmnopqrstuvwxyz"
|
|
asciiUppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
asciiNumbers = "0123456789"
|
|
asciiSymbols = "@#&-+=?"
|
|
)
|
|
|
|
var (
|
|
// pool is the complete collection of characters that can be used for a
|
|
// passphrase
|
|
pool []byte
|
|
)
|
|
|
|
func init() {
|
|
pool = append(pool, []byte(asciiLowers)...)
|
|
pool = append(pool, []byte(asciiUppers)...)
|
|
pool = append(pool, []byte(asciiNumbers)...)
|
|
pool = append(pool, []byte(asciiSymbols)...)
|
|
}
|
|
|
|
// PassphraseEngine is used to generate secure random passphrases
|
|
type PassphraseEngine struct {
|
|
rng *rand.Rand
|
|
pool []byte
|
|
}
|
|
|
|
// NewPassphraseEngine creates an PassphraseEngine using src. If src is nil,
|
|
// the returned PassphraseEngine will use the default Source
|
|
func NewPassphraseEngine(src rand.Source) *PassphraseEngine {
|
|
if src == nil {
|
|
src = &Source{}
|
|
}
|
|
return &PassphraseEngine{
|
|
rng: rand.New(src),
|
|
pool: pool,
|
|
}
|
|
}
|
|
|
|
// GeneratePassphrase returns a secure random string of length 24,
|
|
// containing at least one of each from the following sets:
|
|
// [0-9]
|
|
// [a-z]
|
|
// [A-Z]
|
|
// [@#&-+=?]
|
|
func (e *PassphraseEngine) GeneratePassphrase() string {
|
|
return e.GeneratePassphraseN(defaultLength)
|
|
}
|
|
|
|
// GeneratePassphraseN returns a secure random string containing at least
|
|
// one of each from the following sets. Its length will be max(length, 24)
|
|
// [0-9]
|
|
// [a-z]
|
|
// [A-Z]
|
|
// [@#&-+=?]
|
|
func (e *PassphraseEngine) GeneratePassphraseN(length int) string {
|
|
if length < defaultLength {
|
|
length = defaultLength
|
|
}
|
|
var passPhrase string
|
|
for !e.isValidPassphrase(passPhrase) {
|
|
var sb strings.Builder
|
|
for i := 0; i < length; i++ {
|
|
randIndex := e.rng.Intn(len(e.pool))
|
|
randChar := e.pool[randIndex]
|
|
sb.WriteString(string(randChar))
|
|
}
|
|
passPhrase = sb.String()
|
|
}
|
|
return passPhrase
|
|
}
|
|
|
|
func (e *PassphraseEngine) isValidPassphrase(passPhrase string) bool {
|
|
if len(passPhrase) < defaultLength {
|
|
return false
|
|
}
|
|
|
|
charSets := []string{
|
|
asciiLowers,
|
|
asciiUppers,
|
|
asciiNumbers,
|
|
asciiSymbols,
|
|
}
|
|
for _, charSet := range charSets {
|
|
if !strings.ContainsAny(passPhrase, charSet) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|