diff options
Diffstat (limited to 'server/szurubooru/func/auth.py')
| -rw-r--r-- | server/szurubooru/func/auth.py | 99 |
1 files changed, 55 insertions, 44 deletions
diff --git a/server/szurubooru/func/auth.py b/server/szurubooru/func/auth.py index 65be79a..d013775 100644 --- a/server/szurubooru/func/auth.py +++ b/server/szurubooru/func/auth.py @@ -1,60 +1,67 @@ -from typing import Tuple, Optional import hashlib import random import uuid from collections import OrderedDict from datetime import datetime +from typing import Optional, Tuple + from nacl import pwhash from nacl.exceptions import InvalidkeyError -from szurubooru import config, db, model, errors -from szurubooru.func import util +from szurubooru import config, db, errors, model +from szurubooru.func import util -RANK_MAP = OrderedDict([ - (model.User.RANK_ANONYMOUS, 'anonymous'), - (model.User.RANK_RESTRICTED, 'restricted'), - (model.User.RANK_REGULAR, 'regular'), - (model.User.RANK_POWER, 'power'), - (model.User.RANK_MODERATOR, 'moderator'), - (model.User.RANK_ADMINISTRATOR, 'administrator'), - (model.User.RANK_NOBODY, 'nobody'), -]) +RANK_MAP = OrderedDict( + [ + (model.User.RANK_ANONYMOUS, "anonymous"), + (model.User.RANK_RESTRICTED, "restricted"), + (model.User.RANK_REGULAR, "regular"), + (model.User.RANK_POWER, "power"), + (model.User.RANK_MODERATOR, "moderator"), + (model.User.RANK_ADMINISTRATOR, "administrator"), + (model.User.RANK_NOBODY, "nobody"), + ] +) def get_password_hash(salt: str, password: str) -> Tuple[str, int]: - ''' Retrieve argon2id password hash. ''' - return pwhash.argon2id.str( - (config.config['secret'] + salt + password).encode('utf8') - ).decode('utf8'), 3 + """ Retrieve argon2id password hash. """ + return ( + pwhash.argon2id.str( + (config.config["secret"] + salt + password).encode("utf8") + ).decode("utf8"), + 3, + ) def get_sha256_legacy_password_hash( - salt: str, password: str) -> Tuple[str, int]: - ''' Retrieve old-style sha256 password hash. ''' + salt: str, password: str +) -> Tuple[str, int]: + """ Retrieve old-style sha256 password hash. """ digest = hashlib.sha256() - digest.update(config.config['secret'].encode('utf8')) - digest.update(salt.encode('utf8')) - digest.update(password.encode('utf8')) + digest.update(config.config["secret"].encode("utf8")) + digest.update(salt.encode("utf8")) + digest.update(password.encode("utf8")) return digest.hexdigest(), 2 def get_sha1_legacy_password_hash(salt: str, password: str) -> Tuple[str, int]: - ''' Retrieve old-style sha1 password hash. ''' + """ Retrieve old-style sha1 password hash. """ digest = hashlib.sha1() - digest.update(b'1A2/$_4xVa') - digest.update(salt.encode('utf8')) - digest.update(password.encode('utf8')) + digest.update(b"1A2/$_4xVa") + digest.update(salt.encode("utf8")) + digest.update(password.encode("utf8")) return digest.hexdigest(), 1 def create_password() -> str: alphabet = { - 'c': list('bcdfghijklmnpqrstvwxyz'), - 'v': list('aeiou'), - 'n': list('0123456789'), + "c": list("bcdfghijklmnpqrstvwxyz"), + "v": list("aeiou"), + "n": list("0123456789"), } - pattern = 'cvcvnncvcv' - return ''.join(random.choice(alphabet[l]) for l in list(pattern)) + pattern = "cvcvnncvcv" + return "".join(random.choice(alphabet[type]) for type in list(pattern)) def is_valid_password(user: model.User, password: str) -> bool: @@ -63,12 +70,13 @@ def is_valid_password(user: model.User, password: str) -> bool: try: return pwhash.verify( - user.password_hash.encode('utf8'), - (config.config['secret'] + salt + password).encode('utf8')) + user.password_hash.encode("utf8"), + (config.config["secret"] + salt + password).encode("utf8"), + ) except InvalidkeyError: possible_hashes = [ get_sha256_legacy_password_hash(salt, password)[0], - get_sha1_legacy_password_hash(salt, password)[0] + get_sha1_legacy_password_hash(salt, password)[0], ] if valid_hash in possible_hashes: # Convert the user password hash to the new hash @@ -82,16 +90,18 @@ def is_valid_password(user: model.User, password: str) -> bool: def is_valid_token(user_token: Optional[model.UserToken]) -> bool: - ''' + """ Token must be enabled and if it has an expiration, it must be greater than now. - ''' + """ if user_token is None: return False if not user_token.enabled: return False - if (user_token.expiration_time is not None - and user_token.expiration_time < datetime.utcnow()): + if ( + user_token.expiration_time is not None + and user_token.expiration_time < datetime.utcnow() + ): return False return True @@ -99,26 +109,27 @@ def is_valid_token(user_token: Optional[model.UserToken]) -> bool: def has_privilege(user: model.User, privilege_name: str) -> bool: assert user all_ranks = list(RANK_MAP.keys()) - assert privilege_name in config.config['privileges'] + assert privilege_name in config.config["privileges"] assert user.rank in all_ranks minimal_rank = util.flip(RANK_MAP)[ - config.config['privileges'][privilege_name]] - good_ranks = all_ranks[all_ranks.index(minimal_rank):] + config.config["privileges"][privilege_name] + ] + good_ranks = all_ranks[all_ranks.index(minimal_rank) :] return user.rank in good_ranks def verify_privilege(user: model.User, privilege_name: str) -> None: assert user if not has_privilege(user, privilege_name): - raise errors.AuthError('Insufficient privileges to do this.') + raise errors.AuthError("Insufficient privileges to do this.") def generate_authentication_token(user: model.User) -> str: - ''' Generate nonguessable challenge (e.g. links in password reminder). ''' + """ Generate nonguessable challenge (e.g. links in password reminder). """ assert user digest = hashlib.md5() - digest.update(config.config['secret'].encode('utf8')) - digest.update(user.password_salt.encode('utf8')) + digest.update(config.config["secret"].encode("utf8")) + digest.update(user.password_salt.encode("utf8")) return digest.hexdigest() |