From 2010fbe06054b9d9cada430f1a60f45ac7689b93 Mon Sep 17 00:00:00 2001
From: Zettat123 
space @mention-user
 /just/a/path.bin
 https://example.com/file.bin
-local link
+local link
 remote link
-local link
+local link
 remote link
 
 
@@ -730,9 +730,9 @@ space
space @mention-user
 /just/a/path.bin
 https://example.com/file.bin
-local link
+local link
 remote link
-local link
+local link
 remote link
 
 
@@ -788,9 +788,9 @@ space
space @mention-user
 /just/a/path.bin
 https://example.com/file.bin
-local link
+local link
 remote link
-local link
+local link
 remote link
 
 
@@ -848,9 +848,9 @@ space
space @mention-user
 /just/a/path.bin
 https://example.com/file.bin
-local link
+local link
 remote link
-local link
+local link
 remote link
 
 
@@ -908,9 +908,9 @@ space
space @mention-user
 /just/a/path.bin
 https://example.com/file.bin
-local link
+local link
 remote link
-local link
+local link
 remote link
 
 
@@ -970,9 +970,9 @@ space
space @mention-user
 /just/a/path.bin
 https://example.com/file.bin
-local link
+local link
 remote link
-local link
+local link
 remote link
 
 
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 13b6a7b8e3..d2056353d8 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -138,18 +138,41 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
 	return content
 }
 
-// wikiContentsByName returns the contents of a wiki page, along with a boolean
-// indicating whether the page exists. Writes to ctx if an error occurs.
-func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
+// wikiEntryByName returns the entry of a wiki page, along with a boolean
+// indicating whether the entry exists. Writes to ctx if an error occurs.
+// The last return value indicates whether the file should be returned as a raw file
+func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) (*git.TreeEntry, string, bool, bool) {
+	isRaw := false
 	gitFilename := wiki_service.WebPathToGitPath(wikiName)
 	entry, err := findEntryForFile(commit, gitFilename)
 	if err != nil && !git.IsErrNotExist(err) {
 		ctx.ServerError("findEntryForFile", err)
-		return nil, nil, "", false
-	} else if entry == nil {
+		return nil, "", false, false
+	}
+	if entry == nil {
+		// check if the file without ".md" suffix exists
+		gitFilename := strings.TrimSuffix(gitFilename, ".md")
+		entry, err = findEntryForFile(commit, gitFilename)
+		if err != nil && !git.IsErrNotExist(err) {
+			ctx.ServerError("findEntryForFile", err)
+			return nil, "", false, false
+		}
+		isRaw = true
+	}
+	if entry == nil {
+		return nil, "", true, false
+	}
+	return entry, gitFilename, false, isRaw
+}
+
+// wikiContentsByName returns the contents of a wiki page, along with a boolean
+// indicating whether the page exists. Writes to ctx if an error occurs.
+func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
+	entry, gitFilename, noEntry, _ := wikiEntryByName(ctx, commit, wikiName)
+	if entry == nil {
 		return nil, nil, "", true
 	}
-	return wikiContentsByEntry(ctx, entry), entry, gitFilename, false
+	return wikiContentsByEntry(ctx, entry), entry, gitFilename, noEntry
 }
 
 func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
@@ -215,11 +238,14 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
 	isSideBar := pageName == "_Sidebar"
 	isFooter := pageName == "_Footer"
 
-	// lookup filename in wiki - get filecontent, gitTree entry , real filename
-	data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
+	// lookup filename in wiki - get gitTree entry , real filename
+	entry, pageFilename, noEntry, isRaw := wikiEntryByName(ctx, commit, pageName)
 	if noEntry {
 		ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
 	}
+	if isRaw {
+		ctx.Redirect(util.URLJoin(ctx.Repo.RepoLink, "wiki/raw", string(pageName)))
+	}
 	if entry == nil || ctx.Written() {
 		if wikiRepo != nil {
 			wikiRepo.Close()
@@ -227,6 +253,15 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
 		return nil, nil
 	}
 
+	// get filecontent
+	data := wikiContentsByEntry(ctx, entry)
+	if ctx.Written() {
+		if wikiRepo != nil {
+			wikiRepo.Close()
+		}
+		return nil, nil
+	}
+
 	var sidebarContent []byte
 	if !isSideBar {
 		sidebarContent, _, _, _ = wikiContentsByName(ctx, commit, "_Sidebar")
@@ -442,15 +477,24 @@ func renderEditPage(ctx *context.Context) {
 	ctx.Data["Title"] = displayName
 	ctx.Data["title"] = displayName
 
-	// lookup filename in wiki - get filecontent, gitTree entry , real filename
-	data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName)
+	// lookup filename in wiki -  gitTree entry , real filename
+	entry, _, noEntry, isRaw := wikiEntryByName(ctx, commit, pageName)
 	if noEntry {
 		ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
 	}
+	if isRaw {
+		ctx.Error(http.StatusForbidden, "Editing of raw wiki files is not allowed")
+	}
 	if entry == nil || ctx.Written() {
 		return
 	}
 
+	// get filecontent
+	data := wikiContentsByEntry(ctx, entry)
+	if ctx.Written() {
+		return
+	}
+
 	ctx.Data["content"] = string(data)
 	ctx.Data["sidebarPresent"] = false
 	ctx.Data["sidebarContent"] = ""
diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go
index 7de5899e21..b81f2ea02e 100644
--- a/routers/web/repo/wiki_test.go
+++ b/routers/web/repo/wiki_test.go
@@ -87,6 +87,13 @@ func TestWiki(t *testing.T) {
 	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
 	assert.EqualValues(t, "Home", ctx.Data["Title"])
 	assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"])
+
+	ctx, _ = contexttest.MockContext(t, "user2/repo1/jpeg.jpg")
+	ctx.SetPathParam("*", "jpeg.jpg")
+	contexttest.LoadRepo(t, ctx, 1)
+	Wiki(ctx)
+	assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status())
+	assert.Equal(t, "/user2/repo1/wiki/raw/jpeg.jpg", ctx.Resp.Header().Get("Location"))
 }
 
 func TestWikiPages(t *testing.T) {
@@ -160,6 +167,13 @@ func TestEditWiki(t *testing.T) {
 	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
 	assert.EqualValues(t, "Home", ctx.Data["Title"])
 	assert.Equal(t, wikiContent(t, ctx.Repo.Repository, "Home"), ctx.Data["content"])
+
+	ctx, _ = contexttest.MockContext(t, "user2/repo1/wiki/jpeg.jpg?action=_edit")
+	ctx.SetPathParam("*", "jpeg.jpg")
+	contexttest.LoadUser(t, ctx, 2)
+	contexttest.LoadRepo(t, ctx, 1)
+	EditWiki(ctx)
+	assert.EqualValues(t, http.StatusForbidden, ctx.Resp.Status())
 }
 
 func TestEditWikiPost(t *testing.T) {