Selaa lähdekoodia

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>
tags/v1.16.0-rc1
zeripath 2 vuotta sitten
vanhempi
commit
bbffcc3aec
No account linked to committer's email address
100 muutettua tiedostoa jossa 640 lisäystä ja 455 poistoa
  1. 2
    2
      integrations/issue_test.go
  2. 1
    1
      integrations/links_test.go
  3. 16
    16
      integrations/nonascii_branches_test.go
  4. 3
    4
      models/action.go
  5. 2
    1
      models/attachment.go
  6. 4
    4
      models/avatars/avatar.go
  7. 2
    2
      models/commit_status.go
  8. 11
    0
      models/issue.go
  9. 2
    1
      models/notification.go
  10. 5
    6
      models/release.go
  11. 8
    13
      models/repo.go
  12. 2
    1
      models/repo_avatar.go
  13. 4
    3
      models/user.go
  14. 13
    3
      modules/context/context.go
  15. 20
    18
      modules/context/repo.go
  16. 6
    5
      modules/convert/git_commit.go
  17. 2
    1
      modules/convert/issue.go
  18. 3
    1
      modules/convert/notification.go
  19. 3
    1
      modules/git/utils.go
  20. 2
    1
      modules/repofiles/action.go
  21. 3
    1
      modules/repofiles/blob.go
  22. 4
    4
      modules/repofiles/file.go
  23. 2
    1
      modules/repofiles/tree.go
  24. 2
    1
      modules/repository/commits.go
  25. 9
    12
      modules/templates/helper.go
  26. 2
    1
      modules/upload/upload.go
  27. 19
    19
      options/locale/locale_en-US.ini
  28. 2
    1
      routers/api/v1/org/member.go
  29. 4
    2
      routers/api/v1/repo/git_ref.go
  30. 6
    5
      routers/api/v1/repo/key.go
  31. 4
    2
      routers/web/admin/auths.go
  32. 2
    2
      routers/web/admin/repos.go
  33. 5
    5
      routers/web/admin/users.go
  34. 104
    30
      routers/web/feed/convert.go
  35. 2
    1
      routers/web/org/setting.go
  36. 10
    9
      routers/web/org/teams.go
  37. 6
    4
      routers/web/repo/blame.go
  38. 1
    3
      routers/web/repo/commit.go
  39. 19
    14
      routers/web/repo/compare.go
  40. 6
    6
      routers/web/repo/editor.go
  41. 15
    10
      routers/web/repo/issue.go
  42. 2
    0
      routers/web/repo/issue_stopwatch.go
  43. 2
    1
      routers/web/repo/lfs.go
  44. 2
    1
      routers/web/repo/migrate.go
  45. 2
    1
      routers/web/repo/milestone.go
  46. 2
    1
      routers/web/repo/projects.go
  47. 36
    36
      routers/web/repo/pull.go
  48. 2
    1
      routers/web/repo/release.go
  49. 2
    2
      routers/web/repo/repo.go
  50. 8
    8
      routers/web/repo/setting.go
  51. 4
    3
      routers/web/repo/setting_protected_branch.go
  52. 1
    1
      routers/web/repo/tag.go
  53. 8
    8
      routers/web/repo/view.go
  54. 6
    5
      routers/web/repo/webhook.go
  55. 57
    8
      routers/web/repo/wiki.go
  56. 11
    11
      routers/web/repo/wiki_test.go
  57. 1
    1
      routers/web/user/home.go
  58. 2
    3
      routers/web/user/notification.go
  59. 1
    1
      routers/web/user/oauth.go
  60. 1
    1
      routers/web/user/profile.go
  61. 15
    13
      routers/web/web.go
  62. 4
    3
      services/lfs/server.go
  63. 4
    3
      services/webhook/dingtalk.go
  64. 4
    3
      services/webhook/discord.go
  65. 8
    6
      services/webhook/general.go
  66. 7
    5
      services/webhook/matrix.go
  67. 4
    3
      services/webhook/msteams.go
  68. 1
    1
      services/wiki/wiki.go
  69. 1
    1
      templates/admin/emails/list.tmpl
  70. 2
    2
      templates/admin/repo/list.tmpl
  71. 1
    1
      templates/admin/user/list.tmpl
  72. 2
    2
      templates/base/head.tmpl
  73. 6
    7
      templates/base/head_navbar.tmpl
  74. 3
    3
      templates/explore/code.tmpl
  75. 1
    1
      templates/mail/auth/activate.tmpl
  76. 1
    1
      templates/mail/auth/activate_email.tmpl
  77. 1
    1
      templates/mail/auth/register_notify.tmpl
  78. 1
    1
      templates/mail/auth/reset_passwd.tmpl
  79. 2
    2
      templates/mail/issue/assigned.tmpl
  80. 14
    14
      templates/mail/issue/default.tmpl
  81. 1
    1
      templates/mail/notify/repo_transfer.tmpl
  82. 4
    6
      templates/mail/release.tmpl
  83. 3
    3
      templates/org/home.tmpl
  84. 2
    2
      templates/org/team/members.tmpl
  85. 2
    2
      templates/org/team/navbar.tmpl
  86. 2
    2
      templates/org/team/new.tmpl
  87. 6
    6
      templates/org/team/repositories.tmpl
  88. 3
    3
      templates/org/team/sidebar.tmpl
  89. 3
    3
      templates/org/team/teams.tmpl
  90. 1
    1
      templates/repo/activity.tmpl
  91. 4
    4
      templates/repo/blame.tmpl
  92. 15
    15
      templates/repo/branch/list.tmpl
  93. 4
    4
      templates/repo/branch_dropdown.tmpl
  94. 3
    3
      templates/repo/commit_page.tmpl
  95. 4
    4
      templates/repo/commits_list.tmpl
  96. 3
    3
      templates/repo/commits_list_small.tmpl
  97. 3
    3
      templates/repo/commits_table.tmpl
  98. 1
    1
      templates/repo/create.tmpl
  99. 6
    6
      templates/repo/diff/blob_excerpt.tmpl
  100. 0
    0
      templates/repo/diff/box.tmpl

+ 2
- 2
integrations/issue_test.go Näytä tiedosto

@@ -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)

+ 1
- 1
integrations/links_test.go Näytä tiedosto

@@ -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 {

+ 16
- 16
integrations/nonascii_branches_test.go Näytä tiedosto

@@ -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,
},
}

+ 3
- 4
models/action.go Näytä tiedosto

@@ -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

+ 2
- 1
models/attachment.go Näytä tiedosto

@@ -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

+ 4
- 4
models/avatars/avatar.go Näytä tiedosto

@@ -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)
}

+ 2
- 2
models/commit_status.go Näytä tiedosto

@@ -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

+ 11
- 0
models/issue.go Näytä tiedosto

@@ -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 {

+ 2
- 1
models/notification.go Näytä tiedosto

@@ -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()
}

+ 5
- 6
models/release.go Näytä tiedosto

@@ -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.

+ 8
- 13
models/repo.go Näytä tiedosto

@@ -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

+ 2
- 1
models/repo_avatar.go Näytä tiedosto

@@ -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.

+ 4
- 3
models/user.go Näytä tiedosto

@@ -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.

+ 13
- 3
modules/context/context.go Näytä tiedosto

@@ -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 != "" {

+ 20
- 18
modules/context/repo.go Näytä tiedosto

@@ -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
}
}

+ 6
- 5
modules/convert/git_commit.go Näytä tiedosto

@@ -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,
},

+ 2
- 1
modules/convert/issue.go Näytä tiedosto

@@ -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)
}

+ 3
- 1
modules/convert/notification.go Näytä tiedosto

@@ -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,

+ 3
- 1
modules/git/utils.go Näytä tiedosto

@@ -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

+ 2
- 1
modules/repofiles/action.go Näytä tiedosto

@@ -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
}

+ 3
- 1
modules/repofiles/blob.go Näytä tiedosto

@@ -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,

+ 4
- 4
modules/repofiles/file.go Näytä tiedosto

@@ -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(),

+ 2
- 1
modules/repofiles/tree.go Näytä tiedosto

@@ -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()

+ 2
- 1
modules/repository/commits.go Näytä tiedosto

@@ -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,

+ 9
- 12
modules/templates/helper.go Näytä tiedosto

@@ -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.

+ 2
- 1
modules/upload/upload.go Näytä tiedosto

@@ -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"
}

+ 19
- 19
options/locale/locale_en-US.ini Näytä tiedosto

@@ -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>


+ 2
- 1
routers/api/v1/org/member.go Näytä tiedosto

@@ -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)
}


+ 4
- 2
routers/api/v1/repo/git_ref.go Näytä tiedosto

@@ -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()),
},
}
}

+ 6
- 5
routers/api/v1/repo/key.go Näytä tiedosto

@@ -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))
}


+ 4
- 2
routers/web/admin/auths.go Näytä tiedosto

@@ -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
}

+ 2
- 2
routers/web/admin/repos.go Näytä tiedosto

@@ -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))
}

+ 5
- 5
routers/web/admin/users.go Näytä tiedosto

@@ -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)

+ 104
- 30
routers/web/feed/convert.go Näytä tiedosto

@@ -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),
)

+ 2
- 1
routers/web/org/setting.go Näytä tiedosto

@@ -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
}

+ 10
- 9
routers/web/org/teams.go Näytä tiedosto

@@ -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

+ 6
- 4
routers/web/repo/blame.go Näytä tiedosto

@@ -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
}

+ 1
- 3
routers/web/repo/commit.go Näytä tiedosto

@@ -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

+ 19
- 14
routers/web/repo/compare.go Näytä tiedosto

@@ -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
}

+ 6
- 6
routers/web/repo/editor.go Näytä tiedosto

@@ -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 {

+ 15
- 10
routers/web/repo/issue.go Näytä tiedosto

@@ -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,

+ 2
- 0
routers/web/repo/issue_stopwatch.go Näytä tiedosto

@@ -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

+ 2
- 1
routers/web/repo/lfs.go Näytä tiedosto

@@ -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() {

+ 2
- 1
routers/web/repo/migrate.go Näytä tiedosto

@@ -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
}


+ 2
- 1
routers/web/repo/milestone.go Näytä tiedosto

@@ -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

+ 2
- 1
routers/web/repo/projects.go Näytä tiedosto

@@ -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

+ 36
- 36
routers/web/repo/pull.go Näytä tiedosto

@@ -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{}{

+ 2
- 1
routers/web/repo/release.go Näytä tiedosto

@@ -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
}


+ 2
- 2
routers/web/repo/repo.go Näytä tiedosto

@@ -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
}
}

+ 8
- 8
routers/web/repo/setting.go Näytä tiedosto

@@ -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

+ 4
- 3
routers/web/repo/setting_protected_branch.go Näytä tiedosto

@@ -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 {

+ 1
- 1
routers/web/repo/tag.go Näytä tiedosto

@@ -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

+ 8
- 8
routers/web/repo/view.go Näytä tiedosto

@@ -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

+ 6
- 5
routers/web/repo/webhook.go Näytä tiedosto

@@ -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,

+ 57
- 8
routers/web/repo/wiki.go Näytä tiedosto

@@ -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"
}

+ 11
- 11
routers/web/repo/wiki_test.go Näytä tiedosto

@@ -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)

+ 1
- 1
routers/web/user/home.go Näytä tiedosto

@@ -887,5 +887,5 @@ func Email2User(ctx *context.Context) {
}
return
}
ctx.Redirect(setting.AppSubURL + "/user/" + u.Name)
ctx.Redirect(u.HomeLink())
}

+ 2
- 3
routers/web/user/notification.go Näytä tiedosto

@@ -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)
}

+ 1
- 1
routers/web/user/oauth.go Näytä tiedosto

@@ -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)

+ 1
- 1
routers/web/user/profile.go Näytä tiedosto

@@ -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())
}

+ 15
- 13
routers/web/web.go Näytä tiedosto

@@ -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
})


+ 4
- 3
services/lfs/server.go Näytä tiedosto

@@ -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.

+ 4
- 3
services/webhook/dingtalk.go Näytä tiedosto

@@ -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)

+ 4
- 3
services/webhook/discord.go Näytä tiedosto

@@ -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)

+ 8
- 6
services/webhook/general.go Näytä tiedosto

@@ -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

+ 7
- 5
services/webhook/matrix.go Näytä tiedosto

@@ -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 {

+ 4
- 3
services/webhook/msteams.go Näytä tiedosto

@@ -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)

+ 1
- 1
services/wiki/wiki.go Näytä tiedosto

@@ -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

+ 1
- 1
templates/admin/emails/list.tmpl Näytä tiedosto

@@ -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>

+ 2
- 2
templates/admin/repo/list.tmpl Näytä tiedosto

@@ -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}}

+ 1
- 1
templates/admin/user/list.tmpl Näytä tiedosto

@@ -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>

+ 2
- 2
templates/base/head.tmpl Näytä tiedosto

@@ -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>

+ 6
- 7
templates/base/head_navbar.tmpl Näytä tiedosto

@@ -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>

+ 3
- 3
templates/explore/code.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/mail/auth/activate.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/mail/auth/activate_email.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/mail/auth/register_notify.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/mail/auth/reset_passwd.tmpl Näytä tiedosto

@@ -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>

+ 2
- 2
templates/mail/issue/assigned.tmpl Näytä tiedosto

@@ -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}}

+ 14
- 14
templates/mail/issue/default.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/mail/notify/repo_transfer.tmpl Näytä tiedosto

@@ -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}}

+ 4
- 6
templates/mail/release.tmpl Näytä tiedosto

@@ -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}}

+ 3
- 3
templates/org/home.tmpl Näytä tiedosto

@@ -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}}

+ 2
- 2
templates/org/team/members.tmpl Näytä tiedosto

@@ -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>

+ 2
- 2
templates/org/team/navbar.tmpl Näytä tiedosto

@@ -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>&nbsp; {{$.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>&nbsp; {{$.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>&nbsp; {{$.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>&nbsp; {{$.i18n.Tr "org.lower_repositories"}}</a>
</div>

+ 2
- 2
templates/org/team/new.tmpl Näytä tiedosto

@@ -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>

+ 6
- 6
templates/org/team/repositories.tmpl Näytä tiedosto

@@ -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}}

+ 3
- 3
templates/org/team/sidebar.tmpl Näytä tiedosto

@@ -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>

+ 3
- 3
templates/org/team/teams.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/repo/activity.tmpl Näytä tiedosto

@@ -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>

+ 4
- 4
templates/repo/blame.tmpl Näytä tiedosto

@@ -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>

+ 15
- 15
templates/repo/branch/list.tmpl Näytä tiedosto

@@ -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"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.DefaultBranch}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments $.DefaultBranch}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;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"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments .Name}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{PathEscapeSegments .Name}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;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}}

+ 4
- 4
templates/repo/branch_dropdown.tmpl Näytä tiedosto

@@ -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">

+ 3
- 3
templates/repo/commit_page.tmpl Näytä tiedosto

@@ -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>

+ 4
- 4
templates/repo/commits_list.tmpl Näytä tiedosto

@@ -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>

+ 3
- 3
templates/repo/commits_list_small.tmpl Näytä tiedosto

@@ -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>

+ 3
- 3
templates/repo/commits_table.tmpl Näytä tiedosto

@@ -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>

+ 1
- 1
templates/repo/create.tmpl Näytä tiedosto

@@ -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}}

+ 6
- 6
templates/repo/diff/blob_excerpt.tmpl Näytä tiedosto

@@ -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}}

+ 0
- 0
templates/repo/diff/box.tmpl Näytä tiedosto


Some files were not shown because too many files changed in this diff

Loading…
Peruuta
Tallenna