import hashlib from config.constant import SecurityConstants from passlib.hash import bcrypt def _prepare_password(password: str) -> bytes: password_bytes = password.encode("utf-8") # SHA-256 = 32 bytes (ALWAYS < 72) digest = hashlib.sha256(password_bytes).digest() # This slice is technically redundant, but explicit return digest[:SecurityConstants.BCRYPT_MAX_BYTES] def hash_password(password: str) -> str: prepared = _prepare_password(password) # ASSERTION (fail fast if something is wrong) assert len(prepared) <= 72, f"bcrypt input too long: {len(prepared)} bytes" return bcrypt.hash(prepared) def verify_password(plain_password: str, hashed_password: str) -> bool: prepared = _prepare_password(plain_password) assert len(prepared) <= 72, f"bcrypt input too long: {len(prepared)} bytes" return bcrypt.verify(prepared, hashed_password)