From 3f497d496fcb002e18cd339c5850a300346b2f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Tue, 30 May 2023 13:21:45 +0200 Subject: [PATCH] Prevent double escaping of image alt-text in Goldmar typographer Fixes #11045 --- markup/goldmark/convert_test.go | 23 +++++++++++++++++++++++ markup/goldmark/render_hooks.go | 17 ++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/markup/goldmark/convert_test.go b/markup/goldmark/convert_test.go index 05279cd2c..666529877 100644 --- a/markup/goldmark/convert_test.go +++ b/markup/goldmark/convert_test.go @@ -584,6 +584,29 @@ rightDoubleQuote = "»" c.Assert(got, qt.Contains, "

A «quote» and ‘another quote’ and a «quote with a ’nested’ quote» and a ‘quote with a «nested» quote’ and an ellipsis…

\n") } +// Issue #11045 +func TestTypographerImageAltText(t *testing.T) { + c := qt.New(t) + + content := ` +!["They didn't even say 'hello'!" I exclaimed.](https://example.com/image.jpg) +` + + confStr := ` +[markup] +[markup.goldmark] + +` + + cfg := config.FromTOMLConfigString(confStr) + conf := testconfig.GetTestConfig(nil, cfg) + + b := convert(c, conf, content) + got := string(b.Bytes()) + + c.Assert(got, qt.Contains, "“They didn’t even say ‘hello’!” I exclaimed.") +} + func unsafeConf() config.AllProvider { cfg := config.FromTOMLConfigString(` [markup] diff --git a/markup/goldmark/render_hooks.go b/markup/goldmark/render_hooks.go index 0bd800dc0..60a3a1efe 100644 --- a/markup/goldmark/render_hooks.go +++ b/markup/goldmark/render_hooks.go @@ -225,7 +225,7 @@ func (r *hookedRenderer) renderImageDefault(w util.BufWriter, source []byte, nod _, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true))) } _, _ = w.WriteString(`" alt="`) - _, _ = w.Write(util.EscapeHTML(n.Text(source))) + _, _ = w.Write(nodeToHTMLText(n, source)) _ = w.WriteByte('"') if n.Title != nil { _, _ = w.WriteString(` title="`) @@ -475,3 +475,18 @@ func (e *links) Extend(m goldmark.Markdown) { util.Prioritized(newLinkRenderer(e.cfg), 100), )) } + +// Borrowed from Goldmark. +func nodeToHTMLText(n ast.Node, source []byte) []byte { + var buf bytes.Buffer + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + if s, ok := c.(*ast.String); ok && s.IsCode() { + buf.Write(s.Text(source)) + } else if !c.HasChildren() { + buf.Write(util.EscapeHTML(c.Text(source))) + } else { + buf.Write(nodeToHTMLText(c, source)) + } + } + return buf.Bytes() +}