1
0
mirror of https://github.com/Luzifer/password.git synced 2024-09-19 10:22:56 +00:00
password/lib/xkcd.go

71 lines
1.6 KiB
Go
Raw Normal View History

package securepassword
import (
"errors"
"fmt"
"strings"
"time"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/Luzifer/go_helpers/v2/str"
)
type (
// XKCD represents a XKCD-style password generator
XKCD struct {
// Separator to be used between words
Separator string
}
)
var (
// ErrTooFewWords represents an error thrown if the password will
// have fewer than four words and are not considered to be safe
ErrTooFewWords = errors.New("XKCD passwords with less than 4 words makes no sense")
// DefaultXKCD contains an default instance of the XKCD password
// generator
DefaultXKCD = NewXKCDGenerator()
)
// NewXKCDGenerator initializes a new XKCD password generator
// https://xkcd.com/936/
func NewXKCDGenerator() *XKCD { return &XKCD{} }
// GeneratePassword generates a password with the number of words
// given and optionally the current date prepended
//
//revive:disable-next-line:flag-parameter
func (x XKCD) GeneratePassword(length int, addDate bool) (string, error) {
if length < minPasswordLength {
return "", ErrTooFewWords
}
var (
password string
usedWords []string
)
if addDate {
password = time.Now().Format("20060102.")
}
for len(usedWords) < length {
widx, err := randIntn(len(xkcdWordList))
if err != nil {
return "", fmt.Errorf("generating random number: %w", err)
}
word := cases.Title(language.AmericanEnglish).String(xkcdWordList[widx])
if str.StringInSlice(word, usedWords) {
// Don't use a word twice
continue
}
usedWords = append(usedWords, word)
}
return password + strings.Join(usedWords, x.Separator), nil
}