"""refresh token 纯函数(packages/identity/tokens.py)。 无 IO、无配置:token 长度/字符域/唯一性、哈希稳定性与不可逆性在这里穷举, 服务层的轮换/撤销语义由 tests/integration/test_auth_refresh.py 用真实 PG 验证。 """ from __future__ import annotations import string from packages.identity.tokens import generate_refresh_token, hash_refresh_token #: token_urlsafe 的字母表:base64url(含 ``-`` ``_``),无 ``+`` ``/`` ``=`` _URLSAFE_ALPHABET = frozenset(string.ascii_letters + string.digits + "_-") def test_token_has_fixed_length() -> None: # 48 字节 → base64 无填充恒 64 字符;长度恒定才好做列宽与日志脱敏 assert len(generate_refresh_token()) == 64 def test_token_stays_within_urlsafe_alphabet() -> None: # 必须能原样放进 JSON / URL / Header,不引入需要转义的字符 tokens = [generate_refresh_token() for _ in range(50)] assert all(set(token) <= _URLSAFE_ALPHABET for token in tokens) def test_tokens_are_unique() -> None: tokens = [generate_refresh_token() for _ in range(100)] assert len(set(tokens)) == len(tokens) def test_hash_is_stable() -> None: # 校验路径 = 重算一次哈希再比对,稳定性是查库成立的前提 token = generate_refresh_token() assert hash_refresh_token(token) == hash_refresh_token(token) def test_hash_is_lowercase_sha256_hex() -> None: digest = hash_refresh_token("abc") # sha256 恒 64 个小写 hex 字符,与 id_session.refresh_token_hash varchar(64) 对齐 assert len(digest) == 64 assert digest == digest.lower() assert set(digest) <= set(string.digits + "abcdef") def test_hash_is_not_the_plaintext_token() -> None: # 不可逆(≠原文):库里存的是哈希,泄漏数据库换不回可用令牌 token = generate_refresh_token() digest = hash_refresh_token(token) assert digest != token assert token not in digest def test_different_tokens_hash_differently() -> None: assert hash_refresh_token(generate_refresh_token()) != hash_refresh_token( generate_refresh_token() )