fix: markdown rendering improvements

Improvements to markdown rendering in notification emails:

- More consistent escaping of values interpolated into notification templates
- Stricter link handling in the notification email renderer, scoped to the notification rendering path
- HTML escaping of values interpolated into the outer email template

- Expanded unit and end-to-end coverage of the notification rendering pipeline
- `make gen` run to regenerate golden files for SMTP and webhook notification templates
This commit is contained in:
Jakub Domeracki
2026-08-10 10:45:19 +02:00
parent 192842c8f2
commit 07f79af65b
37 changed files with 962 additions and 70 deletions
+21 -2
View File
@@ -114,10 +114,29 @@ func PlaintextFromMarkdown(markdown string) (string, error) {
}
func HTMLFromMarkdown(markdown string) string {
p := parser.NewWithExtensions(parser.CommonExtensions | parser.HardLineBreak) // Added HardLineBreak.
return renderHTMLFromMarkdown(markdown, parser.CommonExtensions|parser.HardLineBreak, html.CommonFlags|html.SkipHTML)
}
// HTMLFromMarkdownSafe renders Markdown to HTML with additional security
// hardening for content that may include user-controlled values (e.g.
// notification emails): autolinks are disabled so that only explicit Markdown
// link syntax produces <a> tags, and Safelink drops links whose scheme is not
// http/https/ftp/mailto.
//
// The hardening is scoped to this function. HTMLFromMarkdown renders
// admin-authored deployment text (OIDCConfig.SignupsDisabledText) and keeps the
// standard flags so links with custom schemes (e.g. slack://) still render.
func HTMLFromMarkdownSafe(markdown string) string {
extensions := parser.CommonExtensions | parser.HardLineBreak
extensions &^= parser.Autolink
return renderHTMLFromMarkdown(markdown, extensions, html.CommonFlags|html.SkipHTML|html.Safelink)
}
func renderHTMLFromMarkdown(markdown string, extensions parser.Extensions, flags html.Flags) string {
p := parser.NewWithExtensions(extensions)
doc := p.Parse([]byte(markdown))
renderer := html.NewRenderer(html.RendererOptions{
Flags: html.CommonFlags | html.SkipHTML,
Flags: flags,
})
return string(bytes.TrimSpace(gomarkdown.Render(doc, renderer)))
}