Skip to content

Commit

Permalink
markdown: sanitize links
Browse files Browse the repository at this point in the history
  • Loading branch information
alixander committed Nov 18, 2024
1 parent ad62935 commit d09d27f
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 15 deletions.
1 change: 1 addition & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
#### Bugfixes ⛑️

- Imports: fixes using substitutions in `icon` values [#2207](https://github.com/terrastruct/d2/pull/2207)
- Markdown: fixes ampersands in URLs in markdown [#2219](https://github.com/terrastruct/d2/pull/2219)
10 changes: 8 additions & 2 deletions d2compiler/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,14 @@ b.(x -> y)[0]: two
}
},
},
{
name: "markdown_ampersand",

text: `memo: |md
<a href="https://www.google.com/search?q=d2&newwindow=1">d2</a>
|
`,
},
{
name: "unsemantic_markdown",

Expand All @@ -943,7 +951,6 @@ foobar
<p>
|
`,
expErr: `d2/testdata/d2compiler/TestCompile/unsemantic_markdown.d2:1:1: malformed Markdown: element <p> closed by </div>`,
},
{
name: "unsemantic_markdown_2",
Expand All @@ -953,7 +960,6 @@ foo<br>
bar
|
`,
expErr: `d2/testdata/d2compiler/TestCompile/unsemantic_markdown_2.d2:1:1: malformed Markdown: element <br> closed by </p>`,
},
{
name: "edge_map",
Expand Down
55 changes: 55 additions & 0 deletions lib/textmeasure/links.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package textmeasure

import (
"bytes"
"net/url"
"strings"

"golang.org/x/net/html"
)

func sanitizeLinks(input string) (string, error) {
doc, err := html.Parse(strings.NewReader(input))
if err != nil {
return "", err
}

var process func(*html.Node)
process = func(n *html.Node) {
if n.Type == html.ElementNode {
for i, a := range n.Attr {
if a.Key == "href" {
if u, err := url.Parse(a.Val); err == nil {
if u.RawQuery != "" {
q := u.Query()
u.RawQuery = q.Encode()
}
n.Attr[i].Val = u.String()
}
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
process(c)
}
}
process(doc)

var buf bytes.Buffer
if doc.FirstChild != nil && doc.FirstChild.FirstChild != nil {
body := doc.FirstChild.LastChild
if body != nil {
for c := body.FirstChild; c != nil; c = c.NextSibling {
// NOTE: this has the effect of also HTML rendering nodes, which is
// robust to some malformed tags like <br>. Since this works in most
// HTML contexts anyway, this is not unintended
err = html.Render(&buf, c)
if err != nil {
return "", err
}
}
return buf.String(), nil
}
}
return input, nil
}
6 changes: 5 additions & 1 deletion lib/textmeasure/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ func RenderMarkdown(m string) (string, error) {
if err := markdownRenderer.Convert([]byte(m), &output); err != nil {
return "", err
}
return output.String(), nil
sanitized, err := sanitizeLinks(output.String())
if err != nil {
return "", err
}
return sanitized, nil
}

func init() {
Expand Down
114 changes: 114 additions & 0 deletions testdata/d2compiler/TestCompile/markdown_ampersand.exp.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 109 additions & 6 deletions testdata/d2compiler/TestCompile/unsemantic_markdown.exp.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d09d27f

Please sign in to comment.