diff --git a/modules/packages/rubygems/metadata.go b/modules/packages/rubygems/metadata.go index 7075b4233e3..357a7a11663 100644 --- a/modules/packages/rubygems/metadata.go +++ b/modules/packages/rubygems/metadata.go @@ -8,6 +8,8 @@ import ( "compress/gzip" "io" "regexp" + "slices" + "strings" "sync" "gitea.dev/modules/packages" @@ -24,6 +26,8 @@ var ( ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid") // ErrInvalidVersion indicates an invalid version in the metadata.gz file ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid") + // ErrInvalidMetadata indicates metadata that would corrupt the generated index + ErrInvalidMetadata = util.NewInvalidArgumentErrorf("package metadata is invalid") ) var globalVars = sync.OnceValue(func() (ret struct { @@ -221,6 +225,19 @@ func parseMetadataFile(r io.Reader) (*Package, error) { } } + values := []string{m.Platform} + reqs := slices.Concat(m.RequiredRubyVersion, m.RequiredRubygemsVersion) + for _, dep := range slices.Concat(m.RuntimeDependencies, m.DevelopmentDependencies) { + values = append(values, dep.Name) + reqs = append(reqs, dep.Version...) + } + for _, req := range reqs { + values = append(values, req.Restriction, req.Version) + } + if slices.ContainsFunc(values, func(s string) bool { return strings.ContainsAny(s, "\r\n") }) { + return nil, ErrInvalidMetadata // the compact index is line-based, a line break would forge entries + } + return &Package{ Name: spec.Name, Version: spec.Version.Version, diff --git a/modules/packages/rubygems/metadata_test.go b/modules/packages/rubygems/metadata_test.go index 8917bd2b36b..eba2cfd25cc 100644 --- a/modules/packages/rubygems/metadata_test.go +++ b/modules/packages/rubygems/metadata_test.go @@ -43,6 +43,19 @@ version: assert.Nil(t, rp) } }) + + t.Run("LineBreakInIndexedMetadata", func(t *testing.T) { + for _, field := range []string{ + `platform: "ruby\nx"`, + `dependencies: [{name: "d\nx"}]`, + `dependencies: [{name: d, requirement: {requirements: [[">=", {version: "1\nx"}]]}}]`, + `required_ruby_version: {requirements: [[">=", {version: "1\nx"}]]}`, + } { + rp, err := parseMetadataFile(test.CompressGzip("name: g\nversion:\n version: 1\n" + field + "\n")) + assert.ErrorIs(t, err, ErrInvalidMetadata, field) + assert.Nil(t, rp) + } + }) } func TestParseMetadataFile(t *testing.T) {