hash_password 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #!/usr/bin/env python
  2. import argparse
  3. import getpass
  4. import sys
  5. import unicodedata
  6. import bcrypt
  7. import yaml
  8. bcrypt_rounds = 12
  9. password_pepper = ""
  10. def prompt_for_pass():
  11. password = getpass.getpass("Password: ")
  12. if not password:
  13. raise Exception("Password cannot be blank.")
  14. confirm_password = getpass.getpass("Confirm password: ")
  15. if password != confirm_password:
  16. raise Exception("Passwords do not match.")
  17. return password
  18. if __name__ == "__main__":
  19. parser = argparse.ArgumentParser(
  20. description=(
  21. "Calculate the hash of a new password, so that passwords can be reset"
  22. )
  23. )
  24. parser.add_argument(
  25. "-p",
  26. "--password",
  27. default=None,
  28. help="New password for user. Will prompt if omitted.",
  29. )
  30. parser.add_argument(
  31. "-c",
  32. "--config",
  33. type=argparse.FileType('r'),
  34. help=(
  35. "Path to server config file. "
  36. "Used to read in bcrypt_rounds and password_pepper."
  37. ),
  38. )
  39. args = parser.parse_args()
  40. if "config" in args and args.config:
  41. config = yaml.safe_load(args.config)
  42. bcrypt_rounds = config.get("bcrypt_rounds", bcrypt_rounds)
  43. password_config = config.get("password_config", None) or {}
  44. password_pepper = password_config.get("pepper", password_pepper)
  45. password = args.password
  46. if not password:
  47. password = prompt_for_pass()
  48. # On Python 2, make sure we decode it to Unicode before we normalise it
  49. if isinstance(password, bytes):
  50. try:
  51. password = password.decode(sys.stdin.encoding)
  52. except UnicodeDecodeError:
  53. print(
  54. "ERROR! Your password is not decodable using your terminal encoding (%s)."
  55. % (sys.stdin.encoding,)
  56. )
  57. pw = unicodedata.normalize("NFKC", password)
  58. hashed = bcrypt.hashpw(
  59. pw.encode('utf8') + password_pepper.encode("utf8"),
  60. bcrypt.gensalt(bcrypt_rounds),
  61. ).decode('ascii')
  62. print(hashed)