From 6c100083c29fb0ccf0cc52e8767e540a260d9468 Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 19 Feb 2024 20:40:53 +0100 Subject: [PATCH] [BUG] Restrict when to make link absolute in markdown - Backport of #2403 - In markdown, links are proccessed to be made absolute against the relevant base in that context. Such that `./src` will be transformed into `http://example.com/owner/repo/src/branch/main/src`. - Don't try to make the link absolute if the link has a schema that's defined in `[markdown].CUSTOM_URL_SCHEMES`, because they can't be made absolute and doing so could lead to problems (see test case, double slash was transformed to single slash). - Adds unit test. - Resolves https://codeberg.org/Codeberg/Community/issues/1489 (cherry picked from commit 65b9a959b8aa9cce954cdc21b70ec6e2d27cd0f9) --- modules/markup/markdown/goldmark.go | 15 +++++++++---- modules/markup/markdown/markdown_test.go | 27 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 3dc5530e00..b650854971 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "regexp" + "slices" "strings" "code.gitea.io/gitea/modules/container" @@ -131,11 +132,17 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa case *ast.Link: // Links need their href to munged to be a real value link := v.Destination - if len(link) > 0 && !markup.IsLink(link) && - link[0] != '#' && !bytes.HasPrefix(link, byteMailto) { - // special case: this is not a link, a hash link or a mailto:, so it's a - // relative URL + // Do not process the link if it's not a link, starts with an hashtag + // (indicating it's an anchor link), starts with `mailto:` or any of the + // custom markdown URLs. + processLink := len(link) > 0 && !markup.IsLink(link) && + link[0] != '#' && !bytes.HasPrefix(link, byteMailto) && + !slices.ContainsFunc(setting.Markdown.CustomURLSchemes, func(s string) bool { + return bytes.HasPrefix(link, []byte(s+":")) + }) + + if processLink { var base string if ctx.IsWiki { base = ctx.Links.WikiLink() diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index ee3ec0fda5..3cb11c9482 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/markup" . "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -960,3 +961,29 @@ space

assert.Equal(t, c.Expected, result, "Unexpected result in testcase %v", i) } } + +func TestCustomMarkdownURL(t *testing.T) { + defer test.MockVariableValue(&setting.Markdown.CustomURLSchemes, []string{"abp"})() + + setting.AppURL = AppURL + setting.AppSubURL = AppSubURL + + test := func(input, expected string) { + buffer, err := RenderString(&markup.RenderContext{ + Ctx: git.DefaultContext, + Links: markup.Links{ + Base: setting.AppSubURL, + BranchPath: "branch/main", + }, + }, input) + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + } + + test("[test](abp:subscribe?location=https://codeberg.org/filters.txt&title=joy)", + `

test

`) + + // Ensure that the schema itself without `:` is still made absolute. + test("[test](abp)", + `

test

`) +}