| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- from __future__ import annotations
- import hashlib
- import hmac
- import secrets
- SCRYPT_N = 2**14
- SCRYPT_R = 8
- SCRYPT_P = 1
- SALT_BYTES = 16
- KEY_BYTES = 32
- def hash_password(password: str) -> str:
- if not password:
- raise ValueError("密码不能为空。")
- salt = secrets.token_bytes(SALT_BYTES)
- derived = hashlib.scrypt(
- password.encode("utf-8"),
- salt=salt,
- n=SCRYPT_N,
- r=SCRYPT_R,
- p=SCRYPT_P,
- dklen=KEY_BYTES,
- )
- return "$".join(
- [
- "scrypt",
- str(SCRYPT_N),
- str(SCRYPT_R),
- str(SCRYPT_P),
- salt.hex(),
- derived.hex(),
- ]
- )
- def verify_password(password: str, encoded: str) -> bool:
- try:
- algorithm, n_raw, r_raw, p_raw, salt_hex, expected_hex = encoded.split("$")
- if algorithm != "scrypt":
- return False
- derived = hashlib.scrypt(
- password.encode("utf-8"),
- salt=bytes.fromhex(salt_hex),
- n=int(n_raw),
- r=int(r_raw),
- p=int(p_raw),
- dklen=len(bytes.fromhex(expected_hex)),
- )
- except (TypeError, ValueError):
- return False
- return hmac.compare_digest(derived.hex(), expected_hex)
- def generate_session_token() -> str:
- return secrets.token_urlsafe(48)
- def generate_csrf_token() -> str:
- return secrets.token_urlsafe(32)
- def hash_token(token: str) -> str:
- return hashlib.sha256(token.encode("utf-8")).hexdigest()
- def validate_new_password(password: str, username: str = "admin") -> list[str]:
- errors: list[str] = []
- if len(password) < 10:
- errors.append("密码至少需要 10 个字符")
- if password.lower() == username.lower():
- errors.append("密码不能与用户名相同")
- if not any(character.isalpha() for character in password):
- errors.append("密码至少需要包含一个字母")
- if not any(character.isdigit() for character in password):
- errors.append("密码至少需要包含一个数字")
- return errors
|