Skip to content

Commit 4deb62b

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Update minimum go version to 1.26.1, golangci-lint to 2.11.2, fix test style (go-gitea#36876) Add render cache for SVG icons (go-gitea#36863) Fix incorrect viewed files counter if reverted change was viewed (go-gitea#36819) [skip ci] Updated translations via Crowdin Clean up `refreshViewedFilesSummary` (go-gitea#36868) Remove `util.URLJoin` and replace all callers with direct path concatenation (go-gitea#36867) Optimize Docker build with dependency layer caching (go-gitea#36864) Fix URLJoin, markup render link reoslving, sign-in/up/linkaccount page common data (go-gitea#36861) Fix CodeQL code scanning alerts (go-gitea#36858) Refactor auth middleware (go-gitea#36848) Update Nix flake (go-gitea#36857) Update JS deps (go-gitea#36850) Load `mentionValues` asynchronously (go-gitea#36739) [skip ci] Updated translations via Crowdin 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)
2 parents 9ad2bd8 + 8d06a94 commit 4deb62b

187 files changed

Lines changed: 4693 additions & 2070 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.

Dockerfile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
44
RUN apk --no-cache add build-base git nodejs pnpm
55
WORKDIR /src
6+
COPY package.json pnpm-lock.yaml .npmrc ./
7+
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
68
COPY --exclude=.git/ . .
7-
RUN --mount=type=cache,target=/root/.local/share/pnpm/store make frontend
9+
RUN make frontend
810

911
# Build backend for each target platform
1012
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
1113

12-
ARG GOPROXY=direct
13-
1414
ARG GITEA_VERSION
1515
ARG TAGS="sqlite sqlite_unlock_notify"
1616
ENV TAGS="bindata timetzdata $TAGS"
@@ -22,14 +22,15 @@ RUN apk --no-cache add \
2222
git
2323

2424
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
25+
COPY go.mod go.sum ./
26+
RUN go mod download
2527
# Use COPY instead of bind mount as read-only one breaks makefile state tracking and read-write one needs binary to be moved as it's discarded.
2628
# ".git" directory is mounted separately later only for version data extraction.
2729
COPY --exclude=.git/ . .
2830
COPY --from=frontend-build /src/public/assets public/assets
2931

3032
# Build gitea, .git mount is required for version data
31-
RUN --mount=type=cache,target=/go/pkg/mod \
32-
--mount=type=cache,target="/root/.cache/go-build" \
33+
RUN --mount=type=cache,target="/root/.cache/go-build" \
3334
--mount=type=bind,source=".git/",target=".git/" \
3435
make backend
3536

Dockerfile.rootless

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
44
RUN apk --no-cache add build-base git nodejs pnpm
55
WORKDIR /src
6+
COPY package.json pnpm-lock.yaml .npmrc ./
7+
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
68
COPY --exclude=.git/ . .
7-
RUN --mount=type=cache,target=/root/.local/share/pnpm/store make frontend
9+
RUN make frontend
810

911
# Build backend for each target platform
1012
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
1113

12-
ARG GOPROXY=direct
13-
1414
ARG GITEA_VERSION
1515
ARG TAGS="sqlite sqlite_unlock_notify"
1616
ENV TAGS="bindata timetzdata $TAGS"
@@ -22,13 +22,14 @@ RUN apk --no-cache add \
2222
git
2323

2424
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
25+
COPY go.mod go.sum ./
26+
RUN go mod download
2527
# See the comments in Dockerfile
2628
COPY --exclude=.git/ . .
2729
COPY --from=frontend-build /src/public/assets public/assets
2830

2931
# Build gitea, .git mount is required for version data
30-
RUN --mount=type=cache,target=/go/pkg/mod \
31-
--mount=type=cache,target="/root/.cache/go-build" \
32+
RUN --mount=type=cache,target="/root/.cache/go-build" \
3233
--mount=type=bind,source=".git/",target=".git/" \
3334
make backend
3435

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ XGO_VERSION := go-1.25.x
1515
AIR_PACKAGE ?= github.com/air-verse/air@v1
1616
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3
1717
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2
18-
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1
18+
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.2
1919
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15
2020
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0
2121
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1

eslint.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ export default defineConfig([
926926
},
927927
extends: [
928928
vue.configs['flat/recommended'],
929-
vueScopedCss.configs['flat/recommended'] as any,
929+
vueScopedCss.configs.recommended as any,
930930
],
931931
rules: {
932932
'vue/attributes-order': [0],

flake.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module code.gitea.io/gitea
22

3-
go 1.26.0
3+
go 1.26.1
44

55
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
66
// But some CAs use negative serial number, just relax the check. related:

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 {

models/dbfs/dbfs.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ The DBFS solution:
4040
* In the future, when Gitea action needs to limit the log size (other CI/CD services also do so), it's easier to calculate the log file size.
4141
* Even sometimes the UI needs to render the tailing lines, the tailing lines can be found be counting the "\n" from the end of the file by seek.
4242
The seeking and finding is not the fastest way, but it's still acceptable and won't affect the performance too much.
43+
44+
Limitations of the DBFS solution:
45+
* Not fully POSIX-compliant, some behaviors may be different from the real filesystem, especially for concurrent read/write
4346
*/
4447

4548
type dbfsMeta struct {

0 commit comments

Comments
 (0)