A vibe coded tangled fork which supports pijul.
at 745a46ef593c5c6c239a88081e8487ce7434ad41 133 lines 4.4 kB view raw
1package sanitizer 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 13var ( 14 defaultPolicy = newDefaultPolicy() 15 descriptionPolicy = newDescriptionPolicy() 16) 17 18func SanitizeDefault(html string) string { 19 return defaultPolicy.Sanitize(html) 20} 21func SanitizeDescription(html string) string { 22 return descriptionPolicy.Sanitize(html) 23} 24 25func newDefaultPolicy() *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 // at-mentions 74 policy.AllowAttrs("class").Matching(regexp.MustCompile(`mention`)).OnElements("a") 75 76 // centering content 77 policy.AllowElements("center") 78 79 policy.AllowAttrs("align", "style", "width", "height").Globally() 80 policy.AllowStyles( 81 "margin", 82 "padding", 83 "text-align", 84 "font-weight", 85 "text-decoration", 86 "padding-left", 87 "padding-right", 88 "padding-top", 89 "padding-bottom", 90 "margin-left", 91 "margin-right", 92 "margin-top", 93 "margin-bottom", 94 ) 95 96 // math 97 mathAttrs := []string{ 98 "accent", "columnalign", "columnlines", "columnspan", "dir", "display", 99 "displaystyle", "encoding", "fence", "form", "largeop", "linebreak", 100 "linethickness", "lspace", "mathcolor", "mathsize", "mathvariant", "minsize", 101 "movablelimits", "notation", "rowalign", "rspace", "rowspacing", "rowspan", 102 "scriptlevel", "stretchy", "symmetric", "title", "voffset", "width", 103 } 104 mathElements := []string{ 105 "annotation", "math", "menclose", "merror", "mfrac", "mi", "mmultiscripts", 106 "mn", "mo", "mover", "mpadded", "mprescripts", "mroot", "mrow", "mspace", 107 "msqrt", "mstyle", "msub", "msubsup", "msup", "mtable", "mtd", "mtext", 108 "mtr", "munder", "munderover", "semantics", 109 } 110 policy.AllowNoAttrs().OnElements(mathElements...) 111 policy.AllowAttrs(mathAttrs...).OnElements(mathElements...) 112 113 // goldmark-callout 114 policy.AllowAttrs("data-callout").OnElements("details") 115 116 return policy 117} 118 119func newDescriptionPolicy() *bluemonday.Policy { 120 policy := bluemonday.NewPolicy() 121 policy.AllowStandardURLs() 122 123 // allow italics and bold. 124 policy.AllowElements("i", "b", "em", "strong") 125 126 // allow code. 127 policy.AllowElements("code") 128 129 // allow links 130 policy.AllowAttrs("href", "target", "rel").OnElements("a") 131 132 return policy 133}