diff --git a/backend/app/utils/html_sanitize.py b/backend/app/utils/html_sanitize.py new file mode 100644 index 0000000..d660a5c --- /dev/null +++ b/backend/app/utils/html_sanitize.py @@ -0,0 +1,39 @@ +"""Backend HTML sanitization for scraped Post.description. + +Provenance descriptions come from gallery-dl (untrusted third-party HTML). +We render them via v-html in the UI sub-slice, so they MUST be sanitized +server-side to a tight allowlist. nh3 (Rust/ammonia bindings) is used; +bleach is deprecated upstream and intentionally not used. +""" + +import nh3 + +ALLOWED_TAGS = { + "p", "a", "br", "em", "strong", "b", "i", "ul", "ol", "li", "blockquote", +} +ALLOWED_ATTRIBUTES = {"a": {"href", "title"}} +ALLOWED_URL_SCHEMES = {"http", "https"} + + +def sanitize_post_html(raw: str | None) -> str | None: + """Return sanitized HTML, or None for null/empty/whitespace input. + + - keeps only ALLOWED_TAGS / ALLOWED_ATTRIBUTES + - only http/https hrefs survive (javascript: etc. dropped) + -
body
') + assert "