func createStrengthPrompt(password []rune) string { symbol, color := "", Red strength := zxcvbn.PasswordStrength(string(password), nil) switch { case strength.Score <= 1: symbol = "✗" color = Red case strength.Score <= 2: symbol = "⚡" color = Magenta case strength.Score <= 3: symbol = "⚠" color = Yellow case strength.Score <= 4: symbol = "✔" color = Green } prompt := Colorize(symbol, color) if strength.Entropy > 0 { entropy := fmt.Sprintf(" %3.0f", strength.Entropy) prompt += Colorize(entropy, Cyan) } else { prompt += Colorize(" ENT", Cyan) } prompt += Colorize(" New Password: ", color) return prompt }
func createStrengthPrompt(password []rune, prefix string) string { symbol, color := "", colors.Red strength := zxcvbn.PasswordStrength(string(password), nil) switch { case strength.Score <= 1: symbol = "✗" color = colors.Red case strength.Score <= 2: symbol = "⚡" color = colors.Magenta case strength.Score <= 3: symbol = "⚠" color = colors.Yellow case strength.Score <= 4: symbol = "✔" color = colors.Green } prompt := colors.Colorize(symbol, color) if strength.Entropy > 0 { entropy := fmt.Sprintf(" %3.0f", strength.Entropy) prompt += colors.Colorize(entropy, colors.Cyan) } else { prompt += colors.Colorize(" ENT", colors.Cyan) } prompt += colors.Colorize(" "+prefix+"passphrase: ", color) return prompt }
// PromptNewPassword asks the user to input a password. // // While typing, the user gets feedback by the prompt color, // which changes with the security of the password to green. // Additionally the entrtopy of the password is shown. // If minEntropy was not reached after hitting enter, // this function will log a message and ask the user again. func PromptNewPassword(minEntropy float64) ([]byte, error) { rl, err := readline.New("") if err != nil { return nil, err } defer util.Closer(rl) passwordCfg := rl.GenPasswordConfig() passwordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { rl.SetPrompt(createStrengthPrompt(line, " New ")) rl.Refresh() return nil, 0, false }) pwd := []byte{} for { pwd, err = rl.ReadPasswordWithConfig(passwordCfg) if err != nil { return nil, err } strength := zxcvbn.PasswordStrength(string(pwd), nil) if strength.Entropy >= minEntropy { break } fmt.Printf(colors.Colorize(msgLowEntropy, colors.Yellow)+"\n", minEntropy) } passwordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { rl.SetPrompt(createStrengthPrompt(line, "Retype ")) rl.Refresh() return nil, 0, false }) fmt.Println(colors.Colorize(msgReEnter, colors.Green)) for { newPwd, err := rl.ReadPasswordWithConfig(passwordCfg) if err != nil { return nil, err } if bytes.Equal(pwd, newPwd) { break } fmt.Println(colors.Colorize(msgBadPassword, colors.Yellow)) } return pwd, nil }
// DeterminePasswordStrength returns a detailed info about the strength of the given password // @userInput e.g. user name. Given strings are matched against password to prohibit similarities between username and password func DeterminePasswordStrength(password string, userInput []string) scoring.MinEntropyMatch { return zxcbvn.PasswordStrength(password, userInput) }