Contenu et mécanisme uniquement, aucun style ajouté (voir consigne du 24/09/2026) : deux nouveaux kinds de contenu (badge/carte, rendu en div brutes sans CSS), un mode SVG inline pour l'image (svg_markup, nettoyé par un nouveau sanitizer allow-list avant chaque rendu) et un fichier téléchargeable joignable à un bouton (upload/download routes, stockage sous db.support_dir). Le futur système de templates portera l'habillage visuel de ces éléments. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
"""Nettoyage du SVG inline collé comme contenu d'image (voir
|
|
document_engine/rendering/sanitize_svg_markup.py) — chaque cas ici
|
|
reproduit une charge malveillante RÉELLE plutôt qu'une simple assertion
|
|
"pas de régression" (voir CLAUDE.md, exigence pour tout changement de
|
|
comportement lié à l'échappement/la sécurité)."""
|
|
|
|
from document_engine.rendering.sanitize_svg_markup import sanitize_svg_markup
|
|
|
|
|
|
def test_strips_script_tag_and_its_content() -> None:
|
|
result = sanitize_svg_markup("<svg><script>alert(document.cookie)</script></svg>")
|
|
assert "<script>" not in result
|
|
assert "alert(document.cookie)" not in result
|
|
|
|
|
|
def test_strips_event_handler_attributes() -> None:
|
|
result = sanitize_svg_markup('<svg onload="alert(1)"><circle onclick="alert(2)" cx="5" cy="5" r="3"/></svg>')
|
|
assert "onload" not in result
|
|
assert "onclick" not in result
|
|
assert "alert(" not in result
|
|
|
|
|
|
def test_strips_href_to_block_javascript_uri() -> None:
|
|
result = sanitize_svg_markup('<svg><a href="javascript:alert(1)"><circle cx="1" cy="1" r="1"/></a></svg>')
|
|
assert "javascript:" not in result
|
|
assert "<a" not in result
|
|
assert "href" not in result
|
|
|
|
|
|
def test_strips_foreignobject_and_embedded_html() -> None:
|
|
result = sanitize_svg_markup(
|
|
'<svg><foreignObject><body onload="alert(1)"><img src="x" onerror="alert(2)"></body></foreignObject></svg>'
|
|
)
|
|
assert "foreignObject".lower() not in result.lower()
|
|
assert "onerror" not in result
|
|
assert "alert(" not in result
|
|
|
|
|
|
def test_strips_style_attribute_and_style_tag() -> None:
|
|
result = sanitize_svg_markup(
|
|
'<svg><style>*{display:none}</style><circle style="fill:red" cx="1" cy="1" r="1"/></svg>'
|
|
)
|
|
assert "<style>" not in result
|
|
assert "style=" not in result
|
|
assert "display:none" not in result
|
|
|
|
|
|
def test_strips_use_tag_referencing_external_content() -> None:
|
|
result = sanitize_svg_markup('<svg><use href="https://evil.test/x.svg#payload"/></svg>')
|
|
assert "<use" not in result
|
|
assert "evil.test" not in result
|
|
|
|
|
|
def test_keeps_allowed_shape_and_presentation_attributes() -> None:
|
|
result = sanitize_svg_markup(
|
|
'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#ff0000" stroke="#000"/></svg>'
|
|
)
|
|
assert "<svg" in result
|
|
assert "<circle" in result
|
|
assert 'cx="12"' in result
|
|
assert 'fill="#ff0000"' in result
|
|
assert 'stroke="#000"' in result
|
|
|
|
|
|
def test_self_closing_disallowed_tag_does_not_swallow_following_content() -> None:
|
|
result = sanitize_svg_markup('<svg><script/><circle cx="1" cy="1" r="1"/></svg>')
|
|
assert "<circle" in result
|
|
|
|
|
|
def test_empty_markup_returns_empty_string() -> None:
|
|
assert sanitize_svg_markup("") == ""
|