Skip to content

Commit f626aa0

Browse files
committed
Merge remote-tracking branch 'origin/main' into fixmerge
* origin/main: (27 commits) 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) Fix dump release asset bug (go-gitea#36799) build(deps): update material-icon-theme v5.32.0 (go-gitea#36832) Fix bug to check whether user can update pull request branch or rebase branch (go-gitea#36465) Fix forwarded proto handling for public URL detection (go-gitea#36810) Fix artifacts v4 backend upload problems (go-gitea#36805) Add a git grep search timeout (go-gitea#36809) fix(repo): unify DEFAULT_SHOW_FULL_NAME output in templates and dropdown (go-gitea#36597) Harden render iframe open-link handling (go-gitea#36811) [skip ci] Updated translations via Crowdin fix: /repos/{owner}/{repo}/actions/{runs,jobs} requiring owner permissions (go-gitea#36818) Fix CRAN package version validation to allow more than 4 version components (go-gitea#36813) Fix API not persisting pull request unit config when has_pull_requests is not set (go-gitea#36718) feat: Add Actions API rerun endpoints for runs and jobs (go-gitea#36768) Fix bug when pushing mirror with wiki (go-gitea#36795) Pull Request Pusher should be the author of the merge (go-gitea#36581) Delete non-exist branch should return 404 (go-gitea#36694) ... # Conflicts: # routers/web/repo/issue_view.go
2 parents 5ff665d + f3bdcc5 commit f626aa0

102 files changed

Lines changed: 4317 additions & 1206 deletions

File tree

Some content is hidden

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

.github/workflows/pull-docker-dryrun.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ jobs:
2929
context: .
3030
platforms: linux/amd64,linux/arm64,linux/riscv64
3131
push: false
32+
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
3233
- name: Build rootless container image
3334
uses: docker/build-push-action@v6
3435
with:
3536
context: .
3637
push: false
3738
platforms: linux/amd64,linux/arm64,linux/riscv64
3839
file: Dockerfile.rootless
40+
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless

.github/workflows/release-nightly.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ jobs:
120120
push: true
121121
tags: ${{ steps.meta.outputs.tags }}
122122
annotations: ${{ steps.meta.outputs.annotations }}
123+
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
124+
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max
123125
- name: build rootless docker image
124126
uses: docker/build-push-action@v6
125127
with:
@@ -129,3 +131,5 @@ jobs:
129131
file: Dockerfile.rootless
130132
tags: ${{ steps.meta_rootless.outputs.tags }}
131133
annotations: ${{ steps.meta_rootless.outputs.annotations }}
134+
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
135+
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless,mode=max

cmd/hook.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ Gitea or set your environment appropriately.`, "")
205205
PullRequestID: prID,
206206
DeployKeyID: deployKeyID,
207207
ActionPerm: actionPerm,
208+
IsWiki: isWiki,
208209
}
209210

210211
scanner := bufio.NewScanner(os.Stdin)
@@ -366,6 +367,7 @@ Gitea or set your environment appropriately.`, "")
366367
GitPushOptions: pushOptions(),
367368
PullRequestID: prID,
368369
PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)),
370+
IsWiki: isWiki,
369371
}
370372
oldCommitIDs := make([]string, hookBatchSize)
371373
newCommitIDs := make([]string, hookBatchSize)
@@ -513,6 +515,7 @@ Gitea or set your environment appropriately.`, "")
513515

514516
reader := bufio.NewReader(os.Stdin)
515517
repoUser := os.Getenv(repo_module.EnvRepoUsername)
518+
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
516519
repoName := os.Getenv(repo_module.EnvRepoName)
517520
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
518521
pusherName := os.Getenv(repo_module.EnvPusherName)
@@ -590,6 +593,7 @@ Gitea or set your environment appropriately.`, "")
590593
UserName: pusherName,
591594
UserID: pusherID,
592595
GitPushOptions: make(map[string]string),
596+
IsWiki: isWiki,
593597
}
594598
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
595599
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)

custom/conf/app.example.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ RUN_USER = ; git
7474
;; especially when the Gitea instance needs to be accessed in a container network.
7575
;; * legacy: detect the public URL from "Host" header if "X-Forwarded-Proto" header exists, otherwise use "ROOT_URL".
7676
;; * auto: always use "Host" header, and also use "X-Forwarded-Proto" header if it exists. If no "Host" header, use "ROOT_URL".
77+
;; * never: always use "ROOT_URL", never detect from request headers.
7778
;PUBLIC_URL_DETECTION = legacy
7879
;;
7980
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ require (
174174
github.com/caddyserver/zerossl v0.1.4 // indirect
175175
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
176176
github.com/cespare/xxhash/v2 v2.3.0 // indirect
177-
github.com/cloudflare/circl v1.6.1 // indirect
177+
github.com/cloudflare/circl v1.6.3 // indirect
178178
github.com/couchbase/go-couchbase v0.1.1 // indirect
179179
github.com/couchbase/gomemcached v0.3.3 // indirect
180180
github.com/couchbase/goutils v0.1.2 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
227227
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
228228
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
229229
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
230-
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
231-
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
230+
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
231+
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
232232
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
233233
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
234234
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/git/branch.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func DeleteBranches(ctx context.Context, repoID, doerID int64, branchIDs []int64
247247
return err
248248
}
249249
for _, branch := range branches {
250-
if err := AddDeletedBranch(ctx, repoID, branch.Name, doerID); err != nil {
250+
if err := MarkBranchAsDeleted(ctx, repoID, branch.Name, doerID); err != nil {
251251
return err
252252
}
253253
}
@@ -268,8 +268,8 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string
268268
})
269269
}
270270

271-
// AddDeletedBranch adds a deleted branch to the database
272-
func AddDeletedBranch(ctx context.Context, repoID int64, branchName string, deletedByID int64) error {
271+
// MarkBranchAsDeleted marks branch as deleted
272+
func MarkBranchAsDeleted(ctx context.Context, repoID int64, branchName string, deletedByID int64) error {
273273
branch, err := GetBranch(ctx, repoID, branchName)
274274
if err != nil {
275275
return err

models/git/branch_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ func TestAddDeletedBranch(t *testing.T) {
2828
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
2929

3030
assert.True(t, firstBranch.IsDeleted)
31-
assert.NoError(t, git_model.AddDeletedBranch(t.Context(), repo.ID, firstBranch.Name, firstBranch.DeletedByID))
32-
assert.NoError(t, git_model.AddDeletedBranch(t.Context(), repo.ID, "branch2", int64(1)))
31+
assert.NoError(t, git_model.MarkBranchAsDeleted(t.Context(), repo.ID, firstBranch.Name, firstBranch.DeletedByID))
32+
assert.NoError(t, git_model.MarkBranchAsDeleted(t.Context(), repo.ID, "branch2", int64(1)))
3333

3434
secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "branch2"})
3535
assert.True(t, secondBranch.IsDeleted)

0 commit comments

Comments
 (0)