gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit f01492ae4899aa6219f29a127da2e749ebf64c30
parent 0245c606d77c8b99833ccc2c0923a298fb482236
Author: Blackle Morisanchetto <isabelle@blackle-mori.com>
Date:   Wed, 31 Aug 2022 11:40:11 -0400

[bugfix] Use custom blackfriday renderer to only add mention/hashtag links in normal text (#787)

* Use custom blackfriday renderer to only add mention/hashtag links in normal text

* Add additional markdown tests
Diffstat:
Minternal/text/markdown.go | 49++++++++++++++++++++++++++++++++++++++++++-------
Minternal/text/markdown_test.go | 18++++++++++++++++++
2 files changed, 60 insertions(+), 7 deletions(-)

diff --git a/internal/text/markdown.go b/internal/text/markdown.go @@ -19,7 +19,9 @@ package text import ( + "bytes" "context" + "io" "github.com/russross/blackfriday/v2" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" @@ -33,18 +35,51 @@ var ( m *minify.M ) +type renderer struct { + f *formatter + ctx context.Context + mentions []*gtsmodel.Mention + tags []*gtsmodel.Tag + blackfriday.HTMLRenderer +} + +func (r *renderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + if node.Type == blackfriday.Text { + // call RenderNode to do the html escaping + var buff bytes.Buffer + status := r.HTMLRenderer.RenderNode(&buff, node, entering) + + html := buff.String() + html = r.f.ReplaceTags(r.ctx, html, r.tags) + html = r.f.ReplaceMentions(r.ctx, html, r.mentions) + + // we don't have much recourse if this fails + _, err := io.WriteString(w, html) + if err != nil { + log.Errorf("error outputting markdown text: %s", err) + } + return status + } + return r.HTMLRenderer.RenderNode(w, node, entering) +} + func (f *formatter) FromMarkdown(ctx context.Context, md string, mentions []*gtsmodel.Mention, tags []*gtsmodel.Tag) string { - // format tags nicely - content := f.ReplaceTags(ctx, md, tags) - // format mentions nicely - content = f.ReplaceMentions(ctx, content, mentions) + renderer := &renderer{ + f: f, + ctx: ctx, + mentions: mentions, + tags: tags, + HTMLRenderer: *blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ + Flags: blackfriday.CommonHTMLFlags, + }), + } - // parse markdown - contentBytes := blackfriday.Run([]byte(content), blackfriday.WithExtensions(bfExtensions)) + // parse markdown, use custom renderer to add hashtag/mention links + contentBytes := blackfriday.Run([]byte(md), blackfriday.WithExtensions(bfExtensions), blackfriday.WithRenderer(renderer)) // clean anything dangerous out of it - content = SanitizeHTML(string(contentBytes)) + content := SanitizeHTML(string(contentBytes)) if m == nil { m = minify.New() diff --git a/internal/text/markdown_test.go b/internal/text/markdown_test.go @@ -65,6 +65,10 @@ const ( mdWithFootnoteExpected = "<p>fox mulder,fbi.<sup id=\"fnref:1\"><a href=\"#fn:1\" rel=\"nofollow noreferrer\">1</a></sup></p><div><hr><ol><li id=\"fn:1\">federated bureau of investigation<br></li></ol></div>" mdWithBlockQuote = "get ready, there's a block quote coming:\n\n>line1\n>line2\n>\n>line3\n\n" mdWithBlockQuoteExpected = "<p>get ready, there’s a block quote coming:</p><blockquote><p>line1<br>line2</p><p>line3</p></blockquote>" + mdHashtagAndCodeBlock = "#Hashtag\n\n```\n#Hashtag\n```" + mdHashtagAndCodeBlockExpected = "<p><a href=\"http://localhost:8080/tags/Hashtag\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>Hashtag</span></a></p><pre><code>#Hashtag\n</code></pre>" + mdMentionAndCodeBlock = "@the_mighty_zork\n\n```\n@the_mighty_zork\n```" + mdMentionAndCodeBlockExpected = "<p><span class=\"h-card\"><a href=\"http://localhost:8080/@the_mighty_zork\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">@<span>the_mighty_zork</span></a></span></p><pre><code>@the_mighty_zork\n</code></pre>" ) type MarkdownTestSuite struct { @@ -133,6 +137,20 @@ func (suite *MarkdownTestSuite) TestParseWithBlockquote() { suite.Equal(mdWithBlockQuoteExpected, s) } +func (suite *MarkdownTestSuite) TestParseHashtagWithCodeBlock() { + s := suite.formatter.FromMarkdown(context.Background(), mdHashtagAndCodeBlock, nil, []*gtsmodel.Tag{ + suite.testTags["Hashtag"], + }) + suite.Equal(mdHashtagAndCodeBlockExpected, s) +} + +func (suite *MarkdownTestSuite) TestParseMentionWithCodeBlock() { + s := suite.formatter.FromMarkdown(context.Background(), mdMentionAndCodeBlock, []*gtsmodel.Mention{ + suite.testMentions["local_user_2_mention_zork"], + }, nil) + suite.Equal(mdMentionAndCodeBlockExpected, s) +} + func TestMarkdownTestSuite(t *testing.T) { suite.Run(t, new(MarkdownTestSuite)) }