forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
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 (s *Sanitizer) SanitizeDefault(html string) string {
26 return s.defaultPolicy.Sanitize(html)
27}
28func (s *Sanitizer) SanitizeDescription(html string) string {
29 return s.descriptionPolicy.Sanitize(html)
30}
31
32func defaultPolicy() *bluemonday.Policy {
33 policy := bluemonday.UGCPolicy()
34
35 // Allow generally safe attributes
36 generalSafeAttrs := []string{
37 "abbr", "accept", "accept-charset",
38 "accesskey", "action", "align", "alt",
39 "aria-describedby", "aria-hidden", "aria-label", "aria-labelledby",
40 "axis", "border", "cellpadding", "cellspacing", "char",
41 "charoff", "charset", "checked",
42 "clear", "cols", "colspan", "color",
43 "compact", "coords", "datetime", "dir",
44 "disabled", "enctype", "for", "frame",
45 "headers", "height", "hreflang",
46 "hspace", "ismap", "label", "lang",
47 "maxlength", "media", "method",
48 "multiple", "name", "nohref", "noshade",
49 "nowrap", "open", "prompt", "readonly", "rel", "rev",
50 "rows", "rowspan", "rules", "scope",
51 "selected", "shape", "size", "span",
52 "start", "summary", "tabindex", "target",
53 "title", "type", "usemap", "valign", "value",
54 "vspace", "width", "itemprop",
55 }
56
57 generalSafeElements := []string{
58 "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt",
59 "div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label",
60 "dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary",
61 "details", "caption", "figure", "figcaption",
62 "abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr",
63 }
64
65 policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...)
66
67 // video
68 policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
69
70 // checkboxes
71 policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
72 policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input")
73
74 // for code blocks
75 policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre")
76 policy.AllowAttrs("class").Matching(regexp.MustCompile(`anchor|footnote-ref|footnote-backref`)).OnElements("a")
77 policy.AllowAttrs("class").Matching(regexp.MustCompile(`heading`)).OnElements("h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8")
78 policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span")
79
80 // at-mentions
81 policy.AllowAttrs("class").Matching(regexp.MustCompile(`mention`)).OnElements("a")
82
83 // centering content
84 policy.AllowElements("center")
85
86 policy.AllowAttrs("align", "style", "width", "height").Globally()
87 policy.AllowStyles(
88 "margin",
89 "padding",
90 "text-align",
91 "font-weight",
92 "text-decoration",
93 "padding-left",
94 "padding-right",
95 "padding-top",
96 "padding-bottom",
97 "margin-left",
98 "margin-right",
99 "margin-top",
100 "margin-bottom",
101 )
102
103 // math
104 mathAttrs := []string{
105 "accent", "columnalign", "columnlines", "columnspan", "dir", "display",
106 "displaystyle", "encoding", "fence", "form", "largeop", "linebreak",
107 "linethickness", "lspace", "mathcolor", "mathsize", "mathvariant", "minsize",
108 "movablelimits", "notation", "rowalign", "rspace", "rowspacing", "rowspan",
109 "scriptlevel", "stretchy", "symmetric", "title", "voffset", "width",
110 }
111 mathElements := []string{
112 "annotation", "math", "menclose", "merror", "mfrac", "mi", "mmultiscripts",
113 "mn", "mo", "mover", "mpadded", "mprescripts", "mroot", "mrow", "mspace",
114 "msqrt", "mstyle", "msub", "msubsup", "msup", "mtable", "mtd", "mtext",
115 "mtr", "munder", "munderover", "semantics",
116 }
117 policy.AllowNoAttrs().OnElements(mathElements...)
118 policy.AllowAttrs(mathAttrs...).OnElements(mathElements...)
119
120 // goldmark-callout
121 policy.AllowAttrs("data-callout").OnElements("details")
122
123 return policy
124}
125
126func descriptionPolicy() *bluemonday.Policy {
127 policy := bluemonday.NewPolicy()
128 policy.AllowStandardURLs()
129
130 // allow italics and bold.
131 policy.AllowElements("i", "b", "em", "strong")
132
133 // allow code.
134 policy.AllowElements("code")
135
136 // allow links
137 policy.AllowAttrs("href", "target", "rel").OnElements("a")
138
139 return policy
140}