Skip to content

Commit b4a4443

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: [skip ci] Updated translations via Crowdin Fix possible nil pointer access (go-gitea#28428) Don't show unnecessary citation JS error on UI (go-gitea#28433) Do some missing checks (go-gitea#28423) Deprecate query string auth tokens (go-gitea#28390)
2 parents de9f6d8 + c229e65 commit b4a4443

File tree

13 files changed

+129
-42
lines changed

13 files changed

+129
-42
lines changed

custom/conf/app.example.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,11 @@ INTERNAL_TOKEN=
492492
;; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
493493
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
494494
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
495+
;;
496+
;; Reject API tokens sent in URL query string (Accept Header-based API tokens only). This avoids security vulnerabilities
497+
;; stemming from cached/logged plain-text API tokens.
498+
;; In future releases, this will become the default behavior
499+
;DISABLE_QUERY_AUTH_TOKEN = false
495500

496501
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
497502
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

modules/setting/security.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ var (
3434
PasswordHashAlgo string
3535
PasswordCheckPwn bool
3636
SuccessfulTokensCacheSize int
37+
DisableQueryAuthToken bool
3738
CSRFCookieName = "_csrf"
3839
CSRFCookieHTTPOnly = true
3940
)
@@ -157,4 +158,11 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
157158
PasswordComplexity = append(PasswordComplexity, name)
158159
}
159160
}
161+
162+
// TODO: default value should be true in future releases
163+
DisableQueryAuthToken = sec.Key("DISABLE_QUERY_AUTH_TOKEN").MustBool(false)
164+
165+
if !DisableQueryAuthToken {
166+
log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.")
167+
}
160168
}

options/locale/locale_lv-LV.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ milestones=Atskaites punkti
8080

8181
ok=Labi
8282
cancel=Atcelt
83+
retry=Mēģināt vēlreiz
8384
rerun=Palaist atkārtoti
8485
rerun_all=Palaist atkārtoti visus darbus
8586
save=Saglabāt
@@ -95,6 +96,7 @@ disabled=Atspējots
9596

9697
copy=Kopēt
9798
copy_url=Kopēt saiti
99+
copy_hash=Kopēt jaucējkodu
98100
copy_content=Kopēt saturu
99101
copy_branch=Kopēt atzara nosaukumu
100102
copy_success=Nokopēts!
@@ -129,6 +131,7 @@ show_timestamps=Rādīt laika zīmogus
129131
show_log_seconds=Rādīt sekundes
130132
show_full_screen=Atvērt pilnā logā
131133

134+
confirm_delete_selected=Apstiprināt, lai izdzēstu visus atlasītos vienumus?
132135

133136
name=Nosaukums
134137
value=Vērtība

routers/api/v1/api.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@
3535
// type: apiKey
3636
// name: token
3737
// in: query
38+
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
3839
// AccessToken:
3940
// type: apiKey
4041
// name: access_token
4142
// in: query
43+
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
4244
// AuthorizationHeaderToken:
4345
// type: apiKey
4446
// name: Authorization
@@ -788,6 +790,31 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
788790
}
789791
}
790792

793+
func individualPermsChecker(ctx *context.APIContext) {
794+
// org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
795+
if ctx.ContextUser.IsIndividual() {
796+
switch {
797+
case ctx.ContextUser.Visibility == api.VisibleTypePrivate:
798+
if ctx.Doer == nil || (ctx.ContextUser.ID != ctx.Doer.ID && !ctx.Doer.IsAdmin) {
799+
ctx.NotFound("Visit Project", nil)
800+
return
801+
}
802+
case ctx.ContextUser.Visibility == api.VisibleTypeLimited:
803+
if ctx.Doer == nil {
804+
ctx.NotFound("Visit Project", nil)
805+
return
806+
}
807+
}
808+
}
809+
}
810+
811+
// check for and warn against deprecated authentication options
812+
func checkDeprecatedAuthMethods(ctx *context.APIContext) {
813+
if ctx.FormString("token") != "" || ctx.FormString("access_token") != "" {
814+
ctx.Resp.Header().Set("Warning", "token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization.")
815+
}
816+
}
817+
791818
// Routes registers all v1 APIs routes to web application.
792819
func Routes() *web.Route {
793820
m := web.NewRoute()
@@ -806,6 +833,8 @@ func Routes() *web.Route {
806833
}
807834
m.Use(context.APIContexter())
808835

836+
m.Use(checkDeprecatedAuthMethods)
837+
809838
// Get user from session if logged in.
810839
m.Use(apiAuth(buildAuthGroup()))
811840

@@ -888,7 +917,7 @@ func Routes() *web.Route {
888917
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
889918

890919
m.Get("/activities/feeds", user.ListUserActivityFeeds)
891-
}, context_service.UserAssignmentAPI())
920+
}, context_service.UserAssignmentAPI(), individualPermsChecker)
892921
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
893922

894923
// Users (requires user scope)

routers/web/web.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,24 @@ func registerRoutes(m *web.Route) {
796796
}
797797
}
798798

799+
individualPermsChecker := func(ctx *context.Context) {
800+
// org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
801+
if ctx.ContextUser.IsIndividual() {
802+
switch {
803+
case ctx.ContextUser.Visibility == structs.VisibleTypePrivate:
804+
if ctx.Doer == nil || (ctx.ContextUser.ID != ctx.Doer.ID && !ctx.Doer.IsAdmin) {
805+
ctx.NotFound("Visit Project", nil)
806+
return
807+
}
808+
case ctx.ContextUser.Visibility == structs.VisibleTypeLimited:
809+
if ctx.Doer == nil {
810+
ctx.NotFound("Visit Project", nil)
811+
return
812+
}
813+
}
814+
}
815+
}
816+
799817
// ***** START: Organization *****
800818
m.Group("/org", func() {
801819
m.Group("/{org}", func() {
@@ -976,11 +994,11 @@ func registerRoutes(m *web.Route) {
976994
return
977995
}
978996
})
979-
})
997+
}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true), individualPermsChecker)
980998

981999
m.Group("", func() {
9821000
m.Get("/code", user.CodeSearch)
983-
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false))
1001+
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker)
9841002
}, ignSignIn, context_service.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code)
9851003

9861004
m.Group("/{username}/{reponame}", func() {

services/auth/oauth2.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
auth_model "code.gitea.io/gitea/models/auth"
1515
user_model "code.gitea.io/gitea/models/user"
1616
"code.gitea.io/gitea/modules/log"
17+
"code.gitea.io/gitea/modules/setting"
1718
"code.gitea.io/gitea/modules/timeutil"
1819
"code.gitea.io/gitea/modules/web/middleware"
1920
"code.gitea.io/gitea/services/auth/source/oauth2"
@@ -62,14 +63,19 @@ func (o *OAuth2) Name() string {
6263
// representing whether the token exists or not
6364
func parseToken(req *http.Request) (string, bool) {
6465
_ = req.ParseForm()
65-
// Check token.
66-
if token := req.Form.Get("token"); token != "" {
67-
return token, true
68-
}
69-
// Check access token.
70-
if token := req.Form.Get("access_token"); token != "" {
71-
return token, true
66+
if !setting.DisableQueryAuthToken {
67+
// Check token.
68+
if token := req.Form.Get("token"); token != "" {
69+
return token, true
70+
}
71+
// Check access token.
72+
if token := req.Form.Get("access_token"); token != "" {
73+
return token, true
74+
}
75+
} else if req.Form.Get("token") != "" || req.Form.Get("access_token") != "" {
76+
log.Warn("API token sent in query string but DISABLE_QUERY_AUTH_TOKEN=true")
7277
}
78+
7379
// check header token
7480
if auHead := req.Header.Get("Authorization"); auHead != "" {
7581
auths := strings.Fields(auHead)

services/packages/alpine/repository.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error {
8282
}
8383

8484
for _, pf := range pfs {
85-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
86-
return err
87-
}
88-
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
85+
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
8986
return err
9087
}
9188
}
@@ -157,12 +154,11 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
157154
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, IndexFilename, fmt.Sprintf("%s|%s|%s", branch, repository, architecture))
158155
if err != nil && !errors.Is(err, util.ErrNotExist) {
159156
return err
157+
} else if pf == nil {
158+
return nil
160159
}
161160

162-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
163-
return err
164-
}
165-
return packages_model.DeleteFileByID(ctx, pf.ID)
161+
return packages_service.DeletePackageFile(ctx, pf)
166162
}
167163

168164
// Cache data needed for all repository files

services/packages/container/cleanup.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
container_model "code.gitea.io/gitea/models/packages/container"
1212
container_module "code.gitea.io/gitea/modules/packages/container"
1313
"code.gitea.io/gitea/modules/util"
14+
packages_service "code.gitea.io/gitea/services/packages"
1415

1516
digest "github.com/opencontainers/go-digest"
1617
)
@@ -47,10 +48,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e
4748
}
4849

4950
for _, pf := range pfs {
50-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
51-
return err
52-
}
53-
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
51+
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
5452
return err
5553
}
5654
}

services/packages/debian/repository.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error {
110110
}
111111

112112
for _, pf := range pfs {
113-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
114-
return err
115-
}
116-
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
113+
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
117114
return err
118115
}
119116
}
@@ -181,12 +178,11 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
181178
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, key)
182179
if err != nil && !errors.Is(err, util.ErrNotExist) {
183180
return err
181+
} else if pf == nil {
182+
continue
184183
}
185184

186-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
187-
return err
188-
}
189-
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
185+
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
190186
return err
191187
}
192188
}
@@ -286,12 +282,11 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages
286282
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, distribution)
287283
if err != nil && !errors.Is(err, util.ErrNotExist) {
288284
return err
285+
} else if pf == nil {
286+
continue
289287
}
290288

291-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
292-
return err
293-
}
294-
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
289+
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
295290
return err
296291
}
297292
}

services/packages/rpm/repository.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,7 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
148148
return err
149149
}
150150
for _, pf := range pfs {
151-
if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
152-
return err
153-
}
154-
if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
151+
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
155152
return err
156153
}
157154
}

templates/swagger/v1_json.tmpl

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

tests/integration/project_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package integration
5+
6+
import (
7+
"net/http"
8+
"testing"
9+
10+
"code.gitea.io/gitea/tests"
11+
)
12+
13+
func TestPrivateRepoProject(t *testing.T) {
14+
defer tests.PrepareTestEnv(t)()
15+
16+
// not logged in user
17+
req := NewRequest(t, "GET", "/user31/-/projects")
18+
MakeRequest(t, req, http.StatusNotFound)
19+
20+
sess := loginUser(t, "user1")
21+
req = NewRequest(t, "GET", "/user31/-/projects")
22+
sess.MakeRequest(t, req, http.StatusOK)
23+
}

web_src/js/features/citation.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import $ from 'jquery';
22

33
const {pageData} = window.config;
44

5-
const initInputCitationValue = async ($citationCopyApa, $citationCopyBibtex) => {
5+
async function initInputCitationValue($citationCopyApa, $citationCopyBibtex) {
66
const [{Cite, plugins}] = await Promise.all([
77
import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
88
import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
@@ -19,9 +19,9 @@ const initInputCitationValue = async ($citationCopyApa, $citationCopyBibtex) =>
1919
const bibtexOutput = citationFormatter.format('bibtex', {lang});
2020
$citationCopyBibtex.attr('data-text', bibtexOutput);
2121
$citationCopyApa.attr('data-text', apaOutput);
22-
};
22+
}
2323

24-
export function initCitationFileCopyContent() {
24+
export async function initCitationFileCopyContent() {
2525
const defaultCitationFormat = 'apa'; // apa or bibtex
2626

2727
if (!pageData.citationFileContent) return;
@@ -39,7 +39,14 @@ export function initCitationFileCopyContent() {
3939
$citationCopyBibtex.toggleClass('primary', isBibtex);
4040
$citationCopyApa.toggleClass('primary', !isBibtex);
4141
};
42-
initInputCitationValue($citationCopyApa, $citationCopyBibtex).then(updateUi);
42+
43+
try {
44+
await initInputCitationValue($citationCopyApa, $citationCopyBibtex);
45+
} catch (e) {
46+
console.error(`initCitationFileCopyContent error: ${e}`, e);
47+
return;
48+
}
49+
updateUi();
4350

4451
$citationCopyApa.on('click', () => {
4552
localStorage.setItem('citation-copy-format', 'apa');

0 commit comments

Comments
 (0)