Fix handling of Debian files with trailing slash (#26087) (#26098)

Backport #26087 by @KN4CK3R

Fixes #26022

- Fix handling of files with trailing slash
- Fix handling of duplicate package file errors
- Added test for both

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
(cherry picked from commit a424f6d4f8224ca7d5db1a27e1db46a5dc47f30b)
This commit is contained in:
Giteabot 2023-07-24 10:56:13 -04:00 committed by Earl Warren
parent 1cd4d4b00e
commit 4be3270e87
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
4 changed files with 67 additions and 47 deletions

View file

@ -80,7 +80,9 @@ func ParsePackage(r io.Reader) (*Package, error) {
if strings.HasPrefix(hd.Name, controlTar) { if strings.HasPrefix(hd.Name, controlTar) {
var inner io.Reader var inner io.Reader
switch hd.Name[len(controlTar):] { // https://man7.org/linux/man-pages/man5/deb-split.5.html#FORMAT
// The file names might contain a trailing slash (since dpkg 1.15.6).
switch strings.TrimSuffix(hd.Name[len(controlTar):], "/") {
case "": case "":
inner = arr inner = arr
case ".gz": case ".gz":

View file

@ -69,59 +69,73 @@ func TestParsePackage(t *testing.T) {
tw.Write([]byte("Package: gitea\nVersion: 1.0.0\nArchitecture: amd64\n")) tw.Write([]byte("Package: gitea\nVersion: 1.0.0\nArchitecture: amd64\n"))
tw.Close() tw.Close()
t.Run("None", func(t *testing.T) { cases := []struct {
data := createArchive(map[string][]byte{"control.tar": buf.Bytes()}) Extension string
WriterFactory func(io.Writer) io.WriteCloser
}{
{
Extension: "",
WriterFactory: func(w io.Writer) io.WriteCloser {
return nopCloser{w}
},
},
{
Extension: ".gz",
WriterFactory: func(w io.Writer) io.WriteCloser {
return gzip.NewWriter(w)
},
},
{
Extension: ".xz",
WriterFactory: func(w io.Writer) io.WriteCloser {
xw, _ := xz.NewWriter(w)
return xw
},
},
{
Extension: ".zst",
WriterFactory: func(w io.Writer) io.WriteCloser {
zw, _ := zstd.NewWriter(w)
return zw
},
},
}
p, err := ParsePackage(data) for _, c := range cases {
assert.NotNil(t, p) t.Run(c.Extension, func(t *testing.T) {
assert.NoError(t, err) var cbuf bytes.Buffer
assert.Equal(t, "gitea", p.Name) w := c.WriterFactory(&cbuf)
}) w.Write(buf.Bytes())
w.Close()
t.Run("gz", func(t *testing.T) { data := createArchive(map[string][]byte{"control.tar" + c.Extension: cbuf.Bytes()})
var zbuf bytes.Buffer
zw := gzip.NewWriter(&zbuf)
zw.Write(buf.Bytes())
zw.Close()
data := createArchive(map[string][]byte{"control.tar.gz": zbuf.Bytes()}) p, err := ParsePackage(data)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, "gitea", p.Name)
p, err := ParsePackage(data) t.Run("TrailingSlash", func(t *testing.T) {
assert.NotNil(t, p) data := createArchive(map[string][]byte{"control.tar" + c.Extension + "/": cbuf.Bytes()})
assert.NoError(t, err)
assert.Equal(t, "gitea", p.Name)
})
t.Run("xz", func(t *testing.T) { p, err := ParsePackage(data)
var xbuf bytes.Buffer assert.NotNil(t, p)
xw, _ := xz.NewWriter(&xbuf) assert.NoError(t, err)
xw.Write(buf.Bytes()) assert.Equal(t, "gitea", p.Name)
xw.Close() })
})
data := createArchive(map[string][]byte{"control.tar.xz": xbuf.Bytes()}) }
p, err := ParsePackage(data)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, "gitea", p.Name)
})
t.Run("zst", func(t *testing.T) {
var zbuf bytes.Buffer
zw, _ := zstd.NewWriter(&zbuf)
zw.Write(buf.Bytes())
zw.Close()
data := createArchive(map[string][]byte{"control.tar.zst": zbuf.Bytes()})
p, err := ParsePackage(data)
assert.NotNil(t, p)
assert.NoError(t, err)
assert.Equal(t, "gitea", p.Name)
})
}) })
} }
type nopCloser struct {
io.Writer
}
func (nopCloser) Close() error {
return nil
}
func TestParseControlFile(t *testing.T) { func TestParseControlFile(t *testing.T) {
buildContent := func(name, version, architecture string) *bytes.Buffer { buildContent := func(name, version, architecture string) *bytes.Buffer {
var buf bytes.Buffer var buf bytes.Buffer

View file

@ -195,7 +195,7 @@ func UploadPackageFile(ctx *context.Context) {
) )
if err != nil { if err != nil {
switch err { switch err {
case packages_model.ErrDuplicatePackageVersion: case packages_model.ErrDuplicatePackageVersion, packages_model.ErrDuplicatePackageFile:
apiError(ctx, http.StatusBadRequest, err) apiError(ctx, http.StatusBadRequest, err)
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err) apiError(ctx, http.StatusForbidden, err)

View file

@ -144,6 +144,10 @@ func TestPackageDebian(t *testing.T) {
} }
return seen return seen
}) })
req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
}) })
t.Run("Download", func(t *testing.T) { t.Run("Download", func(t *testing.T) {