95 lines
3.5 KiB
Python
95 lines
3.5 KiB
Python
# ============================================================
|
|
# 免登录云部署:每个浏览器访客只看到自己的项目/会话/个人世界
|
|
# ============================================================
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
@pytest.fixture()
|
|
def open_app(tmp_path, monkeypatch):
|
|
monkeypatch.setenv("APS_DB_PATH", str(tmp_path / "open.db"))
|
|
monkeypatch.setenv("APS_WORLD_PATH", str(tmp_path / "world.json"))
|
|
monkeypatch.setenv("APS_AUTH_ENABLED", "0")
|
|
from server.db.database import reset_engine
|
|
from server.state import store as world_store
|
|
|
|
world_store._stores.clear()
|
|
reset_engine()
|
|
from server.gateway.app import create_app
|
|
|
|
app = create_app()
|
|
yield app
|
|
reset_engine()
|
|
world_store._stores.clear()
|
|
|
|
|
|
def _client(app, visitor: str) -> TestClient:
|
|
client = TestClient(app)
|
|
client.headers["X-APS-Visitor-ID"] = visitor
|
|
return client
|
|
|
|
|
|
def test_anonymous_visitors_get_distinct_identities(open_app):
|
|
alpha = _client(open_app, "visitor-alpha-0001")
|
|
bravo = _client(open_app, "visitor-bravo-0002")
|
|
|
|
user_a = alpha.get("/api/auth/me").json()["user"]
|
|
user_b = bravo.get("/api/auth/me").json()["user"]
|
|
|
|
assert user_a["auth_kind"] == "anonymous"
|
|
assert user_a["user_id"] != user_b["user_id"]
|
|
|
|
|
|
def test_anonymous_visitors_only_see_own_projects_and_sessions(open_app):
|
|
alpha = _client(open_app, "visitor-alpha-0001")
|
|
bravo = _client(open_app, "visitor-bravo-0002")
|
|
|
|
assert alpha.post(
|
|
"/api/projects", json={"id": "proj_anon_a", "name": "访客 A 项目"},
|
|
).status_code == 200
|
|
|
|
alpha_workspace = alpha.get("/api/workspace").json()
|
|
assert [row["id"] for row in alpha_workspace["projects"]] == ["proj_anon_a"]
|
|
|
|
bravo_workspace = bravo.get("/api/workspace").json()
|
|
assert bravo_workspace["projects"] == []
|
|
assert bravo.get("/api/projects/proj_anon_a/members").status_code == 404
|
|
|
|
bravo_session = next(row for row in bravo_workspace["sessions"] if row["scope"] == "personal")
|
|
assert bravo.get(f"/api/sessions/{bravo_session['id']}/messages").status_code == 200
|
|
alpha_personal = next(
|
|
row for row in alpha_workspace["sessions"] if row["scope"] == "personal"
|
|
)
|
|
assert alpha_personal["id"] != bravo_session["id"]
|
|
assert bravo.get(f"/api/sessions/{alpha_personal['id']}/messages").status_code == 404
|
|
|
|
|
|
def test_same_visitor_reuses_own_workspace(open_app):
|
|
first = _client(open_app, "visitor-same-0001")
|
|
first.post("/api/projects", json={"id": "proj_anon_same", "name": "同一访客项目"})
|
|
|
|
cookie = first.cookies.get("aps_anonymous_id")
|
|
assert cookie
|
|
|
|
second = TestClient(open_app)
|
|
second.cookies.set("aps_anonymous_id", cookie)
|
|
workspace = second.get("/api/workspace").json()
|
|
assert [row["id"] for row in workspace["projects"]] == ["proj_anon_same"]
|
|
|
|
|
|
def test_anonymous_cookie_survives_localstorage_reset(open_app):
|
|
first = _client(open_app, "visitor-ls-reset-0001")
|
|
first.post("/api/projects", json={"id": "proj_anon_cookie", "name": "Cookie 项目"})
|
|
|
|
cookie = first.cookies.get("aps_anonymous_id")
|
|
assert cookie
|
|
|
|
# 模拟 localStorage 被清空:新浏览器上下文没有访客头,只有服务端 Cookie。
|
|
second = TestClient(open_app)
|
|
second.cookies.set("aps_anonymous_id", cookie)
|
|
second.headers["X-APS-Visitor-ID"] = "visitor-recreated-0001"
|
|
workspace = second.get("/api/workspace").json()
|
|
assert [row["id"] for row in workspace["projects"]] == ["proj_anon_cookie"]
|