Files
FabledCurator/backend/app/utils/html_sanitize.py
T
2026-05-18 18:05:45 -04:00

40 lines
1.2 KiB
Python

"""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)
- <script> content removed entirely
- all <a> get rel="noopener noreferrer" (nh3 default link_rel)
- never raises
"""
if raw is None:
return None
stripped = raw.strip()
if not stripped:
return None
return nh3.clean(
stripped,
tags=ALLOWED_TAGS,
attributes=ALLOWED_ATTRIBUTES,
url_schemes=ALLOWED_URL_SCHEMES,
link_rel="noopener noreferrer",
clean_content_tags={"script", "style"},
)