summaryrefslogtreecommitdiffstats
path: root/modules/templates
diff options
context:
space:
mode:
authorKN4CK3R <admin@oldschoolhack.me>2024-01-16 03:13:29 +0100
committerGitHub <noreply@github.com>2024-01-16 02:13:29 +0000
commit022552d5b6adc792d3cd16df7de6e52cb7b41a72 (patch)
tree4c709003d9d529475f563ff3997b7be874448052 /modules/templates
parent376fa0d8c49ca8a290ebb328281a56af346f5785 (diff)
downloadgitea-022552d5b6adc792d3cd16df7de6e52cb7b41a72.tar.gz
gitea-022552d5b6adc792d3cd16df7de6e52cb7b41a72.zip
Rework markup link rendering (#26745) (#28803)
Backport #26745 Fixes #26548 This PR refactors the rendering of markup links. The old code uses `strings.Replace` to change some urls while the new code uses more context to decide which link should be generated. The added tests should ensure the same output for the old and new behaviour (besides the bug). We may need to refactor the rendering a bit more to make it clear how the different helper methods render the input string. There are lots of options (resolve links / images / mentions / git hashes / emojis / ...) but you don't really know what helper uses which options. For example, we currently support images in the user description which should not be allowed I think: <details> <summary>Profile</summary> https://try.gitea.io/KN4CK3R ![grafik](https://github.com/go-gitea/gitea/assets/1666336/109ae422-496d-4200-b52e-b3a528f553e5) </details>
Diffstat (limited to 'modules/templates')
-rw-r--r--modules/templates/helper.go1
-rw-r--r--modules/templates/util_render.go52
-rw-r--r--modules/templates/util_render_test.go141
3 files changed, 149 insertions, 45 deletions
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index bb1411cbfd..7605320ed2 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -157,7 +157,6 @@ func NewFuncMap() template.FuncMap {
"RenderEmoji": RenderEmoji,
"RenderEmojiPlain": emoji.ReplaceAliases,
"ReactionToEmoji": ReactionToEmoji,
- "RenderNote": RenderNote,
"RenderMarkdownToHtml": RenderMarkdownToHtml,
"RenderLabel": RenderLabel,
diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go
index 639d58126c..1d9635410b 100644
--- a/modules/templates/util_render.go
+++ b/modules/templates/util_render.go
@@ -24,21 +24,13 @@ import (
)
// RenderCommitMessage renders commit message with XSS-safe and special links.
-func RenderCommitMessage(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
- return RenderCommitMessageLink(ctx, msg, urlPrefix, "", metas)
-}
-
-// RenderCommitMessageLink renders commit message as a XXS-safe link to the provided
-// default url, handling for special links.
-func RenderCommitMessageLink(ctx context.Context, msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML {
+func RenderCommitMessage(ctx context.Context, msg string, metas map[string]string) template.HTML {
cleanMsg := template.HTMLEscapeString(msg)
// we can safely assume that it will not return any error, since there
// shouldn't be any special HTML.
fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
- DefaultLink: urlDefault,
- Metas: metas,
+ Ctx: ctx,
+ Metas: metas,
}, cleanMsg)
if err != nil {
log.Error("RenderCommitMessage: %v", err)
@@ -51,9 +43,9 @@ func RenderCommitMessageLink(ctx context.Context, msg, urlPrefix, urlDefault str
return template.HTML(msgLines[0])
}
-// RenderCommitMessageLinkSubject renders commit message as a XXS-safe link to
+// RenderCommitMessageLinkSubject renders commit message as a XSS-safe link to
// the provided default url, handling for special links without email to links.
-func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML {
+func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlDefault string, metas map[string]string) template.HTML {
msgLine := strings.TrimLeftFunc(msg, unicode.IsSpace)
lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 {
@@ -68,7 +60,6 @@ func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlPrefix, urlDefa
// shouldn't be any special HTML.
renderedMessage, err := markup.RenderCommitMessageSubject(&markup.RenderContext{
Ctx: ctx,
- URLPrefix: urlPrefix,
DefaultLink: urlDefault,
Metas: metas,
}, template.HTMLEscapeString(msgLine))
@@ -80,7 +71,7 @@ func RenderCommitMessageLinkSubject(ctx context.Context, msg, urlPrefix, urlDefa
}
// RenderCommitBody extracts the body of a commit message without its title.
-func RenderCommitBody(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
+func RenderCommitBody(ctx context.Context, msg string, metas map[string]string) template.HTML {
msgLine := strings.TrimSpace(msg)
lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 {
@@ -94,9 +85,8 @@ func RenderCommitBody(ctx context.Context, msg, urlPrefix string, metas map[stri
}
renderedMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
- Metas: metas,
+ Ctx: ctx,
+ Metas: metas,
}, template.HTMLEscapeString(msgLine))
if err != nil {
log.Error("RenderCommitMessage: %v", err)
@@ -115,11 +105,10 @@ func RenderCodeBlock(htmlEscapedTextToRender template.HTML) template.HTML {
}
// RenderIssueTitle renders issue/pull title with defined post processors
-func RenderIssueTitle(ctx context.Context, text, urlPrefix string, metas map[string]string) template.HTML {
+func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) template.HTML {
renderedText, err := markup.RenderIssueTitle(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
- Metas: metas,
+ Ctx: ctx,
+ Metas: metas,
}, template.HTMLEscapeString(text))
if err != nil {
log.Error("RenderIssueTitle: %v", err)
@@ -211,25 +200,10 @@ func ReactionToEmoji(reaction string) template.HTML {
return template.HTML(fmt.Sprintf(`<img alt=":%s:" src="%s/assets/img/emoji/%s.png"></img>`, reaction, setting.StaticURLPrefix, url.PathEscape(reaction)))
}
-// RenderNote renders the contents of a git-notes file as a commit message.
-func RenderNote(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
- cleanMsg := template.HTMLEscapeString(msg)
- fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
- Metas: metas,
- }, cleanMsg)
- if err != nil {
- log.Error("RenderNote: %v", err)
- return ""
- }
- return template.HTML(fullMessage)
-}
-
func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //nolint:revive
output, err := markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: setting.AppSubURL,
+ Ctx: ctx,
+ Metas: map[string]string{"mode": "document"},
}, input)
if err != nil {
log.Error("RenderString: %v", err)
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index 29d3ed3a56..8648967d38 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -6,17 +6,64 @@ package templates
import (
"context"
"html/template"
+ "os"
"testing"
+ "code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/markup"
+
"github.com/stretchr/testify/assert"
)
+const testInput = ` space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+[local link](file.bin)
+[remote link](https://example.com)
+[[local link|file.bin]]
+[[remote link|https://example.com]]
+![local image](image.jpg)
+![remote image](https://example.com/image.jpg)
+[[local image|image.jpg]]
+[[remote link|https://example.com/image.jpg]]
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+:+1:
+mail@domain.com
+@mention-user test
+#123
+ space
+`
+
+var testMetas = map[string]string{
+ "user": "user13",
+ "repo": "repo11",
+ "repoPath": "../../tests/gitea-repositories-meta/user13/repo11.git/",
+ "mode": "comment",
+}
+
+func TestMain(m *testing.M) {
+ unittest.InitSettings()
+ if err := git.InitSimple(context.Background()); err != nil {
+ log.Fatal("git init failed, err: %v", err)
+ }
+ markup.Init(&markup.ProcessorHelper{
+ IsUsernameMentionable: func(ctx context.Context, username string) bool {
+ return username == "mention-user"
+ },
+ })
+ os.Exit(m.Run())
+}
+
func TestRenderCommitBody(t *testing.T) {
type args struct {
- ctx context.Context
- msg string
- urlPrefix string
- metas map[string]string
+ ctx context.Context
+ msg string
+ metas map[string]string
}
tests := []struct {
name string
@@ -50,7 +97,91 @@ func TestRenderCommitBody(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- assert.Equalf(t, tt.want, RenderCommitBody(tt.args.ctx, tt.args.msg, tt.args.urlPrefix, tt.args.metas), "RenderCommitBody(%v, %v, %v, %v)", tt.args.ctx, tt.args.msg, tt.args.urlPrefix, tt.args.metas)
+ assert.Equalf(t, tt.want, RenderCommitBody(tt.args.ctx, tt.args.msg, tt.args.metas), "RenderCommitBody(%v, %v, %v)", tt.args.ctx, tt.args.msg, tt.args.metas)
})
}
+
+ expected := `/just/a/path.bin
+<a href="https://example.com/file.bin" class="link">https://example.com/file.bin</a>
+[local link](file.bin)
+[remote link](<a href="https://example.com" class="link">https://example.com</a>)
+[[local link|file.bin]]
+[[remote link|<a href="https://example.com" class="link">https://example.com</a>]]
+![local image](image.jpg)
+![remote image](<a href="https://example.com/image.jpg" class="link">https://example.com/image.jpg</a>)
+[[local image|image.jpg]]
+[[remote link|<a href="https://example.com/image.jpg" class="link">https://example.com/image.jpg</a>]]
+<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" class="compare"><code class="nohighlight">88fc37a3c0...12fc37a3c0 (hash)</code></a>
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" class="commit"><code class="nohighlight">88fc37a3c0</code></a>
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+<span class="emoji" aria-label="thumbs up">👍</span>
+<a href="mailto:mail@domain.com" class="mailto">mail@domain.com</a>
+<a href="http://localhost:3000/mention-user" class="mention">@mention-user</a> test
+<a href="http://localhost:3000/user13/repo11/issues/123" class="ref-issue">#123</a>
+ space`
+
+ assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas))
+}
+
+func TestRenderCommitMessage(t *testing.T) {
+ expected := `space <a href="http://localhost:3000/mention-user" class="mention">@mention-user</a> `
+
+ assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas))
+}
+
+func TestRenderCommitMessageLinkSubject(t *testing.T) {
+ expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="http://localhost:3000/mention-user" class="mention">@mention-user</a>`
+
+ assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas))
+}
+
+func TestRenderIssueTitle(t *testing.T) {
+ expected := ` space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+[local link](file.bin)
+[remote link](https://example.com)
+[[local link|file.bin]]
+[[remote link|https://example.com]]
+![local image](image.jpg)
+![remote image](https://example.com/image.jpg)
+[[local image|image.jpg]]
+[[remote link|https://example.com/image.jpg]]
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+<span class="emoji" aria-label="thumbs up">👍</span>
+mail@domain.com
+@mention-user test
+<a href="http://localhost:3000/user13/repo11/issues/123" class="ref-issue">#123</a>
+ space
+`
+ assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
+}
+
+func TestRenderMarkdownToHtml(t *testing.T) {
+ expected := `<p>space <a href="http://localhost:3000/mention-user" rel="nofollow">@mention-user</a><br/>
+/just/a/path.bin
+<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a>
+<a href="/file.bin" rel="nofollow">local link</a>
+<a href="https://example.com" rel="nofollow">remote link</a>
+<a href="/src/file.bin" rel="nofollow">local link</a>
+<a href="https://example.com" rel="nofollow">remote link</a>
+<a href="/image.jpg" target="_blank" rel="nofollow noopener"><img src="/image.jpg" alt="local image"/></a>
+<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a>
+<a href="/image.jpg" rel="nofollow"><img src="/image.jpg" title="local image" alt="local image"/></a>
+<a href="https://example.com/image.jpg" rel="nofollow"><img src="https://example.com/image.jpg" title="remote link" alt="remote link"/></a>
+<a href="https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash" rel="nofollow"><code>88fc37a3c0...12fc37a3c0 (hash)</code></a>
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+<a href="https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb" rel="nofollow"><code>88fc37a3c0</code></a>
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+<span class="emoji" aria-label="thumbs up">👍</span>
+<a href="mailto:mail@domain.com" rel="nofollow">mail@domain.com</a>
+<a href="http://localhost:3000/mention-user" rel="nofollow">@mention-user</a> test
+#123
+space</p>
+`
+ assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput))
}