diff --git a/changelog.d/4161.bugfix b/changelog.d/4161.bugfix
new file mode 100644
index 0000000000..252a40376b
--- /dev/null
+++ b/changelog.d/4161.bugfix
@@ -0,0 +1 @@
+The hash_password script now works on Python 3.
diff --git a/scripts/hash_password b/scripts/hash_password
index a62bb5aa83..a1eb0769da 100755
--- a/scripts/hash_password
+++ b/scripts/hash_password
@@ -3,13 +3,15 @@
import argparse
import getpass
import sys
+import unicodedata
import bcrypt
import yaml
-bcrypt_rounds=12
+bcrypt_rounds = 12
password_pepper = ""
+
def prompt_for_pass():
password = getpass.getpass("Password: ")
@@ -23,19 +25,27 @@ def prompt_for_pass():
return password
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(
- description="Calculate the hash of a new password, so that passwords"
- " can be reset")
+ description=(
+ "Calculate the hash of a new password, so that passwords can be reset"
+ )
+ )
parser.add_argument(
- "-p", "--password",
+ "-p",
+ "--password",
default=None,
help="New password for user. Will prompt if omitted.",
)
parser.add_argument(
- "-c", "--config",
+ "-c",
+ "--config",
type=argparse.FileType('r'),
- help="Path to server config file. Used to read in bcrypt_rounds and password_pepper.",
+ help=(
+ "Path to server config file. "
+ "Used to read in bcrypt_rounds and password_pepper."
+ ),
)
args = parser.parse_args()
@@ -49,4 +59,21 @@ if __name__ == "__main__":
if not password:
password = prompt_for_pass()
- print bcrypt.hashpw(password + password_pepper, bcrypt.gensalt(bcrypt_rounds))
+ # On Python 2, make sure we decode it to Unicode before we normalise it
+ if isinstance(password, bytes):
+ try:
+ password = password.decode(sys.stdin.encoding)
+ except UnicodeDecodeError:
+ print(
+ "ERROR! Your password is not decodable using your terminal encoding (%s)."
+ % (sys.stdin.encoding,)
+ )
+
+ pw = unicodedata.normalize("NFKC", password)
+
+ hashed = bcrypt.hashpw(
+ pw.encode('utf8') + password_pepper.encode("utf8"),
+ bcrypt.gensalt(bcrypt_rounds),
+ ).decode('ascii')
+
+ print(hashed)
diff --git a/tox.ini b/tox.ini
index 920211bf50..03ddaeb0b7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -122,7 +122,7 @@ skip_install = True
basepython = python3.6
deps =
flake8
-commands = /bin/sh -c "flake8 synapse tests scripts scripts-dev scripts/register_new_matrix_user scripts/synapse_port_db synctl {env:PEP8SUFFIX:}"
+commands = /bin/sh -c "flake8 synapse tests scripts scripts-dev scripts/hash_password scripts/register_new_matrix_user scripts/synapse_port_db synctl {env:PEP8SUFFIX:}"
[testenv:check_isort]
skip_install = True
|