From cf810fe208b068f805699a9ebc52a3afab31427b Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Fri, 15 Aug 2025 16:09:53 +0100 Subject: [PATCH] appview/pages/markup: move sanitizer to separate file Change-Id: wzpnqqmqvtyvumzwwryuqxuuqpzztyon Signed-off-by: oppiliappan --- appview/pages/markup/markdown.go | 83 ---------------------------- appview/pages/markup/sanitizer.go | 90 +++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 83 deletions(-) create mode 100644 appview/pages/markup/sanitizer.go diff --git a/appview/pages/markup/markdown.go b/appview/pages/markup/markdown.go index 223f860a..b00081a2 100644 --- a/appview/pages/markup/markdown.go +++ b/appview/pages/markup/markdown.go @@ -5,17 +5,12 @@ import ( "bytes" "fmt" "io" - "maps" "net/url" "path" - "regexp" - "slices" "strings" - "github.com/alecthomas/chroma/v2" chromahtml "github.com/alecthomas/chroma/v2/formatters/html" "github.com/alecthomas/chroma/v2/styles" - "github.com/microcosm-cc/bluemonday" "github.com/yuin/goldmark" highlighting "github.com/yuin/goldmark-highlighting/v2" "github.com/yuin/goldmark/ast" @@ -50,10 +45,6 @@ type RenderContext struct { Sanitizer Sanitizer } -type Sanitizer struct { - defaultPolicy *bluemonday.Policy -} - func (rctx *RenderContext) RenderMarkdown(source string) string { md := goldmark.New( goldmark.WithExtensions( @@ -170,80 +161,6 @@ func (rctx *RenderContext) SanitizeDefault(html string) string { return rctx.Sanitizer.defaultPolicy.Sanitize(html) } -func NewSanitizer() Sanitizer { - return Sanitizer{ - defaultPolicy: defaultPolicy(), - } -} -func defaultPolicy() *bluemonday.Policy { - policy := bluemonday.UGCPolicy() - - // Allow generally safe attributes - generalSafeAttrs := []string{ - "abbr", "accept", "accept-charset", - "accesskey", "action", "align", "alt", - "aria-describedby", "aria-hidden", "aria-label", "aria-labelledby", - "axis", "border", "cellpadding", "cellspacing", "char", - "charoff", "charset", "checked", - "clear", "cols", "colspan", "color", - "compact", "coords", "datetime", "dir", - "disabled", "enctype", "for", "frame", - "headers", "height", "hreflang", - "hspace", "ismap", "label", "lang", - "maxlength", "media", "method", - "multiple", "name", "nohref", "noshade", - "nowrap", "open", "prompt", "readonly", "rel", "rev", - "rows", "rowspan", "rules", "scope", - "selected", "shape", "size", "span", - "start", "summary", "tabindex", "target", - "title", "type", "usemap", "valign", "value", - "vspace", "width", "itemprop", - } - - generalSafeElements := []string{ - "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt", - "div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label", - "dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary", - "details", "caption", "figure", "figcaption", - "abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr", - } - - policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...) - - // video - policy.AllowAttrs("src", "autoplay", "controls").OnElements("video") - - // checkboxes - policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input") - policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input") - - // for code blocks - policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre") - policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span") - - // centering content - policy.AllowElements("center") - - policy.AllowAttrs("align", "style", "width", "height").Globally() - policy.AllowStyles( - "margin", - "padding", - "text-align", - "font-weight", - "text-decoration", - "padding-left", - "padding-right", - "padding-top", - "padding-bottom", - "margin-left", - "margin-right", - "margin-top", - "margin-bottom", - ) - - return policy -} - type MarkdownTransformer struct { rctx *RenderContext } diff --git a/appview/pages/markup/sanitizer.go b/appview/pages/markup/sanitizer.go new file mode 100644 index 00000000..92696374 --- /dev/null +++ b/appview/pages/markup/sanitizer.go @@ -0,0 +1,90 @@ +package markup + +import ( + "maps" + "regexp" + "slices" + "strings" + + "github.com/alecthomas/chroma/v2" + "github.com/microcosm-cc/bluemonday" +) + +type Sanitizer struct { + defaultPolicy *bluemonday.Policy +} + +func NewSanitizer() Sanitizer { + return Sanitizer{ + defaultPolicy: defaultPolicy(), + } +} + +func defaultPolicy() *bluemonday.Policy { + policy := bluemonday.UGCPolicy() + + // Allow generally safe attributes + generalSafeAttrs := []string{ + "abbr", "accept", "accept-charset", + "accesskey", "action", "align", "alt", + "aria-describedby", "aria-hidden", "aria-label", "aria-labelledby", + "axis", "border", "cellpadding", "cellspacing", "char", + "charoff", "charset", "checked", + "clear", "cols", "colspan", "color", + "compact", "coords", "datetime", "dir", + "disabled", "enctype", "for", "frame", + "headers", "height", "hreflang", + "hspace", "ismap", "label", "lang", + "maxlength", "media", "method", + "multiple", "name", "nohref", "noshade", + "nowrap", "open", "prompt", "readonly", "rel", "rev", + "rows", "rowspan", "rules", "scope", + "selected", "shape", "size", "span", + "start", "summary", "tabindex", "target", + "title", "type", "usemap", "valign", "value", + "vspace", "width", "itemprop", + } + + generalSafeElements := []string{ + "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt", + "div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label", + "dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary", + "details", "caption", "figure", "figcaption", + "abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr", + } + + policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...) + + // video + policy.AllowAttrs("src", "autoplay", "controls").OnElements("video") + + // checkboxes + policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input") + policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input") + + // for code blocks + policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre") + policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span") + + // centering content + policy.AllowElements("center") + + policy.AllowAttrs("align", "style", "width", "height").Globally() + policy.AllowStyles( + "margin", + "padding", + "text-align", + "font-weight", + "text-decoration", + "padding-left", + "padding-right", + "padding-top", + "padding-bottom", + "margin-left", + "margin-right", + "margin-top", + "margin-bottom", + ) + + return policy +} -- 2.43.0