"""
Saneado del HTML de los posts del foro (el editor del cliente puede enviar HTML).
El proyecto original guardaba el HTML sin sanear y lo renderizaba con |raw
(XSS almacenado). Aquí lo saneamos con nh3 (allowlist) al guardar, de modo que
la plantilla puede renderizarlo con |safe sin riesgo.
"""
import nh3
# Etiquetas permitidas (formato básico de foro)
_ALLOWED_TAGS = {
"p", "br", "hr", "span", "div",
"strong", "b", "em", "i", "u", "s", "strike", "sub", "sup",
"ul", "ol", "li", "blockquote", "code", "pre",
"h1", "h2", "h3", "h4", "h5", "h6",
"a", "img",
"table", "thead", "tbody", "tr", "th", "td",
}
_ALLOWED_ATTRIBUTES = {
"a": {"href", "title", "target"},
"img": {"src", "alt", "title", "width", "height"},
"span": {"style"},
"div": {"style"},
"td": {"colspan", "rowspan"},
"th": {"colspan", "rowspan"},
}
# Solo esquemas de URL seguros
_ALLOWED_URL_SCHEMES = {"http", "https", "mailto"}
def clean_post_html(html):
"""Devuelve el HTML saneado y seguro para renderizar con |safe."""
if not html:
return ""
return nh3.clean(
html,
tags=_ALLOWED_TAGS,
attributes=_ALLOWED_ATTRIBUTES,
url_schemes=_ALLOWED_URL_SCHEMES,
link_rel="noopener noreferrer nofollow",
)
def plain_length(html):
"""Longitud del texto plano (sin etiquetas), para validar longitud mínima."""
if not html:
return 0
text = nh3.clean(html, tags=set(), attributes={})
return len(text.strip())