Skip to content

Commit 896f53d

Browse files
authored
Merge branch 'main' into bugfix/issue-34504
2 parents 0a5b405 + 181db69 commit 896f53d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1011
-890
lines changed

models/repo/repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ func (repo *Repository) AllowsPulls(ctx context.Context) bool {
653653

654654
// CanEnableEditor returns true if repository meets the requirements of web editor.
655655
func (repo *Repository) CanEnableEditor() bool {
656-
return !repo.IsMirror
656+
return !repo.IsMirror && !repo.IsArchived
657657
}
658658

659659
// DescriptionHTML does special handles to description and return HTML string.

modules/markup/sanitizer_default.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package markup
55

66
import (
7+
"html/template"
78
"io"
89
"net/url"
910
"regexp"
@@ -92,9 +93,9 @@ func (st *Sanitizer) createDefaultPolicy() *bluemonday.Policy {
9293
return policy
9394
}
9495

95-
// Sanitize takes a string that contains a HTML fragment or document and applies policy whitelist.
96-
func Sanitize(s string) string {
97-
return GetDefaultSanitizer().defaultPolicy.Sanitize(s)
96+
// Sanitize use default sanitizer policy to sanitize a string
97+
func Sanitize(s string) template.HTML {
98+
return template.HTML(GetDefaultSanitizer().defaultPolicy.Sanitize(s))
9899
}
99100

100101
// SanitizeReader sanitizes a Reader

modules/markup/sanitizer_default_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,6 @@ func TestSanitizer(t *testing.T) {
6969
}
7070

7171
for i := 0; i < len(testCases); i += 2 {
72-
assert.Equal(t, testCases[i+1], Sanitize(testCases[i]))
72+
assert.Equal(t, testCases[i+1], string(Sanitize(testCases[i])))
7373
}
7474
}

modules/templates/helper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ func safeHTML(s any) template.HTML {
176176
panic(fmt.Sprintf("unexpected type %T", s))
177177
}
178178

179-
// SanitizeHTML sanitizes the input by pre-defined markdown rules
179+
// SanitizeHTML sanitizes the input by default sanitization rules.
180180
func SanitizeHTML(s string) template.HTML {
181-
return template.HTML(markup.Sanitize(s))
181+
return markup.Sanitize(s)
182182
}
183183

184184
func htmlEscape(s any) template.HTML {

modules/web/router_path.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package web
66
import (
77
"net/http"
88
"regexp"
9+
"slices"
910
"strings"
1011

1112
"code.gitea.io/gitea/modules/container"
@@ -36,11 +37,21 @@ func (g *RouterPathGroup) ServeHTTP(resp http.ResponseWriter, req *http.Request)
3637
g.r.chiRouter.NotFoundHandler().ServeHTTP(resp, req)
3738
}
3839

40+
type RouterPathGroupPattern struct {
41+
re *regexp.Regexp
42+
params []routerPathParam
43+
middlewares []any
44+
}
45+
3946
// MatchPath matches the request method, and uses regexp to match the path.
40-
// The pattern uses "<...>" to define path parameters, for example: "/<name>" (different from chi router)
41-
// It is only designed to resolve some special cases which chi router can't handle.
47+
// The pattern uses "<...>" to define path parameters, for example, "/<name>" (different from chi router)
48+
// It is only designed to resolve some special cases that chi router can't handle.
4249
// For most cases, it shouldn't be used because it needs to iterate all rules to find the matched one (inefficient).
4350
func (g *RouterPathGroup) MatchPath(methods, pattern string, h ...any) {
51+
g.MatchPattern(methods, g.PatternRegexp(pattern), h...)
52+
}
53+
54+
func (g *RouterPathGroup) MatchPattern(methods string, pattern *RouterPathGroupPattern, h ...any) {
4455
g.matchers = append(g.matchers, newRouterPathMatcher(methods, pattern, h...))
4556
}
4657

@@ -96,8 +107,8 @@ func isValidMethod(name string) bool {
96107
return false
97108
}
98109

99-
func newRouterPathMatcher(methods, pattern string, h ...any) *routerPathMatcher {
100-
middlewares, handlerFunc := wrapMiddlewareAndHandler(nil, h)
110+
func newRouterPathMatcher(methods string, patternRegexp *RouterPathGroupPattern, h ...any) *routerPathMatcher {
111+
middlewares, handlerFunc := wrapMiddlewareAndHandler(patternRegexp.middlewares, h)
101112
p := &routerPathMatcher{methods: make(container.Set[string]), middlewares: middlewares, handlerFunc: handlerFunc}
102113
for method := range strings.SplitSeq(methods, ",") {
103114
method = strings.TrimSpace(method)
@@ -106,19 +117,25 @@ func newRouterPathMatcher(methods, pattern string, h ...any) *routerPathMatcher
106117
}
107118
p.methods.Add(method)
108119
}
120+
p.re, p.params = patternRegexp.re, patternRegexp.params
121+
return p
122+
}
123+
124+
func patternRegexp(pattern string, h ...any) *RouterPathGroupPattern {
125+
p := &RouterPathGroupPattern{middlewares: slices.Clone(h)}
109126
re := []byte{'^'}
110127
lastEnd := 0
111128
for lastEnd < len(pattern) {
112129
start := strings.IndexByte(pattern[lastEnd:], '<')
113130
if start == -1 {
114-
re = append(re, pattern[lastEnd:]...)
131+
re = append(re, regexp.QuoteMeta(pattern[lastEnd:])...)
115132
break
116133
}
117134
end := strings.IndexByte(pattern[lastEnd+start:], '>')
118135
if end == -1 {
119136
panic("invalid pattern: " + pattern)
120137
}
121-
re = append(re, pattern[lastEnd:lastEnd+start]...)
138+
re = append(re, regexp.QuoteMeta(pattern[lastEnd:lastEnd+start])...)
122139
partName, partExp, _ := strings.Cut(pattern[lastEnd+start+1:lastEnd+start+end], ":")
123140
lastEnd += start + end + 1
124141

@@ -140,7 +157,10 @@ func newRouterPathMatcher(methods, pattern string, h ...any) *routerPathMatcher
140157
p.params = append(p.params, param)
141158
}
142159
re = append(re, '$')
143-
reStr := string(re)
144-
p.re = regexp.MustCompile(reStr)
160+
p.re = regexp.MustCompile(string(re))
145161
return p
146162
}
163+
164+
func (g *RouterPathGroup) PatternRegexp(pattern string, h ...any) *RouterPathGroupPattern {
165+
return patternRegexp(pattern, h...)
166+
}

modules/web/router_test.go

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestPathProcessor(t *testing.T) {
3434
testProcess := func(pattern, uri string, expectedPathParams map[string]string) {
3535
chiCtx := chi.NewRouteContext()
3636
chiCtx.RouteMethod = "GET"
37-
p := newRouterPathMatcher("GET", pattern, http.NotFound)
37+
p := newRouterPathMatcher("GET", patternRegexp(pattern), http.NotFound)
3838
assert.True(t, p.matchPath(chiCtx, uri), "use pattern %s to process uri %s", pattern, uri)
3939
assert.Equal(t, expectedPathParams, chiURLParamsToMap(chiCtx), "use pattern %s to process uri %s", pattern, uri)
4040
}
@@ -56,18 +56,20 @@ func TestRouter(t *testing.T) {
5656
recorder.Body = buff
5757

5858
type resultStruct struct {
59-
method string
60-
pathParams map[string]string
61-
handlerMark string
59+
method string
60+
pathParams map[string]string
61+
handlerMarks []string
6262
}
63-
var res resultStruct
6463

64+
var res resultStruct
6565
h := func(optMark ...string) func(resp http.ResponseWriter, req *http.Request) {
6666
mark := util.OptionalArg(optMark, "")
6767
return func(resp http.ResponseWriter, req *http.Request) {
6868
res.method = req.Method
6969
res.pathParams = chiURLParamsToMap(chi.RouteContext(req.Context()))
70-
res.handlerMark = mark
70+
if mark != "" {
71+
res.handlerMarks = append(res.handlerMarks, mark)
72+
}
7173
}
7274
}
7375

@@ -77,6 +79,8 @@ func TestRouter(t *testing.T) {
7779
if stop := req.FormValue("stop"); stop != "" && (mark == "" || mark == stop) {
7880
h(stop)(resp, req)
7981
resp.WriteHeader(http.StatusOK)
82+
} else if mark != "" {
83+
res.handlerMarks = append(res.handlerMarks, mark)
8084
}
8185
}
8286
}
@@ -108,7 +112,7 @@ func TestRouter(t *testing.T) {
108112
m.Delete("", h())
109113
})
110114
m.PathGroup("/*", func(g *RouterPathGroup) {
111-
g.MatchPath("GET", `/<dir:*>/<file:[a-z]{1,2}>`, stopMark("s2"), h("match-path"))
115+
g.MatchPattern("GET", g.PatternRegexp(`/<dir:*>/<file:[a-z]{1,2}>`, stopMark("s2")), stopMark("s3"), h("match-path"))
112116
}, stopMark("s1"))
113117
})
114118
})
@@ -126,31 +130,31 @@ func TestRouter(t *testing.T) {
126130
}
127131

128132
t.Run("RootRouter", func(t *testing.T) {
129-
testRoute(t, "GET /the-user/the-repo/other", resultStruct{method: "GET", handlerMark: "not-found:/"})
133+
testRoute(t, "GET /the-user/the-repo/other", resultStruct{method: "GET", handlerMarks: []string{"not-found:/"}})
130134
testRoute(t, "GET /the-user/the-repo/pulls", resultStruct{
131-
method: "GET",
132-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "pulls"},
133-
handlerMark: "list-issues-b",
135+
method: "GET",
136+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "pulls"},
137+
handlerMarks: []string{"list-issues-b"},
134138
})
135139
testRoute(t, "GET /the-user/the-repo/issues/123", resultStruct{
136-
method: "GET",
137-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "issues", "index": "123"},
138-
handlerMark: "view-issue",
140+
method: "GET",
141+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "issues", "index": "123"},
142+
handlerMarks: []string{"view-issue"},
139143
})
140144
testRoute(t, "GET /the-user/the-repo/issues/123?stop=hijack", resultStruct{
141-
method: "GET",
142-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "issues", "index": "123"},
143-
handlerMark: "hijack",
145+
method: "GET",
146+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "type": "issues", "index": "123"},
147+
handlerMarks: []string{"hijack"},
144148
})
145149
testRoute(t, "POST /the-user/the-repo/issues/123/update", resultStruct{
146-
method: "POST",
147-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "index": "123"},
148-
handlerMark: "update-issue",
150+
method: "POST",
151+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "index": "123"},
152+
handlerMarks: []string{"update-issue"},
149153
})
150154
})
151155

152156
t.Run("Sub Router", func(t *testing.T) {
153-
testRoute(t, "GET /api/v1/other", resultStruct{method: "GET", handlerMark: "not-found:/api/v1"})
157+
testRoute(t, "GET /api/v1/other", resultStruct{method: "GET", handlerMarks: []string{"not-found:/api/v1"}})
154158
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches", resultStruct{
155159
method: "GET",
156160
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo"},
@@ -179,31 +183,37 @@ func TestRouter(t *testing.T) {
179183

180184
t.Run("MatchPath", func(t *testing.T) {
181185
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/d1/d2/fn", resultStruct{
182-
method: "GET",
183-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn", "dir": "d1/d2", "file": "fn"},
184-
handlerMark: "match-path",
186+
method: "GET",
187+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn", "dir": "d1/d2", "file": "fn"},
188+
handlerMarks: []string{"s1", "s2", "s3", "match-path"},
185189
})
186190
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/d1%2fd2/fn", resultStruct{
187-
method: "GET",
188-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1%2fd2/fn", "dir": "d1%2fd2", "file": "fn"},
189-
handlerMark: "match-path",
191+
method: "GET",
192+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1%2fd2/fn", "dir": "d1%2fd2", "file": "fn"},
193+
handlerMarks: []string{"s1", "s2", "s3", "match-path"},
190194
})
191195
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/d1/d2/000", resultStruct{
192-
method: "GET",
193-
pathParams: map[string]string{"reponame": "the-repo", "username": "the-user", "*": "d1/d2/000"},
194-
handlerMark: "not-found:/api/v1",
196+
method: "GET",
197+
pathParams: map[string]string{"reponame": "the-repo", "username": "the-user", "*": "d1/d2/000"},
198+
handlerMarks: []string{"s1", "not-found:/api/v1"},
195199
})
196200

197201
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/d1/d2/fn?stop=s1", resultStruct{
198-
method: "GET",
199-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn"},
200-
handlerMark: "s1",
202+
method: "GET",
203+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn"},
204+
handlerMarks: []string{"s1"},
201205
})
202206

203207
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/d1/d2/fn?stop=s2", resultStruct{
204-
method: "GET",
205-
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn", "dir": "d1/d2", "file": "fn"},
206-
handlerMark: "s2",
208+
method: "GET",
209+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn", "dir": "d1/d2", "file": "fn"},
210+
handlerMarks: []string{"s1", "s2"},
211+
})
212+
213+
testRoute(t, "GET /api/v1/repos/the-user/the-repo/branches/d1/d2/fn?stop=s3", resultStruct{
214+
method: "GET",
215+
pathParams: map[string]string{"username": "the-user", "reponame": "the-repo", "*": "d1/d2/fn", "dir": "d1/d2", "file": "fn"},
216+
handlerMarks: []string{"s1", "s2", "s3"},
207217
})
208218
})
209219
}

options/locale/locale_en-US.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,13 @@ editor.revert = Revert %s onto:
13991399
editor.failed_to_commit = Failed to commit changes.
14001400
editor.failed_to_commit_summary = Error Message:
14011401
1402+
editor.fork_create = Fork Repository to Propose Changes
1403+
editor.fork_create_description = You can not edit this repository directly. Instead you can create a fork, make edits and create a pull request.
1404+
editor.fork_edit_description = You can not edit this repository directly. The changes will be written to your fork <b>%s</b>, so you can create a pull request.
1405+
editor.fork_not_editable = You have forked this repository but your fork is not editable.
1406+
editor.fork_failed_to_push_branch = Failed to push branch %s to your repository.
1407+
editor.fork_branch_exists = Branch "%s" already exists in your fork, please choose a new branch name.
1408+
14021409
commits.desc = Browse source code change history.
14031410
commits.commits = Commits
14041411
commits.no_commits = No commits in common. "%s" and "%s" have entirely different histories.

0 commit comments

Comments
 (0)