"""Unit tests for web-based Login Flow v2 provisioning routes. Tests validation, HTML escaping, URL rewriting, route handlers, and background polling logic. """ import time from unittest.mock import AsyncMock, MagicMock, patch import pytest from nextcloud_mcp_server.auth.login_flow import LoginFlowPollResult from nextcloud_mcp_server.auth.provision_routes import ( _poll_and_store, _provision_sessions, _render_error, _validate_redirect_uri, provision_page, provision_status, ) pytestmark = pytest.mark.unit @pytest.fixture(autouse=True) def _clear_provision_sessions(): """Ensure _provision_sessions is empty before and after each test.""" _provision_sessions.clear() yield _provision_sessions.clear() # ── _validate_redirect_uri tests ───────────────────────────────────────── async def test_validate_redirect_uri_accepts_https(): """Valid HTTPS URL is accepted.""" assert _validate_redirect_uri("https://app.example.com/callback") is True async def test_validate_redirect_uri_accepts_http_localhost(): """Valid HTTP localhost URL is accepted.""" assert _validate_redirect_uri("http://localhost:3000/callback") is True async def test_validate_redirect_uri_rejects_javascript(): """javascript: URIs are rejected.""" assert _validate_redirect_uri("javascript:alert(1)") is False async def test_validate_redirect_uri_rejects_relative_url(): """Relative URLs are rejected (no scheme/netloc).""" assert _validate_redirect_uri("/relative/path") is False async def test_validate_redirect_uri_rejects_bare_hostname(): """Bare hostnames without scheme are rejected.""" assert _validate_redirect_uri("example.com") is False async def test_validate_redirect_uri_rejects_data_uri(): """data: URIs are rejected.""" assert _validate_redirect_uri("data:text/html,

hi

") is False async def test_validate_redirect_uri_rejects_empty(): """Empty string is rejected.""" assert _validate_redirect_uri("") is False # ── _render_error tests ────────────────────────────────────────────────── async def test_render_error_escapes_html(): """XSS regression: HTML in error messages must be escaped.""" html_output = _render_error("") assert "