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 <wxiaoguang@gmail.com>
This commit is contained in:
parent
cca189ef97
commit
0c8ce71188
2 changed files with 77 additions and 55 deletions
|
@ -69,7 +69,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
|
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
|
||||||
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
|
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
|
||||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
|
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/conan", func() {
|
r.Group("/conan", func() {
|
||||||
r.Group("/v1", func() {
|
r.Group("/v1", func() {
|
||||||
r.Get("/ping", conan.Ping)
|
r.Get("/ping", conan.Ping)
|
||||||
|
@ -157,7 +157,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
}, conan.ExtractPathParameters)
|
}, conan.ExtractPathParameters)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/generic", func() {
|
r.Group("/generic", func() {
|
||||||
r.Group("/{packagename}/{packageversion}", func() {
|
r.Group("/{packagename}/{packageversion}", func() {
|
||||||
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
|
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
|
||||||
|
@ -169,33 +169,35 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/helm", func() {
|
r.Group("/helm", func() {
|
||||||
r.Get("/index.yaml", helm.Index)
|
r.Get("/index.yaml", helm.Index)
|
||||||
r.Get("/{filename}", helm.DownloadPackageFile)
|
r.Get("/{filename}", helm.DownloadPackageFile)
|
||||||
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
|
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/maven", func() {
|
r.Group("/maven", func() {
|
||||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
||||||
r.Get("/*", maven.DownloadPackageFile)
|
r.Get("/*", maven.DownloadPackageFile)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/nuget", func() {
|
r.Group("/nuget", func() {
|
||||||
r.Get("/index.json", nuget.ServiceIndex)
|
r.Get("/index.json", nuget.ServiceIndex) // Needs to be unauthenticated for the NuGet client.
|
||||||
r.Get("/query", nuget.SearchService)
|
|
||||||
r.Group("/registration/{id}", func() {
|
|
||||||
r.Get("/index.json", nuget.RegistrationIndex)
|
|
||||||
r.Get("/{version}", nuget.RegistrationLeaf)
|
|
||||||
})
|
|
||||||
r.Group("/package/{id}", func() {
|
|
||||||
r.Get("/index.json", nuget.EnumeratePackageVersions)
|
|
||||||
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
|
||||||
})
|
|
||||||
r.Group("", func() {
|
r.Group("", func() {
|
||||||
r.Put("/", nuget.UploadPackage)
|
r.Get("/query", nuget.SearchService)
|
||||||
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
r.Group("/registration/{id}", func() {
|
||||||
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
r.Get("/index.json", nuget.RegistrationIndex)
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
r.Get("/{version}", nuget.RegistrationLeaf)
|
||||||
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
|
})
|
||||||
|
r.Group("/package/{id}", func() {
|
||||||
|
r.Get("/index.json", nuget.EnumeratePackageVersions)
|
||||||
|
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
||||||
|
})
|
||||||
|
r.Group("", func() {
|
||||||
|
r.Put("/", nuget.UploadPackage)
|
||||||
|
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
||||||
|
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
||||||
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
|
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
|
||||||
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
})
|
})
|
||||||
r.Group("/npm", func() {
|
r.Group("/npm", func() {
|
||||||
r.Group("/@{scope}/{id}", func() {
|
r.Group("/@{scope}/{id}", func() {
|
||||||
|
@ -239,7 +241,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
r.Group("/-/v1/search", func() {
|
r.Group("/-/v1/search", func() {
|
||||||
r.Get("", npm.PackageSearch)
|
r.Get("", npm.PackageSearch)
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/pub", func() {
|
r.Group("/pub", func() {
|
||||||
r.Group("/api/packages", func() {
|
r.Group("/api/packages", func() {
|
||||||
r.Group("/versions/new", func() {
|
r.Group("/versions/new", func() {
|
||||||
|
@ -253,12 +255,12 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
r.Get("/{version}", pub.PackageVersionMetadata)
|
r.Get("/{version}", pub.PackageVersionMetadata)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/pypi", func() {
|
r.Group("/pypi", func() {
|
||||||
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
|
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
|
||||||
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
|
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
|
||||||
r.Get("/simple/{id}", pypi.PackageMetadata)
|
r.Get("/simple/{id}", pypi.PackageMetadata)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/rubygems", func() {
|
r.Group("/rubygems", func() {
|
||||||
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
|
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
|
||||||
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
|
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
|
||||||
|
@ -269,7 +271,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
r.Post("/", rubygems.UploadPackageFile)
|
r.Post("/", rubygems.UploadPackageFile)
|
||||||
r.Delete("/yank", rubygems.DeletePackage)
|
r.Delete("/yank", rubygems.DeletePackage)
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/vagrant", func() {
|
r.Group("/vagrant", func() {
|
||||||
r.Group("/authenticate", func() {
|
r.Group("/authenticate", func() {
|
||||||
r.Get("", vagrant.CheckAuthenticate)
|
r.Get("", vagrant.CheckAuthenticate)
|
||||||
|
@ -282,8 +284,8 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), vagrant.UploadPackageFile)
|
r.Put("", reqPackageAccess(perm.AccessModeWrite), vagrant.UploadPackageFile)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
}, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
}, context_service.UserAssignmentWeb(), context.PackageAssignment())
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/routers/api/packages/nuget"
|
"code.gitea.io/gitea/routers/api/packages/nuget"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
@ -66,39 +67,58 @@ func TestPackageNuGet(t *testing.T) {
|
||||||
t.Run("ServiceIndex", func(t *testing.T) {
|
t.Run("ServiceIndex", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate})
|
||||||
req = AddBasicAuthHeader(req, user.Name)
|
|
||||||
MakeRequest(t, req, http.StatusOK)
|
|
||||||
|
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
cases := []struct {
|
||||||
req = addNuGetAPIKeyHeader(req, token)
|
Owner string
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
UseBasicAuth bool
|
||||||
|
UseTokenAuth bool
|
||||||
|
}{
|
||||||
|
{privateUser.Name, false, false},
|
||||||
|
{privateUser.Name, true, false},
|
||||||
|
{privateUser.Name, false, true},
|
||||||
|
{user.Name, false, false},
|
||||||
|
{user.Name, true, false},
|
||||||
|
{user.Name, false, true},
|
||||||
|
}
|
||||||
|
|
||||||
var result nuget.ServiceIndexResponse
|
for _, c := range cases {
|
||||||
DecodeJSON(t, resp, &result)
|
url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
|
||||||
|
|
||||||
assert.Equal(t, "3.0.0", result.Version)
|
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||||
assert.NotEmpty(t, result.Resources)
|
if c.UseBasicAuth {
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
} else if c.UseTokenAuth {
|
||||||
|
req = addNuGetAPIKeyHeader(req, token)
|
||||||
|
}
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
root := setting.AppURL + url[1:]
|
var result nuget.ServiceIndexResponse
|
||||||
for _, r := range result.Resources {
|
DecodeJSON(t, resp, &result)
|
||||||
switch r.Type {
|
|
||||||
case "SearchQueryService":
|
assert.Equal(t, "3.0.0", result.Version)
|
||||||
fallthrough
|
assert.NotEmpty(t, result.Resources)
|
||||||
case "SearchQueryService/3.0.0-beta":
|
|
||||||
fallthrough
|
root := setting.AppURL + url[1:]
|
||||||
case "SearchQueryService/3.0.0-rc":
|
for _, r := range result.Resources {
|
||||||
assert.Equal(t, root+"/query", r.ID)
|
switch r.Type {
|
||||||
case "RegistrationsBaseUrl":
|
case "SearchQueryService":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "RegistrationsBaseUrl/3.0.0-beta":
|
case "SearchQueryService/3.0.0-beta":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "RegistrationsBaseUrl/3.0.0-rc":
|
case "SearchQueryService/3.0.0-rc":
|
||||||
assert.Equal(t, root+"/registration", r.ID)
|
assert.Equal(t, root+"/query", r.ID)
|
||||||
case "PackageBaseAddress/3.0.0":
|
case "RegistrationsBaseUrl":
|
||||||
assert.Equal(t, root+"/package", r.ID)
|
fallthrough
|
||||||
case "PackagePublish/2.0.0":
|
case "RegistrationsBaseUrl/3.0.0-beta":
|
||||||
assert.Equal(t, root, r.ID)
|
fallthrough
|
||||||
|
case "RegistrationsBaseUrl/3.0.0-rc":
|
||||||
|
assert.Equal(t, root+"/registration", r.ID)
|
||||||
|
case "PackageBaseAddress/3.0.0":
|
||||||
|
assert.Equal(t, root+"/package", r.ID)
|
||||||
|
case "PackagePublish/2.0.0":
|
||||||
|
assert.Equal(t, root, r.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Reference in a new issue