diff --git a/docs/usage.md b/docs/usage.md index ae8281d..8281423 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -212,8 +212,12 @@ checked, a quoted value stays quoted until its quote closes, and a variable in a ends there and the browser would never run it. A template including one that ends inside such a block, a tag or an end tag is not established either: the markup after the include continues it. A template extending another ends where that one ends. A comment -hides what it holds only up to its first template tag, since an include there may close -it and a condition around its `" in the title, and the variable after it names a tag. +def test_a_comment_closed_inside_an_attribute_after_its_tags_is_cross_site_scripting(tmp_path: Path) -> None: + templates = {"page.html": '<{{ name }}">x\n'} + + assert xss(tmp_path, templates) == [("app/views.py", 5)] + + +@pytest.mark.parametrize( + "template", + [ + '<{{ name }}">x\n', + '\n', + ], + ids=["close-inside-a-title", "later-tag-inside-a-title"], +) +def test_a_comment_resuming_elsewhere_than_in_html_data_is_not_established(tmp_path: Path, template: str) -> None: + assert escaped(tmp_path, {"page.html": template}) == [] + + +@pytest.mark.parametrize( + "template", + [ + "\n", + "
{{ name }}
\n", + '\n', + 'hello
\n', + ], + ids=["tags-around-text", "variable-after-the-comment", "tags-in-a-class", "no-tag"], +) +def test_a_comment_resuming_in_html_data_everywhere_stays_established(tmp_path: Path, template: str) -> None: + assert escaped(tmp_path, {"page.html": template}) == ["page.html"] + + +def test_an_include_of_a_name_two_files_have_anywhere_in_a_comment_is_refused(tmp_path: Path) -> None: + # The tag before it may render nothing: the include then stands inside the comment. + templates = { + "part.html": "x\n", + "other/templates/part.html": "y\n", + "page.html": "\n", + } + + assert escaped(tmp_path, templates) == ["part.html"] + + +def test_a_comment_holding_tags_left_open_does_not_end_in_html_data(tmp_path: Path) -> None: + # Its tags may render nothing: the comment then hides what follows the include. + templates = { + "part.html": "x\n", + "other/templates/part.html": "y ", + "tag-then-open-start-tag": "' * (SIZE // 38), + }[shape] + + escaped(tmp_path, {"page.html": template}) + + +# Pieces of a template's markup as the reader sees it: markup, a variable, a template tag +# and an inserted markup (#273). +OUTPUT, TAG, INSERTED = "\x00", "\x01", "\x02" +PIECES = ["", "", "--!>", TAG, OUTPUT, '", "", "x", " ", "<", " bool: + """The reading of ``html`` that follows every continuation of each comment holding + template tags: from each of its tags, and from its close. Its cost is not linear; + it is the reference the reading of the engine must never be more lenient than.""" + + from coretrace_python.taint import templates + + @cache + def from_position(position: int) -> bool: + while (start := html.find("<", position)) != -1: + if html.startswith("