// Package markdown renders untrusted Markdown to sanitized HTML. package markdown import ( "bytes" "github.com/microcosm-cc/bluemonday" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer/html" ) var md = goldmark.New( goldmark.WithExtensions(extension.GFM, extension.Typographer), goldmark.WithParserOptions(parser.WithAutoHeadingID()), goldmark.WithRendererOptions(html.WithHardWraps(), html.WithUnsafe()), // unsafe output is sanitized below ) var policy = func() *bluemonday.Policy { p := bluemonday.UGCPolicy() p.AllowAttrs("id").OnElements("h1", "h2", "h3", "h4", "h5", "h6") p.AllowAttrs("class").Matching(bluemonday.SpaceSeparatedTokens).OnElements("code", "pre", "span", "div", "table", "input", "li", "ul") p.AllowAttrs("type", "checked", "disabled").OnElements("input") p.AllowAttrs("align").OnElements("th", "td") p.AllowAttrs("width", "height").OnElements("img") p.RequireNoFollowOnLinks(false) return p }() // Render converts Markdown to HTML that is safe to embed unescaped. func Render(src string) string { var buf bytes.Buffer if err := md.Convert([]byte(src), &buf); err != nil { return "
(could not render content)
" } return policy.Sanitize(buf.String()) }