Changed password setup to use libsodium and argon2id
* regular SHA256 is not secure * added code to auto migrate old passwords to the new password_hash if the existing password_hash matches either of the old password generation schemes.
This commit is contained in:
parent
838ced3aae
commit
0e5fbde097
4 changed files with 40 additions and 12 deletions
|
@ -11,3 +11,4 @@ scipy>=0.18.1
|
||||||
elasticsearch>=5.0.0
|
elasticsearch>=5.0.0
|
||||||
elasticsearch-dsl>=5.0.0
|
elasticsearch-dsl>=5.0.0
|
||||||
scikit-image>=0.12
|
scikit-image>=0.12
|
||||||
|
pynacl>=1.2.1
|
|
@ -1,8 +1,11 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import random
|
import random
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from szurubooru import config, model, errors
|
from nacl.exceptions import InvalidkeyError
|
||||||
|
|
||||||
|
from szurubooru import config, model, errors, db
|
||||||
from szurubooru.func import util
|
from szurubooru.func import util
|
||||||
|
from nacl.pwhash import argon2id, verify
|
||||||
|
|
||||||
|
|
||||||
RANK_MAP = OrderedDict([
|
RANK_MAP = OrderedDict([
|
||||||
|
@ -17,7 +20,14 @@ RANK_MAP = OrderedDict([
|
||||||
|
|
||||||
|
|
||||||
def get_password_hash(salt: str, password: str) -> str:
|
def get_password_hash(salt: str, password: str) -> str:
|
||||||
''' Retrieve new-style password hash. '''
|
""" Retrieve argon2id password hash."""
|
||||||
|
return argon2id.str(
|
||||||
|
(config.config['secret'] + salt + password).encode('utf8')
|
||||||
|
).decode('utf8')
|
||||||
|
|
||||||
|
|
||||||
|
def get_sha256_legacy_password_hash(salt: str, password: str) -> str:
|
||||||
|
""" Retrieve old-style sha256 password hash."""
|
||||||
digest = hashlib.sha256()
|
digest = hashlib.sha256()
|
||||||
digest.update(config.config['secret'].encode('utf8'))
|
digest.update(config.config['secret'].encode('utf8'))
|
||||||
digest.update(salt.encode('utf8'))
|
digest.update(salt.encode('utf8'))
|
||||||
|
@ -25,8 +35,8 @@ def get_password_hash(salt: str, password: str) -> str:
|
||||||
return digest.hexdigest()
|
return digest.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def get_legacy_password_hash(salt: str, password: str) -> str:
|
def get_sha1_legacy_password_hash(salt: str, password: str) -> str:
|
||||||
''' Retrieve old-style password hash. '''
|
""" Retrieve old-style sha1 password hash."""
|
||||||
digest = hashlib.sha1()
|
digest = hashlib.sha1()
|
||||||
digest.update(b'1A2/$_4xVa')
|
digest.update(b'1A2/$_4xVa')
|
||||||
digest.update(salt.encode('utf8'))
|
digest.update(salt.encode('utf8'))
|
||||||
|
@ -47,11 +57,22 @@ def create_password() -> str:
|
||||||
def is_valid_password(user: model.User, password: str) -> bool:
|
def is_valid_password(user: model.User, password: str) -> bool:
|
||||||
assert user
|
assert user
|
||||||
salt, valid_hash = user.password_salt, user.password_hash
|
salt, valid_hash = user.password_salt, user.password_hash
|
||||||
possible_hashes = [
|
|
||||||
get_password_hash(salt, password),
|
try:
|
||||||
get_legacy_password_hash(salt, password)
|
return verify(user.password_hash.encode('utf8'),
|
||||||
]
|
(config.config['secret'] + salt + password).encode('utf8'))
|
||||||
return valid_hash in possible_hashes
|
except InvalidkeyError:
|
||||||
|
possible_hashes = [
|
||||||
|
get_sha256_legacy_password_hash(salt, password),
|
||||||
|
get_sha1_legacy_password_hash(salt, password)
|
||||||
|
]
|
||||||
|
if valid_hash in possible_hashes:
|
||||||
|
# Convert the user password hash to the new hash
|
||||||
|
user.password_hash = get_password_hash(salt, password)
|
||||||
|
db.session.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def has_privilege(user: model.User, privilege_name: str) -> bool:
|
def has_privilege(user: model.User, privilege_name: str) -> bool:
|
||||||
|
|
|
@ -35,7 +35,11 @@ def run_migrations_offline():
|
||||||
'''
|
'''
|
||||||
url = alembic_config.get_main_option('sqlalchemy.url')
|
url = alembic_config.get_main_option('sqlalchemy.url')
|
||||||
alembic.context.configure(
|
alembic.context.configure(
|
||||||
url=url, target_metadata=target_metadata, literal_binds=True)
|
url=url,
|
||||||
|
target_metadata=target_metadata,
|
||||||
|
literal_binds=True,
|
||||||
|
compare_type=True
|
||||||
|
)
|
||||||
|
|
||||||
with alembic.context.begin_transaction():
|
with alembic.context.begin_transaction():
|
||||||
alembic.context.run_migrations()
|
alembic.context.run_migrations()
|
||||||
|
@ -56,7 +60,9 @@ def run_migrations_online():
|
||||||
with connectable.connect() as connection:
|
with connectable.connect() as connection:
|
||||||
alembic.context.configure(
|
alembic.context.configure(
|
||||||
connection=connection,
|
connection=connection,
|
||||||
target_metadata=target_metadata)
|
target_metadata=target_metadata,
|
||||||
|
compare_type=True
|
||||||
|
)
|
||||||
|
|
||||||
with alembic.context.begin_transaction():
|
with alembic.context.begin_transaction():
|
||||||
alembic.context.run_migrations()
|
alembic.context.run_migrations()
|
||||||
|
|
|
@ -23,7 +23,7 @@ class User(Base):
|
||||||
last_login_time = sa.Column('last_login_time', sa.DateTime)
|
last_login_time = sa.Column('last_login_time', sa.DateTime)
|
||||||
version = sa.Column('version', sa.Integer, default=1, nullable=False)
|
version = sa.Column('version', sa.Integer, default=1, nullable=False)
|
||||||
name = sa.Column('name', sa.Unicode(50), nullable=False, unique=True)
|
name = sa.Column('name', sa.Unicode(50), nullable=False, unique=True)
|
||||||
password_hash = sa.Column('password_hash', sa.Unicode(64), nullable=False)
|
password_hash = sa.Column('password_hash', sa.Unicode(128), nullable=False)
|
||||||
password_salt = sa.Column('password_salt', sa.Unicode(32))
|
password_salt = sa.Column('password_salt', sa.Unicode(32))
|
||||||
email = sa.Column('email', sa.Unicode(64), nullable=True)
|
email = sa.Column('email', sa.Unicode(64), nullable=True)
|
||||||
rank = sa.Column('rank', sa.Unicode(32), nullable=False)
|
rank = sa.Column('rank', sa.Unicode(32), nullable=False)
|
||||||
|
|
Loading…
Reference in a new issue