53 lines
2.1 KiB
Python
53 lines
2.1 KiB
Python
"""test_auth.py — pure unit tests for server/auth.py (no server, no HTTP).
|
|
|
|
The per-IP budget and the XFF trust rule live here; the per-username
|
|
lockout's HTTP behaviour stays covered in test_api.py.
|
|
"""
|
|
import time
|
|
from types import SimpleNamespace
|
|
|
|
|
|
def _req(headers=None, host="203.0.113.7"):
|
|
return SimpleNamespace(headers=dict(headers or {}),
|
|
client=SimpleNamespace(host=host))
|
|
|
|
|
|
def test_ip_budget_counts_prunes_isolates(monkeypatch):
|
|
from server import auth
|
|
monkeypatch.setattr(auth, "IP_FAILS", 3)
|
|
monkeypatch.setattr(auth, "IP_WINDOW", 60.0)
|
|
auth._ip_fails.clear()
|
|
assert not auth.ip_locked("203.0.113.1")
|
|
for _ in range(3):
|
|
auth.ip_fail("203.0.113.1")
|
|
assert auth.ip_locked("203.0.113.1")
|
|
assert not auth.ip_locked("203.0.113.2") # per-IP isolation
|
|
auth._ip_fails["203.0.113.1"] = [time.time() - 10_000] # stale -> pruned
|
|
assert not auth.ip_locked("203.0.113.1")
|
|
|
|
|
|
def test_client_ip_xff_trust_rule(monkeypatch):
|
|
from server import auth
|
|
r = _req({"x-forwarded-for": "9.9.9.9"})
|
|
monkeypatch.delenv("ANIWEB_TRUST_XFF", raising=False)
|
|
assert auth.client_ip(r) == "203.0.113.7" # header NOT trusted by default
|
|
monkeypatch.setenv("ANIWEB_TRUST_XFF", "1")
|
|
assert auth.client_ip(r) == "9.9.9.9" # honored only when explicitly on
|
|
assert auth.client_ip(_req()) == "203.0.113.7" # no header -> socket peer
|
|
|
|
|
|
def test_lock_locked_user_never_reaches_verify(monkeypatch):
|
|
from server import auth
|
|
monkeypatch.setattr(auth, "IP_FAILS", 1000)
|
|
auth._lockout["ghost"] = {"fails": 0, "until": time.time() + 900}
|
|
assert auth.lock("ghost", "x", "203.0.113.3") == "locked"
|
|
|
|
|
|
def test_lock_wrong_password_is_bad_and_records_ip_failure(monkeypatch):
|
|
from server import auth
|
|
monkeypatch.setattr(auth, "IP_FAILS", 1000) # keep the IP gate out of the way
|
|
auth._ip_fails.clear()
|
|
auth._lockout.clear() # module state is shared across tests
|
|
assert auth.lock("ghost", "wrong123456", "203.0.113.4") == "bad" # ghost: no user
|
|
assert len(auth._ip_fails.get("203.0.113.4", [])) == 1
|