aboutsummaryrefslogtreecommitdiffstats
path: root/routers/web
diff options
context:
space:
mode:
Diffstat (limited to 'routers/web')
-rw-r--r--routers/web/admin/auths.go6
-rw-r--r--routers/web/admin/repos.go4
-rw-r--r--routers/web/admin/users.go10
-rw-r--r--routers/web/feed/convert.go134
-rw-r--r--routers/web/org/setting.go3
-rw-r--r--routers/web/org/teams.go19
-rw-r--r--routers/web/repo/blame.go10
-rw-r--r--routers/web/repo/commit.go4
-rw-r--r--routers/web/repo/compare.go33
-rw-r--r--routers/web/repo/editor.go12
-rw-r--r--routers/web/repo/issue.go25
-rw-r--r--routers/web/repo/issue_stopwatch.go2
-rw-r--r--routers/web/repo/lfs.go3
-rw-r--r--routers/web/repo/migrate.go3
-rw-r--r--routers/web/repo/milestone.go3
-rw-r--r--routers/web/repo/projects.go3
-rw-r--r--routers/web/repo/pull.go72
-rw-r--r--routers/web/repo/release.go3
-rw-r--r--routers/web/repo/repo.go4
-rw-r--r--routers/web/repo/setting.go16
-rw-r--r--routers/web/repo/setting_protected_branch.go7
-rw-r--r--routers/web/repo/tag.go2
-rw-r--r--routers/web/repo/view.go16
-rw-r--r--routers/web/repo/webhook.go11
-rw-r--r--routers/web/repo/wiki.go65
-rw-r--r--routers/web/repo/wiki_test.go22
-rw-r--r--routers/web/user/home.go2
-rw-r--r--routers/web/user/notification.go5
-rw-r--r--routers/web/user/oauth.go2
-rw-r--r--routers/web/user/profile.go2
-rw-r--r--routers/web/web.go28
31 files changed, 339 insertions, 192 deletions
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index 460b740171..5fd15b5c5a 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -8,7 +8,9 @@ import (
"errors"
"fmt"
"net/http"
+ "net/url"
"regexp"
+ "strconv"
"code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/modules/auth/pam"
@@ -396,7 +398,7 @@ func EditAuthSourcePost(ctx *context.Context) {
log.Trace("Authentication changed by admin(%s): %d", ctx.User.Name, source.ID)
ctx.Flash.Success(ctx.Tr("admin.auths.update_success"))
- ctx.Redirect(setting.AppSubURL + "/admin/auths/" + fmt.Sprint(form.ID))
+ ctx.Redirect(setting.AppSubURL + "/admin/auths/" + strconv.FormatInt(form.ID, 10))
}
// DeleteAuthSource response for deleting an auth source
@@ -414,7 +416,7 @@ func DeleteAuthSource(ctx *context.Context) {
ctx.Flash.Error(fmt.Sprintf("DeleteLoginSource: %v", err))
}
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": setting.AppSubURL + "/admin/auths/" + ctx.Params(":authid"),
+ "redirect": setting.AppSubURL + "/admin/auths/" + url.PathEscape(ctx.Params(":authid")),
})
return
}
diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go
index a13f7317e4..432dd2f6ae 100644
--- a/routers/web/admin/repos.go
+++ b/routers/web/admin/repos.go
@@ -58,7 +58,7 @@ func DeleteRepo(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": setting.AppSubURL + "/admin/repos?page=" + ctx.FormString("page") + "&sort=" + ctx.FormString("sort"),
+ "redirect": setting.AppSubURL + "/admin/repos?page=" + url.QueryEscape(ctx.FormString("page")) + "&sort=" + url.QueryEscape(ctx.FormString("sort")),
})
}
@@ -161,5 +161,5 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir))
}
- ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + page)
+ ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + url.QueryEscape(page))
}
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index db7fe7b36f..8bafd1f19c 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -6,8 +6,8 @@
package admin
import (
- "fmt"
"net/http"
+ "net/url"
"strconv"
"strings"
@@ -188,7 +188,7 @@ func NewUserPost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("admin.users.new_success", u.Name))
- ctx.Redirect(setting.AppSubURL + "/admin/users/" + fmt.Sprint(u.ID))
+ ctx.Redirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10))
}
func prepareUserInfo(ctx *context.Context) *models.User {
@@ -366,7 +366,7 @@ func EditUserPost(ctx *context.Context) {
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success"))
- ctx.Redirect(setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"))
+ ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
}
// DeleteUser response for deleting a user
@@ -382,12 +382,12 @@ func DeleteUser(ctx *context.Context) {
case models.IsErrUserOwnRepos(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"),
+ "redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
case models.IsErrUserHasOrgs(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_has_org"))
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"),
+ "redirect": setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")),
})
default:
ctx.ServerError("DeleteUser", err)
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index dfb03785a6..4743668621 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -15,10 +15,35 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/modules/util"
"github.com/gorilla/feeds"
)
+func toBranchLink(act *models.Action) string {
+ return act.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch())
+}
+
+func toTagLink(act *models.Action) string {
+ return act.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag())
+}
+
+func toIssueLink(act *models.Action) string {
+ return act.GetRepoLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0])
+}
+
+func toPullLink(act *models.Action) string {
+ return act.GetRepoLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0])
+}
+
+func toSrcLink(act *models.Action) string {
+ return act.GetRepoLink() + "/src/" + util.PathEscapeSegments(act.GetBranch())
+}
+
+func toReleaseLink(act *models.Action) string {
+ return act.GetRepoLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
+}
+
// feedActionsToFeedItems convert gitea's Action feed to feeds Item
func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (items []*feeds.Item, err error) {
for _, act := range actions {
@@ -32,62 +57,111 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite
title = act.ActUser.DisplayName() + " "
switch act.OpType {
case models.ActionCreateRepo:
- title += ctx.Tr("action.create_repo", act.GetRepoLink(), act.ShortRepoPath())
+ title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoLink(), act.ShortRepoPath())
+ link.Href = act.GetRepoLink()
case models.ActionRenameRepo:
- title += ctx.Tr("action.rename_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
+ title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
+ link.Href = act.GetRepoLink()
case models.ActionCommitRepo:
- branchLink := act.GetBranch()
+ link.Href = toBranchLink(act)
if len(act.Content) != 0 {
- title += ctx.Tr("action.commit_repo", act.GetRepoLink(), branchLink, act.GetBranch(), act.ShortRepoPath())
+ title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
} else {
- title += ctx.Tr("action.create_branch", act.GetRepoLink(), branchLink, act.GetBranch(), act.ShortRepoPath())
+ title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
}
case models.ActionCreateIssue:
- title += ctx.Tr("action.create_issue", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ link.Href = toIssueLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionCreatePullRequest:
- title += ctx.Tr("action.create_pull_request", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ link.Href = toPullLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionTransferRepo:
- title += ctx.Tr("action.transfer_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
+ link.Href = act.GetRepoLink()
+ title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
case models.ActionPushTag:
- title += ctx.Tr("action.push_tag", act.GetRepoLink(), url.QueryEscape(act.GetTag()), act.ShortRepoPath())
+ link.Href = toTagLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoLink(), link.Href, act.GetTag(), act.ShortRepoPath())
case models.ActionCommentIssue:
- title += ctx.Tr("action.comment_issue", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ issueLink := toIssueLink(act)
+ if link.Href == "#" {
+ link.Href = issueLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionMergePullRequest:
- title += ctx.Tr("action.merge_pull_request", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ pullLink := toPullLink(act)
+ if link.Href == "#" {
+ link.Href = pullLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionCloseIssue:
- title += ctx.Tr("action.close_issue", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ issueLink := toIssueLink(act)
+ if link.Href == "#" {
+ link.Href = issueLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionReopenIssue:
- title += ctx.Tr("action.reopen_issue", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ issueLink := toIssueLink(act)
+ if link.Href == "#" {
+ link.Href = issueLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionClosePullRequest:
- title += ctx.Tr("action.close_pull_request", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ pullLink := toPullLink(act)
+ if link.Href == "#" {
+ link.Href = pullLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionReopenPullRequest:
- title += ctx.Tr("action.reopen_pull_request", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath)
+ pullLink := toPullLink(act)
+ if link.Href == "#" {
+ link.Href = pullLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionDeleteTag:
- title += ctx.Tr("action.delete_tag", act.GetRepoLink(), html.EscapeString(act.GetTag()), act.ShortRepoPath())
+ link.Href = act.GetRepoLink()
+ title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoLink(), act.GetTag(), act.ShortRepoPath())
case models.ActionDeleteBranch:
- title += ctx.Tr("action.delete_branch", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
+ link.Href = act.GetRepoLink()
+ title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
case models.ActionMirrorSyncPush:
- title += ctx.Tr("action.mirror_sync_push", act.GetRepoLink(), url.QueryEscape(act.GetBranch()), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
+ srcLink := toSrcLink(act)
+ if link.Href == "#" {
+ link.Href = srcLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
case models.ActionMirrorSyncCreate:
- title += ctx.Tr("action.mirror_sync_create", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
+ srcLink := toSrcLink(act)
+ if link.Href == "#" {
+ link.Href = srcLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
case models.ActionMirrorSyncDelete:
- title += ctx.Tr("action.mirror_sync_delete", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
+ link.Href = act.GetRepoLink()
+ title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoLink(), act.GetBranch(), act.ShortRepoPath())
case models.ActionApprovePullRequest:
- title += ctx.Tr("action.approve_pull_request", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ pullLink := toPullLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionRejectPullRequest:
- title += ctx.Tr("action.reject_pull_request", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ pullLink := toPullLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionCommentPull:
- title += ctx.Tr("action.comment_pull", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath())
+ pullLink := toPullLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
case models.ActionPublishRelease:
- title += ctx.Tr("action.publish_release", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath(), act.Content)
+ releaseLink := toReleaseLink(act)
+ if link.Href == "#" {
+ link.Href = releaseLink
+ }
+ title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoLink(), releaseLink, act.ShortRepoPath(), act.Content)
case models.ActionPullReviewDismissed:
- title += ctx.Tr("action.review_dismissed", act.GetRepoLink(), act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1])
+ pullLink := toPullLink(act)
+ title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1])
case models.ActionStarRepo:
- title += ctx.Tr("action.starred_repo", act.GetRepoLink(), act.GetRepoPath())
- link = &feeds.Link{Href: act.GetRepoLink()}
+ link.Href = act.GetRepoLink()
+ title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoLink(), act.GetRepoPath())
case models.ActionWatchRepo:
- title += ctx.Tr("action.watched_repo", act.GetRepoLink(), act.GetRepoPath())
- link = &feeds.Link{Href: act.GetRepoLink()}
+ link.Href = act.GetRepoLink()
+ title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoLink(), act.GetRepoPath())
default:
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
}
@@ -104,7 +178,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite
desc += "\n\n"
}
desc += fmt.Sprintf("<a href=\"%s\">%s</a>\n%s",
- fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), commit.Sha1),
+ html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), commit.Sha1)),
commit.Sha1,
templates.RenderCommitMessage(commit.Message, repoLink, nil),
)
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index d8add77f66..53c31a1c60 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -7,6 +7,7 @@ package org
import (
"net/http"
+ "net/url"
"strings"
"code.gitea.io/gitea/models"
@@ -76,7 +77,7 @@ func SettingsPost(ctx *context.Context) {
return
}
// reset ctx.org.OrgLink with new name
- ctx.Org.OrgLink = setting.AppSubURL + "/org/" + form.Name
+ ctx.Org.OrgLink = setting.AppSubURL + "/org/" + url.PathEscape(form.Name)
log.Trace("Organization name changed: %s -> %s", org.Name, form.Name)
nameChanged = false
}
diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go
index 3fe97142ae..2fc72f0620 100644
--- a/routers/web/org/teams.go
+++ b/routers/web/org/teams.go
@@ -7,6 +7,7 @@ package org
import (
"net/http"
+ "net/url"
"path"
"strings"
@@ -105,7 +106,7 @@ func TeamsAction(ctx *context.Context) {
}
ctx.JSON(http.StatusOK,
map[string]interface{}{
- "redirect": ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName,
+ "redirect": ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName),
})
return
case "add":
@@ -119,7 +120,7 @@ func TeamsAction(ctx *context.Context) {
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName))
} else {
ctx.ServerError(" GetUserByName", err)
}
@@ -128,7 +129,7 @@ func TeamsAction(ctx *context.Context) {
if u.IsOrganization() {
ctx.Flash.Error(ctx.Tr("form.cannot_add_org_to_team"))
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName))
return
}
@@ -156,7 +157,7 @@ func TeamsAction(ctx *context.Context) {
switch page {
case "team":
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName))
case "home":
ctx.Redirect(ctx.Org.Organization.HomeLink())
default:
@@ -181,7 +182,7 @@ func TeamsRepoAction(ctx *context.Context) {
if err != nil {
if models.IsErrRepoNotExist(err) {
ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo"))
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName) + "/repositories")
return
}
ctx.ServerError("GetRepositoryByName", err)
@@ -204,11 +205,11 @@ func TeamsRepoAction(ctx *context.Context) {
if action == "addall" || action == "removeall" {
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories",
+ "redirect": ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName) + "/repositories",
})
return
}
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName) + "/repositories")
}
// NewTeam render create new team page
@@ -273,7 +274,7 @@ func NewTeamPost(ctx *context.Context) {
return
}
log.Trace("Team created: %s/%s", ctx.Org.Organization.Name, t.Name)
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(t.LowerName))
}
// TeamMembers render team members page
@@ -375,7 +376,7 @@ func EditTeamPost(ctx *context.Context) {
}
return
}
- ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
+ ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(t.LowerName))
}
// DeleteTeam response for the delete team request
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index 3632d1846e..110ec037e1 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -8,6 +8,7 @@ import (
"fmt"
gotemplate "html/template"
"net/http"
+ "net/url"
"strings"
"code.gitea.io/gitea/models"
@@ -17,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
)
const (
@@ -54,7 +56,7 @@ func RefBlame(ctx *context.Context) {
rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
if len(ctx.Repo.TreePath) > 0 {
- treeLink += "/" + ctx.Repo.TreePath
+ treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
}
var treeNames []string
@@ -85,7 +87,7 @@ func RefBlame(ctx *context.Context) {
ctx.Data["TreeNames"] = treeNames
ctx.Data["BranchLink"] = branchLink
- ctx.Data["RawFileLink"] = rawLink + "/" + ctx.Repo.TreePath
+ ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
ctx.Data["PageIsViewCode"] = true
ctx.Data["IsBlame"] = true
@@ -236,8 +238,8 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
br.RepoLink = repoLink
br.PartSha = part.Sha
br.PreviousSha = previousSha
- br.PreviousShaURL = fmt.Sprintf("%s/blame/commit/%s/%s", repoLink, previousSha, ctx.Repo.TreePath)
- br.CommitURL = fmt.Sprintf("%s/commit/%s", repoLink, part.Sha)
+ br.PreviousShaURL = fmt.Sprintf("%s/blame/commit/%s/%s", repoLink, url.PathEscape(previousSha), util.PathEscapeSegments(ctx.Repo.TreePath))
+ br.CommitURL = fmt.Sprintf("%s/commit/%s", repoLink, url.PathEscape(part.Sha))
br.CommitMessage = commit.CommitMessage
br.CommitSince = commitSince
}
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index 4c0f94f15d..06cce92417 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -8,7 +8,6 @@ package repo
import (
"errors"
"net/http"
- "path"
"strings"
"code.gitea.io/gitea/models"
@@ -323,8 +322,7 @@ func Diff(ctx *context.Context) {
return
}
}
- headTarget := path.Join(userName, repoName)
- setCompareContext(ctx, parentCommit, commit, headTarget)
+ setCompareContext(ctx, parentCommit, commit, userName, repoName)
ctx.Data["Title"] = commit.Summary() + " ยท " + base.ShortSha(commitID)
ctx.Data["Commit"] = commit
ctx.Data["Diff"] = diff
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index 86ecc2bab1..01c324e9e9 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -12,7 +12,7 @@ import (
"html"
"io"
"net/http"
- "path"
+ "net/url"
"path/filepath"
"strings"
@@ -38,7 +38,7 @@ const (
)
// setCompareContext sets context data.
-func setCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headTarget string) {
+func setCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headOwner, headName string) {
ctx.Data["BaseCommit"] = base
ctx.Data["HeadCommit"] = head
@@ -54,22 +54,28 @@ func setCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit,
return blob
}
- setPathsCompareContext(ctx, base, head, headTarget)
+ setPathsCompareContext(ctx, base, head, headOwner, headName)
setImageCompareContext(ctx)
setCsvCompareContext(ctx)
}
-// setPathsCompareContext sets context data for source and raw paths
-func setPathsCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headTarget string) {
- sourcePath := setting.AppSubURL + "/%s/src/commit/%s"
- rawPath := setting.AppSubURL + "/%s/raw/commit/%s"
+// SourceCommitURL creates a relative URL for a commit in the given repository
+func SourceCommitURL(owner, name string, commit *git.Commit) string {
+ return setting.AppSubURL + "/" + url.PathEscape(owner) + "/" + url.PathEscape(name) + "/src/commit/" + url.PathEscape(commit.ID.String())
+}
- ctx.Data["SourcePath"] = fmt.Sprintf(sourcePath, headTarget, head.ID)
- ctx.Data["RawPath"] = fmt.Sprintf(rawPath, headTarget, head.ID)
+// RawCommitURL creates a relative URL for the raw commit in the given repository
+func RawCommitURL(owner, name string, commit *git.Commit) string {
+ return setting.AppSubURL + "/" + url.PathEscape(owner) + "/" + url.PathEscape(name) + "/raw/commit/" + url.PathEscape(commit.ID.String())
+}
+
+// setPathsCompareContext sets context data for source and raw paths
+func setPathsCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headOwner, headName string) {
+ ctx.Data["SourcePath"] = SourceCommitURL(headOwner, headName, head)
+ ctx.Data["RawPath"] = RawCommitURL(headOwner, headName, head)
if base != nil {
- baseTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
- ctx.Data["BeforeSourcePath"] = fmt.Sprintf(sourcePath, baseTarget, base.ID)
- ctx.Data["BeforeRawPath"] = fmt.Sprintf(rawPath, baseTarget, base.ID)
+ ctx.Data["BeforeSourcePath"] = SourceCommitURL(headOwner, headName, head)
+ ctx.Data["BeforeRawPath"] = RawCommitURL(headOwner, headName, head)
}
}
@@ -619,8 +625,7 @@ func PrepareCompareDiff(
ctx.Data["Username"] = ci.HeadUser.Name
ctx.Data["Reponame"] = ci.HeadRepo.Name
- headTarget := path.Join(ci.HeadUser.Name, repo.Name)
- setCompareContext(ctx, baseCommit, headCommit, headTarget)
+ setCompareContext(ctx, baseCommit, headCommit, ci.HeadUser.Name, repo.Name)
return false
}
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index d9f8c20092..088edbfd29 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -204,7 +204,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
ctx.Data["TreePath"] = form.TreePath
ctx.Data["TreeNames"] = treeNames
ctx.Data["TreePaths"] = treePaths
- ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + ctx.Repo.BranchName
+ ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
ctx.Data["FileContent"] = form.Content
ctx.Data["commit_summary"] = form.CommitSummary
ctx.Data["commit_message"] = form.CommitMessage
@@ -299,9 +299,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
ctx.Error(http.StatusInternalServerError, err.Error())
}
} else if models.IsErrCommitIDDoesNotMatch(err) {
- ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form)
+ ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplEditFile, &form)
} else if git.IsErrPushOutOfDate(err) {
- ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+util.PathEscapeSegments(form.NewBranchName)), tplEditFile, &form)
+ ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(form.NewBranchName)), tplEditFile, &form)
} else if git.IsErrPushRejected(err) {
errPushRej := err.(*git.ErrPushRejected)
if len(errPushRej.Message) == 0 {
@@ -495,7 +495,7 @@ func DeleteFilePost(ctx *context.Context) {
ctx.Error(http.StatusInternalServerError, err.Error())
}
} else if models.IsErrCommitIDDoesNotMatch(err) || git.IsErrPushOutOfDate(err) {
- ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
+ ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplDeleteFile, &form)
} else if git.IsErrPushRejected(err) {
errPushRej := err.(*git.ErrPushRejected)
if len(errPushRej.Message) == 0 {
@@ -602,7 +602,7 @@ func UploadFilePost(ctx *context.Context) {
ctx.Data["TreePath"] = form.TreePath
ctx.Data["TreeNames"] = treeNames
ctx.Data["TreePaths"] = treePaths
- ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + branchName
+ ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName)
ctx.Data["commit_summary"] = form.CommitSummary
ctx.Data["commit_message"] = form.CommitMessage
ctx.Data["commit_choice"] = form.CommitChoice
@@ -698,7 +698,7 @@ func UploadFilePost(ctx *context.Context) {
branchErr := err.(models.ErrBranchAlreadyExists)
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplUploadFile, &form)
} else if git.IsErrPushOutOfDate(err) {
- ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+ctx.Repo.CommitID+"..."+util.PathEscapeSegments(form.NewBranchName)), tplUploadFile, &form)
+ ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(ctx.Repo.CommitID)+"..."+util.PathEscapeSegments(form.NewBranchName)), tplUploadFile, &form)
} else if git.IsErrPushRejected(err) {
errPushRej := err.(*git.ErrPushRejected)
if len(errPushRej.Message) == 0 {
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index d9e15a784f..95363258e9 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"net/http"
+ "net/url"
"path"
"strconv"
"strings"
@@ -106,7 +107,7 @@ func MustAllowPulls(ctx *context.Context) {
// User can send pull request if owns a forked repository.
if ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID) {
ctx.Repo.PullRequest.Allowed = true
- ctx.Repo.PullRequest.HeadInfo = ctx.User.Name + ":" + ctx.Repo.BranchName
+ ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.User.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
}
}
@@ -764,7 +765,7 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleDirs [
for _, repoLabel := range repoLabels {
if strings.EqualFold(repoLabel.Name, metaLabel) {
repoLabel.IsChecked = true
- labelIDs = append(labelIDs, fmt.Sprintf("%d", repoLabel.ID))
+ labelIDs = append(labelIDs, strconv.FormatInt(repoLabel.ID, 10))
break
}
}
@@ -983,6 +984,7 @@ func NewIssuePost(ctx *context.Context) {
issue := &models.Issue{
RepoID: repo.ID,
+ Repo: repo,
Title: form.Title,
PosterID: ctx.User.ID,
Poster: ctx.User,
@@ -1009,9 +1011,9 @@ func NewIssuePost(ctx *context.Context) {
log.Trace("Issue created: %d/%d", repo.ID, issue.ID)
if ctx.FormString("redirect_after_creation") == "project" {
- ctx.Redirect(ctx.Repo.RepoLink + "/projects/" + fmt.Sprint(form.ProjectID))
+ ctx.Redirect(ctx.Repo.RepoLink + "/projects/" + strconv.FormatInt(form.ProjectID, 10))
} else {
- ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
}
}
@@ -1097,13 +1099,16 @@ func ViewIssue(ctx *context.Context) {
}
return
}
+ if issue.Repo == nil {
+ issue.Repo = ctx.Repo.Repository
+ }
// Make sure type and URL matches.
if ctx.Params(":type") == "issues" && issue.IsPull {
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
} else if ctx.Params(":type") == "pulls" && !issue.IsPull {
- ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -1496,7 +1501,7 @@ func ViewIssue(ctx *context.Context) {
log.Error("IsProtectedBranch: %v", err)
} else if !protected {
canDelete = true
- ctx.Data["DeleteBranchLink"] = ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index) + "/cleanup"
+ ctx.Data["DeleteBranchLink"] = issue.Link() + "/cleanup"
}
}
}
@@ -1624,7 +1629,7 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["NumParticipants"] = len(participants)
ctx.Data["Issue"] = issue
ctx.Data["ReadOnly"] = false
- ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + ctx.Data["Link"].(string)
+ ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + url.QueryEscape(ctx.Data["Link"].(string))
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
ctx.Data["HasProjectsWritePermission"] = ctx.Repo.CanWrite(unit.TypeProjects)
@@ -1773,7 +1778,7 @@ func UpdateIssueContent(ctx *context.Context) {
}
content, err := markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.FormString("context"),
+ URLPrefix: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
Metas: ctx.Repo.Repository.ComposeMetas(),
GitRepo: ctx.Repo.GitRepo,
Ctx: ctx,
@@ -2205,7 +2210,7 @@ func UpdateCommentContent(ctx *context.Context) {
}
content, err := markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.FormString("context"),
+ URLPrefix: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
Metas: ctx.Repo.Repository.ComposeMetas(),
GitRepo: ctx.Repo.GitRepo,
Ctx: ctx,
diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go
index b8efb3b841..0e9405fde4 100644
--- a/routers/web/repo/issue_stopwatch.go
+++ b/routers/web/repo/issue_stopwatch.go
@@ -94,6 +94,7 @@ func GetActiveStopwatch(c *context.Context) {
}
c.Data["ActiveStopwatch"] = StopwatchTmplInfo{
+ issue.Link(),
issue.Repo.FullName(),
issue.Index,
sw.Seconds() + 1, // ensure time is never zero in ui
@@ -102,6 +103,7 @@ func GetActiveStopwatch(c *context.Context) {
// StopwatchTmplInfo is a view on a stopwatch specifically for template rendering
type StopwatchTmplInfo struct {
+ IssueLink string
RepoSlug string
IssueIndex int64
Seconds int64
diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go
index 5e24cfa3c0..b15c7628db 100644
--- a/routers/web/repo/lfs.go
+++ b/routers/web/repo/lfs.go
@@ -10,6 +10,7 @@ import (
gotemplate "html/template"
"io"
"net/http"
+ "net/url"
"path"
"strconv"
"strings"
@@ -285,7 +286,7 @@ func LFSFileGet(ctx *context.Context) {
fileSize := meta.Size
ctx.Data["FileSize"] = meta.Size
- ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s.git/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), meta.Oid, "direct")
+ ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s/%s.git/info/lfs/objects/%s/%s", setting.AppURL, url.PathEscape(ctx.Repo.Repository.OwnerName), url.PathEscape(ctx.Repo.Repository.Name), url.PathEscape(meta.Oid), "direct")
switch {
case isRepresentableAsText:
if st.IsSvgImage() {
diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go
index d5e0a7696b..f91c344e94 100644
--- a/routers/web/repo/migrate.go
+++ b/routers/web/repo/migrate.go
@@ -7,6 +7,7 @@ package repo
import (
"net/http"
+ "net/url"
"strings"
"code.gitea.io/gitea/models"
@@ -237,7 +238,7 @@ func MigratePost(ctx *context.Context) {
err = task.MigrateRepository(ctx.User, ctxUser, opts)
if err == nil {
- ctx.Redirect(ctxUser.HomeLink() + "/" + opts.RepoName)
+ ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(opts.RepoName))
return
}
diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go
index 21e1fb2eab..eadc89333f 100644
--- a/routers/web/repo/milestone.go
+++ b/routers/web/repo/milestone.go
@@ -6,6 +6,7 @@ package repo
import (
"net/http"
+ "net/url"
"time"
"code.gitea.io/gitea/models"
@@ -244,7 +245,7 @@ func ChangeMilestoneStatus(ctx *context.Context) {
}
return
}
- ctx.Redirect(ctx.Repo.RepoLink + "/milestones?state=" + ctx.Params(":action"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/milestones?state=" + url.QueryEscape(ctx.Params(":action")))
}
// DeleteMilestone delete a milestone
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 08b285df0a..437da14d45 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -7,6 +7,7 @@ package repo
import (
"fmt"
"net/http"
+ "net/url"
"strings"
"code.gitea.io/gitea/models"
@@ -173,7 +174,7 @@ func ChangeProjectStatus(ctx *context.Context) {
}
return
}
- ctx.Redirect(ctx.Repo.RepoLink + "/projects?state=" + ctx.Params(":action"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/projects?state=" + url.QueryEscape(ctx.Params(":action")))
}
// DeleteProject delete a project
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 0ac05a7609..4337278214 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -10,8 +10,10 @@ import (
"crypto/subtle"
"errors"
"fmt"
+ "html"
"net/http"
- "path"
+ "net/url"
+ "strconv"
"strings"
"time"
@@ -34,7 +36,6 @@ import (
"code.gitea.io/gitea/services/gitdiff"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
- "github.com/unknwon/com"
)
const (
@@ -109,8 +110,7 @@ func getForkRepository(ctx *context.Context) *models.Repository {
ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate
canForkToUser := forkRepo.OwnerID != ctx.User.ID && !ctx.User.HasForkedRepo(forkRepo.ID)
- ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name
- ctx.Data["ForkFromOwnerID"] = forkRepo.Owner.ID
+ ctx.Data["ForkRepo"] = forkRepo
if err := ctx.User.GetOwnedOrganizations(); err != nil {
ctx.ServerError("GetOwnedOrganizations", err)
@@ -202,7 +202,7 @@ func ForkPost(ctx *context.Context) {
}
repo, has := models.HasForkedRepo(ctxUser.ID, traverseParentRepo.ID)
if has {
- ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
+ ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
return
}
if !traverseParentRepo.IsFork {
@@ -248,7 +248,7 @@ func ForkPost(ctx *context.Context) {
}
log.Trace("Repository forked[%d]: %s/%s", forkRepo.ID, ctxUser.Name, repo.Name)
- ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
+ ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
}
func checkPullInfo(ctx *context.Context) *models.Issue {
@@ -682,8 +682,7 @@ func ViewPullFiles(ctx *context.Context) {
}
}
- headTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
- setCompareContext(ctx, baseCommit, commit, headTarget)
+ setCompareContext(ctx, baseCommit, commit, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireSimpleMDE"] = true
@@ -746,7 +745,7 @@ func UpdatePullRequest(ctx *context.Context) {
// ToDo: add check if maintainers are allowed to change branch ... (need migration & co)
if (!allowedUpdateByMerge && !rebase) || (rebase && !allowedUpdateByRebase) {
ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -766,7 +765,7 @@ func UpdatePullRequest(ctx *context.Context) {
return
}
ctx.Flash.Error(flashError)
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
} else if models.IsErrRebaseConflicts(err) {
conflictError := err.(models.ErrRebaseConflicts)
@@ -780,19 +779,19 @@ func UpdatePullRequest(ctx *context.Context) {
return
}
ctx.Flash.Error(flashError)
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
ctx.Flash.Error(err.Error())
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
time.Sleep(1 * time.Second)
ctx.Flash.Success(ctx.Tr("repo.pulls.update_branch_success"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
}
// MergePullRequest response for merging pull request
@@ -805,11 +804,11 @@ func MergePullRequest(ctx *context.Context) {
if issue.IsClosed {
if issue.IsPull {
ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
- ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -822,13 +821,13 @@ func MergePullRequest(ctx *context.Context) {
}
if !allowedMerge {
ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
if pr.HasMerged {
ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -837,11 +836,11 @@ func MergePullRequest(ctx *context.Context) {
if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
+ ctx.Redirect(issue.Link())
return
} else if strings.Contains(err.Error(), "Wrong commit ID") {
ctx.Flash.Error(ctx.Tr("repo.pulls.wrong_commit_id"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -849,19 +848,19 @@ func MergePullRequest(ctx *context.Context) {
return
}
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
if !pr.CanAutoMerge() {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
+ ctx.Redirect(issue.Link())
return
}
if pr.IsWorkInProgress() {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -875,14 +874,14 @@ func MergePullRequest(ctx *context.Context) {
return
} else if !isRepoAdmin {
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
}
}
if ctx.HasError() {
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
}
@@ -914,14 +913,14 @@ func MergePullRequest(ctx *context.Context) {
if !noDeps {
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
}
if err = pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
} else if models.IsErrMergeConflicts(err) {
conflictError := err.(models.ErrMergeConflicts)
@@ -935,7 +934,7 @@ func MergePullRequest(ctx *context.Context) {
return
}
ctx.Flash.Error(flashError)
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
} else if models.IsErrRebaseConflicts(err) {
conflictError := err.(models.ErrRebaseConflicts)
@@ -949,17 +948,17 @@ func MergePullRequest(ctx *context.Context) {
return
}
ctx.Flash.Error(flashError)
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
} else if models.IsErrMergeUnrelatedHistories(err) {
log.Debug("MergeUnrelatedHistories error: %v", err)
ctx.Flash.Error(ctx.Tr("repo.pulls.unrelated_histories"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
} else if git.IsErrPushOutOfDate(err) {
log.Debug("MergePushOutOfDate error: %v", err)
ctx.Flash.Error(ctx.Tr("repo.pulls.merge_out_of_date"))
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
} else if git.IsErrPushRejected(err) {
log.Debug("MergePushRejected error: %v", err)
@@ -979,7 +978,7 @@ func MergePullRequest(ctx *context.Context) {
}
ctx.Flash.Error(flashError)
}
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
return
}
ctx.ServerError("Merge", err)
@@ -1008,7 +1007,7 @@ func MergePullRequest(ctx *context.Context) {
deleteBranch(ctx, pr, headRepo)
}
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pr.Index))
+ ctx.Redirect(issue.Link())
}
func stopTimerIfAvailable(user *models.User, issue *models.Issue) error {
@@ -1097,6 +1096,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
pullIssue := &models.Issue{
RepoID: repo.ID,
+ Repo: repo,
Title: form.Title,
PosterID: ctx.User.ID,
Poster: ctx.User,
@@ -1138,7 +1138,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
}
ctx.Flash.Error(flashError)
}
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pullIssue.Index))
+ ctx.Redirect(pullIssue.Link())
return
}
ctx.ServerError("NewPullRequest", err)
@@ -1146,7 +1146,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
}
log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID)
- ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + fmt.Sprint(pullIssue.Index))
+ ctx.Redirect(pullIssue.Link())
}
// TriggerTask response for a trigger task request
@@ -1261,7 +1261,7 @@ func CleanUpPullRequest(ctx *context.Context) {
defer func() {
ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": pr.BaseRepo.Link() + "/pulls/" + fmt.Sprint(issue.Index),
+ "redirect": issue.Link(),
})
}()
@@ -1369,7 +1369,7 @@ func UpdatePullRequestTarget(ctx *context.Context) {
err := err.(models.ErrPullRequestAlreadyExists)
RepoRelPath := ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
- errorMessage := ctx.Tr("repo.pulls.has_pull_request", ctx.Repo.RepoLink, RepoRelPath, err.IssueID)
+ errorMessage := ctx.Tr("repo.pulls.has_pull_request", html.EscapeString(ctx.Repo.RepoLink+"/pulls/"+strconv.FormatInt(err.IssueID, 10)), html.EscapeString(RepoRelPath), err.IssueID) // FIXME: Creates url insidde locale string
ctx.Flash.Error(errorMessage)
ctx.JSON(http.StatusConflict, map[string]interface{}{
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 20f6ddd2a5..3f12ee72bc 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/upload"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
releaseservice "code.gitea.io/gitea/services/release"
@@ -350,7 +351,7 @@ func NewReleasePost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.tag.create_success", form.TagName))
- ctx.Redirect(ctx.Repo.RepoLink + "/src/tag/" + form.TagName)
+ ctx.Redirect(ctx.Repo.RepoLink + "/src/tag/" + util.PathEscapeSegments(form.TagName))
return
}
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index c70dec6481..46cef7664a 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -244,7 +244,7 @@ func CreatePost(ctx *context.Context) {
repo, err = repo_service.GenerateRepository(ctx.User, ctxUser, templateRepo, opts)
if err == nil {
log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
- ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
+ ctx.Redirect(repo.Link())
return
}
} else {
@@ -263,7 +263,7 @@ func CreatePost(ctx *context.Context) {
})
if err == nil {
log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
- ctx.Redirect(ctxUser.HomeLink() + "/" + repo.Name)
+ ctx.Redirect(repo.Link())
return
}
}
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index cecd1da07c..641052316c 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -615,7 +615,7 @@ func SettingsPost(ctx *context.Context) {
log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName()))
- ctx.Redirect(ctx.Repo.Owner.HomeLink() + "/" + repo.Name + "/settings")
+ ctx.Redirect(repo.Link() + "/settings")
case "cancel_transfer":
if !ctx.Repo.IsOwner() {
@@ -627,7 +627,7 @@ func SettingsPost(ctx *context.Context) {
if err != nil {
if models.IsErrNoPendingTransfer(err) {
ctx.Flash.Error("repo.settings.transfer_abort_invalid")
- ctx.Redirect(ctx.User.HomeLink() + "/" + repo.Name + "/settings")
+ ctx.Redirect(repo.Link() + "/settings")
} else {
ctx.ServerError("GetPendingRepositoryTransfer", err)
}
@@ -647,7 +647,7 @@ func SettingsPost(ctx *context.Context) {
log.Trace("Repository transfer process was cancelled: %s/%s ", ctx.Repo.Owner.Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_abort_success", repoTransfer.Recipient.Name))
- ctx.Redirect(ctx.Repo.Owner.HomeLink() + "/" + repo.Name + "/settings")
+ ctx.Redirect(repo.Link() + "/settings")
case "delete":
if !ctx.Repo.IsOwner() {
@@ -796,7 +796,7 @@ func Collaboration(ctx *context.Context) {
func CollaborationPost(ctx *context.Context) {
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("collaborator")))
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
return
}
@@ -804,7 +804,7 @@ func CollaborationPost(ctx *context.Context) {
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
} else {
ctx.ServerError("GetUserByName", err)
}
@@ -813,14 +813,14 @@ func CollaborationPost(ctx *context.Context) {
if !u.IsActive {
ctx.Flash.Error(ctx.Tr("repo.settings.add_collaborator_inactive_user"))
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
return
}
// Organization is not allowed to be added as a collaborator.
if u.IsOrganization() {
ctx.Flash.Error(ctx.Tr("repo.settings.org_not_allowed_to_be_collaborator"))
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
return
}
@@ -840,7 +840,7 @@ func CollaborationPost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success"))
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
}
// ChangeCollaborationAccessMode response for changing access of a collaboration
diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go
index 876ff9ba46..32105b1d43 100644
--- a/routers/web/repo/setting_protected_branch.go
+++ b/routers/web/repo/setting_protected_branch.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/forms"
pull_service "code.gitea.io/gitea/services/pull"
@@ -89,7 +90,7 @@ func ProtectedBranchPost(ctx *context.Context) {
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
default:
ctx.NotFound("", nil)
}
@@ -197,7 +198,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
}
if f.RequiredApprovals < 0 {
ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_approvals_min"))
- ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, branch))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, util.PathEscapeSegments(branch)))
}
var whitelistUsers, whitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams []int64
@@ -274,7 +275,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.update_protect_branch_success", branch))
- ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, branch))
+ ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, util.PathEscapeSegments(branch)))
} else {
if protectBranch != nil {
if err := ctx.Repo.Repository.DeleteProtectedBranch(protectBranch.ID); err != nil {
diff --git a/routers/web/repo/tag.go b/routers/web/repo/tag.go
index a180399c9e..b4d268759c 100644
--- a/routers/web/repo/tag.go
+++ b/routers/web/repo/tag.go
@@ -58,7 +58,7 @@ func NewProtectedTagPost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
+ ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
}
// EditProtectedTag render the page to edit a protect tag
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index cecd8437b6..12b3aef505 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -232,7 +232,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
}
if readmeFile != nil {
readmeFile.name = entry.Name() + "/" + readmeFile.name
- readmeTreelink = treeLink + "/" + entry.GetSubJumpablePathName()
+ readmeTreelink = treeLink + "/" + util.PathEscapeSegments(entry.GetSubJumpablePathName())
break
}
}
@@ -301,7 +301,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
fileSize = meta.Size
ctx.Data["FileSize"] = meta.Size
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name))
- ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s.git/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), meta.Oid, filenameBase64)
+ ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.HTMLURL(), url.PathEscape(meta.Oid), url.PathEscape(filenameBase64))
}
}
}
@@ -376,7 +376,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
fileSize := blob.Size()
ctx.Data["FileIsSymlink"] = entry.IsLink()
ctx.Data["FileName"] = blob.Name()
- ctx.Data["RawFileLink"] = rawLink + "/" + ctx.Repo.TreePath
+ ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
buf := make([]byte, 1024)
n, _ := util.ReadAtMost(dataRc, buf)
@@ -422,7 +422,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
isTextFile = st.IsText()
fileSize = meta.Size
- ctx.Data["RawFileLink"] = fmt.Sprintf("%s/media/%s/%s", ctx.Repo.RepoLink, ctx.Repo.BranchNameSubURL(), ctx.Repo.TreePath)
+ ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/media/" + ctx.Repo.BranchNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
}
}
}
@@ -628,7 +628,7 @@ func checkHomeCodeViewable(ctx *context.Context) {
}
if firstUnit != nil {
- ctx.Redirect(fmt.Sprintf("%s/%s%s", setting.AppSubURL, ctx.Repo.Repository.FullName(), firstUnit.URI))
+ ctx.Redirect(fmt.Sprintf("%s%s", ctx.Repo.Repository.Link(), firstUnit.URI))
return
}
}
@@ -684,7 +684,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
return nil
}
- ctx.Data["LastCommitLoaderURL"] = ctx.Repo.RepoLink + "/lastcommit/" + ctx.Repo.CommitID + "/" + ctx.Repo.TreePath
+ ctx.Data["LastCommitLoaderURL"] = ctx.Repo.RepoLink + "/lastcommit/" + url.PathEscape(ctx.Repo.CommitID) + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
// Get current entry user currently looking at.
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
@@ -766,7 +766,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
treeLink := branchLink
if len(ctx.Repo.TreePath) > 0 {
- treeLink += "/" + ctx.Repo.TreePath
+ treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
}
ctx.Data["TreeLink"] = treeLink
@@ -815,7 +815,7 @@ func renderCode(ctx *context.Context) {
rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
if len(ctx.Repo.TreePath) > 0 {
- treeLink += "/" + ctx.Repo.TreePath
+ treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
}
// Get Topics of this repo
diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go
index f47f8d651d..4f6660926e 100644
--- a/routers/web/repo/webhook.go
+++ b/routers/web/repo/webhook.go
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"net/http"
+ "net/url"
"path"
"strings"
@@ -414,7 +415,7 @@ func TelegramHooksNewPost(ctx *context.Context) {
w := &webhook.Webhook{
RepoID: orCtx.RepoID,
- URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID),
+ URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", url.PathEscape(form.BotToken), url.QueryEscape(form.ChatID)),
ContentType: webhook.ContentTypeJSON,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
@@ -468,7 +469,7 @@ func MatrixHooksNewPost(ctx *context.Context) {
w := &webhook.Webhook{
RepoID: orCtx.RepoID,
- URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, form.RoomID),
+ URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, url.PathEscape(form.RoomID)),
ContentType: webhook.ContentTypeJSON,
HTTPMethod: "PUT",
HookEvent: ParseHookEvent(form.WebhookForm),
@@ -976,7 +977,7 @@ func TelegramHooksEditPost(ctx *context.Context) {
return
}
w.Meta = string(meta)
- w.URL = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID)
+ w.URL = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", url.PathEscape(form.BotToken), url.QueryEscape(form.ChatID))
w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active
if err := w.UpdateEvent(); err != nil {
@@ -1020,7 +1021,7 @@ func MatrixHooksEditPost(ctx *context.Context) {
return
}
w.Meta = string(meta)
- w.URL = fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, form.RoomID)
+ w.URL = fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, url.PathEscape(form.RoomID))
w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active
@@ -1162,7 +1163,7 @@ func TestWebhook(ctx *context.Context) {
apiCommit := &api.PayloadCommit{
ID: commit.ID.String(),
Message: commit.Message(),
- URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
+ URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()),
Author: &api.PayloadUser{
Name: commit.Author.Name,
Email: commit.Author.Email,
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 16927de2e9..82f56a8c4a 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -180,7 +180,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
ctx.Data["Pages"] = pages
// get requested pagename
- pageName := wiki_service.NormalizeWikiName(ctx.Params(":page"))
+ pageName := wiki_service.NormalizeWikiName(ctx.Params("*"))
if len(pageName) == 0 {
pageName = "Home"
}
@@ -193,7 +193,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
//lookup filename in wiki - get filecontent, gitTree entry , real filename
data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
if noEntry {
- ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages")
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
}
if entry == nil || ctx.Written() {
if wikiRepo != nil {
@@ -276,7 +276,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
}
// get requested pagename
- pageName := wiki_service.NormalizeWikiName(ctx.Params(":page"))
+ pageName := wiki_service.NormalizeWikiName(ctx.Params("*"))
if len(pageName) == 0 {
pageName = "Home"
}
@@ -291,7 +291,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
//lookup filename in wiki - get filecontent, gitTree entry , real filename
data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
if noEntry {
- ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages")
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
}
if entry == nil || ctx.Written() {
if wikiRepo != nil {
@@ -352,7 +352,7 @@ func renderEditPage(ctx *context.Context) {
}()
// get requested pagename
- pageName := wiki_service.NormalizeWikiName(ctx.Params(":page"))
+ pageName := wiki_service.NormalizeWikiName(ctx.Params("*"))
if len(pageName) == 0 {
pageName = "Home"
}
@@ -365,7 +365,7 @@ func renderEditPage(ctx *context.Context) {
//lookup filename in wiki - get filecontent, gitTree entry , real filename
data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName)
if noEntry {
- ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_pages")
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
}
if entry == nil || ctx.Written() {
return
@@ -378,6 +378,32 @@ func renderEditPage(ctx *context.Context) {
ctx.Data["footerContent"] = ""
}
+// WikiPost renders post of wiki page
+func WikiPost(ctx *context.Context) {
+ switch ctx.FormString("action") {
+ case "_new":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ NewWikiPost(ctx)
+ return
+ case "_delete":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ DeleteWikiPagePost(ctx)
+ return
+ }
+
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ EditWikiPost(ctx)
+}
+
// Wiki renders single wiki page
func Wiki(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
@@ -389,6 +415,29 @@ func Wiki(ctx *context.Context) {
return
}
+ switch ctx.FormString("action") {
+ case "_pages":
+ WikiPages(ctx)
+ return
+ case "_revision":
+ WikiRevision(ctx)
+ return
+ case "_edit":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ EditWiki(ctx)
+ return
+ case "_new":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ NewWiki(ctx)
+ return
+ }
+
wikiRepo, entry := renderViewPage(ctx)
defer func() {
if wikiRepo != nil {
@@ -652,7 +701,7 @@ func EditWikiPost(ctx *context.Context) {
return
}
- oldWikiName := wiki_service.NormalizeWikiName(ctx.Params(":page"))
+ oldWikiName := wiki_service.NormalizeWikiName(ctx.Params("*"))
newWikiName := wiki_service.NormalizeWikiName(form.Title)
if len(form.Message) == 0 {
@@ -669,7 +718,7 @@ func EditWikiPost(ctx *context.Context) {
// DeleteWikiPagePost delete wiki page
func DeleteWikiPagePost(ctx *context.Context) {
- wikiName := wiki_service.NormalizeWikiName(ctx.Params(":page"))
+ wikiName := wiki_service.NormalizeWikiName(ctx.Params("*"))
if len(wikiName) == 0 {
wikiName = "Home"
}
diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go
index cf49f19afe..87f2779c1a 100644
--- a/routers/web/repo/wiki_test.go
+++ b/routers/web/repo/wiki_test.go
@@ -76,8 +76,8 @@ func assertPagesMetas(t *testing.T, expectedNames []string, metas interface{}) {
func TestWiki(t *testing.T) {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_pages")
- ctx.SetParams(":page", "Home")
+ ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages")
+ ctx.SetParams("*", "Home")
test.LoadRepo(t, ctx, 1)
Wiki(ctx)
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
@@ -88,7 +88,7 @@ func TestWiki(t *testing.T) {
func TestWikiPages(t *testing.T) {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_pages")
+ ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages")
test.LoadRepo(t, ctx, 1)
WikiPages(ctx)
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
@@ -98,7 +98,7 @@ func TestWikiPages(t *testing.T) {
func TestNewWiki(t *testing.T) {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_new")
+ ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new")
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
NewWiki(ctx)
@@ -113,7 +113,7 @@ func TestNewWikiPost(t *testing.T) {
} {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_new")
+ ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new")
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
web.SetForm(ctx, &forms.NewWikiForm{
@@ -131,7 +131,7 @@ func TestNewWikiPost(t *testing.T) {
func TestNewWikiPost_ReservedName(t *testing.T) {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_new")
+ ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new")
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
web.SetForm(ctx, &forms.NewWikiForm{
@@ -148,8 +148,8 @@ func TestNewWikiPost_ReservedName(t *testing.T) {
func TestEditWiki(t *testing.T) {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_edit/Home")
- ctx.SetParams(":page", "Home")
+ ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit")
+ ctx.SetParams("*", "Home")
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
EditWiki(ctx)
@@ -164,8 +164,8 @@ func TestEditWikiPost(t *testing.T) {
"New/<page>",
} {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/_new/Home")
- ctx.SetParams(":page", "Home")
+ ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_new")
+ ctx.SetParams("*", "Home")
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
web.SetForm(ctx, &forms.NewWikiForm{
@@ -186,7 +186,7 @@ func TestEditWikiPost(t *testing.T) {
func TestDeleteWikiPagePost(t *testing.T) {
unittest.PrepareTestEnv(t)
- ctx := test.MockContext(t, "user2/repo1/wiki/Home/delete")
+ ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete")
test.LoadUser(t, ctx, 2)
test.LoadRepo(t, ctx, 1)
DeleteWikiPagePost(ctx)
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 1305b0095a..b9f5d044fa 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -887,5 +887,5 @@ func Email2User(ctx *context.Context) {
}
return
}
- ctx.Redirect(setting.AppSubURL + "/user/" + u.Name)
+ ctx.Redirect(u.HomeLink())
}
diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go
index 080ec4b582..08cd1b8b31 100644
--- a/routers/web/user/notification.go
+++ b/routers/web/user/notification.go
@@ -167,7 +167,7 @@ func NotificationStatusPost(c *context.Context) {
}
if !c.FormBool("noredirect") {
- url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, c.FormString("page"))
+ url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, url.QueryEscape(c.FormString("page")))
c.Redirect(url, http.StatusSeeOther)
}
@@ -189,6 +189,5 @@ func NotificationPurgePost(c *context.Context) {
return
}
- url := fmt.Sprintf("%s/notifications", setting.AppSubURL)
- c.Redirect(url, http.StatusSeeOther)
+ c.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther)
}
diff --git a/routers/web/user/oauth.go b/routers/web/user/oauth.go
index 642a7f33b0..3210d033d3 100644
--- a/routers/web/user/oauth.go
+++ b/routers/web/user/oauth.go
@@ -454,7 +454,7 @@ func AuthorizeOAuth(ctx *context.Context) {
ctx.Data["State"] = form.State
ctx.Data["Scope"] = form.Scope
ctx.Data["Nonce"] = form.Nonce
- ctx.Data["ApplicationUserLink"] = "<a href=\"" + html.EscapeString(setting.AppURL) + html.EscapeString(url.PathEscape(user.LowerName)) + "\">@" + html.EscapeString(user.Name) + "</a>"
+ ctx.Data["ApplicationUserLink"] = "<a href=\"" + html.EscapeString(user.HTMLURL()) + "\">@" + html.EscapeString(user.Name) + "</a>"
ctx.Data["ApplicationRedirectDomainHTML"] = "<strong>" + html.EscapeString(form.RedirectURI) + "</strong>"
// TODO document SESSION <=> FORM
err = ctx.Session.Set("client_id", app.ClientID)
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index f8fcbf6565..17c4783c69 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -364,6 +364,6 @@ func Action(ctx *context.Context) {
ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
return
}
-
+ // FIXME: We should check this URL and make sure that it's a valid Gitea URL
ctx.RedirectToFirst(ctx.FormString("redirect_to"), u.HomeLink())
}
diff --git a/routers/web/web.go b/routers/web/web.go
index 69f737c3e1..a20bf484b3 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -895,21 +895,23 @@ func RegisterRoutes(m *web.Route) {
}, reqRepoProjectsReader, repo.MustEnableProjects)
m.Group("/wiki", func() {
- m.Get("/", repo.Wiki)
- m.Get("/{page}", repo.Wiki)
- m.Get("/_pages", repo.WikiPages)
- m.Get("/{page}/_revision", repo.WikiRevision)
+ m.Combo("/").
+ Get(repo.Wiki).
+ Post(context.RepoMustNotBeArchived(),
+ reqSignIn,
+ reqRepoWikiWriter,
+ bindIgnErr(forms.NewWikiForm{}),
+ repo.WikiPost)
+ m.Combo("/*").
+ Get(repo.Wiki).
+ Post(context.RepoMustNotBeArchived(),
+ reqSignIn,
+ reqRepoWikiWriter,
+ bindIgnErr(forms.NewWikiForm{}),
+ repo.WikiPost)
m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff)
-
- m.Group("", func() {
- m.Combo("/_new").Get(repo.NewWiki).
- Post(bindIgnErr(forms.NewWikiForm{}), repo.NewWikiPost)
- m.Combo("/{page}/_edit").Get(repo.EditWiki).
- Post(bindIgnErr(forms.NewWikiForm{}), repo.EditWikiPost)
- m.Post("/{page}/delete", repo.DeleteWikiPagePost)
- }, context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter)
- }, repo.MustEnableWiki, context.RepoRef(), func(ctx *context.Context) {
+ }, repo.MustEnableWiki, func(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
})