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 // centering content 81 policy.AllowElements("center") 82 83 policy.AllowAttrs("align", "style", "width", "height").Globally() 84 policy.AllowStyles( 85 "margin", 86 "padding", 87 "text-align", 88 "font-weight", 89 "text-decoration", 90 "padding-left", 91 "padding-right", 92 "padding-top", 93 "padding-bottom", 94 "margin-left", 95 "margin-right", 96 "margin-top", 97 "margin-bottom", 98 ) 99 100 return policy 101} 102 103func descriptionPolicy() *bluemonday.Policy { 104 policy := bluemonday.NewPolicy() 105 policy.AllowStandardURLs() 106 107 // allow italics and bold. 108 policy.AllowElements("i", "b", "em", "strong") 109 110 // allow code. 111 policy.AllowElements("code") 112 113 // allow links 114 policy.AllowAttrs("href", "target", "rel").OnElements("a") 115 116 return policy 117}