You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
2.4 KiB

  1. // This is a small example using readline to read a password
  2. // and check it's strength while typing using the zxcvbn library.
  3. // Depending on the strength the prompt is colored nicely to indicate strength.
  4. //
  5. // This file is licensed under the WTFPL:
  6. //
  7. // DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  8. // Version 2, December 2004
  9. //
  10. // Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  11. //
  12. // Everyone is permitted to copy and distribute verbatim or modified
  13. // copies of this license document, and changing it is allowed as long
  14. // as the name is changed.
  15. //
  16. // DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  17. // TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  18. //
  19. // 0. You just DO WHAT THE FUCK YOU WANT TO.
  20. package main
  21. import (
  22. "fmt"
  23. "github.com/chzyer/readline"
  24. zxcvbn "github.com/nbutton23/zxcvbn-go"
  25. )
  26. const (
  27. Cyan = 36
  28. Green = 32
  29. Magenta = 35
  30. Red = 31
  31. Yellow = 33
  32. BackgroundRed = 41
  33. )
  34. // Reset sequence
  35. var ColorResetEscape = "\033[0m"
  36. // ColorResetEscape translates a ANSI color number to a color escape.
  37. func ColorEscape(color int) string {
  38. return fmt.Sprintf("\033[0;%dm", color)
  39. }
  40. // Colorize the msg using ANSI color escapes
  41. func Colorize(msg string, color int) string {
  42. return ColorEscape(color) + msg + ColorResetEscape
  43. }
  44. func createStrengthPrompt(password []rune) string {
  45. symbol, color := "", Red
  46. strength := zxcvbn.PasswordStrength(string(password), nil)
  47. switch {
  48. case strength.Score <= 1:
  49. symbol = "✗"
  50. color = Red
  51. case strength.Score <= 2:
  52. symbol = "⚡"
  53. color = Magenta
  54. case strength.Score <= 3:
  55. symbol = "⚠"
  56. color = Yellow
  57. case strength.Score <= 4:
  58. symbol = "✔"
  59. color = Green
  60. }
  61. prompt := Colorize(symbol, color)
  62. if strength.Entropy > 0 {
  63. entropy := fmt.Sprintf(" %3.0f", strength.Entropy)
  64. prompt += Colorize(entropy, Cyan)
  65. } else {
  66. prompt += Colorize(" ENT", Cyan)
  67. }
  68. prompt += Colorize(" New Password: ", color)
  69. return prompt
  70. }
  71. func main() {
  72. rl, err := readline.New("")
  73. if err != nil {
  74. return
  75. }
  76. defer rl.Close()
  77. setPasswordCfg := rl.GenPasswordConfig()
  78. setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
  79. rl.SetPrompt(createStrengthPrompt(line))
  80. rl.Refresh()
  81. return nil, 0, false
  82. })
  83. pswd, err := rl.ReadPasswordWithConfig(setPasswordCfg)
  84. if err != nil {
  85. return
  86. }
  87. fmt.Println("Your password was:", string(pswd))
  88. }