mirror of
https://github.com/Heretek-AI/AetherTable.git
synced 2026-11-13 00:01:31 -10:00
- vtt-server: activate the dormant CrdtRelayHub with a live PeerRegistry and
actix-ws endpoint /ws/sessions/{id}/sync (root + /api/v1 alias). Token moves
pass LWW vector-clock arbitration before fan-out; stale transforms are
suppressed. GET /rooms/{id}/presence reports connected peers.
- client: VttCrdtSyncClient gains remote-update listeners, exponential
backoff reconnect, solo-safe no-ops; App.tsx instantiates it, broadcasts
token drags, applies peer updates; LobbyView polls live relay presence
- orchestrator: /api/v1/auth/{signup,login,session} — PBKDF2-salted password
hashes, HMAC-signed 12h tokens (AUTH_SECRET env), default GM seed account;
AuthModal uses the server with demo-account fallback offline
- tests: +5 auth suite; all suites green (46 pytest engine-up, cargo clean,
client ~1s build, MCR 100% / HCI 1.0)
Co-Authored-By: Claude <[email protected]>
77 lines
2.3 KiB
Python
77 lines
2.3 KiB
Python
"""Tests for orchestrator-backed identity & sessions (/api/v1/auth/*)."""
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from vtt_orchestrator.server import app
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
@pytest.fixture()
|
|
def fresh_account(request):
|
|
email = f"player_{abs(hash(request.node.name)) % 10**8}@aethertable.io"
|
|
password = "secret-dice"
|
|
resp = client.post(
|
|
"/api/v1/auth/signup",
|
|
json={
|
|
"email": email,
|
|
"display_name": "Test Hero",
|
|
"password": password,
|
|
"role": "player",
|
|
},
|
|
)
|
|
assert resp.status_code == 200, resp.text
|
|
return {"email": email, "password": password}
|
|
|
|
|
|
def test_signup_login_and_session_roundtrip(fresh_account):
|
|
login = client.post(
|
|
"/api/v1/auth/login",
|
|
json={"email": fresh_account["email"], "password": fresh_account["password"]},
|
|
)
|
|
assert login.status_code == 200
|
|
body = login.json()
|
|
assert body["user"]["role"] == "player"
|
|
assert body["expires_in"] > 0
|
|
|
|
session = client.get("/api/v1/auth/session", params={"token": body["token"]})
|
|
assert session.status_code == 200
|
|
assert session.json()["valid"] is True
|
|
assert session.json()["user"]["email"] == fresh_account["email"]
|
|
|
|
|
|
def test_wrong_password_rejected():
|
|
resp = client.post(
|
|
"/api/v1/auth/login",
|
|
json={"email": "[email protected]", "password": "wrong-password"},
|
|
)
|
|
assert resp.status_code == 401
|
|
|
|
|
|
def test_default_gm_account_seeds_on_first_login():
|
|
resp = client.post(
|
|
"/api/v1/auth/login", json={"email": "[email protected]", "password": "dragonlance"}
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.json()["user"]["role"] == "gm"
|
|
|
|
|
|
def test_tampered_token_rejected():
|
|
login = client.post(
|
|
"/api/v1/auth/login",
|
|
json={"email": "[email protected]", "password": "dragonlance"},
|
|
)
|
|
token = login.json()["token"]
|
|
tampered = token[:-4] + ("0000" if not token.endswith("0000") else "1111")
|
|
resp = client.get("/api/v1/auth/session", params={"token": tampered})
|
|
assert resp.status_code == 401
|
|
|
|
|
|
def test_duplicate_signup_conflict(fresh_account):
|
|
resp = client.post(
|
|
"/api/v1/auth/signup",
|
|
json={"email": fresh_account["email"], "password": fresh_account["password"]},
|
|
)
|
|
assert resp.status_code == 409
|