mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	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:
		@@ -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)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user