Skip to content

Commit 0c8ce71

Browse files
KN4CK3Rwxiaoguang
andauthored
Make NuGet service index publicly accessible (#21242)
Addition to #20734, Fixes #20717 The `/index.json` endpoint needs to be accessible even if the registry is private. The NuGet client uses this endpoint without authentification. The old fix only works if the NuGet cli is used with `--source <name>` but not with `--source <url>/index.json`. Co-authored-by: wxiaoguang <[email protected]>
1 parent cca189e commit 0c8ce71

File tree

2 files changed

+78
-56
lines changed

2 files changed

+78
-56
lines changed

routers/api/packages/api.go

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func Routes(ctx gocontext.Context) *web.Route {
6969
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
7070
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
7171
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
72-
})
72+
}, reqPackageAccess(perm.AccessModeRead))
7373
r.Group("/conan", func() {
7474
r.Group("/v1", func() {
7575
r.Get("/ping", conan.Ping)
@@ -157,7 +157,7 @@ func Routes(ctx gocontext.Context) *web.Route {
157157
}, conan.ExtractPathParameters)
158158
})
159159
})
160-
})
160+
}, reqPackageAccess(perm.AccessModeRead))
161161
r.Group("/generic", func() {
162162
r.Group("/{packagename}/{packageversion}", func() {
163163
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
@@ -169,33 +169,35 @@ func Routes(ctx gocontext.Context) *web.Route {
169169
}, reqPackageAccess(perm.AccessModeWrite))
170170
})
171171
})
172-
})
172+
}, reqPackageAccess(perm.AccessModeRead))
173173
r.Group("/helm", func() {
174174
r.Get("/index.yaml", helm.Index)
175175
r.Get("/{filename}", helm.DownloadPackageFile)
176176
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
177-
})
177+
}, reqPackageAccess(perm.AccessModeRead))
178178
r.Group("/maven", func() {
179179
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
180180
r.Get("/*", maven.DownloadPackageFile)
181-
})
181+
}, reqPackageAccess(perm.AccessModeRead))
182182
r.Group("/nuget", func() {
183-
r.Get("/index.json", nuget.ServiceIndex)
184-
r.Get("/query", nuget.SearchService)
185-
r.Group("/registration/{id}", func() {
186-
r.Get("/index.json", nuget.RegistrationIndex)
187-
r.Get("/{version}", nuget.RegistrationLeaf)
188-
})
189-
r.Group("/package/{id}", func() {
190-
r.Get("/index.json", nuget.EnumeratePackageVersions)
191-
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
192-
})
183+
r.Get("/index.json", nuget.ServiceIndex) // Needs to be unauthenticated for the NuGet client.
193184
r.Group("", func() {
194-
r.Put("/", nuget.UploadPackage)
195-
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
196-
r.Delete("/{id}/{version}", nuget.DeletePackage)
197-
}, reqPackageAccess(perm.AccessModeWrite))
198-
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
185+
r.Get("/query", nuget.SearchService)
186+
r.Group("/registration/{id}", func() {
187+
r.Get("/index.json", nuget.RegistrationIndex)
188+
r.Get("/{version}", nuget.RegistrationLeaf)
189+
})
190+
r.Group("/package/{id}", func() {
191+
r.Get("/index.json", nuget.EnumeratePackageVersions)
192+
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
193+
})
194+
r.Group("", func() {
195+
r.Put("/", nuget.UploadPackage)
196+
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
197+
r.Delete("/{id}/{version}", nuget.DeletePackage)
198+
}, reqPackageAccess(perm.AccessModeWrite))
199+
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
200+
}, reqPackageAccess(perm.AccessModeRead))
199201
})
200202
r.Group("/npm", func() {
201203
r.Group("/@{scope}/{id}", func() {
@@ -239,7 +241,7 @@ func Routes(ctx gocontext.Context) *web.Route {
239241
r.Group("/-/v1/search", func() {
240242
r.Get("", npm.PackageSearch)
241243
})
242-
})
244+
}, reqPackageAccess(perm.AccessModeRead))
243245
r.Group("/pub", func() {
244246
r.Group("/api/packages", func() {
245247
r.Group("/versions/new", func() {
@@ -253,12 +255,12 @@ func Routes(ctx gocontext.Context) *web.Route {
253255
r.Get("/{version}", pub.PackageVersionMetadata)
254256
})
255257
})
256-
})
258+
}, reqPackageAccess(perm.AccessModeRead))
257259
r.Group("/pypi", func() {
258260
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
259261
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
260262
r.Get("/simple/{id}", pypi.PackageMetadata)
261-
})
263+
}, reqPackageAccess(perm.AccessModeRead))
262264
r.Group("/rubygems", func() {
263265
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
264266
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
@@ -269,7 +271,7 @@ func Routes(ctx gocontext.Context) *web.Route {
269271
r.Post("/", rubygems.UploadPackageFile)
270272
r.Delete("/yank", rubygems.DeletePackage)
271273
}, reqPackageAccess(perm.AccessModeWrite))
272-
})
274+
}, reqPackageAccess(perm.AccessModeRead))
273275
r.Group("/vagrant", func() {
274276
r.Group("/authenticate", func() {
275277
r.Get("", vagrant.CheckAuthenticate)
@@ -282,8 +284,8 @@ func Routes(ctx gocontext.Context) *web.Route {
282284
r.Put("", reqPackageAccess(perm.AccessModeWrite), vagrant.UploadPackageFile)
283285
})
284286
})
285-
})
286-
}, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
287+
}, reqPackageAccess(perm.AccessModeRead))
288+
}, context_service.UserAssignmentWeb(), context.PackageAssignment())
287289

288290
return r
289291
}

tests/integration/api_packages_nuget_test.go

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
user_model "code.gitea.io/gitea/models/user"
2020
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
2121
"code.gitea.io/gitea/modules/setting"
22+
"code.gitea.io/gitea/modules/structs"
2223
"code.gitea.io/gitea/routers/api/packages/nuget"
2324
"code.gitea.io/gitea/tests"
2425

@@ -66,39 +67,58 @@ func TestPackageNuGet(t *testing.T) {
6667
t.Run("ServiceIndex", func(t *testing.T) {
6768
defer tests.PrintCurrentTest(t)()
6869

69-
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
70-
req = AddBasicAuthHeader(req, user.Name)
71-
MakeRequest(t, req, http.StatusOK)
70+
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate})
7271

73-
req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
74-
req = addNuGetAPIKeyHeader(req, token)
75-
resp := MakeRequest(t, req, http.StatusOK)
72+
cases := []struct {
73+
Owner string
74+
UseBasicAuth bool
75+
UseTokenAuth bool
76+
}{
77+
{privateUser.Name, false, false},
78+
{privateUser.Name, true, false},
79+
{privateUser.Name, false, true},
80+
{user.Name, false, false},
81+
{user.Name, true, false},
82+
{user.Name, false, true},
83+
}
7684

77-
var result nuget.ServiceIndexResponse
78-
DecodeJSON(t, resp, &result)
85+
for _, c := range cases {
86+
url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
7987

80-
assert.Equal(t, "3.0.0", result.Version)
81-
assert.NotEmpty(t, result.Resources)
82-
83-
root := setting.AppURL + url[1:]
84-
for _, r := range result.Resources {
85-
switch r.Type {
86-
case "SearchQueryService":
87-
fallthrough
88-
case "SearchQueryService/3.0.0-beta":
89-
fallthrough
90-
case "SearchQueryService/3.0.0-rc":
91-
assert.Equal(t, root+"/query", r.ID)
92-
case "RegistrationsBaseUrl":
93-
fallthrough
94-
case "RegistrationsBaseUrl/3.0.0-beta":
95-
fallthrough
96-
case "RegistrationsBaseUrl/3.0.0-rc":
97-
assert.Equal(t, root+"/registration", r.ID)
98-
case "PackageBaseAddress/3.0.0":
99-
assert.Equal(t, root+"/package", r.ID)
100-
case "PackagePublish/2.0.0":
101-
assert.Equal(t, root, r.ID)
88+
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
89+
if c.UseBasicAuth {
90+
req = AddBasicAuthHeader(req, user.Name)
91+
} else if c.UseTokenAuth {
92+
req = addNuGetAPIKeyHeader(req, token)
93+
}
94+
resp := MakeRequest(t, req, http.StatusOK)
95+
96+
var result nuget.ServiceIndexResponse
97+
DecodeJSON(t, resp, &result)
98+
99+
assert.Equal(t, "3.0.0", result.Version)
100+
assert.NotEmpty(t, result.Resources)
101+
102+
root := setting.AppURL + url[1:]
103+
for _, r := range result.Resources {
104+
switch r.Type {
105+
case "SearchQueryService":
106+
fallthrough
107+
case "SearchQueryService/3.0.0-beta":
108+
fallthrough
109+
case "SearchQueryService/3.0.0-rc":
110+
assert.Equal(t, root+"/query", r.ID)
111+
case "RegistrationsBaseUrl":
112+
fallthrough
113+
case "RegistrationsBaseUrl/3.0.0-beta":
114+
fallthrough
115+
case "RegistrationsBaseUrl/3.0.0-rc":
116+
assert.Equal(t, root+"/registration", r.ID)
117+
case "PackageBaseAddress/3.0.0":
118+
assert.Equal(t, root+"/package", r.ID)
119+
case "PackagePublish/2.0.0":
120+
assert.Equal(t, root, r.ID)
121+
}
102122
}
103123
}
104124
})

0 commit comments

Comments
 (0)