feat(classes): allow the Blog Editor's own markup in the HTML policy
- figure data-embed ^youtube$ and data-id ^[A-Za-z0-9_-]{11}$ (the embed
placeholder), img alt with any text, ol start ^[0-9]+$; nothing else
- TestEditorOutputPassesPolicy checks every editor-corpus.json entry byte
for byte with an empty report, plus the negative cases;
TestSanitizeHTMLReport pins the removal report
- CheckHTML documented as a predicate no write path refuses with; README
lists the four additions and the report API
This commit is contained in:
@@ -54,6 +54,22 @@ func newHTMLPolicy() *bluemonday.Policy {
|
||||
p.AllowAttrs("dir").Matching(regexp.MustCompile(`(?i)^(ltr|rtl|auto)$`)).Globally()
|
||||
p.AllowAttrs("data-message-author-role", "data-message-id").
|
||||
Matching(regexp.MustCompile(`^[A-Za-z0-9_-]+$`)).OnElements("div")
|
||||
// Blog Editor output (Phase 16.2 D-05), exactly what the editor writes
|
||||
// and nothing more; plan 02's editor-corpus.json pins it
|
||||
// (TestEditorOutputPassesPolicy) and the site layer mirrors these rules.
|
||||
// The embed placeholder <figure data-embed="youtube" data-id="..."></figure>:
|
||||
// the provider name and the 11-character video id, on figure only. The
|
||||
// layer expands it; no iframe is ever stored.
|
||||
p.AllowAttrs("data-embed").Matching(regexp.MustCompile(`^youtube$`)).OnElements("figure")
|
||||
p.AllowAttrs("data-id").Matching(regexp.MustCompile(`^[A-Za-z0-9_-]{11}$`)).OnElements("figure")
|
||||
// The editor's alt field takes free text, which UGC's Paragraph pattern
|
||||
// cuts at ':', '?', '"' and more. bluemonday accepts an attribute when
|
||||
// any of its rules matches and escapes the value on output; alt carries
|
||||
// no URL.
|
||||
p.AllowAttrs("alt").OnElements("img")
|
||||
// TipTap's ordered-list input rule writes start when a list does not
|
||||
// begin at 1.
|
||||
p.AllowAttrs("start").Matching(regexp.MustCompile(`^[0-9]+$`)).OnElements("ol")
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -310,10 +326,12 @@ func textOf(v any) string {
|
||||
}
|
||||
}
|
||||
|
||||
// CheckHTML gates HTML that is stored as is, such as category content. It
|
||||
// uses the FormatHTML allow-list but refuses instead of stripping: doc is
|
||||
// refused when the policy would remove or change any element, attribute or
|
||||
// text in it.
|
||||
// CheckHTML reports whether the FormatHTML allow-list would remove or
|
||||
// change any element, attribute or text in doc: it returns an error when it
|
||||
// would, nil when the policy keeps doc whole. Since Phase 16.2 no admin or
|
||||
// API write path refuses with it (admin saves strip and report through
|
||||
// SanitizeHTMLReport, D-10 amended); it is the predicate counterpart of the
|
||||
// site layer's isSafeJournalHtml, and the policy cross-check tests use it.
|
||||
func CheckHTML(doc string) error {
|
||||
if _, changed := sanitizeHTML(doc); changed {
|
||||
return errors.New("journal: HTML contains elements, attributes or URLs that are not allowed")
|
||||
|
||||
Reference in New Issue
Block a user