POST /auth/guest mints a real user row (wanderer-<4 hex>, collision retry, unusable random password) and issues the normal session cookie, per-IP rate limited at 5/hour. EnterPage gains the guest action; the séance shows a dismissible claim-a-name note for wanderer- users. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
61 lines
2.0 KiB
Python
61 lines
2.0 KiB
Python
import pytest
|
|
|
|
import app.routes.auth as auth_module
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _reset_guest_limiter():
|
|
# The limiter is module-level state; a previous test's hits would bleed
|
|
# into the next one's per-IP budget.
|
|
auth_module.guest_limiter._hits.clear()
|
|
yield
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_guest_creates_wanderer_and_cookie_works_on_me(client):
|
|
response = await client.post("/auth/guest")
|
|
assert response.status_code == 201
|
|
body = response.json()
|
|
assert body["username"].startswith("wanderer-")
|
|
assert "password" not in body
|
|
assert "qm_session" in response.cookies
|
|
|
|
me_resp = await client.get("/auth/me")
|
|
assert me_resp.status_code == 200
|
|
assert me_resp.json()["username"] == body["username"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_guest_cannot_login_with_any_password(client):
|
|
response = await client.post("/auth/guest")
|
|
username = response.json()["username"]
|
|
login_resp = await client.post(
|
|
"/auth/login", json={"username": username, "password": "anythingatall"}
|
|
)
|
|
assert login_resp.status_code == 401
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_guest_rate_limit_fires_per_ip(client):
|
|
for _ in range(5):
|
|
response = await client.post("/auth/guest")
|
|
assert response.status_code == 201
|
|
response = await client.post("/auth/guest")
|
|
assert response.status_code == 429
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_guest_username_collision_retries(client, monkeypatch):
|
|
taken_resp = await client.post("/auth/guest")
|
|
taken = taken_resp.json()["username"].removeprefix("wanderer-")
|
|
|
|
# First attempt collides with the existing wanderer; the retry must land
|
|
# on the fresh suffix instead of erroring out.
|
|
suffixes = iter([taken, "f4ee"])
|
|
monkeypatch.setattr(
|
|
auth_module.secrets, "token_hex", lambda n: next(suffixes)
|
|
)
|
|
response = await client.post("/auth/guest")
|
|
assert response.status_code == 201
|
|
assert response.json()["username"] == "wanderer-f4ee"
|