# -*- coding: utf-8 -*- """口令哈希常量与校验。 (自 auth_system.py 拆出,行为与原实现一致。) """ import hashlib import secrets # 口令哈希升级。旧库 SHA-256(salt+pwd) 哈希在登录成功时透明升级为 PBKDF2 _PBKDF2_ITERS = 100_000 # ============ 密码与用户 ============ def _hash(password: str, salt: str) -> str: """旧版口令哈希:SHA-256(salt + password)。仅用于校验存量库,新哈希一律走 _hash_new""" return hashlib.sha256((salt + password).encode('utf-8')).hexdigest() def _hash_new(password: str, salt: str = '', iterations: int = _PBKDF2_ITERS) -> str: """新版口令哈希:PBKDF2-HMAC-SHA256,格式 pbkdf2$iter$salt$digest""" salt = salt or secrets.token_hex(8) digest = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), iterations).hex() return f'pbkdf2${iterations}${salt}${digest}' def _verify_password(stored: str, password: str, salt: str) -> tuple[bool, bool]: """校验口令。返回 (是否正确, 是否需要升级到 PBKDF2)""" if stored.startswith('pbkdf2$'): try: _, iters, psalt, digest = stored.split('$', 3) calc = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), psalt.encode('utf-8'), int(iters)).hex() return secrets.compare_digest(calc, digest), False except Exception: return False, False ok = secrets.compare_digest(stored, _hash(password, salt)) return ok, ok # 旧哈希校验通过 → 登录时升级 def _normalize_email(email: str) -> str: """:邮箱归一化——剥离 Gmail 等服务商的 +tag 别名 (user+1@ 与 user@ 视为同一邮箱),堵住别名的无限刷号绕过;无 + 原样返回。 local 为空(如 '+a@gmail.com')时返回空串,由调用方按格式错误拒绝。""" email = (email or '').strip().lower() if '+' in email: local, _, domain = email.partition('@') local = local.split('+', 1)[0] if local and domain: email = f'{local}@{domain}' elif not local: return '' return email