fix: sanitize journal HTML instead of blanking it on a regex match

The three-regex gate could be bypassed (an attribute without a space,
<svg/onload>, entity-encoded or tab-split javascript: URLs, MathML
xlink:href, base, meta refresh, forms) and it blanked a whole post or
category when ordinary text such as "Data: 12 maja 2024" matched.

- sanitizeJournalHtml runs sanitize-html with the Journal plugin's
  bluemonday policy: UGC elements plus footer, class, schema.org
  microdata, four validated inline styles, footnote roles, dir=auto,
  two chat transcript data attributes; http, https, mailto and
  relative URLs only
- gateJournalHtml and isSafeJournalHtml keep their signatures; html is
  always the sanitized value and is never blanked
- post body, category content and both page payloads are sanitized;
  the blocked notice, its style and string, and the blocked props and
  content_blocked field are removed
- toPostView moves to postView.ts so list pages and cards do not load
  the sanitizer
- tests cover every bypass from the review, the Data:/metadata: text
  and an imported author footer; the SSR smoke expects the unsafe
  sample's safe paragraphs
This commit is contained in:
2026-10-10 00:01:01 +02:00
parent 3275a267f6
commit 5beb1c5634
13 changed files with 487 additions and 112 deletions

View File

@@ -6,7 +6,7 @@
# Single post
200 /blog/hello-acme contains=Hello Acme
404 /blog/missing-post
200 /blog/unsafe-sample contains=journal-post-body--blocked notcontains=alert(
200 /blog/unsafe-sample contains=<p>Before</p><p>After</p> notcontains=alert(
404 /blog/draft-note
# Post index and pagination (9 per page, 13 published posts: 2 pages)