From c3d9d0770253fcb168da979094d07ed522be5905 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 17 May 2026 21:52:08 -0700 Subject: [PATCH] fix: Add missed token scope checking (#37735) Follow #37698 --- routers/web/repo/repo.go | 8 ++++++ tests/integration/download_test.go | 46 ++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index c7813feae2..fdabd08a9a 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -364,6 +364,10 @@ func RedirectDownload(ctx *context.Context) { // Download an archive of a repository func Download(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"), ctx.FormStrings("path")) if err != nil { if errors.Is(err, util.ErrInvalidArgument) { @@ -389,6 +393,10 @@ func Download(ctx *context.Context) { // a request that's already in-progress, but the archiver service will just // kind of drop it on the floor if this is the case. func InitiateDownload(ctx *context.Context) { + if !checkDownloadTokenScope(ctx) { + return + } + paths := ctx.FormStrings("path") if setting.Repository.StreamArchives || len(paths) > 0 { ctx.JSON(http.StatusOK, map[string]any{ diff --git a/tests/integration/download_test.go b/tests/integration/download_test.go index b55a5a89bb..7270178f1f 100644 --- a/tests/integration/download_test.go +++ b/tests/integration/download_test.go @@ -17,6 +17,7 @@ import ( type downloadScopeCase struct { name string + method string url string withScope int publicOnlyOK bool @@ -88,68 +89,107 @@ func TestDownloadRepoContentTokenScopes(t *testing.T) { publicOnlyToken := getUserToken(t, "user2", auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopePublicOnly) cases := []downloadScopeCase{ + { + name: "PublicArchiveDownload", + method: http.MethodGet, + url: "/user2/repo1/archive/master.tar.gz", + withScope: http.StatusOK, + publicOnlyOK: true, + }, + { + name: "PrivateArchiveDownload", + method: http.MethodGet, + url: "/user2/repo2/archive/master.tar.gz", + withScope: http.StatusOK, + publicOnlyOK: false, + }, + { + name: "PublicArchiveInitiate", + method: http.MethodPost, + url: "/user2/repo1/archive/master.tar.gz", + withScope: http.StatusOK, + publicOnlyOK: true, + }, + { + name: "PrivateArchiveInitiate", + method: http.MethodPost, + url: "/user2/repo2/archive/master.tar.gz", + withScope: http.StatusOK, + publicOnlyOK: false, + }, { name: "PublicRawBlob", + method: http.MethodGet, url: "/user2/repo1/raw/blob/4b4851ad51df6a7d9f25c979345979eaeb5b349f", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicRawBranch", + method: http.MethodGet, url: "/user2/repo1/raw/branch/master/README.md", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicRawTag", + method: http.MethodGet, url: "/user2/repo1/raw/tag/v1.1/README.md", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicRawCommit", + method: http.MethodGet, url: "/user2/repo1/raw/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicMediaBlob", + method: http.MethodGet, url: "/user2/repo1/media/blob/4b4851ad51df6a7d9f25c979345979eaeb5b349f", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicMediaBranch", + method: http.MethodGet, url: "/user2/repo1/media/branch/master/README.md", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicMediaTag", + method: http.MethodGet, url: "/user2/repo1/media/tag/v1.1/README.md", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PublicMediaCommit", + method: http.MethodGet, url: "/user2/repo1/media/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md", withScope: http.StatusOK, publicOnlyOK: true, }, { name: "PrivateRawBranch", + method: http.MethodGet, url: "/user2/repo2/raw/branch/master/test.xml", withScope: http.StatusOK, publicOnlyOK: false, }, { name: "PrivateRawBlob", + method: http.MethodGet, url: "/user2/repo2/raw/blob/6395b68e1feebb1e4c657b4f9f6ba2676a283c0b", withScope: http.StatusOK, publicOnlyOK: false, }, { name: "PrivateMediaBranch", + method: http.MethodGet, url: "/user2/repo2/media/branch/master/test.xml", withScope: http.StatusOK, publicOnlyOK: false, @@ -158,14 +198,14 @@ func TestDownloadRepoContentTokenScopes(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - MakeRequest(t, NewRequest(t, "GET", tc.url).AddTokenAuth(miscToken), http.StatusForbidden) - MakeRequest(t, NewRequest(t, "GET", tc.url).AddTokenAuth(ownerReadToken), tc.withScope) + MakeRequest(t, NewRequest(t, tc.method, tc.url).AddTokenAuth(miscToken), http.StatusForbidden) + MakeRequest(t, NewRequest(t, tc.method, tc.url).AddTokenAuth(ownerReadToken), tc.withScope) publicOnlyStatus := http.StatusForbidden if tc.publicOnlyOK { publicOnlyStatus = tc.withScope } - MakeRequest(t, NewRequest(t, "GET", tc.url).AddTokenAuth(publicOnlyToken), publicOnlyStatus) + MakeRequest(t, NewRequest(t, tc.method, tc.url).AddTokenAuth(publicOnlyToken), publicOnlyStatus) }) } }