"""Preview-route XSS guard.

Staged Canvas bodies are semi-untrusted (imported cartridges, prior IDs, faculty
edits). Rendering them inline on the staging-server origin let injected script
read the synchronizer token from a same-origin page and PUT over any staged
artifact, so a human could approve one body and push another.

These tests pin the two barriers on the direct /preview route: the sanitizer and
the sandbox attribute. Both must survive any refactor of _wrap_html.
"""

import pathlib
import sys

SCRIPTS_DIR = pathlib.Path(__file__).resolve().parents[1] / "scripts"
sys.path.insert(0, str(SCRIPTS_DIR))

import staging_server


HOSTILE = (
    '<p>legit copy</p>'
    '<script>fetch("/courses/1/review")</script>'
    '<img src=x onerror="alert(1)">'
    '<a href="javascript:alert(2)">click</a>'
)


def test_sandboxed_fragment_strips_active_content():
    out = staging_server._sandboxed_fragment(HOSTILE, "123")
    # The sanitizer escapes into srcdoc, so assert on the un-escaped payload too.
    assert "<script" not in out
    assert "onerror" not in out
    assert "javascript:" not in out


def test_sandboxed_fragment_is_opaque_origin_with_scripting_off():
    out = staging_server._sandboxed_fragment("<p>hi</p>", "123")
    assert "<iframe sandbox " in out, "content must render inside a sandboxed iframe"
    # An empty sandbox= is the whole point: either token re-enables the attack.
    assert "allow-scripts" not in out
    assert "allow-same-origin" not in out


def test_sandboxed_fragment_preserves_benign_markup_and_image_tokens():
    body = '<h2>Week 1</h2><img src="asucb-staged-file://banner.png" alt="Banner">'
    out = staging_server._sandboxed_fragment(body, "123")
    assert "Week 1" in out
    # Tokens are rewritten to the local staging-files route, not left as tokens.
    assert "asucb-staged-file://" not in out
    assert "/courses/123/staging-files/banner.png" in out


def test_wrap_html_never_inlines_untrusted_script():
    out = staging_server._wrap_html(HOSTILE, "Pages week-1", course_id="123")
    assert "<script>fetch" not in out
    assert "onerror=" not in out
    assert "<iframe sandbox " in out


def test_wrap_html_escapes_the_title_slot():
    out = staging_server._wrap_html("<p>x</p>", '<script>alert(1)</script>', course_id="123")
    assert "<script>alert(1)</script>" not in out


def test_rubrics_wrapper_does_not_return_raw_content():
    """rubrics previously returned staged HTML verbatim as the whole response."""
    wrapper = staging_server.STAGING_TYPES["rubrics"].wrapper
    out = wrapper(HOSTILE, "123", "rubric-1")
    assert out != HOSTILE
    assert "<script" not in out
    assert "<iframe sandbox " in out


def test_interactives_preview_keeps_scripts_but_stays_cross_origin():
    """Interactives legitimately run JS; they must still not be same-origin."""
    out = staging_server._wrap_interactive_preview("<script>go()</script>", "123", "demo")
    assert "allow-scripts" in out
    assert "allow-same-origin" not in out
