Files
baozaotumao2025 14722be770 first commit
2026-07-18 21:00:26 +08:00

92 lines
3.1 KiB
Python

import pytest
from app.core.config import Settings
from app.services.auth_service import (
derive_refresh_token,
hash_password,
issue_refresh_token,
issue_token,
verify_password,
verify_token,
)
def settings(**overrides):
return Settings(
target_base_url="https://target.test",
judge_base_url="https://judge.test",
**overrides,
)
def test_password_hash_is_salted_and_verifiable():
encoded = hash_password("correct-horse-battery-staple")
assert encoded.startswith("pbkdf2_sha256$600000$")
assert "correct-horse-battery-staple" not in encoded
assert verify_password("correct-horse-battery-staple", encoded)
assert not verify_password("wrong", encoded)
assert not verify_password("wrong", "not-a-password-hash")
def test_signed_token_rejects_tampering_and_requires_secret_outside_tests():
token, expires_at = issue_token(7, settings(auth_token_secret="x" * 32))
assert expires_at > 0
assert verify_token(token, settings(auth_token_secret="x" * 32)) == 7
assert verify_token(token + "x", settings(auth_token_secret="x" * 32)) is None
with pytest.raises(ValueError):
issue_token(7, settings(app_env="production", auth_token_secret=""))
with pytest.raises(ValueError):
issue_token(7, settings(app_env="production", auth_token_secret="too-short"))
def test_refresh_tokens_are_random_but_idempotent_rotation_is_stable():
config = settings(auth_token_secret="x" * 32)
first, second = issue_refresh_token(), issue_refresh_token()
assert first != second
assert derive_refresh_token(first, "attempt-1", config) == derive_refresh_token(
first, "attempt-1", config
)
assert derive_refresh_token(first, "attempt-1", config) != derive_refresh_token(
first, "attempt-2", config
)
def test_session_timing_configuration_requires_refresh_window_before_expiry():
assert settings().auth_token_ttl_seconds == 3600
assert settings().auth_token_refresh_window_seconds == 1800
assert settings().auth_refresh_token_ttl_seconds == 28800
with pytest.raises(ValueError):
settings(auth_token_ttl_seconds=1800, auth_token_refresh_window_seconds=1800)
def test_create_user_cli_prompts_and_never_accepts_password_argument(monkeypatch):
from app import create_user
created = {}
class FakeDatabase:
def __enter__(self):
return self
def __exit__(self, *_):
return None
class FakeRepository:
def __init__(self, _):
pass
def create(self, *, username, password, is_admin):
created.update(username=username, password=password, is_admin=is_admin)
monkeypatch.setattr(create_user, "SessionLocal", FakeDatabase)
monkeypatch.setattr(create_user, "UserRepository", FakeRepository)
monkeypatch.setattr(create_user.getpass, "getpass", lambda _: "correct-horse-battery-staple")
monkeypatch.setattr("sys.argv", ["create_user", "auditor"])
create_user.main()
assert created == {
"username": "auditor",
"password": "correct-horse-battery-staple",
"is_admin": True,
}