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