-83
appview/pages/markup/markdown.go
-83
appview/pages/markup/markdown.go
···
5
5
"bytes"
6
6
"fmt"
7
7
"io"
8
-
"maps"
9
8
"net/url"
10
9
"path"
11
-
"regexp"
12
-
"slices"
13
10
"strings"
14
11
15
-
"github.com/alecthomas/chroma/v2"
16
12
chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
17
13
"github.com/alecthomas/chroma/v2/styles"
18
-
"github.com/microcosm-cc/bluemonday"
19
14
"github.com/yuin/goldmark"
20
15
highlighting "github.com/yuin/goldmark-highlighting/v2"
21
16
"github.com/yuin/goldmark/ast"
···
48
43
IsDev bool
49
44
RendererType RendererType
50
45
Sanitizer Sanitizer
51
-
}
52
-
53
-
type Sanitizer struct {
54
-
defaultPolicy *bluemonday.Policy
55
46
}
56
47
57
48
func (rctx *RenderContext) RenderMarkdown(source string) string {
···
168
159
169
160
func (rctx *RenderContext) SanitizeDefault(html string) string {
170
161
return rctx.Sanitizer.defaultPolicy.Sanitize(html)
171
-
}
172
-
173
-
func NewSanitizer() Sanitizer {
174
-
return Sanitizer{
175
-
defaultPolicy: defaultPolicy(),
176
-
}
177
-
}
178
-
func defaultPolicy() *bluemonday.Policy {
179
-
policy := bluemonday.UGCPolicy()
180
-
181
-
// Allow generally safe attributes
182
-
generalSafeAttrs := []string{
183
-
"abbr", "accept", "accept-charset",
184
-
"accesskey", "action", "align", "alt",
185
-
"aria-describedby", "aria-hidden", "aria-label", "aria-labelledby",
186
-
"axis", "border", "cellpadding", "cellspacing", "char",
187
-
"charoff", "charset", "checked",
188
-
"clear", "cols", "colspan", "color",
189
-
"compact", "coords", "datetime", "dir",
190
-
"disabled", "enctype", "for", "frame",
191
-
"headers", "height", "hreflang",
192
-
"hspace", "ismap", "label", "lang",
193
-
"maxlength", "media", "method",
194
-
"multiple", "name", "nohref", "noshade",
195
-
"nowrap", "open", "prompt", "readonly", "rel", "rev",
196
-
"rows", "rowspan", "rules", "scope",
197
-
"selected", "shape", "size", "span",
198
-
"start", "summary", "tabindex", "target",
199
-
"title", "type", "usemap", "valign", "value",
200
-
"vspace", "width", "itemprop",
201
-
}
202
-
203
-
generalSafeElements := []string{
204
-
"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt",
205
-
"div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label",
206
-
"dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary",
207
-
"details", "caption", "figure", "figcaption",
208
-
"abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr",
209
-
}
210
-
211
-
policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...)
212
-
213
-
// video
214
-
policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
215
-
216
-
// checkboxes
217
-
policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
218
-
policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input")
219
-
220
-
// for code blocks
221
-
policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre")
222
-
policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span")
223
-
224
-
// centering content
225
-
policy.AllowElements("center")
226
-
227
-
policy.AllowAttrs("align", "style", "width", "height").Globally()
228
-
policy.AllowStyles(
229
-
"margin",
230
-
"padding",
231
-
"text-align",
232
-
"font-weight",
233
-
"text-decoration",
234
-
"padding-left",
235
-
"padding-right",
236
-
"padding-top",
237
-
"padding-bottom",
238
-
"margin-left",
239
-
"margin-right",
240
-
"margin-top",
241
-
"margin-bottom",
242
-
)
243
-
244
-
return policy
245
162
}
246
163
247
164
type MarkdownTransformer struct {
+90
appview/pages/markup/sanitizer.go
+90
appview/pages/markup/sanitizer.go
···
1
+
package markup
2
+
3
+
import (
4
+
"maps"
5
+
"regexp"
6
+
"slices"
7
+
"strings"
8
+
9
+
"github.com/alecthomas/chroma/v2"
10
+
"github.com/microcosm-cc/bluemonday"
11
+
)
12
+
13
+
type Sanitizer struct {
14
+
defaultPolicy *bluemonday.Policy
15
+
}
16
+
17
+
func NewSanitizer() Sanitizer {
18
+
return Sanitizer{
19
+
defaultPolicy: defaultPolicy(),
20
+
}
21
+
}
22
+
23
+
func defaultPolicy() *bluemonday.Policy {
24
+
policy := bluemonday.UGCPolicy()
25
+
26
+
// Allow generally safe attributes
27
+
generalSafeAttrs := []string{
28
+
"abbr", "accept", "accept-charset",
29
+
"accesskey", "action", "align", "alt",
30
+
"aria-describedby", "aria-hidden", "aria-label", "aria-labelledby",
31
+
"axis", "border", "cellpadding", "cellspacing", "char",
32
+
"charoff", "charset", "checked",
33
+
"clear", "cols", "colspan", "color",
34
+
"compact", "coords", "datetime", "dir",
35
+
"disabled", "enctype", "for", "frame",
36
+
"headers", "height", "hreflang",
37
+
"hspace", "ismap", "label", "lang",
38
+
"maxlength", "media", "method",
39
+
"multiple", "name", "nohref", "noshade",
40
+
"nowrap", "open", "prompt", "readonly", "rel", "rev",
41
+
"rows", "rowspan", "rules", "scope",
42
+
"selected", "shape", "size", "span",
43
+
"start", "summary", "tabindex", "target",
44
+
"title", "type", "usemap", "valign", "value",
45
+
"vspace", "width", "itemprop",
46
+
}
47
+
48
+
generalSafeElements := []string{
49
+
"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt",
50
+
"div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label",
51
+
"dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary",
52
+
"details", "caption", "figure", "figcaption",
53
+
"abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr",
54
+
}
55
+
56
+
policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...)
57
+
58
+
// video
59
+
policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
60
+
61
+
// checkboxes
62
+
policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
63
+
policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input")
64
+
65
+
// for code blocks
66
+
policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre")
67
+
policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span")
68
+
69
+
// centering content
70
+
policy.AllowElements("center")
71
+
72
+
policy.AllowAttrs("align", "style", "width", "height").Globally()
73
+
policy.AllowStyles(
74
+
"margin",
75
+
"padding",
76
+
"text-align",
77
+
"font-weight",
78
+
"text-decoration",
79
+
"padding-left",
80
+
"padding-right",
81
+
"padding-top",
82
+
"padding-bottom",
83
+
"margin-left",
84
+
"margin-right",
85
+
"margin-top",
86
+
"margin-bottom",
87
+
)
88
+
89
+
return policy
90
+
}