41 lines
1.2 KiB
Python
41 lines
1.2 KiB
Python
|
|
import pytest
|
||
|
|
from fastapi import HTTPException
|
||
|
|
|
||
|
|
from app.auth import (
|
||
|
|
decode_access_token,
|
||
|
|
hash_password,
|
||
|
|
issue_access_token,
|
||
|
|
issue_refresh_token,
|
||
|
|
verify_password,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_bcrypt_roundtrip() -> None:
|
||
|
|
h = hash_password("hunter2-correct-horse-battery")
|
||
|
|
assert verify_password("hunter2-correct-horse-battery", h)
|
||
|
|
assert not verify_password("wrong", h)
|
||
|
|
|
||
|
|
|
||
|
|
def test_access_token_carries_scopes_and_decodes() -> None:
|
||
|
|
token, ttl = issue_access_token(42, ["read:fleet"])
|
||
|
|
assert ttl > 0
|
||
|
|
claims = decode_access_token(token)
|
||
|
|
assert claims["sub"] == "42"
|
||
|
|
assert claims["scopes"] == ["read:fleet"]
|
||
|
|
assert claims["typ"] == "access"
|
||
|
|
|
||
|
|
|
||
|
|
def test_decode_rejects_tampered_token() -> None:
|
||
|
|
token, _ = issue_access_token(1, ["read:fleet"])
|
||
|
|
tampered = token[:-1] + ("A" if token[-1] != "A" else "B")
|
||
|
|
with pytest.raises(HTTPException) as exc_info:
|
||
|
|
decode_access_token(tampered)
|
||
|
|
assert exc_info.value.status_code == 401
|
||
|
|
|
||
|
|
|
||
|
|
def test_refresh_token_returns_distinct_raw_and_hash() -> None:
|
||
|
|
raw, expires_at, token_hash = issue_refresh_token(account_id=1)
|
||
|
|
assert raw != token_hash
|
||
|
|
assert len(token_hash) == 64
|
||
|
|
assert expires_at.tzinfo is not None
|