forked from tangled.org/core
this repo has no description

appview: post-process rendered markdown after sanitization

also ensures that every (RunContext).RenderMarkdown callsite gets back a
sanitized value (or very loudly decides not to sanitize by passing e.g.
func(s string) string { return s } as the sanitizer argument)

Changed files
+17 -8
appview
+3 -1
appview/pages/funcmap.go
··· 145 }, 146 "markdown": func(text string) template.HTML { 147 rctx := &markup.RenderContext{RendererType: markup.RendererTypeDefault} 148 - return template.HTML(bluemonday.UGCPolicy().Sanitize(rctx.RenderMarkdown(text))) 149 }, 150 "isNil": func(t any) bool { 151 // returns false for other "zero" values
··· 145 }, 146 "markdown": func(text string) template.HTML { 147 rctx := &markup.RenderContext{RendererType: markup.RendererTypeDefault} 148 + return template.HTML( 149 + rctx.RenderMarkdown(text, bluemonday.UGCPolicy().Sanitize), 150 + ) 151 }, 152 "isNil": func(t any) bool { 153 // returns false for other "zero" values
+10 -3
appview/pages/markup/markdown.go
··· 44 RendererType RendererType 45 } 46 47 - func (rctx *RenderContext) RenderMarkdown(source string) string { 48 md := goldmark.New( 49 goldmark.WithExtensions(extension.GFM, 50 highlighting.NewHighlighting( ··· 74 return source 75 } 76 77 var processed strings.Builder 78 - if err := postProcess(rctx, strings.NewReader(buf.String()), &processed); err != nil { 79 return source 80 } 81 82 return processed.String() 83 } 84 85 - func postProcess(ctx *RenderContext, input io.Reader, output io.Writer) error { 86 node, err := htmlparse.Parse(io.MultiReader( 87 strings.NewReader("<html><body>"), 88 input, ··· 127 return nil 128 } 129 130 func visitNode(ctx *RenderContext, node *htmlparse.Node) { 131 switch node.Type { 132 case htmlparse.ElementNode:
··· 44 RendererType RendererType 45 } 46 47 + // RenderMarkdown renders the given markdown source into sanitized HTML. sanitizer is used to sanitize the HTML output. 48 + func (rctx *RenderContext) RenderMarkdown(source string, sanitizer func(string) string) string { 49 md := goldmark.New( 50 goldmark.WithExtensions(extension.GFM, 51 highlighting.NewHighlighting( ··· 75 return source 76 } 77 78 + sanitizedHtml := sanitizer(buf.String()) 79 + 80 var processed strings.Builder 81 + if err := postProcessSanitizedHtml(rctx, strings.NewReader(sanitizedHtml), &processed); err != nil { 82 return source 83 } 84 85 return processed.String() 86 } 87 88 + // postProcessSanitizedHtml processes the HTML output from the markdown renderer. 89 + // WARNING: Do not insert raw HTML from user-controlled input. Sanitization already happened beforehand at this point. 90 + func postProcessSanitizedHtml(ctx *RenderContext, input io.Reader, output io.Writer) error { 91 node, err := htmlparse.Parse(io.MultiReader( 92 strings.NewReader("<html><body>"), 93 input, ··· 132 return nil 133 } 134 135 + // visitNode is called on every node of a SANITIZED html document. 136 + // WARNING: Do not insert raw HTML from user-controlled input. Sanitization already happened beforehand at this point. 137 func visitNode(ctx *RenderContext, node *htmlparse.Node) { 138 switch node.Type { 139 case htmlparse.ElementNode:
+4 -4
appview/pages/pages.go
··· 432 ext := filepath.Ext(params.ReadmeFileName) 433 switch ext { 434 case ".md", ".markdown", ".mdown", ".mkdn", ".mkd": 435 - htmlString = p.rctx.RenderMarkdown(params.Readme) 436 params.Raw = false 437 - params.HTMLReadme = template.HTML(p.rctx.Sanitize(htmlString)) 438 default: 439 htmlString = string(params.Readme) 440 params.Raw = true ··· 564 case markup.FormatMarkdown: 565 p.rctx.RepoInfo = params.RepoInfo 566 p.rctx.RendererType = markup.RendererTypeRepoMarkdown 567 - htmlString := p.rctx.RenderMarkdown(params.Contents) 568 - params.RenderedContents = template.HTML(p.rctx.Sanitize(htmlString)) 569 } 570 } 571
··· 432 ext := filepath.Ext(params.ReadmeFileName) 433 switch ext { 434 case ".md", ".markdown", ".mdown", ".mkdn", ".mkd": 435 + htmlString = p.rctx.RenderMarkdown(params.Readme, p.rctx.Sanitize) 436 params.Raw = false 437 + params.HTMLReadme = template.HTML(htmlString) 438 default: 439 htmlString = string(params.Readme) 440 params.Raw = true ··· 564 case markup.FormatMarkdown: 565 p.rctx.RepoInfo = params.RepoInfo 566 p.rctx.RendererType = markup.RendererTypeRepoMarkdown 567 + htmlString := p.rctx.RenderMarkdown(params.Contents, p.rctx.Sanitize) 568 + params.RenderedContents = template.HTML(htmlString) 569 } 570 } 571