"""Tests for the /auth/mobile-done bridge page — sid validation and output escaping."""
import uuid
import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def client():
from navi.main import app
return TestClient(app)
def test_mobile_done_valid_sid_renders_intent(client):
sid = uuid.uuid4().hex
resp = client.get(f"/auth/mobile-done?sid={sid}")
assert resp.status_code == 200
body = resp.text
assert f"sid={sid}" in body
# Auto deep-link must survive (JS string is json-escaped)
assert "window.location.href=" in body
assert "Content-Security-Policy" in resp.headers
def test_mobile_done_rejects_malformed_sid(client):
"""Anything that is not a 32-char lowercase hex sid is refused — this is the
reflected-XSS vector (sid lands in href and a JS string)."""
for bad in ["abc123", '"><script>alert(1)</script>', "", "0" * 33, "Z" * 32]:
resp = client.get("/auth/mobile-done", params={"sid": bad})
assert resp.status_code == 400, f"sid={bad!r} must be rejected"
def test_mobile_done_no_injection_in_html(client):
"""Even with a valid-format sid, the rendered page contains no script
breakout payloads (static markup quotes like lang="en"><head> are fine)."""
sid = uuid.uuid4().hex
resp = client.get(f"/auth/mobile-done?sid={sid}")
assert "<script>alert" not in resp.text
assert '"><script>' not in resp.text
# The sid must appear only inside the two intent URLs — nowhere else.
assert resp.text.count(f"sid={sid}") == 2