this repo has no description
1package markup
2
3import (
4 "maps"
5 "regexp"
6 "slices"
7 "strings"
8
9 "github.com/alecthomas/chroma/v2"
10 "github.com/microcosm-cc/bluemonday"
11)
12
13type Sanitizer struct {
14 defaultPolicy *bluemonday.Policy
15 descriptionPolicy *bluemonday.Policy
16}
17
18func NewSanitizer() Sanitizer {
19 return Sanitizer{
20 defaultPolicy: defaultPolicy(),
21 descriptionPolicy: descriptionPolicy(),
22 }
23}
24
25func defaultPolicy() *bluemonday.Policy {
26 policy := bluemonday.UGCPolicy()
27
28 // Allow generally safe attributes
29 generalSafeAttrs := []string{
30 "abbr", "accept", "accept-charset",
31 "accesskey", "action", "align", "alt",
32 "aria-describedby", "aria-hidden", "aria-label", "aria-labelledby",
33 "axis", "border", "cellpadding", "cellspacing", "char",
34 "charoff", "charset", "checked",
35 "clear", "cols", "colspan", "color",
36 "compact", "coords", "datetime", "dir",
37 "disabled", "enctype", "for", "frame",
38 "headers", "height", "hreflang",
39 "hspace", "ismap", "label", "lang",
40 "maxlength", "media", "method",
41 "multiple", "name", "nohref", "noshade",
42 "nowrap", "open", "prompt", "readonly", "rel", "rev",
43 "rows", "rowspan", "rules", "scope",
44 "selected", "shape", "size", "span",
45 "start", "summary", "tabindex", "target",
46 "title", "type", "usemap", "valign", "value",
47 "vspace", "width", "itemprop",
48 }
49
50 generalSafeElements := []string{
51 "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt",
52 "div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label",
53 "dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary",
54 "details", "caption", "figure", "figcaption",
55 "abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr",
56 }
57
58 policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...)
59
60 // video
61 policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
62
63 // checkboxes
64 policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
65 policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input")
66
67 // for code blocks
68 policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre")
69 policy.AllowAttrs("class").Matching(regexp.MustCompile(`anchor|footnote-ref|footnote-backref`)).OnElements("a")
70 policy.AllowAttrs("class").Matching(regexp.MustCompile(`heading`)).OnElements("h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8")
71 policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span")
72
73 // centering content
74 policy.AllowElements("center")
75
76 policy.AllowAttrs("align", "style", "width", "height").Globally()
77 policy.AllowStyles(
78 "margin",
79 "padding",
80 "text-align",
81 "font-weight",
82 "text-decoration",
83 "padding-left",
84 "padding-right",
85 "padding-top",
86 "padding-bottom",
87 "margin-left",
88 "margin-right",
89 "margin-top",
90 "margin-bottom",
91 )
92
93 return policy
94}
95
96func descriptionPolicy() *bluemonday.Policy {
97 policy := bluemonday.NewPolicy()
98 policy.AllowStandardURLs()
99
100 // allow italics and bold.
101 policy.AllowElements("i", "b", "em", "strong")
102
103 // allow code.
104 policy.AllowElements("code")
105
106 // allow links
107 policy.AllowAttrs("href", "target", "rel").OnElements("a")
108
109 return policy
110}