#53 Add coinflip algorithm and improve error messages

Introduced a new password generation algorithm, called 'coinflip', which simply returns "Heads" or "Tails". Associated CLI flag has been added as well. Also, improved error messages during password generation. This addition provides a simpler algorithm option and clearer user feedback during errors.
This commit is contained in:
Winni Neessen 2023-08-05 18:10:11 +02:00
parent 8d42651e58
commit 2822f73f56
Signed by: wneessen
GPG key ID: 5F3AF39B820C119D
3 changed files with 42 additions and 4 deletions

View file

@ -11,6 +11,9 @@ const (
// AlgoRandom represents the algorithm for purely random passwords according
// to the provided password modes/flags
AlgoRandom
// AlgoCoinFlip represents a very simple coinflip algorithm returning "heads"
// or "tails"
AlgoCoinFlip
// AlgoUnsupported represents an unsupported algorithm
AlgoUnsupported
)
@ -23,6 +26,8 @@ func IntToAlgo(a int) Algorithm {
return AlgoPronouncable
case 1:
return AlgoRandom
case 2:
return AlgoCoinFlip
default:
return AlgoUnsupported
}

View file

@ -15,8 +15,10 @@ func main() {
// Configure and parse the CLI flags
// See usage() for flag details
var al int
var ms string
var co, hr, lc, nu, sp, uc bool
flag.IntVar(&al, "a", 1, "")
flag.BoolVar(&lc, "L", false, "")
flag.Int64Var(&c.MinLowerCase, "mL", c.MinLowerCase, "")
flag.BoolVar(&uc, "U", false, "")
@ -62,14 +64,22 @@ func main() {
c.Mode = apg.ModesFromFlags(ms)
}
// Check if algorithm is supported
c.Algorithm = apg.IntToAlgo(al)
if c.Algorithm == apg.AlgoUnsupported {
_, _ = fmt.Fprintf(os.Stderr, "unsupported algorithm value: %d\n", al)
os.Exit(1)
}
// Generate the password based on the given flags
g := apg.New(c)
for i := int64(0); i < c.NumberPass; i++ {
pl, err := g.GetPasswordLength()
p, err := g.Generate()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Error during password generation: %s\n", err)
_, _ = fmt.Fprintf(os.Stderr, "failed to generate password: %s\n", err)
os.Exit(1)
}
fmt.Printf("PW length: %d\n", pl)
fmt.Println(p)
}
}
@ -88,6 +98,7 @@ Flags:
-a ALGORITH Choose the password generation algorithm (Default: 1)
- 0: pronounceable password generation (koremutake syllables)
- 1: random password generation according to password modes/flags
- 2: coinflip (returns heads or tails)
-m LENGTH Minimum length of the password to be generated (Default: 12)
-x LENGTH Maximum length of the password to be generated (Default: 20)
-f LENGTH Fixed length of the password to be generated (Ignores -m and -x)

View file

@ -27,6 +27,28 @@ var (
ErrInvalidCharRange = errors.New("provided character range is not valid or empty")
)
// Generate generates a password based on all the different config flags and returns
// it as string type. If the generation fails, an error will be thrown
func (g *Generator) Generate() (string, error) {
// Coinflip mode
if g.config.Algorithm == AlgoCoinFlip {
switch g.CoinFlipBool() {
case true:
return "Heads", nil
case false:
return "Tails", nil
}
}
l, err := g.GetPasswordLength()
if err != nil {
return "", fmt.Errorf("failed to calculate password length: %w", err)
}
_ = l
return "", nil
}
// RandomBytes returns a byte slice of random bytes with length n that got generated by
// the crypto/rand generator
func (g *Generator) RandomBytes(n int64) ([]byte, error) {
@ -121,7 +143,7 @@ func (g *Generator) GetPasswordLength() (int64, error) {
diff := mal - mil + 1
ra, err := g.RandNum(diff)
if err != nil {
return 0, fmt.Errorf("failed to calculate password length: %w", err)
return 0, err
}
l := mil + ra
if l <= 0 {