Skip to content

Commit 0d0db1c

Browse files
committed
Merge branch 'main' into lunny/refactor_org_setting
2 parents 22cdf7e + 429efc8 commit 0d0db1c

File tree

125 files changed

+1990
-2089
lines changed

Some content is hidden

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

125 files changed

+1990
-2089
lines changed

SECURITY.md

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ Please **DO NOT** file a public issue, instead send your report privately to `se
1414

1515
Due to the sensitive nature of security information, you can use the below GPG public key to encrypt your mail body.
1616

17-
The PGP key is valid until July 9, 2025.
17+
The PGP key is valid until July 4, 2026.
1818

1919
```
2020
Key ID: 6FCD2D5B
2121
Key Type: RSA
22-
Expires: 7/9/2025
22+
Expires: 7/4/2026
2323
Key Size: 4096/4096
2424
Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
2525
```
@@ -42,18 +42,18 @@ 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
@@ -65,19 +65,19 @@ s+GsP9I3cmWWQcKYxWHtE8xTXnNCVPFZQj2nwhJzae8ypfOtulBRA3dUKWGKuDH/
6565
axFENhUsT397aOU3qkP/od4a64JyNIEo4CTTSPVeWd7njsGqli2U3A4xL2CcyYvt
6666
D/MWcMBGEoLSNTswwKdom4FaJpn5KThnK/T0bQcmJblJhoCtppXisbexZnCpuS0x
6767
Zdlm2T14KJ3LABEBAAGJAjwEGAEIACYCGwwWIQQ94D0eFEp/BpNZmdyq/SOBb80t
68-
WwUCZoyyjQUJBbh+DwAKCRCq/SOBb80tW18XD/9MXztmf01MT+1kZdBouZ/7Rp/7
69-
9kuqo//B1G+RXau4oFtPqb67kNe2WaIc3u5B73PUHsMf3i6z4ib2KbMhZZerLn0O
70-
dRglcuPeNWmsASY3dH/XVG0cT0zvvWegagd12TJEl3Vs+7XNrOw4cwDj9L1+GH9m
71-
kSt4uaANWn/6a3RvMRhiVEYuNwhAzcKaactPmYqrLJgoVLbRSDkgyHaMQ2jKgLxk
72-
ifS/fvluGV0ub2Po6DJiqfRpd1tDvPhe9y1+r1WFDZsOcvTcZUfSt/7dXMGfqGu0
73-
2daVFlfeSXSALrDE5uc0UxodHCpP3sqRYDZevGLBRaaTkIjYXG/+N898+7K5WJF4
74-
xXOLWxM2cwGkG7eC9pugcDnBp9XlF7O+GBiZ05JUe5flXDQFZ+h3exjopu6KHF1B
75-
RnzNy8LC0UKb+AuvRIOLV92a9Q9wGWU/jaVDu6nZ0umAeuSzxiHoDsonm0Fl9QAz
76-
2/xCokebuoeLrEK7R2af3X86mqq3sVO4ax+HPYChzOaVQBiHUW/TAldWcldYYphR
77-
/e2WsbmQfvCRtz/bZfo+aUVnrHNjzVMtF2SszdVmA/04Y8pS28MqtuRqhm5DPOOd
78-
g1YeUywK5jRZ1twyo1kzJEFPLaoeaXaycsR1PMVBW0Urik5mrR/pOWq7PPoZoKb2
79-
lXYLE8bwkuQTmsyL1g==
80-
=9i7d
68+
WwUCaGgeJAUJB5PppgAKCRCq/SOBb80tW/NWEACB6Jrf0gWlk7e+hNCdnbM0ZVWU
69+
f2sHNFfXxxsdhpcDgKbNHtkZb8nZgv8AX+5fTtUwMVa3vKcdw30xFiIM5N7cCIPV
70+
vg/5z5BtfEaitnabEUG2iiVDIy8IHXIcK10rX+7BosA3QDl2PsiBHwyi5G13lRk8
71+
zGTSNDuOalug33h5/lr2dPigamkq74Aoy29q8Rjad6GfWHipL2bFimgtY+Zdi0BH
72+
NLk4EJXxj1SgVx5dtkQzWJReBA5M+FQ4QYQZBO+f4TDoOLmjui152uhkoLBQbGAa
73+
WWJFTVxm0bG5MXloEL3gA8DfU7XDwuW/sHJC5pBko8RpQViooOhckMepZV3Y83DK
74+
bwLYa3JmPgj2rEv4993dvrJbQhpGd082HOxOsllCs8pgNq1SnXpWYfcGTgGKC3ts
75+
U8YZUUJUQ7mi2L8Tv3ix20c9EiGmA30JAmA8eZTC3cWup91ZkkVBFRml2czTXajd
76+
RWZ6GbHV5503ueDQcB8yBVgF3CSixs67+dGSbD3p86OqGrjAcJzM5TFbNKcnGLdE
77+
kGbZpNwAISy750lXzXKmyrh5RTCeTOQerbwCMBvHZO+HAevA/LXDTw2OAiSIQlP5
78+
sYA4sFYLQ30OAkgJcmdp/pSgVj/erNtSN07ClrOpDb/uFpQymO6K2h0Pst3feNVK
79+
9M2VbqL9C51z/wyHLg==
80+
=SfZA
8181
-----END PGP PUBLIC KEY BLOCK-----
8282
8383
```

models/issues/comment.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,8 @@ func (c *Comment) LoadReactions(ctx context.Context, repo *repo_model.Repository
715715
return nil
716716
}
717717

718-
func (c *Comment) loadReview(ctx context.Context) (err error) {
718+
// LoadReview loads the associated review
719+
func (c *Comment) LoadReview(ctx context.Context) (err error) {
719720
if c.ReviewID == 0 {
720721
return nil
721722
}
@@ -732,11 +733,6 @@ func (c *Comment) loadReview(ctx context.Context) (err error) {
732733
return nil
733734
}
734735

735-
// LoadReview loads the associated review
736-
func (c *Comment) LoadReview(ctx context.Context) error {
737-
return c.loadReview(ctx)
738-
}
739-
740736
// DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes.
741737
func (c *Comment) DiffSide() string {
742738
if c.Line < 0 {
@@ -856,7 +852,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
856852
}
857853
if comment.ReviewID != 0 {
858854
if comment.Review == nil {
859-
if err := comment.loadReview(ctx); err != nil {
855+
if err := comment.LoadReview(ctx); err != nil {
860856
return err
861857
}
862858
}

modules/auth/httpauth/httpauth.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package httpauth
5+
6+
import (
7+
"encoding/base64"
8+
"strings"
9+
10+
"code.gitea.io/gitea/modules/util"
11+
)
12+
13+
type BasicAuth struct {
14+
Username, Password string
15+
}
16+
17+
type BearerToken struct {
18+
Token string
19+
}
20+
21+
type ParsedAuthorizationHeader struct {
22+
BasicAuth *BasicAuth
23+
BearerToken *BearerToken
24+
}
25+
26+
func ParseAuthorizationHeader(header string) (ret ParsedAuthorizationHeader, _ bool) {
27+
parts := strings.Fields(header)
28+
if len(parts) != 2 {
29+
return ret, false
30+
}
31+
if util.AsciiEqualFold(parts[0], "basic") {
32+
s, err := base64.StdEncoding.DecodeString(parts[1])
33+
if err != nil {
34+
return ret, false
35+
}
36+
u, p, ok := strings.Cut(string(s), ":")
37+
if !ok {
38+
return ret, false
39+
}
40+
ret.BasicAuth = &BasicAuth{Username: u, Password: p}
41+
return ret, true
42+
} else if util.AsciiEqualFold(parts[0], "token") || util.AsciiEqualFold(parts[0], "bearer") {
43+
ret.BearerToken = &BearerToken{Token: parts[1]}
44+
return ret, true
45+
}
46+
return ret, false
47+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package httpauth
5+
6+
import (
7+
"encoding/base64"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestParseAuthorizationHeader(t *testing.T) {
14+
type parsed = ParsedAuthorizationHeader
15+
type basic = BasicAuth
16+
type bearer = BearerToken
17+
cases := []struct {
18+
headerValue string
19+
expected parsed
20+
ok bool
21+
}{
22+
{"", parsed{}, false},
23+
{"?", parsed{}, false},
24+
{"foo", parsed{}, false},
25+
{"any value", parsed{}, false},
26+
27+
{"Basic ?", parsed{}, false},
28+
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo")), parsed{}, false},
29+
{"Basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), parsed{BasicAuth: &basic{"foo", "bar"}}, true},
30+
{"basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), parsed{BasicAuth: &basic{"foo", "bar"}}, true},
31+
32+
{"token value", parsed{BearerToken: &bearer{"value"}}, true},
33+
{"Token value", parsed{BearerToken: &bearer{"value"}}, true},
34+
{"bearer value", parsed{BearerToken: &bearer{"value"}}, true},
35+
{"Bearer value", parsed{BearerToken: &bearer{"value"}}, true},
36+
{"Bearer wrong value", parsed{}, false},
37+
}
38+
for _, c := range cases {
39+
ret, ok := ParseAuthorizationHeader(c.headerValue)
40+
assert.Equal(t, c.ok, ok, "header %q", c.headerValue)
41+
assert.Equal(t, c.expected, ret, "header %q", c.headerValue)
42+
}
43+
}

modules/base/tool.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ import (
88
"crypto/sha1"
99
"crypto/sha256"
1010
"crypto/subtle"
11-
"encoding/base64"
1211
"encoding/hex"
13-
"errors"
1412
"fmt"
1513
"hash"
1614
"strconv"
17-
"strings"
1815
"time"
1916

2017
"code.gitea.io/gitea/modules/setting"
@@ -36,19 +33,6 @@ func ShortSha(sha1 string) string {
3633
return util.TruncateRunes(sha1, 10)
3734
}
3835

39-
// BasicAuthDecode decode basic auth string
40-
func BasicAuthDecode(encoded string) (string, string, error) {
41-
s, err := base64.StdEncoding.DecodeString(encoded)
42-
if err != nil {
43-
return "", "", err
44-
}
45-
46-
if username, password, ok := strings.Cut(string(s), ":"); ok {
47-
return username, password, nil
48-
}
49-
return "", "", errors.New("invalid basic authentication")
50-
}
51-
5236
// VerifyTimeLimitCode verify time limit code
5337
func VerifyTimeLimitCode(now time.Time, data string, minutes int, code string) bool {
5438
if len(code) <= 18 {

modules/base/tool_test.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,6 @@ func TestShortSha(t *testing.T) {
2626
assert.Equal(t, "veryverylo", ShortSha("veryverylong"))
2727
}
2828

29-
func TestBasicAuthDecode(t *testing.T) {
30-
_, _, err := BasicAuthDecode("?")
31-
assert.Equal(t, "illegal base64 data at input byte 0", err.Error())
32-
33-
user, pass, err := BasicAuthDecode("Zm9vOmJhcg==")
34-
assert.NoError(t, err)
35-
assert.Equal(t, "foo", user)
36-
assert.Equal(t, "bar", pass)
37-
38-
_, _, err = BasicAuthDecode("aW52YWxpZA==")
39-
assert.Error(t, err)
40-
41-
_, _, err = BasicAuthDecode("invalid")
42-
assert.Error(t, err)
43-
44-
_, _, err = BasicAuthDecode("YWxpY2U=") // "alice", no colon
45-
assert.Error(t, err)
46-
}
47-
4829
func TestVerifyTimeLimitCode(t *testing.T) {
4930
defer test.MockVariableValue(&setting.InstallLock, true)()
5031
initGeneralSecret := func(secret string) {

modules/structs/repo_file.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,17 @@ type ContentsExtResponse struct {
116116

117117
// ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content
118118
type ContentsResponse struct {
119-
Name string `json:"name"`
120-
Path string `json:"path"`
121-
SHA string `json:"sha"`
122-
LastCommitSHA string `json:"last_commit_sha"`
119+
Name string `json:"name"`
120+
Path string `json:"path"`
121+
SHA string `json:"sha"`
122+
123+
LastCommitSHA *string `json:"last_commit_sha,omitempty"`
123124
// swagger:strfmt date-time
124-
LastCommitterDate time.Time `json:"last_committer_date"`
125+
LastCommitterDate *time.Time `json:"last_committer_date,omitempty"`
125126
// swagger:strfmt date-time
126-
LastAuthorDate time.Time `json:"last_author_date"`
127+
LastAuthorDate *time.Time `json:"last_author_date,omitempty"`
128+
LastCommitMessage *string `json:"last_commit_message,omitempty"`
129+
127130
// `type` will be `file`, `dir`, `symlink`, or `submodule`
128131
Type string `json:"type"`
129132
Size int64 `json:"size"`
@@ -141,8 +144,8 @@ type ContentsResponse struct {
141144
SubmoduleGitURL *string `json:"submodule_git_url"`
142145
Links *FileLinksResponse `json:"_links"`
143146

144-
LfsOid *string `json:"lfs_oid"`
145-
LfsSize *int64 `json:"lfs_size"`
147+
LfsOid *string `json:"lfs_oid,omitempty"`
148+
LfsSize *int64 `json:"lfs_size,omitempty"`
146149
}
147150

148151
// FileCommitResponse contains information generated from a Git commit for a repo's file.

modules/util/string.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,24 @@ func SplitTrimSpace(input, sep string) []string {
110110
}
111111
return stringList
112112
}
113+
114+
func asciiLower(b byte) byte {
115+
if 'A' <= b && b <= 'Z' {
116+
return b + ('a' - 'A')
117+
}
118+
return b
119+
}
120+
121+
// AsciiEqualFold is from Golang https://cs.opensource.google/go/go/+/refs/tags/go1.24.4:src/net/http/internal/ascii/print.go
122+
// ASCII only. In most cases for protocols, we should only use this but not [strings.EqualFold]
123+
func AsciiEqualFold(s, t string) bool { //nolint:revive // PascalCase
124+
if len(s) != len(t) {
125+
return false
126+
}
127+
for i := 0; i < len(s); i++ {
128+
if asciiLower(s[i]) != asciiLower(t[i]) {
129+
return false
130+
}
131+
}
132+
return true
133+
}

modules/web/router_path.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func (g *RouterPathGroup) ServeHTTP(resp http.ResponseWriter, req *http.Request)
2626
path := chiCtx.URLParam(g.pathParam)
2727
for _, m := range g.matchers {
2828
if m.matchPath(chiCtx, path) {
29+
chiCtx.RoutePatterns = append(chiCtx.RoutePatterns, m.pattern)
2930
handler := m.handlerFunc
3031
for i := len(m.middlewares) - 1; i >= 0; i-- {
3132
handler = m.middlewares[i](handler).ServeHTTP
@@ -38,6 +39,7 @@ func (g *RouterPathGroup) ServeHTTP(resp http.ResponseWriter, req *http.Request)
3839
}
3940

4041
type RouterPathGroupPattern struct {
42+
pattern string
4143
re *regexp.Regexp
4244
params []routerPathParam
4345
middlewares []any
@@ -62,6 +64,7 @@ type routerPathParam struct {
6264

6365
type routerPathMatcher struct {
6466
methods container.Set[string]
67+
pattern string
6568
re *regexp.Regexp
6669
params []routerPathParam
6770
middlewares []func(http.Handler) http.Handler
@@ -117,7 +120,7 @@ func newRouterPathMatcher(methods string, patternRegexp *RouterPathGroupPattern,
117120
}
118121
p.methods.Add(method)
119122
}
120-
p.re, p.params = patternRegexp.re, patternRegexp.params
123+
p.pattern, p.re, p.params = patternRegexp.pattern, patternRegexp.re, patternRegexp.params
121124
return p
122125
}
123126

@@ -157,7 +160,7 @@ func patternRegexp(pattern string, h ...any) *RouterPathGroupPattern {
157160
p.params = append(p.params, param)
158161
}
159162
re = append(re, '$')
160-
p.re = regexp.MustCompile(string(re))
163+
p.pattern, p.re = pattern, regexp.MustCompile(string(re))
161164
return p
162165
}
163166

0 commit comments

Comments
 (0)