blob: afcef45b3ec262d19f97afa2ea26376030c79cfa [file] [log] [blame]
// This is a small example using readline to read a password
// and check it's strength while typing using the zxcvbn library.
// Depending on the strength the prompt is colored nicely to indicate strength.
//
// This file is licensed under the WTFPL:
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
package main
import (
"fmt"
"github.com/chzyer/readline"
zxcvbn "github.com/nbutton23/zxcvbn-go"
)
const (
Cyan = 36
Green = 32
Magenta = 35
Red = 31
Yellow = 33
BackgroundRed = 41
)
// Reset sequence
var ColorResetEscape = "\033[0m"
// ColorResetEscape translates a ANSI color number to a color escape.
func ColorEscape(color int) string {
return fmt.Sprintf("\033[0;%dm", color)
}
// Colorize the msg using ANSI color escapes
func Colorize(msg string, color int) string {
return ColorEscape(color) + msg + ColorResetEscape
}
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 main() {
rl, err := readline.New("")
if err != nil {
return
}
defer rl.Close()
setPasswordCfg := rl.GenPasswordConfig()
setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
rl.SetPrompt(createStrengthPrompt(line))
rl.Refresh()
return nil, 0, false
})
pswd, err := rl.ReadPasswordWithConfig(setPasswordCfg)
if err != nil {
return
}
fmt.Println("Your password was:", string(pswd))
}