diff options
author | zeripath <art27@cantab.net> | 2021-11-16 18:18:25 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-16 18:18:25 +0000 |
commit | bbffcc3aecda040a40d49078e7141213bc8d78af (patch) | |
tree | 1b96c621edadabc85dec2c15c30b1b870af09467 | |
parent | 7e1ae380975df0afab3fdc04c7a926181e5daba9 (diff) | |
download | gitea-bbffcc3aecda040a40d49078e7141213bc8d78af.tar.gz gitea-bbffcc3aecda040a40d49078e7141213bc8d78af.zip |
Multiple Escaping Improvements (#17551)
There are multiple places where Gitea does not properly escape URLs that it is building and there are multiple places where it builds urls when there is already a simpler function available to use this.
This is an extensive PR attempting to fix these issues.
1. The first commit in this PR looks through all href, src and links in the Gitea codebase and has attempted to catch all the places where there is potentially incomplete escaping.
2. Whilst doing this we will prefer to use functions that create URLs over recreating them by hand.
3. All uses of strings should be directly escaped - even if they are not currently expected to contain escaping characters. The main benefit to doing this will be that we can consider relaxing the constraints on user names and reponames in future.
4. The next commit looks at escaping in the wiki and re-considers the urls that are used there. Using the improved escaping here wiki files containing '/'. (This implementation will currently still place all of the wiki files the root directory of the repo but this would not be difficult to change.)
5. The title generation in feeds is now properly escaped.
6. EscapePound is no longer needed - urls should be PathEscaped / QueryEscaped as necessary but then re-escaped with Escape when creating html with locales Signed-off-by: Andrew Thornton <art27@cantab.net>
Signed-off-by: Andrew Thornton <art27@cantab.net>
153 files changed, 891 insertions, 712 deletions
diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 03ca382de4..56cddcb063 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -65,7 +65,7 @@ func TestViewIssuesSortByType(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) session := loginUser(t, user.Name) - req := NewRequest(t, "GET", repo.RelLink()+"/issues?type=created_by") + req := NewRequest(t, "GET", repo.Link()+"/issues?type=created_by") resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) @@ -97,7 +97,7 @@ func TestViewIssuesKeyword(t *testing.T) { issues.UpdateIssueIndexer(issue) time.Sleep(time.Second * 1) const keyword = "first" - req := NewRequestf(t, "GET", "%s/issues?q=%s", repo.RelLink(), keyword) + req := NewRequestf(t, "GET", "%s/issues?q=%s", repo.Link(), keyword) resp := MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) diff --git a/integrations/links_test.go b/integrations/links_test.go index 03229e10e1..91166274a2 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -156,7 +156,7 @@ func testLinksAsUser(userName string, t *testing.T) { "/releases", "/releases/new", //"/wiki/_pages", - "/wiki/_new", + "/wiki/?action=_new", } for _, repo := range apiRepos { diff --git a/integrations/nonascii_branches_test.go b/integrations/nonascii_branches_test.go index 22d71e6ee2..cf6261dffe 100644 --- a/integrations/nonascii_branches_test.go +++ b/integrations/nonascii_branches_test.go @@ -63,17 +63,17 @@ func TestNonasciiBranches(t *testing.T) { }, { from: "ГлавнаяВетка", - to: "branch/%d0%93%d0%bb%d0%b0%d0%b2%d0%bd%d0%b0%d1%8f%d0%92%d0%b5%d1%82%d0%ba%d0%b0", + to: "branch/%D0%93%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F%D0%92%D0%B5%D1%82%D0%BA%D0%B0", status: http.StatusOK, }, { from: "а/б/в", - to: "branch/%d0%b0/%d0%b1/%d0%b2", + to: "branch/%D0%B0/%D0%B1/%D0%B2", status: http.StatusOK, }, { from: "Grüßen/README.md", - to: "branch/Gr%c3%bc%c3%9fen/README.md", + to: "branch/Gr%C3%BC%C3%9Fen/README.md", status: http.StatusOK, }, { @@ -83,7 +83,7 @@ func TestNonasciiBranches(t *testing.T) { }, { from: "Plus+Is+Not+Space/Файл.md", - to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md", + to: "branch/Plus+Is+Not+Space/%D0%A4%D0%B0%D0%B9%D0%BB.md", status: http.StatusOK, }, { @@ -93,28 +93,28 @@ func TestNonasciiBranches(t *testing.T) { }, { from: "ブランチ", - to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81", + to: "branch/%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81", status: http.StatusOK, }, // Tags { from: "Тэг", - to: "tag/%d0%a2%d1%8d%d0%b3", + to: "tag/%D0%A2%D1%8D%D0%B3", status: http.StatusOK, }, { from: "Ё/人", - to: "tag/%d0%81/%e4%ba%ba", + to: "tag/%D0%81/%E4%BA%BA", status: http.StatusOK, }, { from: "タグ", - to: "tag/%e3%82%bf%e3%82%b0", + to: "tag/%E3%82%BF%E3%82%B0", status: http.StatusOK, }, { from: "タグ/ファイル.md", - to: "tag/%e3%82%bf%e3%82%b0/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md", + to: "tag/%E3%82%BF%E3%82%B0/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.md", status: http.StatusOK, }, // Files @@ -125,38 +125,38 @@ func TestNonasciiBranches(t *testing.T) { }, { from: "Файл.md", - to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md", + to: "branch/Plus+Is+Not+Space/%D0%A4%D0%B0%D0%B9%D0%BB.md", status: http.StatusOK, }, { from: "ファイル.md", - to: "branch/Plus+Is+Not+Space/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md", + to: "branch/Plus+Is+Not+Space/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.md", status: http.StatusNotFound, // it's not on default branch }, // Same but url-encoded (few tests) { from: "%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81", - to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81", + to: "branch/%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81", status: http.StatusOK, }, { from: "%E3%82%BF%E3%82%b0", - to: "tag/%e3%82%bf%e3%82%b0", + to: "tag/%E3%82%BF%E3%82%B0", status: http.StatusOK, }, { from: "%D0%A4%D0%B0%D0%B9%D0%BB.md", - to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md", + to: "branch/Plus+Is+Not+Space/%D0%A4%D0%B0%D0%B9%D0%BB.md", status: http.StatusOK, }, { from: "%D0%81%2F%E4%BA%BA", - to: "tag/%d0%81/%e4%ba%ba", + to: "tag/%D0%81/%E4%BA%BA", status: http.StatusOK, }, { from: "Ё%2F%E4%BA%BA", - to: "tag/%d0%81/%e4%ba%ba", + to: "tag/%D0%81/%E4%BA%BA", status: http.StatusOK, }, } diff --git a/models/action.go b/models/action.go index 7c970e1fdb..80ac3e16f8 100644 --- a/models/action.go +++ b/models/action.go @@ -7,6 +7,7 @@ package models import ( "fmt" + "net/url" "path" "strconv" "strings" @@ -185,10 +186,8 @@ func (a *Action) ShortRepoPath() string { // GetRepoLink returns relative link to action repository. func (a *Action) GetRepoLink() string { - if len(setting.AppSubURL) > 0 { - return path.Join(setting.AppSubURL, a.GetRepoPath()) - } - return "/" + a.GetRepoPath() + // path.Join will skip empty strings + return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName())) } // GetRepositoryFromMatch returns a *Repository from a username and repo strings diff --git a/models/attachment.go b/models/attachment.go index ed82aaf483..34edc676cf 100644 --- a/models/attachment.go +++ b/models/attachment.go @@ -7,6 +7,7 @@ package models import ( "context" "fmt" + "net/url" "path" "code.gitea.io/gitea/models/db" @@ -59,7 +60,7 @@ func (a *Attachment) RelativePath() string { // DownloadURL returns the download url of the attached file func (a *Attachment) DownloadURL() string { - return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) + return setting.AppURL + "attachments/" + url.PathEscape(a.UUID) } // LinkedRepository returns the linked repo if any diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index 0a1445d2f2..da63dfd106 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -112,15 +112,15 @@ func GenerateUserAvatarFastLink(userName string, size int) string { if size < 0 { size = 0 } - return setting.AppSubURL + "/user/avatar/" + userName + "/" + strconv.Itoa(size) + return setting.AppSubURL + "/user/avatar/" + url.PathEscape(userName) + "/" + strconv.Itoa(size) } // GenerateUserAvatarImageLink returns a link for `User.Avatar` image file: "/avatars/${User.Avatar}" func GenerateUserAvatarImageLink(userAvatar string, size int) string { if size > 0 { - return setting.AppSubURL + "/avatars/" + userAvatar + "?size=" + strconv.Itoa(size) + return setting.AppSubURL + "/avatars/" + url.PathEscape(userAvatar) + "?size=" + strconv.Itoa(size) } - return setting.AppSubURL + "/avatars/" + userAvatar + return setting.AppSubURL + "/avatars/" + url.PathEscape(userAvatar) } // generateRecognizedAvatarURL generate a recognized avatar (Gravatar/Libravatar) URL, it modifies the URL so the parameter is passed by a copy @@ -155,7 +155,7 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return generateRecognizedAvatarURL(*avatarURL, size) } // for non-final link, we should return fast (use a 302 redirection link) - urlStr := setting.AppSubURL + "/avatar/" + emailHash + urlStr := setting.AppSubURL + "/avatar/" + url.PathEscape(emailHash) if size > 0 { urlStr += "?size=" + strconv.Itoa(size) } diff --git a/models/commit_status.go b/models/commit_status.go index a6ded049c3..df34b93ec5 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -7,6 +7,7 @@ package models import ( "crypto/sha1" "fmt" + "net/url" "strings" "time" @@ -137,8 +138,7 @@ func (status *CommitStatus) loadAttributes(e db.Engine) (err error) { // APIURL returns the absolute APIURL to this commit-status. func (status *CommitStatus) APIURL() string { _ = status.loadAttributes(db.GetEngine(db.DefaultContext)) - return fmt.Sprintf("%sapi/v1/repos/%s/statuses/%s", - setting.AppURL, status.Repo.FullName(), status.SHA) + return status.Repo.APIURL() + "/statuses/" + url.PathEscape(status.SHA) } // CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc diff --git a/models/issue.go b/models/issue.go index 0d34bdcaf3..983fb7aa8d 100644 --- a/models/issue.go +++ b/models/issue.go @@ -372,6 +372,17 @@ func (issue *Issue) HTMLURL() string { return fmt.Sprintf("%s/%s/%d", issue.Repo.HTMLURL(), path, issue.Index) } +// Link returns the Link URL to this issue. +func (issue *Issue) Link() string { + var path string + if issue.IsPull { + path = "pulls" + } else { + path = "issues" + } + return fmt.Sprintf("%s/%s/%d", issue.Repo.Link(), path, issue.Index) +} + // DiffURL returns the absolute URL to this diff func (issue *Issue) DiffURL() string { if issue.IsPull { diff --git a/models/notification.go b/models/notification.go index 48249ae84c..1e18073618 100644 --- a/models/notification.go +++ b/models/notification.go @@ -6,6 +6,7 @@ package models import ( "fmt" + "net/url" "strconv" "code.gitea.io/gitea/models/db" @@ -475,7 +476,7 @@ func (n *Notification) HTMLURL() string { } return n.Issue.HTMLURL() case NotificationSourceCommit: - return n.Repository.HTMLURL() + "/commit/" + n.CommitID + return n.Repository.HTMLURL() + "/commit/" + url.PathEscape(n.CommitID) case NotificationSourceRepository: return n.Repository.HTMLURL() } diff --git a/models/release.go b/models/release.go index 4624791b8f..f7bd67b8ca 100644 --- a/models/release.go +++ b/models/release.go @@ -10,10 +10,10 @@ import ( "errors" "fmt" "sort" + "strconv" "strings" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -78,23 +78,22 @@ func (r *Release) LoadAttributes() error { // APIURL the api url for a release. release must have attributes loaded func (r *Release) APIURL() string { - return fmt.Sprintf("%sapi/v1/repos/%s/releases/%d", - setting.AppURL, r.Repo.FullName(), r.ID) + return r.Repo.APIURL() + "/releases/" + strconv.FormatInt(r.ID, 10) } // ZipURL the zip url for a release. release must have attributes loaded func (r *Release) ZipURL() string { - return fmt.Sprintf("%s/archive/%s.zip", r.Repo.HTMLURL(), r.TagName) + return r.Repo.HTMLURL() + "/archive/" + util.PathEscapeSegments(r.TagName) + ".zip" } // TarURL the tar.gz url for a release. release must have attributes loaded func (r *Release) TarURL() string { - return fmt.Sprintf("%s/archive/%s.tar.gz", r.Repo.HTMLURL(), r.TagName) + return r.Repo.HTMLURL() + "/archive/" + util.PathEscapeSegments(r.TagName) + ".tar.gz" } // HTMLURL the url for a release on the web UI. release must have attributes loaded func (r *Release) HTMLURL() string { - return fmt.Sprintf("%s/releases/tag/%s", r.Repo.HTMLURL(), r.TagName) + return r.Repo.HTMLURL() + "/releases/tag/" + util.PathEscapeSegments(r.TagName) } // IsReleaseExist returns true if release with given tag name already exists. diff --git a/models/repo.go b/models/repo.go index f44fc763a5..16396e181d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -314,7 +314,7 @@ func (repo *Repository) FullName() string { // HTMLURL returns the repository HTML URL func (repo *Repository) HTMLURL() string { - return setting.AppURL + repo.FullName() + return setting.AppURL + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) } // CommitLink make link to by commit full ID @@ -323,14 +323,14 @@ func (repo *Repository) CommitLink(commitID string) (result string) { if commitID == "" || commitID == "0000000000000000000000000000000000000000" { result = "" } else { - result = repo.HTMLURL() + "/commit/" + commitID + result = repo.HTMLURL() + "/commit/" + url.PathEscape(commitID) } return } // APIURL returns the repository API URL func (repo *Repository) APIURL() string { - return setting.AppURL + "api/v1/repos/" + repo.FullName() + return setting.AppURL + "api/v1/repos/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) } // GetCommitsCountCacheKey returns cache key used for commits count caching. @@ -709,19 +709,14 @@ func (repo *Repository) GitConfigPath() string { return GitConfigPath(repo.RepoPath()) } -// RelLink returns the repository relative link -func (repo *Repository) RelLink() string { - return "/" + repo.FullName() -} - // Link returns the repository link func (repo *Repository) Link() string { - return setting.AppSubURL + "/" + repo.FullName() + return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) } // ComposeCompareURL returns the repository comparison URL func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) string { - return fmt.Sprintf("%s/compare/%s...%s", repo.FullName(), oldCommitID, newCommitID) + return fmt.Sprintf("%s/%s/compare/%s...%s", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), util.PathEscapeSegments(oldCommitID), util.PathEscapeSegments(newCommitID)) } // UpdateDefaultBranch updates the default branch @@ -930,11 +925,11 @@ func (repo *Repository) cloneLink(isWiki bool) *CloneLink { } if setting.SSH.Port != 22 { - cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), repo.OwnerName, repoName) + cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, net.JoinHostPort(setting.SSH.Domain, strconv.Itoa(setting.SSH.Port)), url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) } else if setting.Repository.UseCompatSSHURI { - cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, repo.OwnerName, repoName) + cl.SSH = fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) } else { - cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, repo.OwnerName, repoName) + cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshDomain, url.PathEscape(repo.OwnerName), url.PathEscape(repoName)) } cl.HTTPS = ComposeHTTPSCloneURL(repo.OwnerName, repoName) return cl diff --git a/models/repo_avatar.go b/models/repo_avatar.go index 6c5e03c0d0..aa1b3bc15f 100644 --- a/models/repo_avatar.go +++ b/models/repo_avatar.go @@ -10,6 +10,7 @@ import ( "fmt" "image/png" "io" + "net/url" "strconv" "strings" @@ -96,7 +97,7 @@ func (repo *Repository) relAvatarLink(e db.Engine) string { return "" } } - return setting.AppSubURL + "/repo-avatars/" + repo.Avatar + return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar) } // AvatarLink returns a link to the repository's avatar. diff --git a/models/user.go b/models/user.go index 12035dbe42..8146c184e7 100644 --- a/models/user.go +++ b/models/user.go @@ -13,6 +13,7 @@ import ( "errors" "fmt" _ "image/jpeg" // Needed for jpeg support + "net/url" "os" "path/filepath" "regexp" @@ -315,17 +316,17 @@ func (u *User) DashboardLink() string { // HomeLink returns the user or organization home page link. func (u *User) HomeLink() string { - return setting.AppSubURL + "/" + u.Name + return setting.AppSubURL + "/" + url.PathEscape(u.Name) } // HTMLURL returns the user or organization's full link. func (u *User) HTMLURL() string { - return setting.AppURL + u.Name + return setting.AppURL + url.PathEscape(u.Name) } // OrganisationLink returns the organization sub page link. func (u *User) OrganisationLink() string { - return setting.AppSubURL + "/org/" + u.Name + return setting.AppSubURL + "/org/" + url.PathEscape(u.Name) } // GenerateEmailActivateCode generates an activate code based on user information and given e-mail. diff --git a/modules/context/context.go b/modules/context/context.go index cb7131907e..8adf1f306b 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -70,6 +70,16 @@ type Context struct { Org *Organization } +// TrHTMLEscapeArgs runs Tr but pre-escapes all arguments with html.EscapeString. +// This is useful if the locale message is intended to only produce HTML content. +func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string { + trArgs := make([]interface{}, len(args)) + for i, arg := range args { + trArgs[i] = html.EscapeString(arg) + } + return ctx.Tr(msg, trArgs...) +} + // GetData returns the data func (ctx *Context) GetData() map[string]interface{} { return ctx.Data @@ -120,9 +130,9 @@ func RedirectToUser(ctx *Context, userName string, redirectUserID int64) { } redirectPath := strings.Replace( - ctx.Req.URL.Path, - userName, - user.Name, + ctx.Req.URL.EscapedPath(), + url.PathEscape(userName), + url.PathEscape(user.Name), 1, ) if ctx.Req.URL.RawQuery != "" { diff --git a/modules/context/repo.go b/modules/context/repo.go index d5763c78a3..3be33f2483 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -41,10 +41,10 @@ var IssueTemplateDirCandidates = []string{ // PullRequest contains information to make a pull request type PullRequest struct { - BaseRepo *models.Repository - Allowed bool - SameRepo bool - HeadInfo string // [<user>:]<branch> + BaseRepo *models.Repository + Allowed bool + SameRepo bool + HeadInfoSubURL string // [<user>:]<branch> url segment } // Repository contains information to operate a repository @@ -189,11 +189,11 @@ func (r *Repository) GetCommitGraphsCount(hidePRRefs bool, branches []string, fi func (r *Repository) BranchNameSubURL() string { switch { case r.IsViewBranch: - return "branch/" + r.BranchName + return "branch/" + util.PathEscapeSegments(r.BranchName) case r.IsViewTag: - return "tag/" + r.BranchName + return "tag/" + util.PathEscapeSegments(r.BranchName) case r.IsViewCommit: - return "commit/" + r.BranchName + return "commit/" + util.PathEscapeSegments(r.BranchName) } log.Error("Unknown view type for repo: %v", r) return "" @@ -321,9 +321,9 @@ func RedirectToRepo(ctx *Context, redirectRepoID int64) { } redirectPath := strings.Replace( - ctx.Req.URL.Path, - fmt.Sprintf("%s/%s", ownerName, previousRepoName), - repo.FullName(), + ctx.Req.URL.EscapedPath(), + url.PathEscape(ownerName)+"/"+url.PathEscape(previousRepoName), + url.PathEscape(repo.OwnerName)+"/"+url.PathEscape(repo.Name), 1, ) if ctx.Req.URL.RawQuery != "" { @@ -588,7 +588,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["BaseRepo"] = repo.BaseRepo ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo ctx.Repo.PullRequest.Allowed = canPush - ctx.Repo.PullRequest.HeadInfo = ctx.Repo.Owner.Name + ":" + ctx.Repo.BranchName + ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.Repo.Owner.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName) } else if repo.AllowsPulls() { // Or, this is repository accepts pull requests between branches. canCompare = true @@ -596,7 +596,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Repo.PullRequest.BaseRepo = repo ctx.Repo.PullRequest.Allowed = canPush ctx.Repo.PullRequest.SameRepo = true - ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName + ctx.Repo.PullRequest.HeadInfoSubURL = util.PathEscapeSegments(ctx.Repo.BranchName) } ctx.Data["CanCompareOrPull"] = canCompare ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest @@ -621,7 +621,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { if ctx.FormString("go-get") == "1" { ctx.Data["GoGetImport"] = ComposeGoGetImport(owner.Name, repo.Name) - prefix := setting.AppURL + path.Join(owner.Name, repo.Name, "src", "branch", ctx.Repo.BranchName) + prefix := repo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName) ctx.Data["GoDocDirectory"] = prefix + "{/dir}" ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}" } @@ -810,7 +810,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context if isRenamedBranch && has { renamedBranchName := ctx.Data["RenamedBranchName"].(string) ctx.Flash.Info(ctx.Tr("repo.branch.renamed", refName, renamedBranchName)) - link := strings.Replace(ctx.Req.RequestURI, refName, renamedBranchName, 1) + link := setting.AppSubURL + strings.Replace(ctx.Req.URL.EscapedPath(), util.PathEscapeSegments(refName), util.PathEscapeSegments(renamedBranchName), 1) ctx.Redirect(link) return } @@ -845,7 +845,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context // If short commit ID add canonical link header if len(refName) < 40 { ctx.Header().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"", - util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), refName, ctx.Repo.Commit.ID.String(), 1)))) + util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1)))) } } else { if len(ignoreNotExistErr) > 0 && ignoreNotExistErr[0] { @@ -857,11 +857,13 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context if refType == RepoRefLegacy { // redirect from old URL scheme to new URL scheme + prefix := strings.TrimPrefix(setting.AppSubURL+strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")), ctx.Repo.RepoLink) + ctx.Redirect(path.Join( - setting.AppSubURL, - strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")), + ctx.Repo.RepoLink, + util.PathEscapeSegments(prefix), ctx.Repo.BranchNameSubURL(), - ctx.Repo.TreePath)) + util.PathEscapeSegments(ctx.Repo.TreePath))) return } } diff --git a/modules/convert/git_commit.go b/modules/convert/git_commit.go index 9f43bb82f8..9905b51fe4 100644 --- a/modules/convert/git_commit.go +++ b/modules/convert/git_commit.go @@ -5,6 +5,7 @@ package convert import ( + "net/url" "time" "code.gitea.io/gitea/models" @@ -126,7 +127,7 @@ func ToCommit(repo *models.Repository, commit *git.Commit, userCache map[string] for i := 0; i < commit.ParentCount(); i++ { sha, _ := commit.ParentID(i) apiParents[i] = &api.CommitMeta{ - URL: repo.APIURL() + "/git/commits/" + sha.String(), + URL: repo.APIURL() + "/git/commits/" + url.PathEscape(sha.String()), SHA: sha.String(), } } @@ -147,13 +148,13 @@ func ToCommit(repo *models.Repository, commit *git.Commit, userCache map[string] return &api.Commit{ CommitMeta: &api.CommitMeta{ - URL: repo.APIURL() + "/git/commits/" + commit.ID.String(), + URL: repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()), SHA: commit.ID.String(), Created: commit.Committer.When, }, - HTMLURL: repo.HTMLURL() + "/commit/" + commit.ID.String(), + HTMLURL: repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()), RepoCommit: &api.RepoCommit{ - URL: repo.APIURL() + "/git/commits/" + commit.ID.String(), + URL: repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()), Author: &api.CommitUser{ Identity: api.Identity{ Name: commit.Author.Name, @@ -170,7 +171,7 @@ func ToCommit(repo *models.Repository, commit *git.Commit, userCache map[string] }, Message: commit.Message(), Tree: &api.CommitMeta{ - URL: repo.APIURL() + "/git/trees/" + commit.ID.String(), + URL: repo.APIURL() + "/git/trees/" + url.PathEscape(commit.ID.String()), SHA: commit.ID.String(), Created: commit.Committer.When, }, diff --git a/modules/convert/issue.go b/modules/convert/issue.go index 3974d460e0..7363cfb8fb 100644 --- a/modules/convert/issue.go +++ b/modules/convert/issue.go @@ -6,6 +6,7 @@ package convert import ( "fmt" + "net/url" "strings" "code.gitea.io/gitea/models" @@ -191,7 +192,7 @@ func ToLabel(label *models.Label, repo *models.Repository, org *models.User) *ap } } else { // BelongsToOrg if org != nil { - result.URL = fmt.Sprintf("%sapi/v1/orgs/%s/labels/%d", setting.AppURL, org.Name, label.ID) + result.URL = fmt.Sprintf("%sapi/v1/orgs/%s/labels/%d", setting.AppURL, url.PathEscape(org.Name), label.ID) } else { log.Error("ToLabel did not get org to calculate url for label with id '%d'", label.ID) } diff --git a/modules/convert/notification.go b/modules/convert/notification.go index fae7be1257..5f4fef02b9 100644 --- a/modules/convert/notification.go +++ b/modules/convert/notification.go @@ -5,6 +5,8 @@ package convert import ( + "net/url" + "code.gitea.io/gitea/models" api "code.gitea.io/gitea/modules/structs" ) @@ -58,7 +60,7 @@ func ToNotificationThread(n *models.Notification) *api.NotificationThread { } } case models.NotificationSourceCommit: - url := n.Repository.HTMLURL() + "/commit/" + n.CommitID + url := n.Repository.HTMLURL() + "/commit/" + url.PathEscape(n.CommitID) result.Subject = &api.NotificationSubject{ Type: api.NotifySubjectCommit, Title: n.CommitID, diff --git a/modules/git/utils.go b/modules/git/utils.go index 13926fba72..6988f31a36 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -11,6 +11,8 @@ import ( "strconv" "strings" "sync" + + "code.gitea.io/gitea/modules/util" ) // ObjectCache provides thread-safe cache operations. @@ -92,7 +94,7 @@ func RefEndName(refStr string) string { // RefURL returns the absolute URL for a ref in a repository func RefURL(repoURL, ref string) string { - refName := RefEndName(ref) + refName := util.PathEscapeSegments(RefEndName(ref)) switch { case strings.HasPrefix(ref, BranchPrefix): return repoURL + "/src/branch/" + refName diff --git a/modules/repofiles/action.go b/modules/repofiles/action.go index d7e3ff4525..0bcdb8c3a1 100644 --- a/modules/repofiles/action.go +++ b/modules/repofiles/action.go @@ -7,6 +7,7 @@ package repofiles import ( "fmt" "html" + "net/url" "regexp" "strconv" "strings" @@ -175,7 +176,7 @@ func UpdateIssuesCommit(doer *models.User, repo *models.Repository, commits []*r continue } - message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, html.EscapeString(strings.SplitN(c.Message, "\n", 2)[0])) + message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, html.EscapeString(repo.Link()), html.EscapeString(url.PathEscape(c.Sha1)), html.EscapeString(strings.SplitN(c.Message, "\n", 2)[0])) if err = models.CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil { return err } diff --git a/modules/repofiles/blob.go b/modules/repofiles/blob.go index 60a05e280e..02bc1ebcab 100644 --- a/modules/repofiles/blob.go +++ b/modules/repofiles/blob.go @@ -5,6 +5,8 @@ package repofiles import ( + "net/url" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" @@ -31,7 +33,7 @@ func GetBlobBySHA(repo *models.Repository, sha string) (*api.GitBlobResponse, er } return &api.GitBlobResponse{ SHA: gitBlob.ID.String(), - URL: repo.APIURL() + "/git/blobs/" + gitBlob.ID.String(), + URL: repo.APIURL() + "/git/blobs/" + url.PathEscape(gitBlob.ID.String()), Size: gitBlob.Size(), Encoding: "base64", Content: content, diff --git a/modules/repofiles/file.go b/modules/repofiles/file.go index abd14b1db8..4030924017 100644 --- a/modules/repofiles/file.go +++ b/modules/repofiles/file.go @@ -36,19 +36,19 @@ func GetFileCommitResponse(repo *models.Repository, commit *git.Commit) (*api.Fi if commit == nil { return nil, fmt.Errorf("commit cannot be nil") } - commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + commit.ID.String()) - commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + commit.Tree.ID.String()) + commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String())) + commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.Tree.ID.String())) parents := make([]*api.CommitMeta, commit.ParentCount()) for i := 0; i <= commit.ParentCount(); i++ { if parent, err := commit.Parent(i); err == nil && parent != nil { - parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + parent.ID.String()) + parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(parent.ID.String())) parents[i] = &api.CommitMeta{ SHA: parent.ID.String(), URL: parentCommitURL.String(), } } } - commitHTMLURL, _ := url.Parse(repo.HTMLURL() + "/commit/" + commit.ID.String()) + commitHTMLURL, _ := url.Parse(repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String())) fileCommit := &api.FileCommitResponse{ CommitMeta: api.CommitMeta{ SHA: commit.ID.String(), diff --git a/modules/repofiles/tree.go b/modules/repofiles/tree.go index b3edea341f..81579dccc5 100644 --- a/modules/repofiles/tree.go +++ b/modules/repofiles/tree.go @@ -6,6 +6,7 @@ package repofiles import ( "fmt" + "net/url" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" @@ -28,7 +29,7 @@ func GetTreeBySHA(repo *models.Repository, sha string, page, perPage int, recurs } tree := new(api.GitTreeResponse) tree.SHA = gitTree.ResolvedID.String() - tree.URL = repo.APIURL() + "/git/trees/" + tree.SHA + tree.URL = repo.APIURL() + "/git/trees/" + url.PathEscape(tree.SHA) var entries git.Entries if recursive { entries, err = gitTree.ListEntriesRecursive() diff --git a/modules/repository/commits.go b/modules/repository/commits.go index c86f0d570b..a545ce952b 100644 --- a/modules/repository/commits.go +++ b/modules/repository/commits.go @@ -6,6 +6,7 @@ package repository import ( "fmt" + "net/url" "time" "code.gitea.io/gitea/models" @@ -81,7 +82,7 @@ func (pc *PushCommits) toAPIPayloadCommit(repoPath, repoLink string, commit *Pus return &api.PayloadCommit{ ID: commit.Sha1, Message: commit.Message, - URL: fmt.Sprintf("%s/commit/%s", repoLink, commit.Sha1), + URL: fmt.Sprintf("%s/commit/%s", repoLink, url.PathEscape(commit.Sha1)), Author: &api.PayloadUser{ Name: commit.AuthorName, Email: commit.AuthorEmail, diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 991816c103..8b46ed40ce 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -139,17 +139,14 @@ func NewFuncMap() []template.FuncMap { } return str[start:end] }, - "EllipsisString": base.EllipsisString, - "DiffTypeToStr": DiffTypeToStr, - "DiffLineTypeToStr": DiffLineTypeToStr, - "Sha1": Sha1, - "ShortSha": base.ShortSha, - "MD5": base.EncodeMD5, - "ActionContent2Commits": ActionContent2Commits, - "PathEscape": url.PathEscape, - "EscapePound": func(str string) string { - return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str) - }, + "EllipsisString": base.EllipsisString, + "DiffTypeToStr": DiffTypeToStr, + "DiffLineTypeToStr": DiffLineTypeToStr, + "Sha1": Sha1, + "ShortSha": base.ShortSha, + "MD5": base.EncodeMD5, + "ActionContent2Commits": ActionContent2Commits, + "PathEscape": url.PathEscape, "PathEscapeSegments": util.PathEscapeSegments, "URLJoin": util.URLJoin, "RenderCommitMessage": RenderCommitMessage, @@ -742,7 +739,7 @@ func ReactionToEmoji(reaction string) template.HTML { if val != nil { return template.HTML(val.Emoji) } - return template.HTML(fmt.Sprintf(`<img alt=":%s:" src="%s/assets/img/emoji/%s.png"></img>`, reaction, setting.StaticURLPrefix, reaction)) + return template.HTML(fmt.Sprintf(`<img alt=":%s:" src="%s/assets/img/emoji/%s.png"></img>`, reaction, setting.StaticURLPrefix, url.PathEscape(reaction))) } // RenderNote renders the contents of a git-notes file as a commit message. diff --git a/modules/upload/upload.go b/modules/upload/upload.go index e430a5d8b3..097facb4d5 100644 --- a/modules/upload/upload.go +++ b/modules/upload/upload.go @@ -6,6 +6,7 @@ package upload import ( "net/http" + "net/url" "path" "regexp" "strings" @@ -83,7 +84,7 @@ func AddUploadContext(ctx *context.Context, uploadType string) { ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments" ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove" if len(ctx.Params(":index")) > 0 { - ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + ctx.Params(":index") + "/attachments" + ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.Params(":index")) + "/attachments" } else { ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/attachments" } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index af68876408..c39063e46e 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1409,7 +1409,7 @@ pulls.filter_branch = Filter branch pulls.no_results = No results found. pulls.nothing_to_compare = These branches are equal. There is no need to create a pull request. pulls.nothing_to_compare_and_allow_empty_pr = These branches are equal. This PR will be empty. -pulls.has_pull_request = `A pull request between these branches already exists: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>` +pulls.has_pull_request = `A pull request between these branches already exists: <a href="%[1]s">%[2]s#%[3]d</a>` pulls.create = Create Pull Request pulls.title_desc = wants to merge %[1]d commits from <code>%[2]s</code> into <code id="branch_target">%[3]s</code> pulls.merged_title_desc = merged %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code> %[4]s @@ -2761,32 +2761,32 @@ notices.delete_success = The system notices have been deleted. [action] create_repo = created repository <a href="%s">%s</a> rename_repo = renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a> -commit_repo = pushed to <a href="%[1]s/src/branch/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a> -create_issue = `opened issue <a href="%s/issues/%s">%s#%[2]s</a>` -close_issue = `closed issue <a href="%s/issues/%s">%s#%[2]s</a>` -reopen_issue = `reopened issue <a href="%s/issues/%s">%s#%[2]s</a>` -create_pull_request = `created pull request <a href="%s/pulls/%s">%s#%[2]s</a>` -close_pull_request = `closed pull request <a href="%s/pulls/%s">%s#%[2]s</a>` -reopen_pull_request = `reopened pull request <a href="%s/pulls/%s">%s#%[2]s</a>` -comment_issue = `commented on issue <a href="%s/issues/%s">%s#%[2]s</a>` -comment_pull = `commented on pull request <a href="%s/pulls/%s">%s#%[2]s</a>` -merge_pull_request = `merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>` +commit_repo = pushed to <a href="%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a> +create_issue = `opened issue <a href="%[1]s">%[3]s#%[2]s</a>` +close_issue = `closed issue <a href="%[1]s">%[3]s#%[2]s</a>` +reopen_issue = `reopened issue <a href="%[1]s">%[3]s#%[2]s</a>` +create_pull_request = `created pull request <a href="%[1]s">%[3]s#%[2]s</a>` +close_pull_request = `closed pull request <a href="%[1]s">%[3]s#%[2]s</a>` +reopen_pull_request = `reopened pull request <a href="%[1]s">%[3]s#%[2]s</a>` +comment_issue = `commented on issue <a href="%[1]s">%[3]s#%[2]s</a>` +comment_pull = `commented on pull request <a href="%[1]s">%[3]s#%[2]s</a>` +merge_pull_request = `merged pull request <a href="%[1]s">%[3]s#%[2]s</a>` transfer_repo = transferred repository <code>%s</code> to <a href="%s">%s</a> -push_tag = pushed tag <a href="%s/src/tag/%s">%[4]s</a> to <a href="%[1]s">%[3]s</a> +push_tag = pushed tag <a href="%[2]s">%[3]s</a> to <a href="%[1]s">%[4]s</a> delete_tag = deleted tag %[2]s from <a href="%[1]s">%[3]s</a> delete_branch = deleted branch %[2]s from <a href="%[1]s">%[3]s</a> compare_branch = Compare compare_commits = Compare %d commits compare_commits_general = Compare commits -mirror_sync_push = synced commits to <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a> from mirror -mirror_sync_create = synced new reference <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a> from mirror +mirror_sync_push = synced commits to <a href="%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a> from mirror +mirror_sync_create = synced new reference <a href="%[2]s">%[3]s</a> to <a href="%[1]s">%[4]s</a> from mirror mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror -approve_pull_request = `approved <a href="%s/pulls/%s">%s#%[2]s</a>` -reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>` -publish_release = `released <a href="%s/releases/tag/%s"> "%[4]s" </a> at <a href="%[1]s">%[3]s</a>` -review_dismissed = `dismissed review from <b>%[4]s</b> for <a href="%[1]s/pulls/%[2]s">%[3]s#%[2]s</a>` +approve_pull_request = `approved <a href="%[1]s">%[3]s#%[2]s</a>` +reject_pull_request = `suggested changes for <a href="%[1]s">%[3]s#%[2]s</a>` +publish_release = `released <a href="%[2]s"> "%[4]s" </a> at <a href="%[1]s">%[3]s</a>` +review_dismissed = `dismissed review from <b>%[4]s</b> for <a href="%[1]s">%[3]s#%[2]s</a>` review_dismissed_reason = Reason: -create_branch = created branch <a href="%[1]s/src/branch/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> +create_branch = created branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> starred_repo = starred <a href="%[1]s">%[2]s</a> watched_repo = started watching <a href="%[1]s">%[2]s</a> diff --git a/routers/api/v1/org/member.go b/routers/api/v1/org/member.go index a6f140c38f..4530349f2c 100644 --- a/routers/api/v1/org/member.go +++ b/routers/api/v1/org/member.go @@ -6,6 +6,7 @@ package org import ( "net/http" + "net/url" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" @@ -159,7 +160,7 @@ func IsMember(ctx *context.APIContext) { } } - redirectURL := setting.AppSubURL + "/api/v1/orgs/" + ctx.Org.Organization.Name + "/public_members/" + userToCheck.Name + redirectURL := setting.AppSubURL + "/api/v1/orgs/" + url.PathEscape(ctx.Org.Organization.Name) + "/public_members/" + url.PathEscape(userToCheck.Name) ctx.Redirect(redirectURL, 302) } diff --git a/routers/api/v1/repo/git_ref.go b/routers/api/v1/repo/git_ref.go index e304e06740..29b126db9a 100644 --- a/routers/api/v1/repo/git_ref.go +++ b/routers/api/v1/repo/git_ref.go @@ -6,9 +6,11 @@ package repo import ( "net/http" + "net/url" "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/v1/utils" ) @@ -89,11 +91,11 @@ func getGitRefsInternal(ctx *context.APIContext, filter string) { for i := range refs { apiRefs[i] = &api.Reference{ Ref: refs[i].Name, - URL: ctx.Repo.Repository.APIURL() + "/git/" + refs[i].Name, + URL: ctx.Repo.Repository.APIURL() + "/git/" + util.PathEscapeSegments(refs[i].Name), Object: &api.GitObject{ SHA: refs[i].Object.String(), Type: refs[i].Type, - URL: ctx.Repo.Repository.APIURL() + "/git/" + refs[i].Type + "s/" + refs[i].Object.String(), + URL: ctx.Repo.Repository.APIURL() + "/git/" + url.PathEscape(refs[i].Type) + "s/" + url.PathEscape(refs[i].Object.String()), }, } } diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index 98ee2b4de5..c20a4776cc 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -8,6 +8,7 @@ package repo import ( "fmt" "net/http" + "net/url" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" @@ -33,8 +34,8 @@ func appendPrivateInformation(apiKey *api.DeployKey, key *models.DeployKey, repo return apiKey, nil } -func composeDeployKeysAPILink(repoPath string) string { - return setting.AppURL + "api/v1/repos/" + repoPath + "/keys/" +func composeDeployKeysAPILink(owner, name string) string { + return setting.AppURL + "api/v1/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(name) + "/keys/" } // ListDeployKeys list all the deploy keys of a repository @@ -94,7 +95,7 @@ func ListDeployKeys(ctx *context.APIContext) { return } - apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name) + apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) apiKeys := make([]*api.DeployKey, len(keys)) for i := range keys { if err := keys[i].GetContent(); err != nil { @@ -154,7 +155,7 @@ func GetDeployKey(ctx *context.APIContext) { return } - apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name) + apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) apiKey := convert.ToDeployKey(apiLink, key) if ctx.User.IsAdmin || ((ctx.Repo.Repository.ID == key.RepoID) && (ctx.User.ID == ctx.Repo.Owner.ID)) { apiKey, _ = appendPrivateInformation(apiKey, key, ctx.Repo.Repository) @@ -233,7 +234,7 @@ func CreateDeployKey(ctx *context.APIContext) { } key.Content = content - apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name) + apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) ctx.JSON(http.StatusCreated, convert.ToDeployKey(apiLink, key)) } 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 }) diff --git a/services/lfs/server.go b/services/lfs/server.go index 5ce2a5498a..7887658816 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -12,6 +12,7 @@ import ( "fmt" "io" "net/http" + "net/url" "path" "regexp" "strconv" @@ -46,17 +47,17 @@ type Claims struct { // DownloadLink builds a URL to download the object. func (rc *requestContext) DownloadLink(p lfs_module.Pointer) string { - return setting.AppURL + path.Join(rc.User, rc.Repo+".git", "info/lfs/objects", p.Oid) + return setting.AppURL + path.Join(url.PathEscape(rc.User), url.PathEscape(rc.Repo+".git"), "info/lfs/objects", url.PathEscape(p.Oid)) } // UploadLink builds a URL to upload the object. func (rc *requestContext) UploadLink(p lfs_module.Pointer) string { - return setting.AppURL + path.Join(rc.User, rc.Repo+".git", "info/lfs/objects", p.Oid, strconv.FormatInt(p.Size, 10)) + return setting.AppURL + path.Join(url.PathEscape(rc.User), url.PathEscape(rc.Repo+".git"), "info/lfs/objects", url.PathEscape(p.Oid), strconv.FormatInt(p.Size, 10)) } // VerifyLink builds a URL for verifying the object. func (rc *requestContext) VerifyLink(p lfs_module.Pointer) string { - return setting.AppURL + path.Join(rc.User, rc.Repo+".git", "info/lfs/verify") + return setting.AppURL + path.Join(url.PathEscape(rc.User), url.PathEscape(rc.Repo+".git"), "info/lfs/verify") } // CheckAcceptMediaType checks if the client accepts the LFS media type. diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index 88e4078922..a949b073a5 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" dingtalk "github.com/lunny/dingtalk_webhook" ) @@ -41,7 +42,7 @@ func (d *DingtalkPayload) Create(p *api.CreatePayload) (api.Payloader, error) { refName := git.RefEndName(p.Ref) title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) - return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+refName), nil + return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName)), nil } // Delete implements PayloadConvertor Delete method @@ -50,7 +51,7 @@ func (d *DingtalkPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { refName := git.RefEndName(p.Ref) title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) - return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+refName), nil + return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName)), nil } // Fork implements PayloadConvertor Fork method @@ -78,7 +79,7 @@ func (d *DingtalkPayload) Push(p *api.PushPayload) (api.Payloader, error) { linkText = fmt.Sprintf("view commit %s...%s", p.Commits[0].ID[:7], p.Commits[len(p.Commits)-1].ID[:7]) } if titleLink == "" { - titleLink = p.Repo.HTMLURL + "/src/" + branchName + titleLink = p.Repo.HTMLURL + "/src/" + util.PathEscapeSegments(branchName) } title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 3de50a8a2f..587d2098eb 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) type ( @@ -115,7 +116,7 @@ func (d *DiscordPayload) Create(p *api.CreatePayload) (api.Payloader, error) { refName := git.RefEndName(p.Ref) title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) - return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+refName, greenColor), nil + return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), greenColor), nil } // Delete implements PayloadConvertor Delete method @@ -124,7 +125,7 @@ func (d *DiscordPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { refName := git.RefEndName(p.Ref) title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) - return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+refName, redColor), nil + return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), redColor), nil } // Fork implements PayloadConvertor Fork method @@ -150,7 +151,7 @@ func (d *DiscordPayload) Push(p *api.PushPayload) (api.Payloader, error) { titleLink = p.CompareURL } if titleLink == "" { - titleLink = p.Repo.HTMLURL + "/src/" + branchName + titleLink = p.Repo.HTMLURL + "/src/" + util.PathEscapeSegments(branchName) } title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) diff --git a/services/webhook/general.go b/services/webhook/general.go index 777ae086b5..32a79c0783 100644 --- a/services/webhook/general.go +++ b/services/webhook/general.go @@ -7,10 +7,12 @@ package webhook import ( "fmt" "html" + "net/url" "strings" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) type linkFormatter = func(string, string) string @@ -22,7 +24,7 @@ func noneLinkFormatter(url string, text string) string { // htmlLinkFormatter creates a HTML link func htmlLinkFormatter(url string, text string) string { - return fmt.Sprintf(`<a href="%s">%s</a>`, url, html.EscapeString(text)) + return fmt.Sprintf(`<a href="%s">%s</a>`, html.EscapeString(url), html.EscapeString(text)) } func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter, withSender bool) (string, string, string, int) { @@ -46,7 +48,7 @@ func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter, with case api.HookIssueAssigned: list := make([]string, len(p.Issue.Assignees)) for i, user := range p.Issue.Assignees { - list[i] = linkFormatter(setting.AppURL+user.UserName, user.UserName) + list[i] = linkFormatter(setting.AppURL+url.PathEscape(user.UserName), user.UserName) } text = fmt.Sprintf("[%s] Issue assigned to %s: %s", repoLink, strings.Join(list, ", "), titleLink) color = greenColor @@ -66,7 +68,7 @@ func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter, with text = fmt.Sprintf("[%s] Issue milestone cleared: %s", repoLink, titleLink) } if withSender { - text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)) + text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName)) } var attachmentText string @@ -139,7 +141,7 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm func getReleasePayloadInfo(p *api.ReleasePayload, linkFormatter linkFormatter, withSender bool) (text string, color int) { repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) - refLink := linkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName) + refLink := linkFormatter(p.Repository.HTMLURL+"/src/"+util.PathEscapeSegments(p.Release.TagName), p.Release.TagName) switch p.Action { case api.HookReleasePublished: @@ -153,7 +155,7 @@ func getReleasePayloadInfo(p *api.ReleasePayload, linkFormatter linkFormatter, w color = redColor } if withSender { - text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)) + text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName)) } return text, color @@ -189,7 +191,7 @@ func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFo color = redColor } if withSender { - text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)) + text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName)) } return text, issueTitle, color diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index 08adaef6fd..4fd78ff5bb 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -10,6 +10,7 @@ import ( "fmt" "html" "net/http" + "net/url" "regexp" "strings" @@ -19,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) const matrixPayloadSizeLimit = 1024 * 64 @@ -94,11 +96,11 @@ func MatrixLinkToRef(repoURL, ref string) string { refName := git.RefEndName(ref) switch { case strings.HasPrefix(ref, git.BranchPrefix): - return MatrixLinkFormatter(repoURL+"/src/branch/"+refName, refName) + return MatrixLinkFormatter(repoURL+"/src/branch/"+util.PathEscapeSegments(refName), refName) case strings.HasPrefix(ref, git.TagPrefix): - return MatrixLinkFormatter(repoURL+"/src/tag/"+refName, refName) + return MatrixLinkFormatter(repoURL+"/src/tag/"+util.PathEscapeSegments(refName), refName) default: - return MatrixLinkFormatter(repoURL+"/src/commit/"+refName, refName) + return MatrixLinkFormatter(repoURL+"/src/commit/"+util.PathEscapeSegments(refName), refName) } } @@ -186,7 +188,7 @@ func (m *MatrixPayloadUnsafe) PullRequest(p *api.PullRequestPayload) (api.Payloa // Review implements PayloadConvertor Review method func (m *MatrixPayloadUnsafe) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { - senderLink := MatrixLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName) + senderLink := MatrixLinkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName) title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) titleLink := fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index) repoLink := MatrixLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName) @@ -281,7 +283,7 @@ func getMatrixHookRequest(w *webhook_model.Webhook, t *webhook_model.HookTask) ( return nil, fmt.Errorf("getMatrixHookRequest: unable to hash payload: %+v", err) } - url := fmt.Sprintf("%s/%s", w.URL, txnID) + url := fmt.Sprintf("%s/%s", w.URL, url.PathEscape(txnID)) req, err := http.NewRequest(w.HTTPMethod, url, strings.NewReader(string(payload))) if err != nil { diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 2b88bb23ff..ae5af8d9b6 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) type ( @@ -79,7 +80,7 @@ func (m *MSTeamsPayload) Create(p *api.CreatePayload) (api.Payloader, error) { p.Sender, title, "", - p.Repo.HTMLURL+"/src/"+refName, + p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), greenColor, &MSTeamsFact{fmt.Sprintf("%s:", p.RefType), refName}, ), nil @@ -96,7 +97,7 @@ func (m *MSTeamsPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { p.Sender, title, "", - p.Repo.HTMLURL+"/src/"+refName, + p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), yellowColor, &MSTeamsFact{fmt.Sprintf("%s:", p.RefType), refName}, ), nil @@ -133,7 +134,7 @@ func (m *MSTeamsPayload) Push(p *api.PushPayload) (api.Payloader, error) { titleLink = p.CompareURL } if titleLink == "" { - titleLink = p.Repo.HTMLURL + "/src/" + branchName + titleLink = p.Repo.HTMLURL + "/src/" + util.PathEscapeSegments(branchName) } title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 944099de1f..9d57ac432f 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -36,7 +36,7 @@ func nameAllowed(name string) error { // NameToSubURL converts a wiki name to its corresponding sub-URL. func NameToSubURL(name string) string { - return url.QueryEscape(strings.ReplaceAll(name, " ", "-")) + return url.PathEscape(strings.ReplaceAll(name, " ", "-")) } // NormalizeWikiName normalizes a wiki name diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index 2d489a495d..e73213c1df 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -49,7 +49,7 @@ <tbody> {{range .Emails}} <tr> - <td><a href="{{AppSubUrl}}/{{.Name}}">{{.Name}}</a></td> + <td><a href="{{AppSubUrl}}/{{.Name | PathEscape}}">{{.Name}}</a></td> <td><span class="text truncate">{{.FullName}}</span></td> <td><span class="text email">{{.Email}}</span></td> <td>{{if .IsPrimary}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index e96d9ebb33..4059cb5deb 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -45,13 +45,13 @@ <tr> <td>{{.ID}}</td> <td> - <a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a> + <a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> {{if .Owner.Visibility.IsPrivate}} <span class="text gold">{{svg "octicon-lock"}}</span> {{end}} </td> <td> - <a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a> + <a href="{{.Link}}">{{.Name}}</a> {{if .IsArchived}} <span class="ui basic mini label">{{$.i18n.Tr "repo.desc.archived"}}</span> {{end}} diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl index ceab7a9b1b..93e6f38c27 100644 --- a/templates/admin/user/list.tmpl +++ b/templates/admin/user/list.tmpl @@ -87,7 +87,7 @@ {{range .Users}} <tr> <td>{{.ID}}</td> - <td><a href="{{AppSubUrl}}/{{.Name}}">{{.Name}}</a></td> + <td><a href="{{.HomeLink}}">{{.Name}}</a></td> <td><span class="text truncate email">{{.Email}}</span></td> <td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> <td>{{if .IsAdmin}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index bf1fcd24bc..d529e6bfda 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -102,10 +102,10 @@ <meta property="og:site_name" content="{{AppName}}" /> {{if .IsSigned }} {{ if ne .SignedUser.Theme "gitea" }} - <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{.SignedUser.Theme}}.css?v={{MD5 AppVer}}"> + <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{.SignedUser.Theme | PathEscape}}.css?v={{MD5 AppVer}}"> {{end}} {{else if ne DefaultTheme "gitea"}} - <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{DefaultTheme}}.css?v={{MD5 AppVer}}"> + <link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{DefaultTheme | PathEscape}}.css?v={{MD5 AppVer}}"> {{end}} {{template "custom/header" .}} </head> diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 348e7671a5..57ddbf732a 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -63,8 +63,7 @@ </div> {{else if .IsSigned}} <div class="right stackable menu"> - {{$issueURL := Printf "%s/%s/issues/%d" AppSubUrl .ActiveStopwatch.RepoSlug .ActiveStopwatch.IssueIndex}} - <a class="active-stopwatch-trigger item ui label {{if not .ActiveStopwatch}}hidden{{end}}" href="{{$issueURL}}"> + <a class="active-stopwatch-trigger item ui label {{if not .ActiveStopwatch}}hidden{{end}}" href="{{.ActiveStopwatch.IssueLink}}"> <span class="text"> <span class="fitted item"> {{svg "octicon-stopwatch"}} @@ -75,14 +74,14 @@ </a> <div class="ui popup very wide"> <div class="df ac"> - <a class="stopwatch-link df ac" href="{{$issueURL}}"> + <a class="stopwatch-link df ac" href="{{.ActiveStopwatch.IssueLink}}"> {{svg "octicon-issue-opened"}} <span class="stopwatch-issue">{{.ActiveStopwatch.RepoSlug}}#{{.ActiveStopwatch.IssueIndex}}</span> <span class="ui label blue stopwatch-time my-0 mx-4" data-seconds="{{.ActiveStopwatch.Seconds}}"> {{if .ActiveStopwatch}}{{Sec2Time .ActiveStopwatch.Seconds}}{{end}} </span> </a> - <form class="stopwatch-commit" method="POST" action="{{$issueURL}}/times/stopwatch/toggle"> + <form class="stopwatch-commit" method="POST" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/toggle"> {{.CsrfTokenHtml}} <button class="ui button mini compact basic icon fitted poping up" @@ -90,7 +89,7 @@ data-position="top right" data-variation="small inverted" >{{svg "octicon-square-fill"}}</button> </form> - <form class="stopwatch-cancel" method="POST" action="{{$issueURL}}/times/stopwatch/cancel"> + <form class="stopwatch-cancel" method="POST" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/cancel"> {{.CsrfTokenHtml}} <button class="ui button mini compact basic icon fitted poping up" @@ -149,12 +148,12 @@ </div> <div class="divider"></div> - <a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}"> + <a class="item" href="{{.SignedUser.HomeLink}}"> {{svg "octicon-person"}} {{.i18n.Tr "your_profile"}}<!-- Your profile --> </a> {{if not .DisableStars}} - <a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}?tab=stars"> + <a class="item" href="{{.SignedUser.HomeLink}}?tab=stars"> {{svg "octicon-star"}} {{.i18n.Tr "your_starred"}} </a> diff --git a/templates/explore/code.tmpl b/templates/explore/code.tmpl index 8cc1b71a7a..29d4075cce 100644 --- a/templates/explore/code.tmpl +++ b/templates/explore/code.tmpl @@ -37,8 +37,8 @@ {{$repo := (index $.RepoMaps .RepoID)}} <div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result"> <h4 class="ui top attached normal header"> - <span class="file"><a rel="nofollow" href="{{EscapePound $repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span> - <a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> + <span class="file"><a rel="nofollow" href="{{$repo.HTMLURL}}">{{$repo.FullName}}</a> - {{.Filename}}</span> + <a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> </h4> <div class="ui attached table segment"> <div class="file-body file-code code-view"> @@ -47,7 +47,7 @@ <tr> <td class="lines-num"> {{range .LineNumbers}} - <a href="{{EscapePound $repo.HTMLURL}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a> + <a href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a> {{end}} </td> <td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td> diff --git a/templates/mail/auth/activate.tmpl b/templates/mail/auth/activate.tmpl index ad34d9eebe..31e9a96882 100644 --- a/templates/mail/auth/activate.tmpl +++ b/templates/mail/auth/activate.tmpl @@ -5,7 +5,7 @@ <title>{{.i18n.Tr "mail.activate_account.title" .DisplayName}}</title> </head> -{{ $activate_url := printf "%suser/activate?code=%s" AppUrl .Code}} +{{ $activate_url := printf "%suser/activate?code=%s" AppUrl (QueryEscape .Code)}} <body> <p>{{.i18n.Tr "mail.activate_account.text_1" .DisplayName AppName | Str2html}}</p><br> <p>{{.i18n.Tr "mail.activate_account.text_2" .ActiveCodeLives | Str2html}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br> diff --git a/templates/mail/auth/activate_email.tmpl b/templates/mail/auth/activate_email.tmpl index a1d7ec37ec..8bd037ae4f 100644 --- a/templates/mail/auth/activate_email.tmpl +++ b/templates/mail/auth/activate_email.tmpl @@ -5,7 +5,7 @@ <title>{{.i18n.Tr "mail.activate_email.title" .DisplayName}}</title> </head> -{{ $activate_url := printf "%suser/activate_email?code=%s&email=%s" AppUrl .Code (QueryEscape .Email)}} +{{ $activate_url := printf "%suser/activate_email?code=%s&email=%s" AppUrl (QueryEscape .Code) (QueryEscape .Email)}} <body> <p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br> <p>{{.i18n.Tr "mail.activate_email.text" .ActiveCodeLives | Str2html}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br> diff --git a/templates/mail/auth/register_notify.tmpl b/templates/mail/auth/register_notify.tmpl index e1ab97b760..45ca95f2c3 100644 --- a/templates/mail/auth/register_notify.tmpl +++ b/templates/mail/auth/register_notify.tmpl @@ -10,7 +10,7 @@ <p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br> <p>{{.i18n.Tr "mail.register_notify.text_1" AppName}}</p><br> <p>{{.i18n.Tr "mail.register_notify.text_2" .Username}}</p><p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p><br> - <p>{{.i18n.Tr "mail.register_notify.text_3" $set_pwd_url | Str2html}}</p><br> + <p>{{.i18n.Tr "mail.register_notify.text_3" ($set_pwd_url | Escape) | Str2html}}</p><br> <p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> </body> diff --git a/templates/mail/auth/reset_passwd.tmpl b/templates/mail/auth/reset_passwd.tmpl index 7cab33bf4e..bf10c1f967 100644 --- a/templates/mail/auth/reset_passwd.tmpl +++ b/templates/mail/auth/reset_passwd.tmpl @@ -5,7 +5,7 @@ <title>{{.i18n.Tr "mail.reset_password.title" .DisplayName}}</title> </head> -{{ $recover_url := printf "%suser/recover_account?code=%s" AppUrl .Code}} +{{ $recover_url := printf "%suser/recover_account?code=%s" AppUrl (QueryEscape .Code)}} <body> <p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br> <p>{{.i18n.Tr "mail.reset_password.text" .ResetPwdCodeLives | Str2html}}</p><p><a href="{{$recover_url}}">{{$recover_url}}</a></p><br> diff --git a/templates/mail/issue/assigned.tmpl b/templates/mail/issue/assigned.tmpl index 1c3b930978..e1156c5335 100644 --- a/templates/mail/issue/assigned.tmpl +++ b/templates/mail/issue/assigned.tmpl @@ -8,8 +8,8 @@ <title>{{.Subject}}</title> </head> -{{$repo_url := printf "<a href='%s'>%s</a>" .Issue.Repo.HTMLURL .Issue.Repo.FullName}} -{{$link := printf "<a href='%s'>#%d</a>" .Link .Issue.Index}} +{{$repo_url := printf "<a href='%s'>%s</a>" (Escape .Issue.Repo.HTMLURL) (Escape .Issue.Repo.FullName)}} +{{$link := printf "<a href='%s'>#%d</a>" (Escape .Link) (Escape .Issue.Index)}} <body> <p> {{if .IsPull}} diff --git a/templates/mail/issue/default.tmpl b/templates/mail/issue/default.tmpl index 0c09c6d043..e01ec667ee 100644 --- a/templates/mail/issue/default.tmpl +++ b/templates/mail/issue/default.tmpl @@ -20,13 +20,13 @@ {{if eq .ActionName "push"}} <p> {{if .Comment.IsForcePush}} - {{$oldCommitUrl := printf "%s%s/%s/commit/%s" AppUrl .Comment.Issue.PullRequest.BaseRepo.OwnerName .Comment.Issue.PullRequest.BaseRepo.Name .Comment.OldCommit}} + {{$oldCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.OldCommit}} {{$oldShortSha := ShortSha .Comment.OldCommit}} - {{$oldCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" $oldCommitUrl $oldShortSha}} + {{$oldCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $oldCommitUrl) (Escape $oldShortSha)}} - {{$newCommitUrl := printf "%s%s/%s/commit/%s" AppUrl .Comment.Issue.PullRequest.BaseRepo.OwnerName .Comment.Issue.PullRequest.BaseRepo.Name .Comment.NewCommit}} + {{$newCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.NewCommit}} {{$newShortSha := ShortSha .Comment.NewCommit}} - {{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" $newCommitUrl $newShortSha}} + {{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}} {{.i18n.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink | Str2html}} {{else}} @@ -36,26 +36,26 @@ {{end}} <p> {{if eq .ActionName "close"}} - {{.i18n.Tr "mail.issue.action.close" .Doer.Name .Issue.Index | Str2html}} + {{.i18n.Tr "mail.issue.action.close" (Escape .Doer.Name) .Issue.Index | Str2html}} {{else if eq .ActionName "reopen"}} - {{.i18n.Tr "mail.issue.action.reopen" .Doer.Name .Issue.Index | Str2html}} + {{.i18n.Tr "mail.issue.action.reopen" (Escape .Doer.Name) .Issue.Index | Str2html}} {{else if eq .ActionName "merge"}} - {{.i18n.Tr "mail.issue.action.merge" .Doer.Name .Issue.Index .Issue.PullRequest.BaseBranch | Str2html}} + {{.i18n.Tr "mail.issue.action.merge" (Escape .Doer.Name) .Issue.Index (Escape .Issue.PullRequest.BaseBranch) | Str2html}} {{else if eq .ActionName "approve"}} - {{.i18n.Tr "mail.issue.action.approve" .Doer.Name | Str2html}} + {{.i18n.Tr "mail.issue.action.approve" (Escape .Doer.Name) | Str2html}} {{else if eq .ActionName "reject"}} - {{.i18n.Tr "mail.issue.action.reject" .Doer.Name | Str2html}} + {{.i18n.Tr "mail.issue.action.reject" (Escape .Doer.Name) | Str2html}} {{else if eq .ActionName "review"}} - {{.i18n.Tr "mail.issue.action.review" .Doer.Name | Str2html}} + {{.i18n.Tr "mail.issue.action.review" (Escape .Doer.Name) | Str2html}} {{else if eq .ActionName "review_dismissed"}} - {{.i18n.Tr "mail.issue.action.review_dismissed" .Doer.Name .Comment.Review.Reviewer.Name | Str2html}} + {{.i18n.Tr "mail.issue.action.review_dismissed" (Escape .Doer.Name) (Escape .Comment.Review.Reviewer.Name) | Str2html}} {{else if eq .ActionName "ready_for_review"}} - {{.i18n.Tr "mail.issue.action.ready_for_review" .Doer.Name | Str2html}} + {{.i18n.Tr "mail.issue.action.ready_for_review" (Escape .Doer.Name) | Str2html}} {{end}} {{- if eq .Body ""}} {{if eq .ActionName "new"}} - {{.i18n.Tr "mail.issue.action.new" .Doer.Name .Issue.Index | Str2html}} + {{.i18n.Tr "mail.issue.action.new" (Escape .Doer.Name) .Issue.Index | Str2html}} {{end}} {{else}} {{.Body | Str2html}} @@ -72,7 +72,7 @@ <ul> {{range .Comment.Commits}} <li> - <a href="{{AppUrl}}{{$.Comment.Issue.PullRequest.BaseRepo.OwnerName}}/{{$.Comment.Issue.PullRequest.BaseRepo.Name}}/commit/{{.ID}}"> + <a href="{{$.Comment.Issue.PullRequest.BaseRepo.HTMLURL}}/commit/{{.ID}}"> {{ShortSha .ID.String}} </a> - {{.Summary}} </li> diff --git a/templates/mail/notify/repo_transfer.tmpl b/templates/mail/notify/repo_transfer.tmpl index 4dea947401..6250ff7c20 100644 --- a/templates/mail/notify/repo_transfer.tmpl +++ b/templates/mail/notify/repo_transfer.tmpl @@ -5,7 +5,7 @@ <title>{{.Subject}}</title> </head> -{{$url := printf "<a href='%[1]s'>%[2]s</a>" .Link .Repo}} +{{$url := printf "<a href='%[1]s'>%[2]s</a>" (Escape .Link) (Escape .Repo)}} <body> <p>{{.Subject}}. {{.i18n.Tr "mail.repo.transfer.body" $url | Str2html}} diff --git a/templates/mail/release.tmpl b/templates/mail/release.tmpl index fabe4999e3..813aba556c 100644 --- a/templates/mail/release.tmpl +++ b/templates/mail/release.tmpl @@ -11,8 +11,8 @@ </head> -{{$release_url := printf "<a href='%s'>%s</a>" .Release.HTMLURL .Release.TagName}} -{{$repo_url := printf "<a href='%s'>%s</a>" .Release.Repo.HTMLURL .Release.Repo.FullName}} +{{$release_url := printf "<a href='%s'>%s</a>" (.Release.HTMLURL | Escape) (.Release.TagName | Escape) }} +{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}} <body> <p> {{.i18n.Tr "mail.release.new.text" .Release.Publisher.Name $release_url $repo_url | Str2html}} @@ -31,13 +31,11 @@ <br> {{.i18n.Tr "mail.release.downloads"}} <ul> - {{$tagname := .Release.TagName | EscapePound}} - {{$archive_url := printf "%s%s/%s/archive" AppUrl .Release.Repo.OwnerName .Release.Repo.Name}} <li> - <a href="{{$archive_url}}/{{$tagname}}.zip" rel="nofollow"><strong>{{.i18n.Tr "mail.release.download.zip"}}</strong></a> + <a href="{{.Release.Repo.Link}}/archive/{{.Release.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{.i18n.Tr "mail.release.download.zip"}}</strong></a> </li> <li> - <a href="{{$archive_url}}/{{$tagname}}.tar.gz" rel="nofollow"><strong>{{.i18n.Tr "mail.release.download.targz"}}</strong></a> + <a href="{{.Release.Repo.Link}}/archive/{{.Release.TagName | PathEscapeSegments}}.tar.gz" rel="nofollow"><strong>{{.i18n.Tr "mail.release.download.targz"}}</strong></a> </li> {{if .Release.Attachments}} {{range .Release.Attachments}} diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index 153de30ca3..868d956011 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -68,10 +68,10 @@ <div class="ui attached table segment teams"> {{range .Teams}} <div class="item"> - <a href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong class="team-name">{{.Name}}</strong></a> + <a href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}"><strong class="team-name">{{.Name}}</strong></a> <p class="text grey"> - <a href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> · - <a href="{{$.OrgLink}}/teams/{{.LowerName}}/repositories"><strong>{{.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a> + <a href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}"><strong>{{.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> · + <a href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}/repositories"><strong>{{.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a> </p> </div> {{end}} diff --git a/templates/org/team/members.tmpl b/templates/org/team/members.tmpl index f2c89e0653..a064ee9b4f 100644 --- a/templates/org/team/members.tmpl +++ b/templates/org/team/members.tmpl @@ -9,7 +9,7 @@ {{template "org/team/navbar" .}} {{if .IsOrganizationOwner}} <div class="ui attached segment"> - <form class="ui form" id="add-member-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/add" method="post"> + <form class="ui form" id="add-member-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post"> {{.CsrfTokenHtml}} <input type="hidden" name="uid" value="{{.SignedUser.ID}}"> <div class="inline field ui left"> @@ -29,7 +29,7 @@ {{if and $.IsOrganizationOwner (not (eq $.SignedUser.ID .ID))}} <form> <button class="ui red button delete-button right" data-modal-id="remove-team-member" - data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove" data-datauid="{{.ID}}" + data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/remove" data-datauid="{{.ID}}" data-name="{{.DisplayName}}" data-data-team-name="{{$.Team.Name}}">{{$.i18n.Tr "org.members.remove"}}</button> </form> diff --git a/templates/org/team/navbar.tmpl b/templates/org/team/navbar.tmpl index b5732ed71b..2dfa244e5f 100644 --- a/templates/org/team/navbar.tmpl +++ b/templates/org/team/navbar.tmpl @@ -1,4 +1,4 @@ <div class="ui top attached tabular menu"> - <a class="item{{if .PageIsOrgTeamMembers}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName}}">{{svg "octicon-person"}} <strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> - <a class="item{{if .PageIsOrgTeamRepos}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/repositories">{{svg "octicon-repo"}} <strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a> + <a class="item{{if .PageIsOrgTeamMembers}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}">{{svg "octicon-person"}} <strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> + <a class="item{{if .PageIsOrgTeamRepos}} active{{end}}" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/repositories">{{svg "octicon-repo"}} <strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a> </div> diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl index b4c385a2b0..d6a0e41417 100644 --- a/templates/org/team/new.tmpl +++ b/templates/org/team/new.tmpl @@ -3,7 +3,7 @@ {{template "org/header" .}} <div class="ui middle very relaxed page grid"> <div class="column"> - <form class="ui form" action="{{if .PageIsOrgTeamsNew}}{{.OrgLink}}/teams/new{{else}}{{.OrgLink}}/teams/{{.Team.LowerName}}/edit{{end}}" data-delete-url="{{.OrgLink}}/teams/{{.Team.LowerName}}/delete" method="post"> + <form class="ui form" action="{{if .PageIsOrgTeamsNew}}{{.OrgLink}}/teams/new{{else}}{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/edit{{end}}" data-delete-url="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/delete" method="post"> {{.CsrfTokenHtml}} <h3 class="ui top attached header"> {{if .PageIsOrgTeamsNew}}{{.i18n.Tr "org.create_new_team"}}{{else}}{{.i18n.Tr "org.teams.settings"}}{{end}} @@ -104,7 +104,7 @@ {{else}} <button class="ui green button">{{.i18n.Tr "org.teams.update_settings"}}</button> {{if not (eq .Team.LowerName "owners")}} - <button class="ui red button delete-button" data-url="{{.OrgLink}}/teams/{{.team_name}}/delete">{{.i18n.Tr "org.teams.delete_team"}}</button> + <button class="ui red button delete-button" data-url="{{.OrgLink}}/teams/{{.team_name | PathEscape}}/delete">{{.i18n.Tr "org.teams.delete_team"}}</button> {{end}} {{end}} </div> diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl index 350e8a4628..ae747ef2cc 100644 --- a/templates/org/team/repositories.tmpl +++ b/templates/org/team/repositories.tmpl @@ -11,7 +11,7 @@ {{if $canAddRemove}} <div class="ui attached segment" id="repo-top-segment"> <div class="inline ui field left"> - <form class="ui form" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/add" method="post"> + <form class="ui form" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post"> {{.CsrfTokenHtml}} <div class="inline field ui left"> <div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search"> @@ -24,9 +24,9 @@ </form> </div> <div class="inline ui field right"> - <form class="ui form" id="repo-multiple-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/repositories" method="post"> - <button class="ui red button delete-button right" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/removeall">{{.i18n.Tr "remove_all"}}</button> - <button class="ui green button add-all-button right" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/addall">{{.i18n.Tr "add_all"}}</button> + <form class="ui form" id="repo-multiple-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/repositories" method="post"> + <button class="ui red button delete-button right" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/removeall">{{.i18n.Tr "remove_all"}}</button> + <button class="ui green button add-all-button right" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/addall">{{.i18n.Tr "add_all"}}</button> </form> </div> </div> @@ -35,12 +35,12 @@ {{range .Team.Repos}} <div class="item"> {{if $canAddRemove}} - <form method="post" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove"> + <form method="post" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/remove"> {{$.CsrfTokenHtml}} <button type="submit" class="ui red small button right" name="repoid" value="{{.ID}}">{{$.i18n.Tr "remove"}}</button> </form> {{end}} - <a class="member" href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}"> + <a class="member" href="{{$.Org.HomeLink}}/{{.Name | PathEscape}}"> {{if .IsPrivate}} {{svg "octicon-lock"}} {{else if .IsFork}} diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 84729a0841..2e3769de47 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -5,11 +5,11 @@ {{if .Team.IsMember $.SignedUser.ID}} <form> <button class="ui red tiny button delete-button" data-modal-id="leave-team-sidebar" - data-url="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave" data-datauid="{{$.SignedUser.ID}}" + data-url="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/action/leave" data-datauid="{{$.SignedUser.ID}}" data-name="{{.Team.Name}}">{{$.i18n.Tr "org.teams.leave"}}</button> </form> {{else if .IsOrganizationOwner}} - <form method="post" action="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join"> + <form method="post" action="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/action/join"> {{$.CsrfTokenHtml}} <input type="hidden" name="page" value="team"/> <button type="submit" class="ui blue tiny button" name="uid" value="{{$.SignedUser.ID}}">{{$.i18n.Tr "org.teams.join"}}</button> @@ -55,7 +55,7 @@ </div> {{if .IsOrganizationOwner}} <div class="ui bottom attached segment"> - <a class="ui teal small button" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/edit">{{svg "octicon-gear"}} {{$.i18n.Tr "org.teams.settings"}}</a> + <a class="ui teal small button" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/edit">{{svg "octicon-gear"}} {{$.i18n.Tr "org.teams.settings"}}</a> </div> {{end}} </div> diff --git a/templates/org/team/teams.tmpl b/templates/org/team/teams.tmpl index 6f4f155072..9165a62bca 100644 --- a/templates/org/team/teams.tmpl +++ b/templates/org/team/teams.tmpl @@ -14,16 +14,16 @@ {{range .Teams}} <div class="column"> <div class="ui top attached header"> - <a class="text black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a> + <a class="text black" href="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}"><strong>{{.Name}}</strong></a> <div class="ui right"> {{if .IsMember $.SignedUser.ID}} <form> <button class="ui red tiny button delete-button" data-modal-id="leave-team" - data-url="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave" data-datauid="{{$.SignedUser.ID}}" + data-url="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}/action/leave" data-datauid="{{$.SignedUser.ID}}" data-name="{{.Name}}">{{$.i18n.Tr "org.teams.leave"}}</button> </form> {{else if $.IsOrganizationOwner}} - <form method="post" action="{{$.OrgLink}}/teams/{{.LowerName}}/action/join"> + <form method="post" action="{{$.OrgLink}}/teams/{{.LowerName | PathEscape}}/action/join"> {{$.CsrfTokenHtml}} <button type="submit" class="ui blue small button" name="uid" value="{{$.SignedUser.ID}}">{{$.i18n.Tr "org.teams.join"}}</button> </form> diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index d4cff880e5..c67925e423 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -126,7 +126,7 @@ <span class="ui green label">{{$.i18n.Tr "repo.activity.published_release_label"}}</span> {{.TagName}} {{if not .IsTag}} - <a class="title" href="{{$.RepoLink}}/src/{{.TagName | EscapePound}}">{{.Title | RenderEmoji}}</a> + <a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji}}</a> {{end}} {{TimeSinceUnix .CreatedUnix $.Lang}} </p> diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index c7c497088a..4c04f1f7b8 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -10,12 +10,12 @@ </div> <div class="file-header-right file-actions df ac"> <div class="ui buttons"> - <a class="ui tiny button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a> + <a class="ui tiny button" href="{{$.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a> {{if not .IsViewCommit}} - <a class="ui tiny button" href="{{.RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a> + <a class="ui tiny button" href="{{.RepoLink}}/src/commit/{{.CommitID | PathEscape}}/{{.TreePath | PathEscapeSegments}}">{{.i18n.Tr "repo.file_permalink"}}</a> {{end}} - <a class="ui tiny button" href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.normal_view"}}</a> - <a class="ui tiny button" href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_history"}}</a> + <a class="ui tiny button" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}">{{.i18n.Tr "repo.normal_view"}}</a> + <a class="ui tiny button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}">{{.i18n.Tr "repo.file_history"}}</a> </div> </div> </h4> diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index cadf91df04..5b95f1be72 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -18,22 +18,22 @@ {{if .IsProtected}} {{svg "octicon-shield-lock"}} {{end}} - <a href="{{$.RepoLink}}/src/branch/{{$.DefaultBranch | EscapePound}}">{{$.DefaultBranch}}</a> - <p class="info df ac my-2">{{svg "octicon-git-commit" 16 "mr-2"}}<a href="{{$.RepoLink}}/commit/{{.Commit.ID.String}}">{{ShortSha .Commit.ID.String}}</a> · <span class="commit-message">{{RenderCommitMessage .Commit.CommitMessage $.RepoLink $.Repository.ComposeMetas}}</span> · {{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p> + <a href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments $.DefaultBranch}}">{{$.DefaultBranch}}</a> + <p class="info df ac my-2">{{svg "octicon-git-commit" 16 "mr-2"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .Commit.ID.String}}">{{ShortSha .Commit.ID.String}}</a> · <span class="commit-message">{{RenderCommitMessage .Commit.CommitMessage $.RepoLink $.Repository.ComposeMetas}}</span> · {{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p> {{end}} {{end}} </td> <td class="right aligned overflow-visible"> {{if and $.IsWriter (not $.Repository.IsArchived) (not .IsDeleted)}} - <div class="ui basic jump button icon poping up show-create-branch-modal" data-content="{{$.i18n.Tr "repo.branch.new_branch_from" ($.DefaultBranch)}}" data-variation="tiny inverted" data-branch-from="{{EscapePound $.DefaultBranch}}" data-modal="#create-branch-modal" data-position="top right"> + <div class="ui basic jump button icon poping up show-create-branch-modal" data-content="{{$.i18n.Tr "repo.branch.new_branch_from" ($.DefaultBranch)}}" data-variation="tiny inverted" data-branch-from="{{$.DefaultBranch}}" data-branch-from-urlcomponent="{{PathEscapeSegments $.DefaultBranch}}" data-modal="#create-branch-modal" data-position="top right"> {{svg "octicon-git-branch"}} </div> {{end}} <div class="ui basic jump dropdown icon button poping up" data-content="{{$.i18n.Tr "repo.branch.download" ($.DefaultBranch)}}" data-variation="tiny inverted" data-position="top right"> {{svg "octicon-download"}} <div class="menu"> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.zip">{{svg "octicon-file-zip"}} ZIP</a> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.DefaultBranch}}.zip">{{svg "octicon-file-zip"}} ZIP</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.DefaultBranch}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a> </div> </div> </td> @@ -54,14 +54,14 @@ <tr> <td class="six wide"> {{if .IsDeleted}} - <s><a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a></s> + <s><a href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .Name}}">{{.Name}}</a></s> <p class="info">{{$.i18n.Tr "repo.branch.deleted_by" .DeletedBranch.DeletedBy.Name}} {{TimeSinceUnix .DeletedBranch.DeletedUnix $.i18n.Lang}}</p> {{else}} {{if .IsProtected}} {{svg "octicon-shield-lock"}} {{end}} - <a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a> - <p class="info df ac my-2">{{svg "octicon-git-commit" 16 "mr-2"}}<a href="{{$.RepoLink}}/commit/{{.Commit.ID.String}}">{{ShortSha .Commit.ID.String}}</a> · <span class="commit-message">{{RenderCommitMessage .Commit.CommitMessage $.RepoLink $.Repository.ComposeMetas}}</span> · {{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p> + <a href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments .Name}}">{{.Name}}</a> + <p class="info df ac my-2">{{svg "octicon-git-commit" 16 "mr-2"}}<a href="{{$.RepoLink}}/commit/{{PathEscape .Commit.ID.String}}">{{ShortSha .Commit.ID.String}}</a> · <span class="commit-message">{{RenderCommitMessage .Commit.CommitMessage $.RepoLink $.Repository.ComposeMetas}}</span> · {{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p> {{end}} </td> <td class="three wide ui"> @@ -85,13 +85,13 @@ {{svg "octicon-git-pull-request"}} {{$.i18n.Tr "repo.branch.included"}} </a> {{else if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}} - <a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}"> + <a href="{{$.RepoLink}}/compare/{{PathEscapeSegments $.DefaultBranch}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{PathEscape $.Owner.Name}}:{{end}}{{PathEscapeSegments .Name}}"> <button id="new-pull-request" class="ui compact basic button mr-0">{{if $.CanPull}}{{$.i18n.Tr "repo.pulls.compare_changes"}}{{else}}{{$.i18n.Tr "action.compare_branch"}}{{end}}</button> </a> {{end}} {{else if and .LatestPullRequest.HasMerged .MergeMovedOn}} {{if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}} - <a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}"> + <a href="{{$.RepoLink}}/compare/{{PathEscapeSegments $.DefaultBranch}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | PathEscapeSegments}}"> <button id="new-pull-request" class="ui compact basic button mr-0">{{if $.CanPull}}{{$.i18n.Tr "repo.pulls.compare_changes"}}{{else}}{{$.i18n.Tr "action.compare_branch"}}{{end}}</button> </a> {{end}} @@ -108,7 +108,7 @@ </td> <td class="two wide right aligned overflow-visible"> {{if and $.IsWriter (not $.Repository.IsArchived) (not .IsDeleted)}} - <div class="ui basic jump button icon poping up show-create-branch-modal" data-branch-from="{{EscapePound .Name}}" data-content="{{$.i18n.Tr "repo.branch.new_branch_from" .Name}}" data-variation="tiny inverted" data-position="top right" data-modal="#create-branch-modal" data-name="{{.Name}}"> + <div class="ui basic jump button icon poping up show-create-branch-modal" data-branch-from="{{.Name}}" data-branch-from-urlcomponent="{{PathEscapeSegments .Name}}" data-content="{{$.i18n.Tr "repo.branch.new_branch_from" .Name}}" data-variation="tiny inverted" data-position="top right" data-modal="#create-branch-modal" data-name="{{.Name}}"> {{svg "octicon-git-branch"}} </div> {{end}} @@ -116,16 +116,16 @@ <div class="ui basic jump dropdown icon button poping up" data-content="{{$.i18n.Tr "repo.branch.download" (.Name)}}" data-variation="tiny inverted" data-position="top right"> {{svg "octicon-download"}} <div class="menu"> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.zip">{{svg "octicon-file-zip"}} ZIP</a> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments .Name}}.zip">{{svg "octicon-file-zip"}} ZIP</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments .Name}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a> </div> </div> {{end}} {{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived) (not .IsProtected)}} {{if .IsDeleted}} - <a class="ui basic jump button icon poping up undo-button" href data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID | urlquery}}&name={{.DeletedBranch.Name | urlquery}}" data-content="{{$.i18n.Tr "repo.branch.restore" (.Name)}}" data-variation="tiny inverted" data-position="top right"><span class="text blue">{{svg "octicon-reply"}}</span></a> + <a class="ui basic jump button icon poping up undo-button" href data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID}}&name={{PathEscapeSegments .DeletedBranch.Name}}" data-content="{{$.i18n.Tr "repo.branch.restore" (.Name)}}" data-variation="tiny inverted" data-position="top right"><span class="text blue">{{svg "octicon-reply"}}</span></a> {{else}} - <a class="ui basic jump button icon poping up delete-button delete-branch-button" href data-url="{{$.Link}}/delete?name={{.Name | urlquery}}" data-content="{{$.i18n.Tr "repo.branch.delete" (.Name)}}" data-variation="tiny inverted" data-position="top right" data-name="{{.Name}}"> + <a class="ui basic jump button icon poping up delete-button delete-branch-button" href data-url="{{$.Link}}/delete?name={{PathEscapeSegments .Name}}" data-content="{{$.i18n.Tr "repo.branch.delete" (.Name)}}" data-variation="tiny inverted" data-position="top right" data-name="{{.Name}}"> {{svg "octicon-trash"}} </a> {{end}} diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl index 1605fa91a7..a2115729b2 100644 --- a/templates/repo/branch_dropdown.tmpl +++ b/templates/repo/branch_dropdown.tmpl @@ -17,14 +17,14 @@ <div class="data" style="display: none" data-mode="{{if .root.IsViewTag}}tags{{else}}branches{{end}}"> {{if $showBranchesInDropdown}} {{range .root.Branches}} - <div class="item branch {{if eq $.root.BranchName .}}selected{{end}}" data-url="{{$.root.RepoLink}}/{{if $.root.PageIsCommits}}commits{{else}}src{{end}}/branch/{{EscapePound .}}{{if $.root.TreePath}}/{{EscapePound $.root.TreePath}}{{end}}">{{.}}</div> + <div class="item branch {{if eq $.root.BranchName .}}selected{{end}}" data-url="{{$.root.RepoLink}}/{{if $.root.PageIsCommits}}commits{{else}}src{{end}}/branch/{{PathEscapeSegments .}}{{if $.root.TreePath}}/{{PathEscapeSegments $.root.TreePath}}{{end}}">{{.}}</div> {{end}} {{end}} {{range .root.Tags}} {{if $release}} - <div class="item tag {{if eq $release.TagName .}}selected{{end}}" data-url="{{$.root.RepoLink}}/compare/{{EscapePound .}}...{{if $release.IsDraft}}{{EscapePound $release.Target}}{{else}}{{if $release.TagName}}{{EscapePound $release.TagName}}{{else}}{{EscapePound $release.Sha1}}{{end}}{{end}}">{{.}}</div> + <div class="item tag {{if eq $release.TagName .}}selected{{end}}" data-url="{{$.root.RepoLink}}/compare/{{PathEscapeSegments .}}...{{if $release.IsDraft}}{{PathEscapeSegments $release.Target}}{{else}}{{if $release.TagName}}{{PathEscapeSegments $release.TagName}}{{else}}{{PathEscapeSegments $release.Sha1}}{{end}}{{end}}">{{.}}</div> {{else}} - <div class="item tag {{if eq $.root.BranchName .}}selected{{end}}" data-url="{{$.root.RepoLink}}/{{if $.root.PageIsCommits}}commits{{else}}src{{end}}/tag/{{EscapePound .}}{{if $.root.TreePath}}/{{EscapePound $.root.TreePath}}{{end}}">{{.}}</div> + <div class="item tag {{if eq $.root.BranchName .}}selected{{end}}" data-url="{{$.root.RepoLink}}/{{if $.root.PageIsCommits}}commits{{else}}src{{end}}/tag/{{PathEscapeSegments .}}{{if $.root.TreePath}}/{{PathEscapeSegments $.root.TreePath}}{{end}}">{{.}}</div> {{end}} {{end}} </div> @@ -71,7 +71,7 @@ {{end}} </div> </a> - <form ref="newBranchForm" action="{{.root.RepoLink}}/branches/_new/{{EscapePound .root.BranchNameSubURL}}" method="post"> + <form ref="newBranchForm" action="{{.root.RepoLink}}/branches/_new/{{.root.BranchNameSubURL}}" method="post"> {{.root.CsrfTokenHtml}} <input type="hidden" name="new_branch_name" v-model="searchTerm"> <input type="hidden" name="create_tag" v-model="createTag"> diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 01cbd5182d..b2aadacb7b 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -19,7 +19,7 @@ {{end}} <div class="ui top attached info clearing segment {{$class}}"> {{if not $.PageIsWiki}} - <a class="ui floated right blue tiny button" href="{{EscapePound .SourcePath}}"> + <a class="ui floated right blue tiny button" href="{{.SourcePath}}"> {{.i18n.Tr "repo.diff.browse_source"}} </a> {{end}} @@ -72,9 +72,9 @@ <div class="item"> {{range .Parents}} {{if $.PageIsWiki}} - <a class="ui blue sha label" href="{{$.RepoLink}}/wiki/commit/{{.}}">{{ShortSha .}}</a> + <a class="ui blue sha label" href="{{$.RepoLink}}/wiki/commit/{{PathEscape .}}">{{ShortSha .}}</a> {{else}} - <a class="ui blue sha label" href="{{$.RepoLink}}/commit/{{.}}">{{ShortSha .}}</a> + <a class="ui blue sha label" href="{{$.RepoLink}}/commit/{{PathEscape .}}">{{ShortSha .}}</a> {{end}} {{end}} </div> diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index 5282430ec7..3a98a3afb2 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -17,7 +17,7 @@ {{if .User.FullName}} {{$userName = .User.FullName}} {{end}} - {{avatar .User 28 "mr-2"}}<a href="{{AppSubUrl}}/{{.User.Name}}">{{$userName}}</a> + {{avatar .User 28 "mr-2"}}<a href="{{.User.HomeLink}}">{{$userName}}</a> {{else}} {{avatarByEmail .Author.Email .Author.Name 28 "mr-2"}} {{$userName}} @@ -40,9 +40,9 @@ {{end}} {{end}} {{if $.PageIsWiki}} - <a href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/wiki/commit/{{.ID}}" rel="nofollow" class="{{$class}}"> + <a href="{{$.RepoLink}}/wiki/commit/{{.ID}}" rel="nofollow" class="{{$class}}"> {{else if $.Reponame}} - <a href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{.ID}}" rel="nofollow" class="{{$class}}"> + <a href="{{$.RepoLink}}/commit/{{.ID}}" rel="nofollow" class="{{$class}}"> {{else}} <span class="{{$class}}"> {{end}} @@ -61,7 +61,7 @@ {{if $.PageIsWiki}} <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji}}</span> {{else }} - {{ $commitLink:= printf "%s/%s/%s/commit/%s" AppSubUrl $.Username $.Reponame .ID }} + {{ $commitLink:= printf "%s/commit/%s" $.RepoLink (PathEscape .ID.String) }} <span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject .Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span> {{end}} </span> diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl index bdbee816cc..4211eda1af 100644 --- a/templates/repo/commits_list_small.tmpl +++ b/templates/repo/commits_list_small.tmpl @@ -6,7 +6,7 @@ <div class="singular-commit" id="{{$tag}}"> <span class="badge badge-commit">{{svg "octicon-git-commit"}}</span> {{if .User}} - <a href="{{AppSubUrl}}/{{.User.Name}}"> + <a href="{.User.HomeLink}}"> {{avatar .User}} </a> {{else}} @@ -31,7 +31,7 @@ {{end}} {{end}} {{if $.comment.Issue.PullRequest.BaseRepo.Name}} - <a href="{{AppSubUrl}}/{{$.comment.Issue.PullRequest.BaseRepo.OwnerName}}/{{$.comment.Issue.PullRequest.BaseRepo.Name}}/commit/{{.ID}}" rel="nofollow" class="{{$class}}"> + <a href="{{$.comment.Issue.PullRequest.BaseRepo.Link}}/commit/{{PathEscape .ID.String}}" rel="nofollow" class="{{$class}}"> {{else}} <span class="{{$class}}"> {{end}} @@ -46,7 +46,7 @@ {{end}} </span> - {{ $commitLink:= printf "%s/%s/%s/commit/%s" AppSubUrl $.comment.Issue.PullRequest.BaseRepo.OwnerName $.comment.Issue.PullRequest.BaseRepo.Name .ID }} + {{ $commitLink:= printf "%s/commit/%s" $.comment.Issue.PullRequest.BaseRepo.Link (PathEscape .ID.String) }} <span class="mono commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject .Message ($.comment.Issue.PullRequest.BaseRepo.Link|Escape) $commitLink $.comment.Issue.PullRequest.BaseRepo.ComposeMetas}}</span> {{if IsMultilineCommitMessage .Message}} <button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button> diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index 7bdcb340d9..4871b688a7 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -11,7 +11,7 @@ </div> <div class="commits-table-right df ac"> {{if .PageIsCommits}} - <form class="ignore-dirty" action="{{.RepoLink}}/commits/{{.BranchNameSubURL | EscapePound}}/search"> + <form class="ignore-dirty" action="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/search"> <div class="ui tiny search input"> <input name="q" placeholder="{{.i18n.Tr "repo.commits.search"}}" value="{{.Keyword}}" autofocus> </div> @@ -23,9 +23,9 @@ <button class="ui primary tiny button mr-0 poping up" data-panel="#add-deploy-key-panel" data-content={{.i18n.Tr "repo.commits.search.tooltip"}}>{{.i18n.Tr "repo.commits.find"}}</button> </form> {{else if .IsDiffCompare}} - <a href="{{$.CommitRepoLink}}/commit/{{.BeforeCommitID}}" class="ui green sha label">{{if not .BaseIsCommit}}{{if .BaseIsBranch}}{{svg "octicon-git-branch"}}{{else if .BaseIsTag}}{{svg "octicon-tag"}}{{end}}{{.BaseBranch}}{{else}}{{ShortSha .BaseBranch}}{{end}}</a> + <a href="{{$.CommitRepoLink}}/commit/{{.BeforeCommitID | PathEscape}}" class="ui green sha label">{{if not .BaseIsCommit}}{{if .BaseIsBranch}}{{svg "octicon-git-branch"}}{{else if .BaseIsTag}}{{svg "octicon-tag"}}{{end}}{{.BaseBranch}}{{else}}{{ShortSha .BaseBranch}}{{end}}</a> ... - <a href="{{$.CommitRepoLink}}/commit/{{.AfterCommitID}}" class="ui green sha label">{{if not .HeadIsCommit}}{{if .HeadIsBranch}}{{svg "octicon-git-branch"}}{{else if .HeadIsTag}}{{svg "octicon-tag"}}{{end}}{{.HeadBranch}}{{else}}{{ShortSha .HeadBranch}}{{end}}</a> + <a href="{{$.CommitRepoLink}}/commit/{{.AfterCommitID | PathEscape}}" class="ui green sha label">{{if not .HeadIsCommit}}{{if .HeadIsBranch}}{{svg "octicon-git-branch"}}{{else if .HeadIsTag}}{{svg "octicon-tag"}}{{end}}{{.HeadBranch}}{{else}}{{ShortSha .HeadBranch}}{{end}}</a> {{end}} </div> </h4> diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index 6915cf3b49..78493629b3 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -11,7 +11,7 @@ {{template "base/alert" .}} {{if not $.DisableMigrations}} - <p class="ui center">{{.i18n.Tr "repo.new_repo_helper" (printf "%s%s" AppSubUrl "/repo/migrate") | Safe}}</p> + <p class="ui center">{{.i18n.Tr "repo.new_repo_helper" ((printf "%s%s" AppSubUrl "/repo/migrate")|Escape) | Safe}}</p> {{end}} {{if not .CanCreateRepo}} diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index 2543756d44..792c539ac5 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -4,17 +4,17 @@ {{if eq .GetType 4}} <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} - <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="{{$.Anchor}}"> + <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="{{$.Anchor}}"> {{svg "octicon-fold-down"}} </a> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} - <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="{{$.Anchor}}"> + <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="{{$.Anchor}}"> {{svg "octicon-fold-up"}} </a> {{end}} {{if eq $line.GetExpandDirection 2}} - <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="{{$.Anchor}}"> + <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="{{$.Anchor}}"> {{svg "octicon-fold"}} </a> {{end}} @@ -36,17 +36,17 @@ {{if eq .GetType 4}} <td colspan="2" class="lines-num"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} - <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="{{$.Anchor}}"> + <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="{{$.Anchor}}"> {{svg "octicon-fold-down"}} </a> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} - <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="{{$.Anchor}}"> + <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="{{$.Anchor}}"> {{svg "octicon-fold-up"}} </a> {{end}} {{if eq $line.GetExpandDirection 2}} - <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="{{$.Anchor}}"> + <a role="button" class="blob-excerpt" data-url="{{$.RepoLink}}/blob_excerpt/{{PathEscape $.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="{{$.Anchor}}"> {{svg "octicon-fold"}} </a> {{end}} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 8aa3242063..56d6942baa 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -96,9 +96,9 @@ {{end}} {{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} {{if $file.IsDeleted}} - <a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> + <a class="ui basic tiny button" rel="nofollow" href="{{$.BeforeSourcePath}}/{{PathEscapeSegments .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> {{else}} - <a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> + <a class="ui basic tiny button" rel="nofollow" href="{{$.SourcePath}}/{{PathEscapeSegments .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> {{end}} {{end}} </div> diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index ce99ccd9e9..9ec42a8d11 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -18,11 +18,11 @@ {{ .OriginalAuthor }} </span> <span class="text grey"> - {{$.root.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} + {{$.root.i18n.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} </span> <span class="text migrate"> {{if $.root.Repository.OriginalURL}} - ({{$.root.i18n.Tr "repo.migrated_from" $.root.Repository.OriginalURL $.root.Repository.GetOriginalURLHostname | Safe }}) + ({{$.root.i18n.Tr "repo.migrated_from" ($.root.Repository.OriginalURL | Escape) ($.root.Repository.GetOriginalURLHostname | Escape) | Safe }}) {{end}} </span> {{else}} @@ -30,7 +30,7 @@ <a {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}> {{.Poster.GetDisplayName}} </a> - {{$.root.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} + {{$.root.i18n.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} </span> {{end}} </div> diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index 54ea461587..51198f4ebf 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -33,7 +33,7 @@ {{- end -}} {{- end -}} <div class="ui segment choose branch"> - <a href="{{$.HeadRepo.Link}}/compare/{{EscapePound $.HeadBranch}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{$.BaseName}}/{{$.Repository.Name}}:{{end}}{{EscapePound $.BaseBranch}}" title="{{.i18n.Tr "repo.pulls.switch_head_and_base"}}">{{svg "octicon-git-compare"}}</a> + <a href="{{$.HeadRepo.Link}}/compare/{{PathEscapeSegments $.HeadBranch}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{PathEscape $.BaseName}}/{{PathEscape $.Repository.Name}}:{{end}}{{PathEscapeSegments $.BaseBranch}}" title="{{.i18n.Tr "repo.pulls.switch_head_and_base"}}">{{svg "octicon-git-compare"}}</a> <div class="ui floating filter dropdown" data-no-results="{{.i18n.Tr "repo.pulls.no_results"}}"> <div class="ui basic small button"> <span class="text">{{if $.PageIsComparePull}}{{.i18n.Tr "repo.pulls.compare_base"}}{{else}}{{.i18n.Tr "repo.compare.compare_base"}}{{end}}: {{$BaseCompareName}}:{{$.BaseBranch}}</span> @@ -62,47 +62,47 @@ </div> <div class="scrolling menu reference-list-menu base-branch-list"> {{range .Branches}} - <div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound $.HeadBranch}}">{{$BaseCompareName}}:{{.}}</div> + <div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{end}}{{PathEscapeSegments $.HeadBranch}}">{{$BaseCompareName}}:{{.}}</div> {{end}} {{if not .PullRequestCtx.SameRepo}} {{range .HeadBranches}} - <div class="item" data-url="{{$.HeadRepo.Link}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$HeadCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.HeadRepo.Link}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{PathEscapeSegments $.HeadBranch}}">{{$HeadCompareName}}:{{.}}</div> {{end}} {{end}} {{if .OwnForkRepo}} {{range .OwnForkRepoBranches}} - <div class="item" data-url="{{$.OwnForkRepo.Link}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$OwnForkCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.OwnForkRepo.Link}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{PathEscapeSegments $.HeadBranch}}">{{$OwnForkCompareName}}:{{.}}</div> {{end}} {{end}} {{if .RootRepo}} {{range .RootRepoBranches}} - <div class="item" data-url="{{$.RootRepo.Link}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$RootRepoCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RootRepo.Link}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{PathEscapeSegments $.HeadBranch}}">{{$RootRepoCompareName}}:{{.}}</div> {{end}} {{end}} </div> <div class="scrolling menu reference-list-menu base-tag-list" style="display: none"> {{range .Tags}} - <div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound $.HeadBranch}}">{{$BaseCompareName}}:{{.}}</div> + <div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{end}}{{PathEscapeSegments $.HeadBranch}}">{{$BaseCompareName}}:{{.}}</div> {{end}} {{if not .PullRequestCtx.SameRepo}} {{range .HeadTags}} - <div class="item" data-url="{{$.HeadRepo.Link}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$HeadCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.HeadRepo.Link}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{PathEscapeSegments $.HeadBranch}}">{{$HeadCompareName}}:{{.}}</div> {{end}} {{end}} {{if .OwnForkRepo}} {{range .OwnForkRepoTags}} - <div class="item" data-url="{{$.OwnForkRepo.Link}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$OwnForkCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.OwnForkRepo.Link}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{PathEscapeSegments $.HeadBranch}}">{{$OwnForkCompareName}}:{{.}}</div> {{end}} {{end}} {{if .RootRepo}} {{range .RootRepoTags}} - <div class="item" data-url="{{$.RootRepo.Link}}/compare/{{EscapePound .}}{{$.CompareSeparator}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$RootRepoCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RootRepo.Link}}/compare/{{PathEscapeSegments .}}{{$.CompareSeparator}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{PathEscapeSegments $.HeadBranch}}">{{$RootRepoCompareName}}:{{.}}</div> {{end}} {{end}} </div> </div> </div> - <a href="{{.RepoLink}}/compare/{{EscapePound .BaseBranch}}{{.OtherCompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound $.HeadBranch}}" title="{{.i18n.Tr "repo.pulls.switch_comparison_type"}}">{{.CompareSeparator}}</a> + <a href="{{.RepoLink}}/compare/{{PathEscapeSegments .BaseBranch}}{{.OtherCompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{end}}{{PathEscapeSegments $.HeadBranch}}" title="{{.i18n.Tr "repo.pulls.switch_comparison_type"}}">{{.CompareSeparator}}</a> <div class="ui floating filter dropdown"> <div class="ui basic small button"> <span class="text">{{if $.PageIsComparePull}}{{.i18n.Tr "repo.pulls.compare_compare"}}{{else}}{{.i18n.Tr "repo.compare.compare_head"}}{{end}}: {{$HeadCompareName}}:{{$.HeadBranch}}</span> @@ -131,41 +131,41 @@ </div> <div class="scrolling menu reference-list-menu head-branch-list"> {{range .HeadBranches}} - <div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound .}}">{{$HeadCompareName}}:{{.}}</div> + <div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{end}}{{PathEscapeSegments .}}">{{$HeadCompareName}}:{{.}}</div> {{end}} {{if not .PullRequestCtx.SameRepo}} {{range .Branches}} - <div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{$.BaseName}}/{{$.Repository.Name}}:{{EscapePound .}}">{{$BaseCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{PathEscape $.BaseName}}/{{PathEscape $.Repository.Name}}:{{PathEscapeSegments .}}">{{$BaseCompareName}}:{{.}}</div> {{end}} {{end}} {{if .OwnForkRepo}} {{range .OwnForkRepoBranches}} - <div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{$.OwnForkRepo.OwnerName}}/{{$.OwnForkRepo.Name}}:{{EscapePound .}}">{{$OwnForkCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{PathEscape $.OwnForkRepo.OwnerName}}/{{PathEscape $.OwnForkRepo.Name}}:{{PathEscapeSegments .}}">{{$OwnForkCompareName}}:{{.}}</div> {{end}} {{end}} {{if .RootRepo}} {{range .RootRepoBranches}} - <div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{$.RootRepo.OwnerName}}/{{$.RootRepo.Name}}:{{EscapePound .}}">{{$RootRepoCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{PathEscape $.RootRepo.OwnerName}}/{{PathEscape $.RootRepo.Name}}:{{PathEscapeSegments .}}">{{$RootRepoCompareName}}:{{.}}</div> {{end}} {{end}} </div> <div class="scrolling menu reference-list-menu head-tag-list" style="display: none"> {{range .HeadTags}} - <div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound .}}">{{$HeadCompareName}}:{{.}}</div> + <div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{if not $.PullRequestCtx.SameRepo}}{{PathEscape $.HeadUser.Name}}/{{PathEscape $.HeadRepo.Name}}:{{end}}{{PathEscapeSegments .}}">{{$HeadCompareName}}:{{.}}</div> {{end}} {{if not .PullRequestCtx.SameRepo}} {{range .Tags}} - <div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{$.BaseName}}/{{$.Repository.Name}}:{{EscapePound .}}">{{$BaseCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{PathEscape $.BaseName}}/{{PathEscape $.Repository.Name}}:{{PathEscapeSegments .}}">{{$BaseCompareName}}:{{.}}</div> {{end}} {{end}} {{if .OwnForkRepo}} {{range .OwnForkRepoTags}} - <div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{$.OwnForkRepo.OwnerName}}/{{$.OwnForkRepo.Name}}:{{EscapePound .}}">{{$OwnForkCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{PathEscape $.OwnForkRepo.OwnerName}}/{{PathEscape $.OwnForkRepo.Name}}:{{PathEscapeSegments .}}">{{$OwnForkCompareName}}:{{.}}</div> {{end}} {{end}} {{if .RootRepo}} {{range .RootRepoTags}} - <div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}{{$.CompareSeparator}}{{$.RootRepo.OwnerName}}/{{$.RootRepo.Name}}:{{EscapePound .}}">{{$RootRepoCompareName}}:{{.}}</div> + <div class="item" data-url="{{$.RepoLink}}/compare/{{PathEscapeSegments $.BaseBranch}}{{$.CompareSeparator}}{{PathEscape $.RootRepo.OwnerName}}/{{PathEscape $.RootRepo.Name}}:{{PathEscapeSegments .}}">{{$RootRepoCompareName}}:{{.}}</div> {{end}} {{end}} </div> @@ -188,7 +188,7 @@ {{else if and .PageIsComparePull (gt .CommitCount 0)}} {{if .HasPullRequest}} <div class="ui segment"> - {{.i18n.Tr "repo.pulls.has_pull_request" $.RepoLink $.RepoRelPath .PullRequest.Index | Safe}} + {{.i18n.Tr "repo.pulls.has_pull_request" (Escape $.RepoLink) (Escape $.RepoRelPath) .PullRequest.Index | Safe}} </div> {{else}} {{if and $.IsSigned (not .Repository.IsArchived)}} diff --git a/templates/repo/diff/image_diff.tmpl b/templates/repo/diff/image_diff.tmpl index 3d100ac992..63481288c9 100644 --- a/templates/repo/diff/image_diff.tmpl +++ b/templates/repo/diff/image_diff.tmpl @@ -1,9 +1,7 @@ -{{ $imagePathOld := printf "%s/%s" .root.BeforeRawPath (EscapePound .file.OldName) }} -{{ $imagePathNew := printf "%s/%s" .root.RawPath (EscapePound .file.Name) }} {{if or .blobBase .blobHead}} <tr> <td colspan="2"> - <div class="image-diff" data-path-before="{{$imagePathOld}}" data-path-after="{{$imagePathNew}}"> + <div class="image-diff" data-path-before="{{.root.BeforeRawPath}}/{{PathEscapeSegments .file.OldName}}" data-path-after="{{.root.RawPath}}/{{PathEscapeSegments .file.Name}}"> <div class="ui secondary pointing tabular top attached borderless menu stackable new-menu"> <div class="new-menu-inner"> <a class="item active" data-tab="diff-side-by-side-{{ .file.Index }}">{{.root.i18n.Tr "repo.diff.image.side_by_side"}}</a> diff --git a/templates/repo/diff/options_dropdown.tmpl b/templates/repo/diff/options_dropdown.tmpl index 92d870ea8a..a6ac49210f 100644 --- a/templates/repo/diff/options_dropdown.tmpl +++ b/templates/repo/diff/options_dropdown.tmpl @@ -7,11 +7,11 @@ <a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.patch" download="{{.Issue.Index}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a> <a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.diff" download="{{.Issue.Index}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a> {{else if $.PageIsWiki}} - <a class="item" href="{{$.RepoLink}}/wiki/commit/{{.Commit.ID.String}}.patch" download="{{ShortSha .Commit.ID.String}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a> - <a class="item" href="{{$.RepoLink}}/wiki/commit/{{.Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a> + <a class="item" href="{{$.RepoLink}}/wiki/commit/{{PathEscape .Commit.ID.String}}.patch" download="{{ShortSha .Commit.ID.String}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a> + <a class="item" href="{{$.RepoLink}}/wiki/commit/{{PathEscape .Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a> {{else if .Commit.ID.String}} - <a class="item" href="{{$.RepoLink}}/commit/{{.Commit.ID.String}}.patch" download="{{ShortSha .Commit.ID.String}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a> - <a class="item" href="{{$.RepoLink}}/commit/{{.Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a> + <a class="item" href="{{$.RepoLink}}/commit/{{PathEscape .Commit.ID.String}}.patch" download="{{ShortSha .Commit.ID.String}}.patch">{{.i18n.Tr "repo.diff.download_patch"}}</a> + <a class="item" href="{{$.RepoLink}}/commit/{{PathEscape .Commit.ID.String}}.diff" download="{{ShortSha .Commit.ID.String}}.diff">{{.i18n.Tr "repo.diff.download_diff"}}</a> {{end}} </div> </div> diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl index ca07085871..fb6977e204 100644 --- a/templates/repo/diff/section_split.tmpl +++ b/templates/repo/diff/section_split.tmpl @@ -7,17 +7,17 @@ {{if eq .GetType 4}} <td class="lines-num lines-num-old"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} - <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> + <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-down"}} </a> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} - <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> + <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-up"}} </a> {{end}} {{if eq $line.GetExpandDirection 2}} - <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> + <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold"}} </a> {{end}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index e89f1a09f7..57e8fb9a16 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -6,17 +6,17 @@ {{if eq .GetType 4}} <td colspan="2" class="lines-num"> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} - <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> + <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-down"}} </a> {{end}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} - <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> + <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold-up"}} </a> {{end}} {{if eq $line.GetExpandDirection 2}} - <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> + <a role="button" class="blob-excerpt" data-url="{{$.root.RepoLink}}/blob_excerpt/{{PathEscape $.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"> {{svg "octicon-fold"}} </a> {{end}} diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index cd417b427f..e42c2a2d8a 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -70,5 +70,5 @@ <button id="commit-button" type="submit" class="ui green button"> {{if eq .commit_choice "commit-to-new-branch"}}{{.i18n.Tr "repo.editor.propose_file_change"}}{{else}}{{.i18n.Tr "repo.editor.commit_changes"}}{{end}} </button> - <a class="ui button red" href="{{EscapePound $.BranchLink}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.editor.cancel"}}</a> + <a class="ui button red" href="{{$.BranchLink}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.editor.cancel"}}</a> </div> diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index b7e1589aa1..a342bb03e0 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -10,7 +10,7 @@ <div class="ui secondary menu"> <div class="fitted item treepath"> <div class="ui breadcrumb field {{if .Err_TreePath}}error{{end}}"> - <a class="section" href="{{EscapePound $.BranchLink}}">{{.Repository.Name}}</a> + <a class="section" href="{{$.BranchLink}}">{{.Repository.Name}}</a> {{ $n := len .TreeNames}} {{ $l := Subtract $n 1}} {{range $i, $v := .TreeNames}} @@ -19,10 +19,10 @@ <input id="file-name" value="{{$v}}" placeholder="{{$.i18n.Tr "repo.editor.name_your_file"}}" data-editorconfig="{{$.Editorconfig}}" required autofocus> <span class="poping up" data-content="{{$.i18n.Tr "repo.editor.filename_help"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-info"}}</span> {{else}} - <span class="section"><a href="{{EscapePound $.BranchLink}}/{{index $.TreePaths $i | EscapePound}}">{{$v}}</a></span> + <span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span> {{end}} {{end}} - <span>{{.i18n.Tr "repo.editor.or"}} <a href="{{EscapePound $.BranchLink}}{{if not .IsNewFile}}/{{EscapePound .TreePath}}{{end}}">{{.i18n.Tr "repo.editor.cancel_lower"}}</a></span> + <span>{{.i18n.Tr "repo.editor.or"}} <a href="{{$.BranchLink}}{{if not .IsNewFile}}/{{PathEscapeSegments .TreePath}}{{end}}">{{.i18n.Tr "repo.editor.cancel_lower"}}</a></span> <input type="hidden" id="tree_path" name="tree_path" value="{{.TreePath}}" required> </div> </div> @@ -31,8 +31,8 @@ <div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff"> <a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a> {{if not .IsNewFile}} - <a class="item" data-tab="preview" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL | EscapePound}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.i18n.Tr "preview"}}</a> - <a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | EscapePound}}/{{.TreePath | EscapePound}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{.i18n.Tr "repo.editor.preview_changes"}}</a> + <a class="item" data-tab="preview" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.i18n.Tr "preview"}}</a> + <a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{.i18n.Tr "repo.editor.preview_changes"}}</a> {{end}} </div> <div class="ui bottom attached active tab segment" data-tab="write"> diff --git a/templates/repo/editor/upload.tmpl b/templates/repo/editor/upload.tmpl index fb00615abd..5fbb42a446 100644 --- a/templates/repo/editor/upload.tmpl +++ b/templates/repo/editor/upload.tmpl @@ -8,7 +8,7 @@ <div class="ui secondary menu"> <div class="item fitted treepath"> <div class="ui breadcrumb field {{if .Err_TreePath}}error{{end}}"> - <a class="section" href="{{EscapePound $.BranchLink}}">{{.Repository.Name}}</a> + <a class="section" href="{{$.BranchLink}}">{{.Repository.Name}}</a> {{ $n := len .TreeNames}} {{ $l := Subtract $n 1}} {{range $i, $v := .TreeNames}} @@ -17,10 +17,10 @@ <input type="text" id="file-name" value="{{$v}}" placeholder="{{$.i18n.Tr "repo.editor.add_subdir"}}" autofocus> <span class="poping up" data-content="{{$.i18n.Tr "repo.editor.filename_help"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-info"}}</span> {{else}} - <span class="section"><a href="{{EscapePound $.BranchLink}}/{{index $.TreePaths $i | EscapePound}}">{{$v}}</a></span> + <span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span> {{end}} {{end}} - <span>{{.i18n.Tr "repo.editor.or"}} <a href="{{EscapePound $.BranchLink}}{{if not .IsNewFile}}/{{EscapePound .TreePath}}{{end}}">{{.i18n.Tr "repo.editor.cancel_lower"}}</a></span> + <span>{{.i18n.Tr "repo.editor.or"}} <a href="{{$.BranchLink}}{{if not .IsNewFile}}/{{.TreePath | PathEscapeSegments}}{{end}}">{{.i18n.Tr "repo.editor.cancel_lower"}}</a></span> <input type="hidden" id="tree_path" name="tree_path" value="{{.TreePath}}" required> </div> </div> diff --git a/templates/repo/forks.tmpl b/templates/repo/forks.tmpl index 192291275f..ff6e9949d3 100644 --- a/templates/repo/forks.tmpl +++ b/templates/repo/forks.tmpl @@ -10,9 +10,9 @@ <div class="item"> {{avatar .Owner}} <div class="link"> - <a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a> + <a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / - <a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a> + <a href="{{.Link}}">{{.Name}}</a> </div> </div> {{end}} diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index 3427aed58c..d054462ebc 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -21,7 +21,7 @@ {{$class = (printf "%s%s" $class " isWarning")}} {{end}} {{end}} - <a href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Rev}}" rel="nofollow" class="{{$class}}"> + <a href="{{$.RepoLink}}/commit/{{$commit.Rev|PathEscape}}" rel="nofollow" class="{{$class}}"> <span class="shortsha">{{ShortSha $commit.Commit.ID.String}}</span> {{- if $commit.Commit.Signature -}} <span class="shortsha-pad"></span>{{template "repo/shabox_badge" dict "root" $ "verification" $commit.Verification}} @@ -44,7 +44,7 @@ {{svg "octicon-tag" 16 "mr-2"}}{{.ShortName}} </a> {{else if eq $refGroup "remotes"}} - <a class="ui labelled icon button basic tiny" href="{{$.RepoLink}}/src/commit/{{$commit.Rev}}"> + <a class="ui labelled icon button basic tiny" href="{{$.RepoLink}}/src/commit/{{$commit.Rev|PathEscape}}"> {{svg "octicon-cross-reference" 16 "mr-2"}}{{.ShortName}} </a> {{else if eq $refGroup "heads"}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 49a651e6c5..765de1a146 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -10,7 +10,7 @@ {{else}} {{template "repo/icon" .}} {{end}} - <a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a> + <a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> <div class="mx-2">/</div> <a href="{{$.RepoLink}}">{{.Name}}</a> <div class="labels df ac fw"> @@ -37,8 +37,8 @@ </div> </div> {{if .IsMirror}}<div class="fork-flag">{{$.i18n.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener noreferrer" href="{{if .SanitizedOriginalURL}}{{.SanitizedOriginalURL}}{{else}}{{(MirrorRemoteAddress $.Mirror).Address}}{{end}}">{{if .SanitizedOriginalURL}}{{.SanitizedOriginalURL}}{{else}}{{(MirrorRemoteAddress $.Mirror).Address}}{{end}}</a></div>{{end}} - {{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{SubStr .BaseRepo.RelLink 1 -1}}</a></div>{{end}} - {{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{SubStr .TemplateRepo.RelLink 1 -1}}</a></div>{{end}} + {{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{.BaseRepo.FullName}}</a></div>{{end}} + {{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{.TemplateRepo.FullName}}</a></div>{{end}} </div> {{if not .IsBeingCreated}} <div class="repo-buttons"> @@ -103,7 +103,7 @@ {{if not .Repository.IsBeingCreated}} <div class="ui tabular stackable menu navbar"> {{if .Permission.CanRead $.UnitTypeCode}} - <a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}"> + <a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL}}{{end}}"> {{svg "octicon-code"}} {{.i18n.Tr "repo.code"}} </a> {{end}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index eb6ee8c0a2..40e782a605 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -64,30 +64,30 @@ {{if eq $n 0}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} <div class="fitted item mx-0"> - <a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}{{if .BaseRepo.IsFork}}/{{.Repository.Name}}{{end}}:{{end}}{{.BranchName | EscapePound}}"> + <a href="{{.BaseRepo.Link}}/compare/{{PathEscapeSegments .BaseRepo.DefaultBranch}}...{{if ne .Repository.Owner.Name .BaseRepo.Owner.Name}}{{PathEscape .Repository.Owner.Name}}{{if .BaseRepo.IsFork}}/{{PathEscape .Repository.Name}}{{end}}:{{end}}{{PathEscapeSegments .BranchName}}"> <button id="new-pull-request" class="ui compact basic button">{{if .PullRequestCtx.Allowed}}{{.i18n.Tr "repo.pulls.compare_changes"}}{{else}}{{.i18n.Tr "action.compare_branch"}}{{end}}</button> </a> </div> {{end}} {{else}} - <div class="fitted item"><span class="ui breadcrumb repo-path"><a class="section" href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}" title="{{.Repository.Name}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section" title="{{$v}}">{{EllipsisString $v 30}}</span>{{else}}{{ $p := index $.Paths $i}}<span class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}" title="{{$v}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span></div> + <div class="fitted item"><span class="ui breadcrumb repo-path"><a class="section" href="{{.RepoLink}}/src/{{.BranchNameSubURL}}" title="{{.Repository.Name}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section" title="{{$v}}">{{EllipsisString $v 30}}</span>{{else}}{{ $p := index $.Paths $i}}<span class="section"><a href="{{$.BranchLink}}/{{PathEscapeSegments $p}}" title="{{$v}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span></div> {{end}} <div class="right fitted item mr-0" id="file-buttons"> <div class="ui tiny primary buttons"> {{if .Repository.CanEnableEditor}} {{if .CanAddFile}} - <a href="{{.RepoLink}}/_new/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" class="ui button"> + <a href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" class="ui button"> {{.i18n.Tr "repo.editor.new_file"}} </a> {{end}} {{if .CanUploadFile}} - <a href="{{.RepoLink}}/_upload/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" class="ui button"> + <a href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" class="ui button"> {{.i18n.Tr "repo.editor.upload_file"}} </a> {{end}} {{end}} {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame) }} - <a href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}" class="ui button"> + <a href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}" class="ui button"> {{.i18n.Tr "repo.file_history"}} </a> {{end}} @@ -113,9 +113,9 @@ <button id="download-btn" class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right"> {{svg "octicon-download"}} <div class="menu"> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_zip"}}</a> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_tar"}}</a> - <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.bundle">{{svg "octicon-package" 16 "mr-3"}}{{.i18n.Tr "repo.download_bundle"}}</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.BranchName}}.zip">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_zip"}}</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.BranchName}}.tar.gz">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_tar"}}</a> + <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.BranchName}}.bundle">{{svg "octicon-package" 16 "mr-3"}}{{.i18n.Tr "repo.download_bundle"}}</a> <a class="item" href="vscode://vscode.git/clone?url={{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}">{{svg "gitea-vscode" 16 "mr-3"}}{{.i18n.Tr "repo.clone_in_vsc"}}</a> </div> </button> diff --git a/templates/repo/issue/labels/label.tmpl b/templates/repo/issue/labels/label.tmpl index a6d52fe544..0afe5cb6e7 100644 --- a/templates/repo/issue/labels/label.tmpl +++ b/templates/repo/issue/labels/label.tmpl @@ -1,7 +1,7 @@ <a class="ui label item {{if not .label.IsChecked}}hide{{end}}" id="label_{{.label.ID}}" - href="{{.root.RepoLink}}/{{if or .root.IsPull .root.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.label.ID}}" + href="{{.root.RepoLink}}/{{if or .root.IsPull .root.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.label.ID}}"{{/* FIXME: use .root.Issue.Link or create .root.Link */}} style="color: {{.label.ForegroundColor}}; background-color: {{.label.Color}}" title="{{.label.Description | RenderEmojiPlain}}" > diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 64b68f145e..63d746f570 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -14,13 +14,13 @@ {{if .PageIsIssueList}} <a class="ui green button" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{.i18n.Tr "repo.issues.new"}}</a> {{else}} - <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.Repository.Link}}/compare/{{.Repository.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | EscapePound}}{{end}}">{{.i18n.Tr "repo.pulls.new"}}</a> + <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.Repository.Link}}/compare/{{.Repository.DefaultBranch | PathEscapeSegments}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{PathEscape .Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | PathEscapeSegments}}{{end}}">{{.i18n.Tr "repo.pulls.new"}}</a> {{end}} </div> {{else}} {{if not .PageIsIssueList}} <div class="column right aligned"> - <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.PullRequestCtx.BaseRepo.Link}}/compare/{{.PullRequestCtx.BaseRepo.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | EscapePound}}{{end}}">{{$.i18n.Tr "action.compare_commits_general"}}</a> + <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.PullRequestCtx.BaseRepo.Link}}/compare/{{.PullRequestCtx.BaseRepo.DefaultBranch | PathEscapeSegments}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{PathEscape .Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | PathEscapeSegments}}{{end}}">{{$.i18n.Tr "action.compare_commits_general"}}</a> </div> {{end}} {{end}} diff --git a/templates/repo/issue/view.tmpl b/templates/repo/issue/view.tmpl index 39d3b77017..acfd25e7e0 100644 --- a/templates/repo/issue/view.tmpl +++ b/templates/repo/issue/view.tmpl @@ -11,7 +11,7 @@ {{if .PageIsIssueList}} <a class="ui green button" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{.i18n.Tr "repo.issues.new"}}</a> {{else}} - <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> + <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | PathEscapeSegments}}...{{.PullRequestCtx.HeadInfoSubURL}}">{{.i18n.Tr "repo.pulls.new"}}</a> {{end}} </div> {{end}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 29c8626596..687f9133b1 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -35,15 +35,15 @@ {{ .Issue.OriginalAuthor }} </span> <span class="text grey"> - {{ .i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe }} + {{ .i18n.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr | Safe }} </span> <span class="text migrate"> - {{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname | Safe }}){{end}} + {{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" (.Repository.OriginalURL|Escape) (.Repository.GetOriginalURLHostname|Escape) | Safe }}){{end}} </span> {{else}} <span class="text grey"> <a class="author"{{if gt .Issue.Poster.ID 0}} href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a> - {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} + {{.i18n.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr | Safe}} </span> {{end}} </div> @@ -180,7 +180,7 @@ {{end}} {{else}} <div class="ui warning message"> - {{.i18n.Tr "repo.issues.sign_in_require_desc" .SignInLink | Safe}} + {{.i18n.Tr "repo.issues.sign_in_require_desc" (.SignInLink|Escape) | Safe}} </div> {{end}} {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 57ec007bed..9907246d9f 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -28,17 +28,17 @@ {{ .OriginalAuthor }} </span> <span class="text grey"> - {{$.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} {{if $.Repository.OriginalURL}} + {{$.i18n.Tr "repo.issues.commented_at" (.Issue.HashTag|Escape) $createdStr | Safe}} {{if $.Repository.OriginalURL}} </span> <span class="text migrate"> - ({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}} + ({{$.i18n.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe }}){{end}} </span> {{else}} <span class="text grey"> <a class="author"{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}> {{.Poster.GetDisplayName}} </a> - {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} + {{$.i18n.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdStr | Safe}} </span> {{end}} </div> @@ -124,18 +124,18 @@ </a> <span class="text grey"> <a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a> - {{$link := printf "%s/commit/%s" $.Repository.HTMLURL $.Issue.PullRequest.MergedCommitID}} + {{$link := printf "%s/commit/%s" $.Repository.HTMLURL ($.Issue.PullRequest.MergedCommitID|PathEscape)}} {{if eq $.Issue.PullRequest.Status 3}} - {{$.i18n.Tr "repo.issues.manually_pull_merged_at" $link (ShortSha $.Issue.PullRequest.MergedCommitID) $.BaseTarget $createdStr | Str2html}} + {{$.i18n.Tr "repo.issues.manually_pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Str2html}} {{else}} - {{$.i18n.Tr "repo.issues.pull_merged_at" $link (ShortSha $.Issue.PullRequest.MergedCommitID) $.BaseTarget $createdStr | Str2html}} + {{$.i18n.Tr "repo.issues.pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Str2html}} {{end}} </span> </div> {{else if eq .Type 3 5 6}} {{ $refFrom:= "" }} {{if ne .RefRepoID .Issue.RepoID}} - {{ $refFrom = $.i18n.Tr "repo.issues.ref_from" .RefRepo.FullName }} + {{ $refFrom = $.i18n.Tr "repo.issues.ref_from" (.RefRepo.FullName|Escape) }} {{end}} {{ $refTr := "repo.issues.ref_issue_from" }} {{if .Issue.IsPull}} @@ -154,7 +154,7 @@ {{if eq .RefAction 3}}<del>{{end}} <span class="text grey"> <a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a> - {{$.i18n.Tr $refTr .EventTag $createdStr .RefCommentHTMLURL $refFrom | Safe}} + {{$.i18n.Tr $refTr (.EventTag|Escape) $createdStr (.RefCommentHTMLURL|Escape) $refFrom | Safe}} </span> {{if eq .RefAction 3}}</del>{{end}} @@ -414,7 +414,7 @@ {{ .OriginalAuthor }} </span> <span class="text grey"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}}</span> + <span class="text migrate">({{$.i18n.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe }}){{end}}</span> {{else}} <a class="author"{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>{{.Poster.GetDisplayName}}</a> {{end}} @@ -444,7 +444,7 @@ {{ .OriginalAuthor }} </span> <span class="text grey"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}}</span> + <span class="text migrate">({{$.i18n.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe }}){{end}}</span> {{else}} <a class="author"{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>{{.Poster.GetDisplayName}}</a> {{end}} @@ -542,11 +542,11 @@ {{ .OriginalAuthor }} </span> <span class="text grey"> {{if $.Repository.OriginalURL}}</span> - <span class="text migrate">({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}}</span> + <span class="text migrate">({{$.i18n.Tr "repo.migrated_from" ($.Repository.OriginalURL|Escape) ($.Repository.GetOriginalURLHostname|Escape) | Safe }}){{end}}</span> {{else}} <a class="author"{{if gt .Poster.ID 0}} href="{{.Poster.HomeLink}}"{{end}}>{{.Poster.GetDisplayName}}</a> {{end}} - {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdSubStr | Safe}} + {{$.i18n.Tr "repo.issues.commented_at" (.HashTag|Escape) $createdSubStr | Safe}} </span> </div> <div class="comment-header-right actions df ac"> @@ -712,7 +712,7 @@ <span class="text grey"> <a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a> {{ if .IsForcePush }} - {{$.i18n.Tr "repo.issues.force_push_codes" $.Issue.PullRequest.HeadBranch (ShortSha .OldCommit) ($.Issue.Repo.CommitLink .OldCommit) (ShortSha .NewCommit) ($.Issue.Repo.CommitLink .NewCommit) $createdStr | Safe}} + {{$.i18n.Tr "repo.issues.force_push_codes" ($.Issue.PullRequest.HeadBranch|Escape) (ShortSha .OldCommit) (($.Issue.Repo.CommitLink .OldCommit)|Escape) (ShortSha .NewCommit) (($.Issue.Repo.CommitLink .NewCommit)|Escape) $createdStr | Safe}} {{else}} {{$.i18n.Tr (TrN $.i18n.Lang (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n") (len .Commits) $createdStr | Safe}} {{end}} diff --git a/templates/repo/issue/view_content/context_menu.tmpl b/templates/repo/issue/view_content/context_menu.tmpl index 71ce03a4ca..2c2129caac 100644 --- a/templates/repo/issue/view_content/context_menu.tmpl +++ b/templates/repo/issue/view_content/context_menu.tmpl @@ -6,13 +6,9 @@ <div class="menu"> {{ $referenceUrl := "" }} {{ if .issue }} - {{ if .ctx.Issue.IsPull}} - {{ $referenceUrl = Printf "%s%s/pulls/%d#%s" AppUrl .ctx.Repository.FullName .ctx.Issue.Index .item.HashTag }} - {{ else }} - {{ $referenceUrl = Printf "%s%s/issues/%d#%s" AppUrl .ctx.Repository.FullName .ctx.Issue.Index .item.HashTag }} - {{ end }} + {{ $referenceUrl = Printf "%s#%s" .ctx.Issue.HTMLURL .item.HashTag }} {{ else }} - {{ $referenceUrl = Printf "%s%s/pulls/%d/files#%s" AppUrl .ctx.Repository.FullName .ctx.Issue.Index .item.HashTag }} + {{ $referenceUrl = Printf "%s/files#%s" .ctx.Issue.HTMLURL .item.HashTag }} {{ end }} <div class="item context" data-clipboard-text="{{$referenceUrl}}">{{.ctx.i18n.Tr "repo.issues.context.copy_link"}}</div> <div class="item context quote-reply {{if .diff}}quote-reply-diff{{end}}" data-target="{{.item.ID}}">{{.ctx.i18n.Tr "repo.issues.context.quote_reply"}}</div> diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 706cc0eac7..a684edfb3a 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -86,7 +86,7 @@ <div class="ui divider"></div> <div class="review-item"> <div class="review-item-left"> - <a href="{{$.Repository.OriginalURL}}" class="ui poping up" data-content="{{$.i18n.Tr "repo.migrated_from_fake" $.Repository.GetOriginalURLHostname | Safe }}"> + <a href="{{$.Repository.OriginalURL}}" class="ui poping up" data-content="{{$.i18n.Tr "repo.migrated_from_fake" ($.Repository.GetOriginalURLHostname|Escape) | Safe }}"> <span class="text black "> {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{ .OriginalAuthor }} @@ -133,11 +133,11 @@ {{if .Issue.PullRequest.HasMerged}} <div class="item text"> {{if .Issue.PullRequest.MergedCommitID}} - {{$link := printf "%s/commit/%s" $.Repository.HTMLURL .Issue.PullRequest.MergedCommitID}} + {{$link := printf "%s/commit/%s" $.Repository.HTMLURL (.Issue.PullRequest.MergedCommitID|PathEscape)}} {{if eq $.Issue.PullRequest.Status 3}} - {{$.i18n.Tr "repo.pulls.manually_merged_as" $link (ShortSha .Issue.PullRequest.MergedCommitID) | Safe}} + {{$.i18n.Tr "repo.pulls.manually_merged_as" ($link|Escape) (ShortSha .Issue.PullRequest.MergedCommitID) | Safe}} {{else}} - {{$.i18n.Tr "repo.pulls.merged_as" $link (ShortSha .Issue.PullRequest.MergedCommitID) | Safe}} + {{$.i18n.Tr "repo.pulls.merged_as" ($link|Escape) (ShortSha .Issue.PullRequest.MergedCommitID) | Safe}} {{end}} {{else}} {{$.i18n.Tr "repo.pulls.has_merged"}} @@ -177,7 +177,7 @@ {{$.i18n.Tr "repo.pulls.data_broken"}} </div> {{else if .IsPullWorkInProgress}} - <div class="item toggle-wip df ac sb" data-title="{{.Issue.Title}}" data-wip-prefix="{{(.WorkInProgressPrefix|Escape)}}" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title"> + <div class="item toggle-wip df ac sb" data-title="{{.Issue.Title}}" data-wip-prefix="{{(.WorkInProgressPrefix|Escape)}}" data-update-url="{{.Issue.Link}}/title"> <div> <i class="icon icon-octicon">{{svg "octicon-x"}}</i> {{$.i18n.Tr "repo.pulls.cannot_merge_work_in_progress" }} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index ed700617ea..a72a9216a5 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -79,7 +79,7 @@ {{end}} {{range .OriginalReviews}} <div class="item" style="margin-bottom: 10px;"> - <a href="{{$.Repository.OriginalURL}}" class="ui poping up" data-content="{{$.i18n.Tr "repo.migrated_from_fake" $.Repository.GetOriginalURLHostname | Safe }}"> + <a href="{{$.Repository.OriginalURL}}" class="ui poping up" data-content="{{$.i18n.Tr "repo.migrated_from_fake" ($.Repository.GetOriginalURLHostname|Escape) | Safe }}"> <span class="text black"> {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} {{ .OriginalAuthor }} @@ -97,7 +97,7 @@ </div> </div> {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .HasMerged) (not .Issue.IsClosed) (not .IsPullWorkInProgress)}} - <div class="toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{(index .PullRequestWorkInProgressPrefixes 0| Escape)}}" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title"> + <div class="toggle-wip" data-title="{{.Issue.Title}}" data-wip-prefix="{{(index .PullRequestWorkInProgressPrefixes 0| Escape)}}" data-update-url="{{.Issue.Link}}/title"> <a class="muted"> {{.i18n.Tr "repo.pulls.still_in_progress"}} {{.i18n.Tr "repo.pulls.add_prefix" (index .PullRequestWorkInProgressPrefixes 0| Escape) | Safe}} </a> @@ -321,7 +321,7 @@ <div class="ui watching"> <span class="text"><strong>{{.i18n.Tr "notification.notifications"}}</strong></span> <div class="mt-3"> - <form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/watch"> + <form method="POST" action="{{.Issue.Link}}/watch"> <input type="hidden" name="watch" value="{{if $.IssueWatch.IsWatching}}0{{else}}1{{end}}" /> {{$.CsrfTokenHtml}} <button class="fluid ui button df jc"> @@ -343,10 +343,10 @@ <div class="ui timetrack"> <span class="text"><strong>{{.i18n.Tr "repo.issues.tracker"}}</strong></span> <div class="mt-3"> - <form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/times/stopwatch/toggle" id="toggle_stopwatch_form"> + <form method="POST" action="{{.Issue.Link}}/times/stopwatch/toggle" id="toggle_stopwatch_form"> {{$.CsrfTokenHtml}} </form> - <form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/times/stopwatch/cancel" id="cancel_stopwatch_form"> + <form method="POST" action="{{.Issue.Link}}/times/stopwatch/cancel" id="cancel_stopwatch_form"> {{$.CsrfTokenHtml}} </form> {{if $.IsStopwatchRunning}} @@ -355,14 +355,14 @@ {{else}} {{if .HasUserStopwatch}} <div class="ui warning message"> - {{.i18n.Tr "repo.issues.tracking_already_started" .OtherStopwatchURL | Safe}} + {{.i18n.Tr "repo.issues.tracking_already_started" (.OtherStopwatchURL|Escape) | Safe}} </div> {{end}} <button class="ui fluid button poping up issue-start-time" data-content='{{.i18n.Tr "repo.issues.start_tracking"}}' data-position="top center" data-variation="small inverted">{{.i18n.Tr "repo.issues.start_tracking_short"}}</button> <div class="ui mini modal issue-start-time-modal"> <div class="header">{{.i18n.Tr "repo.issues.add_time"}}</div> <div class="content"> - <form method="POST" id="add_time_manual_form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/times/add" class="ui action input fluid"> + <form method="POST" id="add_time_manual_form" action="{{.Issue.Link}}/times/add" class="ui action input fluid"> {{$.CsrfTokenHtml}} <input placeholder='{{.i18n.Tr "repo.issues.add_time_hours"}}' type="number" name="hours"> <input placeholder='{{.i18n.Tr "repo.issues.add_time_minutes"}}' type="number" name="minutes" class="ui compact"> @@ -429,7 +429,7 @@ {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} <div {{if ne .Issue.DeadlineUnix 0}} style="display: none;"{{end}} id="deadlineForm"> - <form class="ui fluid action input issue-due-form" action="{{AppSubUrl}}/api/v1/repos/{{.Repository.Owner.Name}}/{{.Repository.Name}}/issues/{{.Issue.Index}}" method="post" id="update-issue-deadline-form"> + <form class="ui fluid action input issue-due-form" action="{{AppSubUrl}}/api/v1/repos/{{PathEscape .Repository.Owner.Name}}/{{PathEscape .Repository.Name}}/issues/{{.Issue.Index}}" method="post" id="update-issue-deadline-form"> {{$.CsrfTokenHtml}} <input required placeholder="{{.i18n.Tr "repo.issues.due_date_form"}}" {{if gt .Issue.DeadlineUnix 0}}value="{{.Issue.DeadlineUnix.Format "2006-01-02"}}"{{end}} type="date" name="deadlineDate" id="deadlineDate"> <button class="ui green icon button"> @@ -468,7 +468,7 @@ {{range .BlockingDependencies}} <div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} df ac sb"> <div class="item-left df jc fc f1"> - <a class="title" href="{{.Repository.Link}}/issues/{{.Issue.Index}}"> + <a class="title" href="{{.Issue.Link}}"> #{{.Issue.Index}} {{.Issue.Title | RenderEmoji}} </a> <div class="text small"> @@ -495,7 +495,7 @@ {{range .BlockedByDependencies}} <div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} df ac sb"> <div class="item-left df jc fc f1"> - <a class="title" href="{{.Repository.Link}}/{{if .Issue.IsPull}}pulls{{else}}issues{{end}}/{{.Issue.Index}}"> + <a class="title" href="{{.Issue.Link}}"> #{{.Issue.Index}} {{.Issue.Title | RenderEmoji}} </a> <div class="text small"> @@ -516,7 +516,7 @@ {{if and .CanCreateIssueDependencies (not .Repository.IsArchived)}} <div> - <form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/dependency/add" id="addDependencyForm"> + <form method="POST" action="{{.Issue.Link}}/dependency/add" id="addDependencyForm"> {{$.CsrfTokenHtml}} <div class="ui fluid action input"> <div class="ui search selection dropdown" id="new-dependency-drop-list" data-issue-id="{{.Issue.ID}}"> @@ -543,7 +543,7 @@ {{.i18n.Tr "repo.issues.dependency.remove_header"}} </div> <div class="content"> - <form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/dependency/delete" id="removeDependencyForm"> + <form method="POST" action="{{.Issue.Link}}/dependency/delete" id="removeDependencyForm"> {{$.CsrfTokenHtml}} <input type="hidden" value="" name="removeDependencyID" id="removeDependencyID"/> <input type="hidden" value="" name="dependencyType" id="dependencyType"/> @@ -601,7 +601,7 @@ {{end}} </div> - <form class="ui form" action="{{$.RepoLink}}/issues/{{.Issue.Index}}{{ if .Issue.IsLocked }}/unlock{{else}}/lock{{end}}" + <form class="ui form" action="{{.Issue.Link}}{{ if .Issue.IsLocked }}/unlock{{else}}/lock{{end}}" method="post"> {{.CsrfTokenHtml}} diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index a21e58068c..c4b391d97a 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -91,9 +91,9 @@ {{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.Lang }} <span class="time-desc"> {{if .Issue.OriginalAuthor }} - {{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr .Issue.OriginalAuthor | Safe}} + {{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}} {{else if gt .Issue.Poster.ID 0}} - {{$.i18n.Tr "repo.issues.opened_by" $createdStr .Issue.Poster.HomeLink (.Issue.Poster.GetDisplayName|Escape) | Safe}} + {{$.i18n.Tr "repo.issues.opened_by" $createdStr (.Issue.Poster.HomeLink|Escape) (.Issue.Poster.GetDisplayName|Escape) | Safe}} {{else}} {{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.Poster.GetDisplayName|Escape) | Safe}} {{end}} diff --git a/templates/repo/projects/view.tmpl b/templates/repo/projects/view.tmpl index d97a0f5942..f7d699d965 100644 --- a/templates/repo/projects/view.tmpl +++ b/templates/repo/projects/view.tmpl @@ -195,7 +195,7 @@ {{end}} {{end}} </span> - <a class="project-board-title vm" href="{{$.RepoLink}}/issues/{{.Index}}"> + <a class="project-board-title vm" href="{{.Link}}"> {{.Title}} </a> </div> @@ -204,9 +204,9 @@ #{{.Index}} {{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.Lang }} {{if .OriginalAuthor }} - {{$.i18n.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor | Safe}} + {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}} {{else if gt .Poster.ID 0}} - {{$.i18n.Tr .GetLastEventLabel $timeStr .Poster.HomeLink (.Poster.GetDisplayName | Escape) | Safe}} + {{$.i18n.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape) | Safe}} {{else}} {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}} {{end}} diff --git a/templates/repo/pulls/commits.tmpl b/templates/repo/pulls/commits.tmpl index ecfe09c1ec..7152e345c3 100644 --- a/templates/repo/pulls/commits.tmpl +++ b/templates/repo/pulls/commits.tmpl @@ -5,7 +5,7 @@ <div class="navbar"> {{template "repo/issue/navbar" .}} <div class="ui right"> - <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> + <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | PathEscapeSegments}}...{{.PullRequestCtx.HeadInfoSubURL}}">{{.i18n.Tr "repo.pulls.new"}}</a> </div> </div> <div class="ui divider"></div> diff --git a/templates/repo/pulls/files.tmpl b/templates/repo/pulls/files.tmpl index 60f47408c2..7866697629 100644 --- a/templates/repo/pulls/files.tmpl +++ b/templates/repo/pulls/files.tmpl @@ -5,7 +5,7 @@ <div class="navbar"> {{template "repo/issue/navbar" .}} <div class="ui right"> - <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> + <a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | PathEscapeSegments}}...{{.PullRequestCtx.HeadInfoSubURL}}">{{.i18n.Tr "repo.pulls.new"}}</a> </div> </div> <div class="ui divider"></div> diff --git a/templates/repo/pulls/fork.tmpl b/templates/repo/pulls/fork.tmpl index bf310e1596..f5ca0e4769 100644 --- a/templates/repo/pulls/fork.tmpl +++ b/templates/repo/pulls/fork.tmpl @@ -37,7 +37,7 @@ <div class="inline field"> <label>{{.i18n.Tr "repo.fork_from"}}</label> - <a href="{{AppSubUrl}}/{{.ForkFrom}}">{{.ForkFrom}}</a> + <a href="{{.ForkRepo.Link}}">{{.ForkRepo.FullName}}</a> </div> <div class="inline required field {{if .Err_RepoName}}error{{end}}"> <label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label> @@ -61,7 +61,7 @@ <button class="ui green button"> {{.i18n.Tr "repo.fork_repo"}} </button> - <a class="ui button" href="{{AppSubUrl}}/{{.ForkFrom}}">{{.i18n.Tr "cancel"}}</a> + <a class="ui button" href="{{.ForkRepo.Link}}">{{.i18n.Tr "cancel"}}</a> </div> </div> </form> diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl index 5a414f7fc2..ace916e9f5 100644 --- a/templates/repo/pulls/tab_menu.tmpl +++ b/templates/repo/pulls/tab_menu.tmpl @@ -1,15 +1,15 @@ <div class="ui top attached pull tabular stackable menu"> - <a class="item {{if .PageIsPullConversation}}active{{end}}" href="{{.RepoLink}}/pulls/{{.Issue.Index}}"> + <a class="item {{if .PageIsPullConversation}}active{{end}}" href="{{.Issue.Link}}"> {{svg "octicon-comment-discussion"}} {{$.i18n.Tr "repo.pulls.tab_conversation"}} <span class="ui {{if not .Issue.NumComments}}gray{{else}}blue{{end}} small label">{{.Issue.NumComments}}</span> </a> - <a class="item {{if .PageIsPullCommits}}active{{end}}" {{if .NumCommits}}href="{{.RepoLink}}/pulls/{{.Issue.Index}}/commits"{{end}}> + <a class="item {{if .PageIsPullCommits}}active{{end}}" {{if .NumCommits}}href="{{.Issue.Link}}/commits"{{end}}> {{svg "octicon-git-commit"}} {{$.i18n.Tr "repo.pulls.tab_commits"}} <span class="ui {{if not .NumCommits}}gray{{else}}blue{{end}} small label">{{if .NumCommits}}{{.NumCommits}}{{else}}N/A{{end}}</span> </a> - <a class="item {{if .PageIsPullFiles}}active{{end}}" {{if .NumFiles}}href="{{.RepoLink}}/pulls/{{.Issue.Index}}/files"{{end}}> + <a class="item {{if .PageIsPullFiles}}active{{end}}" {{if .NumFiles}}href="{{.Issue.Link}}/files"{{end}}> {{svg "octicon-diff"}} {{$.i18n.Tr "repo.pulls.tab_files"}} <span class="ui {{if not .NumFiles}}gray{{else}}blue{{end}} small label">{{if .NumFiles}}{{.NumFiles}}{{else}}N/A{{end}}</span> diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 5f06bf45d4..b47e7c482c 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -32,15 +32,15 @@ <tr> <td class="tag"> <h3 class="release-tag-name mb-3"> - <a class="df ac" href="{{$.RepoLink}}/src/tag/{{.TagName | EscapePound}}" rel="nofollow">{{.TagName}}</a> + <a class="df ac" href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{.TagName}}</a> </h3> <div class="download df ac"> {{if $.Permission.CanRead $.UnitTypeCode}} <a class="mr-3 mono" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}}</a> - <a class="archive-link mr-3" data-url="{{$.RepoLink}}/archive/{{.TagName | EscapePound}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-2"}}ZIP</a> - <a class="archive-link mr-3" data-url="{{$.RepoLink}}/archive/{{.TagName | EscapePound}}.tar.gz">{{svg "octicon-file-zip" 16 "mr-2"}}TAR.GZ</a> + <a class="archive-link mr-3" data-url="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-2"}}ZIP</a> + <a class="archive-link mr-3" data-url="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.tar.gz">{{svg "octicon-file-zip" 16 "mr-2"}}TAR.GZ</a> {{if (and $.CanCreateRelease $release.IsTag)}} - <a class="mr-3" href="{{$.RepoLink}}/releases/new?tag={{.TagName | EscapePound}}">{{svg "octicon-tag" 16 "mr-2"}}{{$.i18n.Tr "repo.release.new_release"}}</a> + <a class="mr-3" href="{{$.RepoLink}}/releases/new?tag={{.TagName | PathEscapeSegments}}">{{svg "octicon-tag" 16 "mr-2"}}{{$.i18n.Tr "repo.release.new_release"}}</a> {{end}} {{if (and ($.Permission.CanWrite $.UnitTypeCode) $release.IsTag)}} <a class="ui red delete-button mr-3" data-url="{{$.RepoLink}}/tags/delete" data-id="{{.ID}}"> @@ -48,7 +48,7 @@ </a> {{end}} {{if (not $release.IsTag)}} - <a class="mr-3" href="{{$.RepoLink}}/releases/tag/{{.TagName | EscapePound}}">{{svg "octicon-tag" 16 "mr-2"}}{{$.i18n.Tr "repo.release.detail"}}</a> + <a class="mr-3" href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}">{{svg "octicon-tag" 16 "mr-2"}}{{$.i18n.Tr "repo.release.detail"}}</a> {{end}} {{end}} </div> @@ -75,7 +75,7 @@ <span class="ui green label">{{$.i18n.Tr "repo.release.stable"}}</span> {{end}} <span class="tag text blue"> - <a class="df ac je" href="{{if .IsDraft}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | EscapePound}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "mr-2"}}{{.TagName}}</a> + <a class="df ac je" href="{{if .IsDraft}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "mr-2"}}{{.TagName}}</a> </span> {{if not .IsDraft}} <span class="commit"> @@ -90,30 +90,30 @@ <div class="ui twelve wide column detail"> {{if .IsTag}} <h4> - <a href="{{$.RepoLink}}/src/tag/{{.TagName | EscapePound}}" rel="nofollow">{{svg "octicon-tag" 16 "mr-2"}}{{.TagName}}</a> + <a href="{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{svg "octicon-tag" 16 "mr-2"}}{{.TagName}}</a> </h4> <p class="text grey"> {{ if gt .Publisher.ID 0 }} <span class="author"> {{avatar .Publisher 20}} - <a href="{{AppSubUrl}}/{{.Publisher.Name}}">{{.Publisher.Name}}</a> + <a href="{{.Publisher.HomeLink}}">{{.Publisher.Name}}</a> </span> {{ end }} - <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | EscapePound}}...{{.Target}}">{{$.i18n.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{$.i18n.Tr "repo.release.ahead.target" $.DefaultBranch}}</span> + <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | PathEscapeSegments}}...{{.Target | PathEscapeSegments}}">{{$.i18n.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{$.i18n.Tr "repo.release.ahead.target" $.DefaultBranch}}</span> </p> <div class="download"> {{if $.Permission.CanRead $.UnitTypeCode}} <a class="mono" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}}</a> - <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | EscapePound}}.zip" rel="nofollow">{{svg "octicon-file-zip"}} ZIP</a> - <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | EscapePound}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a> + <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow">{{svg "octicon-file-zip"}} ZIP</a> + <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.tar.gz">{{svg "octicon-file-zip"}} TAR.GZ</a> {{end}} </div> {{else}} <h4 class="release-list-title df ac"> - <a href="{{$.RepoLink}}/releases/tag/{{.TagName | EscapePound}}">{{.Title}}</a> + <a href="{{$.RepoLink}}/releases/tag/{{.TagName | PathEscapeSegments}}">{{.Title}}</a> {{if $.CanCreateRelease}} <small class="ml-2"> - (<a href="{{$.RepoLink}}/releases/edit/{{.TagName | EscapePound}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>) + (<a href="{{$.RepoLink}}/releases/edit/{{.TagName | PathEscapeSegments}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>) </small> {{end}} </h4> @@ -123,7 +123,7 @@ {{svg "octicon-mark-github" 16 "mr-2"}}{{.OriginalAuthor}} {{else if .Publisher}} {{avatar .Publisher 20}} - <a href="{{AppSubUrl}}/{{.Publisher.Name}}">{{.Publisher.GetDisplayName}}</a> + <a href="{{.Publisher.HomeLink}}">{{.Publisher.GetDisplayName}}</a> {{else}} Ghost {{end}} @@ -135,7 +135,7 @@ <span class="time">{{TimeSinceUnix .CreatedUnix $.Lang}}</span> {{end}} {{if not .IsDraft}} - | <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | EscapePound}}...{{.Target}}">{{$.i18n.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{$.i18n.Tr "repo.release.ahead.target" .Target}}</span> + | <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | PathEscapeSegments}}...{{.Target | PathEscapeSegments}}">{{$.i18n.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{$.i18n.Tr "repo.release.ahead.target" .Target}}</span> {{end}} </p> <div class="markup desc"> @@ -148,10 +148,10 @@ <ul class="list"> {{if and (not .IsDraft) ($.Permission.CanRead $.UnitTypeCode)}} <li> - <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | EscapePound}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "mr-2"}}{{$.i18n.Tr "repo.release.source_code"}} (ZIP)</strong></a> + <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.zip" rel="nofollow"><strong>{{svg "octicon-file-zip" 16 "mr-2"}}{{$.i18n.Tr "repo.release.source_code"}} (ZIP)</strong></a> </li> <li> - <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | EscapePound}}.tar.gz"><strong>{{svg "octicon-file-zip" 16 "mr-2"}}{{$.i18n.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a> + <a class="archive-link" data-url="{{$.RepoLink}}/archive/{{.TagName | PathEscapeSegments}}.tar.gz"><strong>{{svg "octicon-file-zip" 16 "mr-2"}}{{$.i18n.Tr "repo.release.source_code"}} (TAR.GZ)</strong></a> </li> {{end}} {{if .Attachments}} diff --git a/templates/repo/search.tmpl b/templates/repo/search.tmpl index bd70690e06..f2c2269af7 100644 --- a/templates/repo/search.tmpl +++ b/templates/repo/search.tmpl @@ -20,11 +20,11 @@ </div> {{if .Keyword}} <h3> - {{.i18n.Tr "repo.search.results" (.Keyword|Escape) .RepoLink .RepoName | Str2html }} + {{.i18n.Tr "repo.search.results" (.Keyword|Escape) (.RepoLink|Escape) (.RepoName|Escape) | Str2html }} </h3> <div class="df ac fw"> {{range $term := .SearchResultLanguages}} - <a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{EscapePound $.SourcePath}}/search?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}"> + <a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{$.SourcePath}}/search?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}"> <i class="color-icon mr-3" style="background-color: {{$term.Color}}"></i> {{$term.Language}} <div class="detail">{{$term.Count}}</div> @@ -36,7 +36,7 @@ <div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result"> <h4 class="ui top attached normal header"> <span class="file">{{.Filename}}</span> - <a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/src/commit/{{$result.CommitID}}/{{EscapePound .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> + <a class="ui basic tiny button" rel="nofollow" href="{{$.SourcePath}}/src/commit/{{PathEscape $result.CommitID}}/{{PathEscapeSegments .Filename}}">{{$.i18n.Tr "repo.diff.view_file"}}</a> </h4> <div class="ui attached table segment"> <div class="file-body file-code code-view"> @@ -45,7 +45,7 @@ <tr> <td class="lines-num"> {{range .LineNumbers}} - <a href="{{EscapePound $.SourcePath}}/src/commit/{{$result.CommitID}}/{{EscapePound $result.Filename}}#L{{.}}"><span>{{.}}</span></a> + <a href="{{$.SourcePath}}/src/commit/{{PathEscape $result.CommitID}}/{{PathEscapeSegments $result.Filename}}#L{{.}}"><span>{{.}}</span></a> {{end}} </td> <td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td> diff --git a/templates/repo/settings/branches.tmpl b/templates/repo/settings/branches.tmpl index 89d7c6db77..5671eca368 100644 --- a/templates/repo/settings/branches.tmpl +++ b/templates/repo/settings/branches.tmpl @@ -53,7 +53,7 @@ <div class="default text">{{.i18n.Tr "repo.settings.choose_branch"}}</div> <div class="menu transition hidden" tabindex="-1" style="display: block !important;"> {{range .LeftBranches}} - <a class="item" href="{{$.Repository.Link}}/settings/branches/{{. | EscapePound}}">{{.}}</a> + <a class="item" href="{{$.Repository.Link}}/settings/branches/{{. | PathEscapeSegments}}">{{.}}</a> {{end}} </div> </div> @@ -67,7 +67,7 @@ {{range .ProtectedBranches}} <tr> <td><div class="ui basic label blue">{{.BranchName}}</div></td> - <td class="right aligned"><a class="rm ui button" href="{{$.Repository.Link}}/settings/branches/{{.BranchName | EscapePound}}">{{$.i18n.Tr "repo.settings.edit_protected_branch"}}</a></td> + <td class="right aligned"><a class="rm ui button" href="{{$.Repository.Link}}/settings/branches/{{.BranchName | PathEscapeSegments}}">{{$.i18n.Tr "repo.settings.edit_protected_branch"}}</a></td> </tr> {{else}} <tr class="center aligned"><td>{{.i18n.Tr "repo.settings.no_protected_branch"}}</td></tr> diff --git a/templates/repo/settings/collaboration.tmpl b/templates/repo/settings/collaboration.tmpl index 864b2968fc..3b584a559b 100644 --- a/templates/repo/settings/collaboration.tmpl +++ b/templates/repo/settings/collaboration.tmpl @@ -12,7 +12,7 @@ {{range .Collaborators}} <div class="item ui grid"> <div class="ui five wide column"> - <a href="{{AppSubUrl}}/{{.Name}}"> + <a href="{{.HomeLink}}"> {{avatar .}} {{.DisplayName}} </a> @@ -62,7 +62,7 @@ {{range $t, $team := .Teams}} <div class="item ui grid"> <div class="ui five wide column"> - <a href="{{AppSubUrl}}/org/{{$.OrgName}}/teams/{{.LowerName}}"> + <a href="{{AppSubUrl}}/org/{{$.OrgName|PathEscape}}/teams/{{.LowerName|PathEscape}}"> {{.Name}} </a> </div> diff --git a/templates/repo/settings/githooks.tmpl b/templates/repo/settings/githooks.tmpl index 40bc787c8d..972d03425c 100644 --- a/templates/repo/settings/githooks.tmpl +++ b/templates/repo/settings/githooks.tmpl @@ -16,7 +16,7 @@ <div class="item"> <span class="text {{if .IsActive}}green{{else}}grey{{end}}">{{svg "octicon-dot-fill"}}</span> <span>{{.Name}}</span> - <a class="text blue ui right" href="{{$.RepoLink}}/settings/hooks/git/{{.Name}}"> + <a class="text blue ui right" href="{{$.RepoLink}}/settings/hooks/git/{{.Name|PathEscape}}"> {{svg "octicon-pencil"}} </a> </div> diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index 478c034e11..f6510f17db 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -20,19 +20,19 @@ {{else if not .IsTextFile}} <div class="view-raw ui center"> {{if .IsImageFile}} - <img src="{{EscapePound $.RawFileLink}}"> + <img src="{{$.RawFileLink}}"> {{else if .IsVideoFile}} - <video controls src="{{EscapePound $.RawFileLink}}"> + <video controls src="{{$.RawFileLink}}"> <strong>{{.i18n.Tr "repo.video_not_supported_in_browser"}}</strong> </video> {{else if .IsAudioFile}} - <audio controls src="{{EscapePound $.RawFileLink}}"> + <audio controls src="{{$.RawFileLink}}"> <strong>{{.i18n.Tr "repo.audio_not_supported_in_browser"}}</strong> </audio> {{else if .IsPDFFile}} - <iframe width="100%" height="600px" src="{{AppSubUrl}}/vendor/plugins/pdfjs/web/viewer.html?file={{EscapePound $.RawFileLink}}"></iframe> + <iframe width="100%" height="600px" src="{{AppSubUrl}}/vendor/plugins/pdfjs/web/viewer.html?file={{$.RawFileLink}}"></iframe> {{else}} - <a href="{{EscapePound $.RawFileLink}}" rel="nofollow" class="btn btn-gray btn-radius">{{.i18n.Tr "repo.file_view_raw"}}</a> + <a href="{{$.RawFileLink}}" rel="nofollow" class="btn btn-gray btn-radius">{{.i18n.Tr "repo.file_view_raw"}}</a> {{end}} </div> {{else if .FileSize}} diff --git a/templates/repo/settings/lfs_file_find.tmpl b/templates/repo/settings/lfs_file_find.tmpl index 83a2e317d5..f5a0e0081c 100644 --- a/templates/repo/settings/lfs_file_find.tmpl +++ b/templates/repo/settings/lfs_file_find.tmpl @@ -14,7 +14,7 @@ <tr> <td> {{svg "octicon-file"}} - <a href="{{EscapePound $.RepoLink}}/src/commit/{{.SHA}}/{{EscapePound .Name}}" title="{{.Name}}">{{.Name}}</a> + <a href="{{$.RepoLink}}/src/commit/{{.SHA}}/{{PathEscapeSegments .Name}}" title="{{.Name}}">{{.Name}}</a> </td> <td class="message"> <span class="truncate"> diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl index 84269dc612..7d6e531bd2 100644 --- a/templates/repo/settings/lfs_locks.tmpl +++ b/templates/repo/settings/lfs_locks.tmpl @@ -24,7 +24,7 @@ <td> {{if index $.Linkable $index}} {{svg "octicon-file"}} - <a href="{{EscapePound $.RepoLink}}/src/branch/{{EscapePound $lock.Repo.DefaultBranch}}/{{EscapePound $lock.Path}}" title="{{$lock.Path}}">{{$lock.Path}}</a> + <a href="{{$.RepoLink}}/src/branch/{{PathEscapeSegments $lock.Repo.DefaultBranch}}/{{PathEscapeSegments $lock.Path}}" title="{{$lock.Path}}">{{$lock.Path}}</a> {{else}} {{svg "octicon-diff"}} <span class="poping up" title="{{$.i18n.Tr "repo.settings.lfs_lock_file_no_exist"}}">{{$lock.Path}}</span> @@ -34,7 +34,7 @@ {{end}} </td> <td> - <a href="{{AppSubUrl}}/{{$lock.Owner.Name}}"> + <a href="{{$lock.Owner.HomeLink}}"> {{avatar $lock.Owner}} {{$lock.Owner.DisplayName}} </a> diff --git a/templates/repo/settings/tags.tmpl b/templates/repo/settings/tags.tmpl index a2c887b1f8..48c42bdf25 100644 --- a/templates/repo/settings/tags.tmpl +++ b/templates/repo/settings/tags.tmpl @@ -101,7 +101,7 @@ {{$teamIDs := .AllowlistTeamIDs}} {{range $.Teams}} {{if contain $teamIDs .ID }} - <a class="ui basic image label" href="{{$.Owner.OrganisationLink}}/teams/{{.LowerName}}">{{.Name}}</a> + <a class="ui basic image label" href="{{$.Owner.OrganisationLink}}/teams/{{PathEscape .LowerName}}">{{.Name}}</a> {{end}} {{end}} {{end}} diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index f00237047e..3b05708c74 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -3,7 +3,7 @@ <div class="ui two horizontal center link list"> {{if and (.Permission.CanRead $.UnitTypeCode) (not .IsEmptyRepo)}} <div class="item{{if .PageIsCommits}} active{{end}}"> - <a class="ui" href="{{.RepoLink}}/commits{{if .IsViewBranch}}/branch{{else if .IsViewTag}}/tag{{else if .IsViewCommit}}/commit{{end}}/{{EscapePound .BranchName}}">{{svg "octicon-history"}} <b>{{.CommitsCount}}</b> {{.i18n.Tr (TrN .i18n.Lang .CommitsCount "repo.commit" "repo.commits") }}</a> + <a class="ui" href="{{.RepoLink}}/commits{{if .IsViewBranch}}/branch{{else if .IsViewTag}}/tag{{else if .IsViewCommit}}/commit{{end}}/{{PathEscapeSegments .BranchName}}">{{svg "octicon-history"}} <b>{{.CommitsCount}}</b> {{.i18n.Tr (TrN .i18n.Lang .CommitsCount "repo.commit" "repo.commits") }}</a> </div> <div class="item{{if .PageIsBranches}} active{{end}}"> <a class="ui" href="{{.RepoLink}}/branches">{{svg "octicon-git-branch"}} <b>{{.BranchesCount}}</b> {{.i18n.Tr (TrN .i18n.Lang .BranchesCount "repo.branch" "repo.branches") }}</a> diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 2c678beb90..afe3306a4d 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -24,7 +24,7 @@ {{if .LFSLock}} <div class="file-info-entry ui poping up" data-content="{{.LFSLockHint}}"> {{svg "octicon-lock" 16 "mr-2"}} - <a href="{{AppSubUrl}}/{{.LFSLock.Owner.Name}}">{{.LFSLockOwner}}</a> + <a href="{{.LFSLock.Owner.HomeLink}}">{{.LFSLockOwner}}</a> </div> {{end}} </div> @@ -39,24 +39,24 @@ </div> {{end}} <div class="ui buttons mr-2"> - <a class="ui mini basic button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a> + <a class="ui mini basic button" href="{{$.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a> {{if not .IsViewCommit}} - <a class="ui mini basic button" href="{{.RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a> + <a class="ui mini basic button" href="{{.RepoLink}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a> {{end}} {{if .IsRepresentableAsText}} - <a class="ui mini basic button" href="{{.RepoLink}}/blame/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.blame"}}</a> + <a class="ui mini basic button" href="{{.RepoLink}}/blame/{{.BranchNameSubURL}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.blame"}}</a> {{end}} - <a class="ui mini basic button" href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_history"}}</a> + <a class="ui mini basic button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.file_history"}}</a> </div> - <a download href="{{EscapePound $.RawFileLink}}"><span class="btn-octicon poping up" data-content="{{.i18n.Tr "repo.download_file"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-download"}}</span></a> + <a download href="{{$.RawFileLink}}"><span class="btn-octicon poping up" data-content="{{.i18n.Tr "repo.download_file"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-download"}}</span></a> {{if .Repository.CanEnableEditor}} {{if .CanEditFile}} - <a href="{{.RepoLink}}/_edit/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}"><span class="btn-octicon poping up" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil"}}</span></a> + <a href="{{.RepoLink}}/_edit/{{PathEscapeSegments .BranchName}}/{{PathEscapeSegments .TreePath}}"><span class="btn-octicon poping up" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil"}}</span></a> {{else}} <span class="btn-octicon poping up disabled" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil"}}</span> {{end}} {{if .CanDeleteFile}} - <a href="{{.RepoLink}}/_delete/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}"><span class="btn-octicon btn-octicon-danger poping up" data-content="{{.DeleteFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-trash"}}</span></a> + <a href="{{.RepoLink}}/_delete/{{PathEscapeSegments .BranchName}}/{{PathEscapeSegments .TreePath}}"><span class="btn-octicon btn-octicon-danger poping up" data-content="{{.DeleteFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-trash"}}</span></a> {{else}} <span class="btn-octicon poping up disabled" data-content="{{.DeleteFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-trash"}}</span> {{end}} @@ -73,19 +73,19 @@ {{else if not .IsTextSource}} <div class="view-raw ui center"> {{if .IsImageFile}} - <img src="{{EscapePound $.RawFileLink}}"> + <img src="{{$.RawFileLink}}"> {{else if .IsVideoFile}} - <video controls src="{{EscapePound $.RawFileLink}}"> + <video controls src="{{$.RawFileLink}}"> <strong>{{.i18n.Tr "repo.video_not_supported_in_browser"}}</strong> </video> {{else if .IsAudioFile}} - <audio controls src="{{EscapePound $.RawFileLink}}"> + <audio controls src="{{$.RawFileLink}}"> <strong>{{.i18n.Tr "repo.audio_not_supported_in_browser"}}</strong> </audio> {{else if .IsPDFFile}} - <iframe width="100%" height="600px" src="{{AssetUrlPrefix}}/vendor/plugins/pdfjs/web/viewer.html?file={{EscapePound $.RawFileLink}}"></iframe> + <iframe width="100%" height="600px" src="{{AssetUrlPrefix}}/vendor/plugins/pdfjs/web/viewer.html?file={{$.RawFileLink}}"></iframe> {{else}} - <a href="{{EscapePound $.RawFileLink}}" rel="nofollow" class="btn btn-gray btn-radius">{{.i18n.Tr "repo.file_view_raw"}}</a> + <a href="{{$.RawFileLink}}" rel="nofollow" class="btn btn-gray btn-radius">{{.i18n.Tr "repo.file_view_raw"}}</a> {{end}} </div> {{else if .FileSize}} @@ -118,11 +118,11 @@ <div class="column"> {{if $.Permission.CanRead $.UnitTypeIssues}} <div class="ui link list"> - <a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{URLJoin AppUrl .RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.issues.context.reference_issue"}}</a> + <a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/" }}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.issues.context.reference_issue"}}</a> </div> {{end}} <div class="ui link list"> - <a data-clipboard-text="{{URLJoin AppUrl .RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}" class="item copy-line-permalink">{{.i18n.Tr "repo.file_copy_permalink"}}</a> + <a data-clipboard-text="{{.Repository.HTMLURL}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}" class="item copy-line-permalink">{{.i18n.Tr "repo.file_copy_permalink"}}</a> </div> </div> </div> diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index 3e7bcbe505..9b28b395d1 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -8,9 +8,9 @@ {{if .LatestCommitUser}} {{avatar .LatestCommitUser 24}} {{if .LatestCommitUser.FullName}} - <a href="{{AppSubUrl}}/{{.LatestCommitUser.Name}}"><strong>{{.LatestCommitUser.FullName}}</strong></a> + <a href="{{.LatestCommitUser.HomeLink}}"><strong>{{.LatestCommitUser.FullName}}</strong></a> {{else}} - <a href="{{AppSubUrl}}/{{.LatestCommitUser.Name}}"><strong>{{if .LatestCommit.Author}}{{.LatestCommit.Author.Name}}{{else}}{{.LatestCommitUser.Name}}{{end}}</strong></a> + <a href="{{.LatestCommitUser.HomeLink}}"><strong>{{if .LatestCommit.Author}}{{.LatestCommit.Author.Name}}{{else}}{{.LatestCommitUser.Name}}{{end}}</strong></a> {{end}} {{else}} {{if .LatestCommit.Author}} @@ -18,14 +18,14 @@ <strong>{{.LatestCommit.Author.Name}}</strong> {{end}} {{end}} - <a rel="nofollow" class="ui sha label {{if .LatestCommit.Signature}} isSigned {{if .LatestCommitVerification.Verified }} isVerified{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}Untrusted{{else}}Unmatched{{end}}{{else if .LatestCommitVerification.Warning}} isWarning{{end}}{{end}}" href="{{.RepoLink}}/commit/{{.LatestCommit.ID}}"> + <a rel="nofollow" class="ui sha label {{if .LatestCommit.Signature}} isSigned {{if .LatestCommitVerification.Verified }} isVerified{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}Untrusted{{else}}Unmatched{{end}}{{else if .LatestCommitVerification.Warning}} isWarning{{end}}{{end}}" href="{{.RepoLink}}/commit/{{PathEscape .LatestCommit.ID.String}}"> <span class="shortsha">{{ShortSha .LatestCommit.ID.String}}</span> {{if .LatestCommit.Signature}} {{template "repo/shabox_badge" dict "root" $ "verification" .LatestCommitVerification}} {{end}} </a> {{template "repo/commit_statuses" dict "Status" .LatestCommitStatus "Statuses" .LatestCommitStatuses "root" $}} - {{ $commitLink:= printf "%s/commit/%s" .RepoLink .LatestCommit.ID }} + {{ $commitLink:= printf "%s/commit/%s" .RepoLink (PathEscape .LatestCommit.ID.String) }} <span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{RenderCommitMessageLinkSubject .LatestCommit.Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span> {{if IsMultilineCommitMessage .LatestCommit.Message}} <button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button> @@ -40,7 +40,7 @@ <tbody> {{if .HasParentPath}} <tr class="has-parent"> - <td colspan="3">{{svg "octicon-reply"}}<a href="{{EscapePound .BranchLink}}{{.ParentPath}}">..</a></td> + <td colspan="3">{{svg "octicon-reply"}}<a href="{{.BranchLink}}{{if .ParentPath}}{{PathEscapeSegments .ParentPath}}{{end}}">..</a></td> </tr> {{end}} {{range $item := .Files}} @@ -54,7 +54,7 @@ {{svg "octicon-file-submodule"}} {{$refURL := $subModuleFile.RefURL AppUrl $.Repository.FullName $.SSHDomain}} {{if $refURL}} - <a href="{{$refURL}}">{{$entry.Name}}</a><span class="at">@</span><a href="{{$refURL}}/commit/{{$subModuleFile.RefID}}">{{ShortSha $subModuleFile.RefID}}</a> + <a href="{{$refURL}}">{{$entry.Name}}</a><span class="at">@</span><a href="{{$refURL}}/commit/{{PathEscape $subModuleFile.RefID}}">{{ShortSha $subModuleFile.RefID}}</a> {{else}} {{$entry.Name}}<span class="at">@</span>{{ShortSha $subModuleFile.RefID}} {{end}} @@ -63,7 +63,7 @@ {{$subJumpablePathName := $entry.GetSubJumpablePathName}} {{$subJumpablePath := SubJumpablePath $subJumpablePathName}} {{svg "octicon-file-directory"}} - <a href="{{EscapePound $.TreeLink}}/{{EscapePound $subJumpablePathName}}" title="{{$subJumpablePathName}}"> + <a href="{{$.TreeLink}}/{{PathEscapeSegments $subJumpablePathName}}" title="{{$subJumpablePathName}}"> {{if eq (len $subJumpablePath) 2}} <span class="jumpable-path">{{index $subJumpablePath 0}}</span>{{index $subJumpablePath 1}} {{else}} @@ -72,7 +72,7 @@ </a> {{else}} {{svg (printf "octicon-%s" (EntryIcon $entry))}} - <a href="{{EscapePound $.TreeLink}}/{{EscapePound $entry.Name}}" title="{{$entry.Name}}">{{$entry.Name}}</a> + <a href="{{$.TreeLink}}/{{PathEscapeSegments $entry.Name}}" title="{{$entry.Name}}">{{$entry.Name}}</a> {{end}} {{end}} </span> @@ -80,7 +80,7 @@ <td class="message nine wide"> <span class="truncate"> {{if $commit}} - <a href="{{$.RepoLink}}/commit/{{$commit.ID}}" title="{{$commit.Summary}}">{{$commit.Summary | RenderEmoji}}</a> + <a href="{{$.RepoLink}}/commit/{{PathEscape $commit.ID.String}}" title="{{$commit.Summary}}">{{$commit.Summary | RenderEmoji}}</a> {{else}} <div class="ui active tiny slow centered inline">…</div> {{end}} diff --git a/templates/repo/wiki/new.tmpl b/templates/repo/wiki/new.tmpl index d887d8ffae..6cfa798374 100644 --- a/templates/repo/wiki/new.tmpl +++ b/templates/repo/wiki/new.tmpl @@ -7,7 +7,7 @@ {{.i18n.Tr "repo.wiki.new_page"}} {{if .PageIsWikiEdit}} <div class="ui right"> - <a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> + <a class="ui green small button" href="{{.RepoLink}}/wiki?action=_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> </div> {{end}} </div> diff --git a/templates/repo/wiki/pages.tmpl b/templates/repo/wiki/pages.tmpl index 3afa7772de..43766771bc 100644 --- a/templates/repo/wiki/pages.tmpl +++ b/templates/repo/wiki/pages.tmpl @@ -8,7 +8,7 @@ </div> <div> {{if and .CanWriteWiki (not .IsRepositoryMirror)}} - <a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> + <a class="ui green small button" href="{{.RepoLink}}/wiki?action=_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> {{end}} </div> </h2> diff --git a/templates/repo/wiki/start.tmpl b/templates/repo/wiki/start.tmpl index e9b7ecb6c9..514ac114ad 100644 --- a/templates/repo/wiki/start.tmpl +++ b/templates/repo/wiki/start.tmpl @@ -7,7 +7,7 @@ <h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2> <p>{{.i18n.Tr "repo.wiki.welcome_desc"}}</p> {{if and .CanWriteWiki (not .Repository.IsMirror)}} - <a class="ui green button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.create_first_page"}}</a> + <a class="ui green button" href="{{.RepoLink}}/wiki?action=_new">{{.i18n.Tr "repo.wiki.create_first_page"}}</a> {{end}} </div> </div> diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index a393fb20a1..b71c950e17 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -37,7 +37,7 @@ <div class="ui dividing header"> <div class="ui stackable grid"> <div class="eight wide column"> - <a class="file-revisions-btn ui basic button" title="{{.i18n.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}/_revision" ><span>{{.CommitCount}}</span> {{svg "octicon-history"}}</a> + <a class="file-revisions-btn ui basic button" title="{{.i18n.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" ><span>{{.CommitCount}}</span> {{svg "octicon-history"}}</a> {{$title}} <div class="ui sub header"> {{$timeSince := TimeSince .Author.When $.Lang}} @@ -47,9 +47,9 @@ <div class="eight wide right aligned column"> {{if and .CanWriteWiki (not .Repository.IsMirror)}} <div class="ui right"> - <a class="ui small button" href="{{.RepoLink}}/wiki/{{.PageURL}}/_edit">{{.i18n.Tr "repo.wiki.edit_page_button"}}</a> - <a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> - <a class="ui red small button delete-button" href="" data-url="{{.RepoLink}}/wiki/{{.PageURL}}/delete" data-id="{{.PageURL}}">{{.i18n.Tr "repo.wiki.delete_page_button"}}</a> + <a class="ui small button" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_edit">{{.i18n.Tr "repo.wiki.edit_page_button"}}</a> + <a class="ui green small button" href="{{.RepoLink}}/wiki?action=_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> + <a class="ui red small button delete-button" href="" data-url="{{.RepoLink}}/wiki/{{.PageURL}}?action=_delete" data-id="{{.PageURL}}">{{.i18n.Tr "repo.wiki.delete_page_button"}}</a> </div> {{end}} </div> @@ -68,7 +68,7 @@ <div class="column" style="padding-top: 0;"> <div class="ui segment"> {{if and .CanWriteWiki (not .Repository.IsMirror)}} - <a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Sidebar/_edit" aria-label="{{.i18n.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a> + <a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Sidebar?action=_edit" aria-label="{{.i18n.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a> {{end}} {{.sidebarContent | Str2html}} </div> @@ -78,7 +78,7 @@ {{if .footerPresent}} <div class="ui segment"> {{if and .CanWriteWiki (not .Repository.IsMirror)}} - <a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Footer/_edit" aria-label="{{.i18n.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a> + <a class="ui right floated muted" href="{{.RepoLink}}/wiki/_Footer?action=_edit" aria-label="{{.i18n.Tr "repo.wiki.edit_page_button"}}">{{svg "octicon-pencil"}}</a> {{end}} {{.footerContent | Str2html}} </div> diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 984ddf4473..80d9fb1172 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -55,19 +55,19 @@ </a> {{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.Lang }} {{if .OriginalAuthor }} - {{$.i18n.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor | Safe}} + {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}} {{else if gt .Poster.ID 0}} - {{$.i18n.Tr .GetLastEventLabel $timeStr .Poster.HomeLink (.Poster.GetDisplayName | Escape) | Safe}} + {{$.i18n.Tr .GetLastEventLabel $timeStr (.Poster.HomeLink|Escape) (.Poster.GetDisplayName | Escape) | Safe}} {{else}} {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}} {{end}} {{if and .Milestone (ne $.listType "milestone")}} - <a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}> + <a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{.Repo.Link}}/milestone/{{.Milestone.ID}}"{{end}}> {{svg "octicon-milestone" 14 "mr-2"}}{{.Milestone.Name}} </a> {{end}} {{if .Ref}} - <a class="ref" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}> + <a class="ref" {{if $.RepoLink}}href="{{index $.IssueRefURLs .ID}}"{{else}}href="{{.Repo.Link}}{{index $.IssueRefURLs .ID}}"{{end}}> {{svg "octicon-git-branch" 14 "mr-2"}}{{index $.IssueRefEndNames .ID}} </a> {{end}} diff --git a/templates/user/auth/grant.tmpl b/templates/user/auth/grant.tmpl index 130c2383e7..2f8dffb52e 100644 --- a/templates/user/auth/grant.tmpl +++ b/templates/user/auth/grant.tmpl @@ -9,11 +9,11 @@ {{template "base/alert" .}} <p> <b>{{.i18n.Tr "auth.authorize_application_description"}}</b><br/> - {{.i18n.Tr "auth.authorize_application_created_by" .ApplicationUserLink | Str2html}} + {{.i18n.Tr "auth.authorize_application_created_by" (.ApplicationUserLink|Escape) | Str2html}} </p> </div> <div class="ui attached segment"> - <p>{{.i18n.Tr "auth.authorize_redirect_notice" .ApplicationRedirectDomainHTML | Str2html}}</p> + <p>{{.i18n.Tr "auth.authorize_redirect_notice" (.ApplicationRedirectDomainHTML|Escape) | Str2html}}</p> </div> <div class="ui attached segment"> <form method="post" action="{{AppSubUrl}}/login/oauth/grant"> diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index 83d064dc95..a2510f43ef 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -8,80 +8,80 @@ <div class="{{if or (eq .GetOpType 5) (eq .GetOpType 18)}}push news{{end}}"> <p> {{if gt .ActUser.ID 0}} - <a href="{{AppSubUrl}}/{{.GetActUserName}}" title="{{.GetDisplayNameTitle}}">{{.GetDisplayName}}</a> + <a href="{{AppSubUrl}}/{{.GetActUserName | PathEscape}}" title="{{.GetDisplayNameTitle}}">{{.GetDisplayName}}</a> {{else}} {{.ShortActUserName}} {{end}} {{if eq .GetOpType 1}} - {{$.i18n.Tr "action.create_repo" .GetRepoLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_repo" (.GetRepoLink|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 2}} - {{$.i18n.Tr "action.rename_repo" .GetContent .GetRepoLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.rename_repo" (.GetContent|Escape) (.GetRepoLink|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 5}} - {{ $branchLink := .GetBranch | EscapePound | Escape}} + {{ $branchLink := .GetBranch | PathEscapeSegments | Escape}} {{if .Content}} - {{$.i18n.Tr "action.commit_repo" .GetRepoLink $branchLink (Escape .GetBranch) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.commit_repo" (.GetRepoLink|Escape) $branchLink (Escape .GetBranch) (.ShortRepoPath|Escape) | Str2html}} {{else}} - {{$.i18n.Tr "action.create_branch" .GetRepoLink $branchLink (Escape .GetBranch) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_branch" (.GetRepoLink|Escape) $branchLink (Escape .GetBranch) (.ShortRepoPath|Escape) | Str2html}} {{end}} {{else if eq .GetOpType 6}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.create_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_issue" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 7}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.create_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.create_pull_request" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 8}} - {{$.i18n.Tr "action.transfer_repo" .GetContent .GetRepoLink .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.transfer_repo" .GetContent (.GetRepoLink|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 9}} - {{ $tagLink := .GetTag | EscapePound | Escape}} - {{$.i18n.Tr "action.push_tag" .GetRepoLink $tagLink .ShortRepoPath .GetTag | Str2html}} + {{ $tagLink := .GetTag | PathEscapeSegments | Escape}} + {{$.i18n.Tr "action.push_tag" (.GetRepoLink|Escape) $tagLink (.ShortRepoPath|Escape) .GetTag | Str2html}} {{else if eq .GetOpType 10}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.comment_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.comment_issue" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 11}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.merge_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.merge_pull_request" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 12}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.close_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.close_issue" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 13}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.reopen_issue" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.reopen_issue" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 14}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.close_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.close_pull_request" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 15}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.reopen_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.reopen_pull_request" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 16}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.delete_tag" .GetRepoLink (.GetTag|Escape) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.delete_tag" (.GetRepoLink|Escape) (.GetTag|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 17}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.delete_branch" .GetRepoLink (.GetBranch|Escape) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.delete_branch" (.GetRepoLink|Escape) (.GetBranch|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 18}} - {{ $branchLink := .GetBranch | EscapePound}} - {{$.i18n.Tr "action.mirror_sync_push" .GetRepoLink $branchLink (.GetBranch|Escape) .ShortRepoPath | Str2html}} + {{ $branchLink := .GetBranch | PathEscapeSegments}} + {{$.i18n.Tr "action.mirror_sync_push" (.GetRepoLink|Escape) $branchLink (.GetBranch|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 19}} - {{$.i18n.Tr "action.mirror_sync_create" .GetRepoLink (.GetBranch|Escape) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.mirror_sync_create" (.GetRepoLink|Escape) (.GetBranch|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 20}} - {{$.i18n.Tr "action.mirror_sync_delete" .GetRepoLink (.GetBranch|Escape) .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.mirror_sync_delete" (.GetRepoLink|Escape) (.GetBranch|Escape) (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 21}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.approve_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.approve_pull_request" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 22}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.reject_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.reject_pull_request" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 23}} {{ $index := index .GetIssueInfos 0}} - {{$.i18n.Tr "action.comment_pull" .GetRepoLink $index .ShortRepoPath | Str2html}} + {{$.i18n.Tr "action.comment_pull" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) | Str2html}} {{else if eq .GetOpType 24}} - {{ $branchLink := .GetBranch | EscapePound | Escape}} + {{ $branchLink := .GetBranch | PathEscapeSegments | Escape}} {{ $linkText := .Content | RenderEmoji }} - {{$.i18n.Tr "action.publish_release" .GetRepoLink $branchLink .ShortRepoPath $linkText | Str2html}} + {{$.i18n.Tr "action.publish_release" (.GetRepoLink|Escape) $branchLink (.ShortRepoPath|Escape) $linkText | Str2html}} {{else if eq .GetOpType 25}} {{ $index := index .GetIssueInfos 0}} {{ $reviewer := index .GetIssueInfos 1}} - {{$.i18n.Tr "action.review_dismissed" .GetRepoLink $index .ShortRepoPath $reviewer | Str2html}} + {{$.i18n.Tr "action.review_dismissed" (.GetRepoLink|Escape) $index (.ShortRepoPath|Escape) $reviewer | Str2html}} {{end}} </p> {{if or (eq .GetOpType 5) (eq .GetOpType 18)}} diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index d2a51fd44a..aca61f9ae9 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -35,18 +35,18 @@ {{range .Repos}} {{with $Repo := .}} <a class="{{range $.RepoIDs}}{{if eq . $Repo.ID}}ui basic blue button{{end}}{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}&repos=[ - {{with $include := true}} - {{range $.RepoIDs}} - {{if eq . $Repo.ID}} + {{- with $include := true -}} + {{- range $.RepoIDs -}} + {{- if eq . $Repo.ID -}} {{$include = false}} - {{else}} + {{- else -}} {{.}}%2C - {{end}} - {{end}} - {{if eq $include true}} + {{- end -}} + {{- end -}} + {{- if eq $include true -}} {{$Repo.ID}}%2C - {{end}} - {{end}} + {{- end -}} + {{- end -}} ]&sort={{$.SortType}}&state={{$.State}}&q={{$.Keyword}}" title="{{.FullName}}"> <span class="text truncate">{{$Repo.FullName}}</span> <div class="ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{CountFmt (index $.Counts $Repo.ID)}}</div> diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index c7416e7cd7..3e1ef95d98 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -13,18 +13,18 @@ {{range .Repos}} {{with $Repo := .}} <a class="{{range $.RepoIDs}}{{if eq . $Repo.ID}}ui basic blue button{{end}}{{end}} repo name item" href="{{$.Link}}?repos=[ - {{with $include := true}} - {{range $.RepoIDs}} - {{if eq . $Repo.ID}} - {{$include = false}} - {{else}} - {{.}}%2C - {{end}} - {{end}} - {{if eq $include true}} - {{$Repo.ID}}%2C - {{end}} - {{end}} + {{- with $include := true -}} + {{- range $.RepoIDs -}} + {{- if eq . $Repo.ID -}} + {{$include = false}} + {{- else -}} + {{.}}%2C + {{- end -}} + {{- end -}} + {{- if eq $include true -}} + {{$Repo.ID}}%2C + {{- end -}} + {{- end -}} ]&sort={{$.SortType}}&state={{$.State}}&q={{$.Keyword}}" title="{{.FullName}}"> <span class="text truncate">{{$Repo.FullName}}</span> <div class="ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{index $.Counts $Repo.ID}}</div> diff --git a/templates/user/dashboard/navbar.tmpl b/templates/user/dashboard/navbar.tmpl index 6f3b4ac51c..740929d46e 100644 --- a/templates/user/dashboard/navbar.tmpl +++ b/templates/user/dashboard/navbar.tmpl @@ -76,21 +76,21 @@ {{if .ContextUser.IsOrganization}} <div class="right stackable menu"> - <a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{.Team.Name}}{{end}}"> + <a class="{{if .PageIsNews}}active{{end}} item" style="margin-left: auto" href="{{.ContextUser.DashboardLink}}{{if .Team}}/{{PathEscape .Team.Name}}{{end}}"> {{svg "octicon-rss"}} {{.i18n.Tr "activities"}} </a> {{if not .UnitIssuesGlobalDisabled}} - <a class="{{if .PageIsIssues}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/issues{{if .Team}}/{{.Team.Name}}{{end}}"> + <a class="{{if .PageIsIssues}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/issues{{if .Team}}/{{PathEscape .Team.Name}}{{end}}"> {{svg "octicon-issue-opened"}} {{.i18n.Tr "issues"}} </a> {{end}} {{if not .UnitPullsGlobalDisabled}} - <a class="{{if .PageIsPulls}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/pulls{{if .Team}}/{{.Team.Name}}{{end}}"> + <a class="{{if .PageIsPulls}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/pulls{{if .Team}}/{{PathEscape.Team.Name}}{{end}}"> {{svg "octicon-git-pull-request"}} {{.i18n.Tr "pull_requests"}} </a> {{end}} {{if and .ShowMilestonesDashboardPage (not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled))}} - <a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/milestones{{if .Team}}/{{.Team.Name}}{{end}}"> + <a class="{{if .PageIsMilestonesDashboard}}active{{end}} item" href="{{.ContextUser.OrganisationLink}}/milestones{{if .Team}}/{{PathEscape .Team.Name}}{{end}}"> {{svg "octicon-milestone"}} {{.i18n.Tr "milestones"}} </a> {{end}} diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl index c02cdecd49..83a0f6b3ad 100644 --- a/templates/user/dashboard/repolist.tmpl +++ b/templates/user/dashboard/repolist.tmpl @@ -122,7 +122,7 @@ <div v-if="repos.length" class="ui attached table segment rounded-bottom"> <ul class="repo-owner-name-list"> <li v-for="repo in repos" :class="{'private': repo.private || repo.internal}"> - <a class="repo-list-link df ac sb" :href="subUrl + '/' + repo.full_name"> + <a class="repo-list-link df ac sb" :href="repo.html_url"> <div class="text truncate item-name f1"> <component v-bind:is="repoIcon(repo)" size="16"></component> <strong>${repo.full_name}</strong> @@ -176,7 +176,7 @@ <div v-if="organizations.length" class="ui attached table segment rounded-bottom"> <ul class="repo-owner-name-list"> <li v-for="org in organizations"> - <a class="repo-list-link df ac sb" :href="subUrl + '/' + org.name"> + <a class="repo-list-link df ac sb" :href="subUrl + '/' + encodeURIComponent(org.name)"> <div class="text truncate item-name f1"> {{svg "octicon-organization" 16 "mr-2"}} <strong>${org.name}</strong> diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index 8976e1fda4..67193169d9 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -68,8 +68,8 @@ {{end}} </a> </td> - <td data-href="{{AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}"> - <a class="item" href="{{AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}"> + <td data-href="{{$repo.Link}}"> + <a class="item" href="{{$repo.Link}}"> {{$repoOwner.Name}}/{{$repo.Name}} </a> </td> diff --git a/templates/user/settings/repos.tmpl b/templates/user/settings/repos.tmpl index b82f131b20..74f2bc0574 100644 --- a/templates/user/settings/repos.tmpl +++ b/templates/user/settings/repos.tmpl @@ -26,11 +26,11 @@ {{else}} <span class="icon">{{svg "octicon-repo"}}</span> {{end}} - <a class="name" href="{{AppSubUrl}}/{{$repo.OwnerName}}/{{$repo.Name}}">{{$repo.OwnerName}}/{{$repo.Name}}</a> + <a class="name" href="{{$repo.Link}}">{{$repo.OwnerName}}/{{$repo.Name}}</a> <span>{{SizeFmt $repo.Size}}</span> {{if $repo.IsFork}} {{$.i18n.Tr "repo.forked_from"}} - <span><a href="{{AppSubUrl}}/{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span> + <span><a href="{{$repo.BaseRepo.Link}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span> {{end}} {{else}} <span class="icon">{{svg "octicon-file-directory"}}</span> @@ -119,11 +119,11 @@ {{else}} <span class="iconFloat">{{svg "octicon-repo"}}</span> {{end}} - <a class="name" href="{{AppSubUrl}}/{{.OwnerName}}/{{.Name}}">{{.OwnerName}}/{{.Name}}</a> + <a class="name" href="{{.Link}}">{{.OwnerName}}/{{.Name}}</a> <span>{{SizeFmt .Size}}</span> {{if .IsFork}} {{$.i18n.Tr "repo.forked_from"}} - <span><a href="{{AppSubUrl}}/{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span> + <span><a href="{{.BaseRepo.Link}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span> {{end}} </div> </div> diff --git a/web_src/js/features/repo-branch.js b/web_src/js/features/repo-branch.js index c9119997ca..4402411bfd 100644 --- a/web_src/js/features/repo-branch.js +++ b/web_src/js/features/repo-branch.js @@ -1,6 +1,6 @@ export function initRepoBranchButton() { $('.show-create-branch-modal.button').on('click', function () { - $('#create-branch-form')[0].action = $('#create-branch-form').data('base-action') + $(this).data('branch-from'); + $('#create-branch-form')[0].action = $('#create-branch-form').data('base-action') + $(this).data('branch-from-urlcomponent'); $('#modal-create-branch-from-span').text($(this).data('branch-from')); $($(this).data('modal')).modal('show'); }); |