mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-23 19:47:07 +09:00
fix(packages): reject newline-bearing rubygems dependency metadata (#39782)
The RubyGems compact index (the shared `/versions` file and per-package `info/<name>` files) is line-based. https://github.com/go-gitea/gitea/pull/38061 rejected line breaks in the gem name, but the platform, dependency names and version requirements from the gemspec still accepted them, letting an uploader forge index lines for bundler clients. The parser now rejects a line break in any of those fields. The Marshal based endpoints are length prefixed and unaffected. Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
1 parent
738ff1d65a
commit
c52e7c0cd2
2 files changed
+30
No files matched your search
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user