""" Pruebas de la sesión local del CRM (patrón SIWEB) — core.local_session. Lógica pura (firma HS256 + claims); no requiere BD ni valkey. """ from datetime import datetime, timezone from jose import jwt from core.config import settings from core.local_session import mint_session_token, verify_session_token, session_start_of def _now() -> int: return int(datetime.now(timezone.utc).timestamp()) def test_round_trip_conserva_identidad(): claims = { "sub": "kc-user-123", "email": "user@example.com", "tenant_id": 11, "tenant_slug": "aduanasoft", "is_hub_admin": True, } token = mint_session_token(claims) out = verify_session_token(token) assert out is not None assert out["sub"] == "kc-user-123" assert out["tenant_id"] == 11 assert out["tenant_slug"] == "aduanasoft" assert out["is_hub_admin"] is True assert out["source"] == "local" assert out["crm_session"] is True assert isinstance(out["sst"], int) def test_cap_absoluto_rechaza_sesion_vieja(): # session_start más allá del cap absoluto → verify debe rechazar aunque no expiró por idle. old_start = _now() - (settings.SESSION_MAX_HOURS * 3600 + 120) token = mint_session_token({"sub": "x"}, session_start=old_start) assert verify_session_token(token) is None def test_preserva_session_start(): start = _now() - 60 token = mint_session_token({"sub": "x"}, session_start=start) out = verify_session_token(token) assert out is not None assert session_start_of(out) == start def test_firma_alterada_se_rechaza(): token = mint_session_token({"sub": "x"}) # Alterar el último carácter de la firma invalida el token. tampered = token[:-1] + ("A" if token[-1] != "A" else "B") assert verify_session_token(tampered) is None def test_token_no_crm_se_rechaza(): # Un HS256 válido pero SIN los marcadores de sesión local no debe aceptarse. other = jwt.encode( {"sub": "x", "exp": _now() + 600}, settings.SECRET_KEY, algorithm="HS256", ) assert verify_session_token(other) is None def test_token_basura_se_rechaza(): assert verify_session_token("no-es-un-jwt") is None assert verify_session_token("") is None