Skip to content

Commit d623eae

Browse files
committed
Merge branch 'main' into up
* main: Fix dbfs error handling (go-gitea#36844) Fix OAuth2 authorization code expiry and reuse handling (go-gitea#36797) Fix org permission API visibility checks for hidden members and private orgs (go-gitea#36798) Fix non-admins unable to automerge PRs from forks (go-gitea#36833) upgrade to github.com/cloudflare/circl 1.6.3, svgo 4.0.1, markdownlint-cli 0.48.0 (go-gitea#36837) # Conflicts: # go.mod # go.sum
2 parents 05e773f + 2ce7162 commit d623eae

File tree

21 files changed

+314
-189
lines changed

21 files changed

+314
-189
lines changed

.github/workflows/cron-flake-updater.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
pull-requests: write
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v6
16+
- uses: actions/checkout@v5
1717
- uses: DeterminateSystems/determinate-nix-action@v3
1818
- uses: DeterminateSystems/update-flake-lock@main
1919
with:

.github/workflows/pull-compliance.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,6 @@ jobs:
213213
env:
214214
GOOS: linux
215215
GOARCH: 386
216-
- name: test-backend-pam
217-
run: |
218-
sudo apt-get install -y -qq libpam0g-dev
219-
echo "auth required pam_deny.so" | sudo tee /etc/pam.d/gitea
220-
go test -tags pam code.gitea.io/gitea/modules/auth/pam
221216

222217
docs:
223218
if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true'

.github/workflows/release-nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
echo "Cleaned name is ${REF_NAME}"
5353
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
5454
- name: configure aws
55-
uses: aws-actions/configure-aws-credentials@v6
55+
uses: aws-actions/configure-aws-credentials@v5
5656
with:
5757
aws-region: ${{ secrets.AWS_REGION }}
5858
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}

.github/workflows/release-tag-rc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
echo "Cleaned name is ${REF_NAME}"
5454
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
5555
- name: configure aws
56-
uses: aws-actions/configure-aws-credentials@v6
56+
uses: aws-actions/configure-aws-credentials@v5
5757
with:
5858
aws-region: ${{ secrets.AWS_REGION }}
5959
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}

.github/workflows/release-tag-version.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
echo "Cleaned name is ${REF_NAME}"
5757
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
5858
- name: configure aws
59-
uses: aws-actions/configure-aws-credentials@v6
59+
uses: aws-actions/configure-aws-credentials@v5
6060
with:
6161
aws-region: ${{ secrets.AWS_REGION }}
6262
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ require (
176176
github.com/cespare/xxhash/v2 v2.3.0 // indirect
177177
github.com/clipperhouse/displaywidth v0.10.0 // indirect
178178
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
179-
github.com/cloudflare/circl v1.6.2 // indirect
179+
github.com/cloudflare/circl v1.6.3 // indirect
180180
github.com/couchbase/go-couchbase v0.1.1 // indirect
181181
github.com/couchbase/gomemcached v0.3.3 // indirect
182182
github.com/couchbase/goutils v0.1.2 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+Urai
233233
github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs=
234234
github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos=
235235
github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
236-
github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ=
237-
github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
236+
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
237+
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
238238
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
239239
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
240240
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=

models/auth/oauth2.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"net/url"
1515
"slices"
1616
"strings"
17+
"time"
1718

1819
"code.gitea.io/gitea/models/db"
1920
"code.gitea.io/gitea/modules/container"
@@ -27,6 +28,11 @@ import (
2728
"xorm.io/xorm"
2829
)
2930

31+
// Authorization codes should expire within 10 minutes per https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2
32+
const oauth2AuthorizationCodeValidity = 10 * time.Minute
33+
34+
var ErrOAuth2AuthorizationCodeInvalidated = errors.New("oauth2 authorization code already invalidated")
35+
3036
// OAuth2Application represents an OAuth2 client (RFC 6749)
3137
type OAuth2Application struct {
3238
ID int64 `xorm:"pk autoincr"`
@@ -386,6 +392,14 @@ func (code *OAuth2AuthorizationCode) TableName() string {
386392
return "oauth2_authorization_code"
387393
}
388394

395+
// IsExpired reports whether the authorization code is expired.
396+
func (code *OAuth2AuthorizationCode) IsExpired() bool {
397+
if code.ValidUntil.IsZero() {
398+
return true
399+
}
400+
return code.ValidUntil <= timeutil.TimeStampNow()
401+
}
402+
389403
// GenerateRedirectURI generates a redirect URI for a successful authorization request. State will be used if not empty.
390404
func (code *OAuth2AuthorizationCode) GenerateRedirectURI(state string) (*url.URL, error) {
391405
redirect, err := url.Parse(code.RedirectURI)
@@ -403,8 +417,14 @@ func (code *OAuth2AuthorizationCode) GenerateRedirectURI(state string) (*url.URL
403417

404418
// Invalidate deletes the auth code from the database to invalidate this code
405419
func (code *OAuth2AuthorizationCode) Invalidate(ctx context.Context) error {
406-
_, err := db.GetEngine(ctx).ID(code.ID).NoAutoCondition().Delete(code)
407-
return err
420+
affected, err := db.GetEngine(ctx).ID(code.ID).NoAutoCondition().Delete(code)
421+
if err != nil {
422+
return err
423+
}
424+
if affected == 0 {
425+
return ErrOAuth2AuthorizationCodeInvalidated
426+
}
427+
return nil
408428
}
409429

410430
// ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation.
@@ -472,13 +492,15 @@ func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redi
472492
// for code scanners to grab sensitive tokens.
473493
codeSecret := "gta_" + base32Lower.EncodeToString(rBytes)
474494

495+
validUntil := time.Now().Add(oauth2AuthorizationCodeValidity)
475496
code = &OAuth2AuthorizationCode{
476497
Grant: grant,
477498
GrantID: grant.ID,
478499
RedirectURI: redirectURI,
479500
Code: codeSecret,
480501
CodeChallenge: codeChallenge,
481502
CodeChallengeMethod: codeChallengeMethod,
503+
ValidUntil: timeutil.TimeStamp(validUntil.Unix()),
482504
}
483505
if err := db.Insert(ctx, code); err != nil {
484506
return nil, err

models/auth/oauth2_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,45 @@ package auth_test
55

66
import (
77
"testing"
8+
"time"
89

910
auth_model "code.gitea.io/gitea/models/auth"
1011
"code.gitea.io/gitea/models/unittest"
12+
"code.gitea.io/gitea/modules/timeutil"
1113

1214
"github.com/stretchr/testify/assert"
1315
)
1416

17+
func TestOAuth2AuthorizationCodeValidity(t *testing.T) {
18+
assert.NoError(t, unittest.PrepareTestDatabase())
19+
20+
t.Run("GenerateSetsValidUntil", func(t *testing.T) {
21+
grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
22+
expectedValidUntil := timeutil.TimeStamp(time.Now().Unix() + 600)
23+
code, err := grant.GenerateNewAuthorizationCode(t.Context(), "http://127.0.0.1/", "", "")
24+
assert.NoError(t, err)
25+
assert.Equal(t, expectedValidUntil, code.ValidUntil)
26+
assert.False(t, code.IsExpired())
27+
assert.NoError(t, code.Invalidate(t.Context()))
28+
})
29+
30+
t.Run("Expired", func(t *testing.T) {
31+
defer timeutil.MockSet(time.Unix(2, 0).UTC())()
32+
33+
code := &auth_model.OAuth2AuthorizationCode{ValidUntil: timeutil.TimeStamp(1)}
34+
assert.True(t, code.IsExpired())
35+
})
36+
37+
t.Run("InvalidateTwice", func(t *testing.T) {
38+
code, err := auth_model.GetOAuth2AuthorizationByCode(t.Context(), "authcode")
39+
assert.NoError(t, err)
40+
if assert.NotNil(t, code) {
41+
assert.NoError(t, code.Invalidate(t.Context()))
42+
assert.ErrorIs(t, code.Invalidate(t.Context()), auth_model.ErrOAuth2AuthorizationCodeInvalidated)
43+
}
44+
})
45+
}
46+
1547
func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
1648
assert.NoError(t, unittest.PrepareTestDatabase())
1749
app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})

models/dbfs/dbfile.go

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (f *file) readAt(fileMeta *dbfsMeta, offset int64, p []byte) (n int, err er
7575
}
7676

7777
func (f *file) Read(p []byte) (n int, err error) {
78-
if f.metaID == 0 || !f.allowRead {
78+
if !f.allowRead {
7979
return 0, os.ErrInvalid
8080
}
8181

@@ -89,7 +89,7 @@ func (f *file) Read(p []byte) (n int, err error) {
8989
}
9090

9191
func (f *file) Write(p []byte) (n int, err error) {
92-
if f.metaID == 0 || !f.allowWrite {
92+
if !f.allowWrite {
9393
return 0, os.ErrInvalid
9494
}
9595

@@ -184,10 +184,6 @@ func (f *file) Close() error {
184184
}
185185

186186
func (f *file) Stat() (os.FileInfo, error) {
187-
if f.metaID == 0 {
188-
return nil, os.ErrInvalid
189-
}
190-
191187
fileMeta, err := findFileMetaByID(f.ctx, f.metaID)
192188
if err != nil {
193189
return nil, err
@@ -232,15 +228,17 @@ func (f *file) open(flag int) (err error) {
232228
if f.metaID != 0 {
233229
return os.ErrExist
234230
}
235-
} else {
236-
// create a new file if none exists.
237-
if f.metaID == 0 {
238-
if err = f.createEmpty(); err != nil {
239-
return err
240-
}
231+
}
232+
// create a new file if not exists.
233+
if f.metaID == 0 {
234+
if err = f.createEmpty(); err != nil {
235+
return err
241236
}
242237
}
243238
}
239+
if f.metaID == 0 {
240+
return os.ErrNotExist
241+
}
244242
if flag&os.O_TRUNC != 0 {
245243
if err = f.truncate(); err != nil {
246244
return err
@@ -252,7 +250,7 @@ func (f *file) open(flag int) (err error) {
252250
}
253251
}
254252
return nil
255-
}
253+
} // end if: allowWrite
256254

257255
// read only mode
258256
if f.metaID == 0 {
@@ -322,9 +320,6 @@ func (f *file) delete() error {
322320
}
323321

324322
func (f *file) size() (int64, error) {
325-
if f.metaID == 0 {
326-
return 0, os.ErrNotExist
327-
}
328323
fileMeta, err := findFileMetaByID(f.ctx, f.metaID)
329324
if err != nil {
330325
return 0, err
@@ -339,7 +334,7 @@ func findFileMetaByID(ctx context.Context, metaID int64) (*dbfsMeta, error) {
339334
} else if ok {
340335
return &fileMeta, nil
341336
}
342-
return nil, nil //nolint:nilnil // return nil to indicate that the object does not exist
337+
return nil, os.ErrNotExist
343338
}
344339

345340
func buildPath(path string) string {

0 commit comments

Comments
 (0)