]> source.dussan.org Git - gitea.git/commitdiff
Use raw Wiki links for non-renderable Wiki files (#30273)
authorRafael <git@rafael.ovh>
Wed, 10 Apr 2024 17:49:57 +0000 (18:49 +0100)
committerGitHub <noreply@github.com>
Wed, 10 Apr 2024 17:49:57 +0000 (17:49 +0000)
In Wiki pages, short-links created to local Wiki files were always
expanded as regular Wiki Links. In particular, if a link wanted to point
to a file that Gitea doesn't know how to render (e.g, a .zip file), a
user following the link would be silently redirected to the Wiki's home
page.

This change makes short-links* in Wiki pages be expanded to raw wiki
links, so these local wiki files may be accessed without manually
accessing their URL.

* only short-links ending in a file extension that isn't renderable are
affected.

Closes #27121.

Signed-off-by: Rafael Girão <rafael.s.girao@tecnico.ulisboa.pt>
Co-authored-by: silverwind <me@silverwind.io>
12 files changed:
modules/markup/html.go
modules/markup/html_test.go
modules/markup/markdown/markdown_test.go
modules/markup/markdown/transform_link.go
routers/web/repo/wiki_test.go
tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7 [new file with mode: 0644]
tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc [new file with mode: 0644]
tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 [new file with mode: 0644]
tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a [new file with mode: 0644]
tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0 [new file with mode: 0644]
tests/gitea-repositories-meta/user2/repo1.wiki.git/refs/heads/master
tests/integration/git_clone_wiki_test.go

index 56aa1cb49cf9ca3c01411ec336d0046e172b9dfe..cef643bf180570ba6199a8e7d7c4d8b12e3ff8fa 100644 (file)
@@ -709,7 +709,8 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
 
                name += tail
                image := false
-               switch ext := filepath.Ext(link); ext {
+               ext := filepath.Ext(link)
+               switch ext {
                // fast path: empty string, ignore
                case "":
                        // leave image as false
@@ -767,11 +768,26 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
                        }
                } else {
                        if !absoluteLink {
+                               var base string
                                if ctx.IsWiki {
-                                       link = util.URLJoin(ctx.Links.WikiLink(), link)
+                                       switch ext {
+                                       case "":
+                                               // no file extension, create a regular wiki link
+                                               base = ctx.Links.WikiLink()
+                                       default:
+                                               // we have a file extension:
+                                               // return a regular wiki link if it's a renderable file (extension),
+                                               // raw link otherwise
+                                               if Type(link) != "" {
+                                                       base = ctx.Links.WikiLink()
+                                               } else {
+                                                       base = ctx.Links.WikiRawLink()
+                                               }
+                                       }
                                } else {
-                                       link = util.URLJoin(ctx.Links.SrcLink(), link)
+                                       base = ctx.Links.SrcLink()
                                }
+                               link = util.URLJoin(base, link)
                        }
                        childNode.Type = html.TextNode
                        childNode.Data = name
index 55de65d196dcae61265d50bdb6daff4a2adfdcd7..916e74fb6228d1c2dd9e51cb71ef2d23295c51f5 100644 (file)
@@ -427,6 +427,10 @@ func TestRender_ShortLinks(t *testing.T) {
        otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg")
        encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg")
        notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
+       renderableFileURL := util.URLJoin(tree, "markdown_file.md")
+       renderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "markdown_file.md")
+       unrenderableFileURL := util.URLJoin(tree, "file.zip")
+       unrenderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "file.zip")
        favicon := "http://google.com/favicon.ico"
 
        test(
@@ -481,6 +485,14 @@ func TestRender_ShortLinks(t *testing.T) {
                "[[Link]] [[Other Link]] [[Link?]]",
                `<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
                `<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
+       test(
+               "[[markdown_file.md]]",
+               `<p><a href="`+renderableFileURL+`" rel="nofollow">markdown_file.md</a></p>`,
+               `<p><a href="`+renderableFileURLWiki+`" rel="nofollow">markdown_file.md</a></p>`)
+       test(
+               "[[file.zip]]",
+               `<p><a href="`+unrenderableFileURL+`" rel="nofollow">file.zip</a></p>`,
+               `<p><a href="`+unrenderableFileURLWiki+`" rel="nofollow">file.zip</a></p>`)
        test(
                "[[Link #.jpg]]",
                `<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
index a9c902498287172b28cc1de7bb5c047e46d67636..d9b67e43af01367f2f94878fa5919d9e00d5557c 100644 (file)
@@ -653,9 +653,9 @@ space</p>
                        Expected: `<p>space @mention-user<br/>
 /just/a/path.bin<br/>
 <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
-<a href="/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
-<a href="/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
 <a href="/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/image.jpg" alt="local image"/></a><br/>
 <a href="/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/path/file" alt="local image"/></a><br/>
@@ -711,9 +711,9 @@ space</p>
                        Expected: `<p>space @mention-user<br/>
 /just/a/path.bin<br/>
 <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
-<a href="https://gitea.io/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="https://gitea.io/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
-<a href="https://gitea.io/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="https://gitea.io/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
 <a href="https://gitea.io/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/image.jpg" alt="local image"/></a><br/>
 <a href="https://gitea.io/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/path/file" alt="local image"/></a><br/>
@@ -769,9 +769,9 @@ space</p>
                        Expected: `<p>space @mention-user<br/>
 /just/a/path.bin<br/>
 <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
 <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
 <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
@@ -829,9 +829,9 @@ space</p>
                        Expected: `<p>space @mention-user<br/>
 /just/a/path.bin<br/>
 <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
 <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
 <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
@@ -889,9 +889,9 @@ space</p>
                        Expected: `<p>space @mention-user<br/>
 /just/a/path.bin<br/>
 <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
 <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
 <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
@@ -951,9 +951,9 @@ space</p>
                        Expected: `<p>space @mention-user<br/>
 /just/a/path.bin<br/>
 <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
-<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
+<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
 <a href="https://example.com" rel="nofollow">remote link</a><br/>
 <a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
 <a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
index 8bf19ea4ceed40e1eaa98e01e4e711afe955d568..7e305b74bcdb132e2b02931c51e5ce9d87cf6c53 100644 (file)
@@ -4,6 +4,8 @@
 package markdown
 
 import (
+       "path/filepath"
+
        "code.gitea.io/gitea/modules/markup"
        giteautil "code.gitea.io/gitea/modules/util"
 
@@ -18,7 +20,16 @@ func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, r
        if !isAnchorFragment && !markup.IsFullURLBytes(link) {
                base := ctx.Links.Base
                if ctx.IsWiki {
-                       base = ctx.Links.WikiLink()
+                       if filepath.Ext(string(link)) == "" {
+                               // This link doesn't have a file extension - assume a regular wiki link
+                               base = ctx.Links.WikiLink()
+                       } else if markup.Type(string(link)) != "" {
+                               // If it's a file type we can render, use a regular wiki link
+                               base = ctx.Links.WikiLink()
+                       } else {
+                               // Otherwise, use a raw link instead
+                               base = ctx.Links.WikiRawLink()
+                       }
                } else if ctx.Links.HasBranchInfo() {
                        base = ctx.Links.SrcLink()
                }
index 2894c06fbdb4cd97666df16f070b774cc93f7989..4602dcfeb40e011a4b3b33c9ea98e87112701362 100644 (file)
@@ -200,12 +200,13 @@ func TestDeleteWikiPagePost(t *testing.T) {
 
 func TestWikiRaw(t *testing.T) {
        for filepath, filetype := range map[string]string{
-               "jpeg.jpg":                 "image/jpeg",
-               "images/jpeg.jpg":          "image/jpeg",
-               "Page With Spaced Name":    "text/plain; charset=utf-8",
-               "Page-With-Spaced-Name":    "text/plain; charset=utf-8",
-               "Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo
-               "Page-With-Spaced-Name.md": "text/plain; charset=utf-8",
+               "jpeg.jpg":                      "image/jpeg",
+               "images/jpeg.jpg":               "image/jpeg",
+               "files/Non-Renderable-File.zip": "application/octet-stream",
+               "Page With Spaced Name":         "text/plain; charset=utf-8",
+               "Page-With-Spaced-Name":         "text/plain; charset=utf-8",
+               "Page With Spaced Name.md":      "", // there is no "Page With Spaced Name.md" in repo
+               "Page-With-Spaced-Name.md":      "text/plain; charset=utf-8",
        } {
                unittest.PrepareTestEnv(t)
 
diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7 b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7
new file mode 100644 (file)
index 0000000..17a5547
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/81/a1c039774e337621609336c0e44ed9f92278f7 differ
diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc
new file mode 100644 (file)
index 0000000..8390a40
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/91/dc55f9de16a558e859123f2b99668469b1a1dc differ
diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02 b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/a5/bbc0fd39a696feabed2d4cccaf05abbcaf3b02
new file mode 100644 (file)
index 0000000..94312d3
--- /dev/null
@@ -0,0 +1 @@
+x\ 1\9d\8fKnÄ \10D³æ\14죱Ávó\19EQ²Ê~nÐ@3Fò\18\vð\89r\94\,d\8e\90^\94T¥ÒSµÏ\8fGj|\9eÅK+DÜÊà\ 1¢\r$\15\ 2\182`å4ÇÉY«\94Y\94u\12{\87\1dXho\\ 4\8fà\82u\104E;k-\ 5  P\114\90Q^H³84Àðlk.ü\86\11iã_©ü|gþV\9ev¨Ã=\15Ì\1f\8dü\9e|\1eÎ-U\97q8Ú;\97ZJµè\ 5,\7f\15ý\98\7fNnô_\98Õ\16\94ê0Ùaì3\ 4¾çýÒ¿        TÐmÄ·ìqã1mÄØ\8db½òµµ£^Çñ\9eÚzº¡/\18ïùÒ\1dá_Ö5ÕzR\1d'-'É~\ 1étl½
\ No newline at end of file
diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a
new file mode 100644 (file)
index 0000000..b384e5c
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/cf/19952a40b92eb2f86689146a65ac2d87c0818a differ
diff --git a/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0 b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0
new file mode 100644 (file)
index 0000000..da281ff
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo1.wiki.git/objects/e1/6da91326b845f1ba86a7df0a67db352f96dcb0 differ
index 38984b12b7868eaa27c4bd19b3002f297e205bc4..b352f15003257334b7384ea50238ea07f2c49a79 100644 (file)
@@ -1 +1 @@
-0dca5bd9b5d7ef937710e056f575e86c0184ba85
+a5bbc0fd39a696feabed2d4cccaf05abbcaf3b02
index d7949dfe25e4b68797b6c3b79fac94c096fa285e..ef662300f3535def88077d3bf086532e99f7f07d 100644 (file)
@@ -45,6 +45,7 @@ func TestRepoCloneWiki(t *testing.T) {
                        assertFileExist(t, filepath.Join(dstPath, "Page-With-Image.md"))
                        assertFileExist(t, filepath.Join(dstPath, "Page-With-Spaced-Name.md"))
                        assertFileExist(t, filepath.Join(dstPath, "images"))
+                       assertFileExist(t, filepath.Join(dstPath, "files/Non-Renderable-File.zip"))
                        assertFileExist(t, filepath.Join(dstPath, "jpeg.jpg"))
                })
        })