From 0c8a92ae14141530f18d84817d849fd5c16d5acb Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Sun, 23 Jul 2023 23:13:00 +0100 Subject: [PATCH 1/2] Fix handling of files with trailing slash. --- modules/packages/debian/metadata.go | 4 +++- routers/api/packages/debian/debian.go | 2 +- tests/integration/api_packages_debian_test.go | 17 ++++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/packages/debian/metadata.go b/modules/packages/debian/metadata.go index dee524c8ff8bf..bb77f7524bf63 100644 --- a/modules/packages/debian/metadata.go +++ b/modules/packages/debian/metadata.go @@ -80,7 +80,9 @@ func ParsePackage(r io.Reader) (*Package, error) { if strings.HasPrefix(hd.Name, controlTar) { 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 "": inner = arr case ".gz": diff --git a/routers/api/packages/debian/debian.go b/routers/api/packages/debian/debian.go index f7270e0ae0ea6..a6da1a11a8ab9 100644 --- a/routers/api/packages/debian/debian.go +++ b/routers/api/packages/debian/debian.go @@ -187,7 +187,7 @@ func UploadPackageFile(ctx *context.Context) { ) if err != nil { switch err { - case packages_model.ErrDuplicatePackageVersion: + case packages_model.ErrDuplicatePackageVersion, packages_model.ErrDuplicatePackageFile: apiError(ctx, http.StatusBadRequest, err) case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize: apiError(ctx, http.StatusForbidden, err) diff --git a/tests/integration/api_packages_debian_test.go b/tests/integration/api_packages_debian_test.go index 3e25acd8cff2c..4340f6c4f1a75 100644 --- a/tests/integration/api_packages_debian_test.go +++ b/tests/integration/api_packages_debian_test.go @@ -33,7 +33,7 @@ func TestPackageDebian(t *testing.T) { packageVersion := "1.0.3" packageDescription := "Package Description" - createArchive := func(name, version, architecture string) io.Reader { + createArchive := func(name, version, architecture string, appendSlash bool) io.Reader { var cbuf bytes.Buffer zw := gzip.NewWriter(&cbuf) tw := tar.NewWriter(zw) @@ -54,6 +54,9 @@ func TestPackageDebian(t *testing.T) { Mode: 0o600, Size: int64(cbuf.Len()), } + if appendSlash { + hdr.Name = hdr.Name + "/" + } aw.WriteHeader(hdr) aw.Write(cbuf.Bytes()) return &buf @@ -92,11 +95,11 @@ func TestPackageDebian(t *testing.T) { AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusBadRequest) - req = NewRequestWithBody(t, "PUT", uploadURL, createArchive("", "", "")) + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive("", "", "", false)) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusBadRequest) - req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture)) + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture, false)) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusCreated) @@ -144,6 +147,14 @@ func TestPackageDebian(t *testing.T) { } return seen }) + + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture, false)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture, true)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) }) t.Run("Download", func(t *testing.T) { From 0ea56be005013db2f331281e4c191faf4b108601 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Mon, 24 Jul 2023 10:44:54 +0000 Subject: [PATCH 2/2] Use unit test for trailing slash testing. --- modules/packages/debian/metadata_test.go | 110 ++++++++++-------- tests/integration/api_packages_debian_test.go | 15 +-- 2 files changed, 66 insertions(+), 59 deletions(-) diff --git a/modules/packages/debian/metadata_test.go b/modules/packages/debian/metadata_test.go index 69fd51ea79002..26c2a6fc68806 100644 --- a/modules/packages/debian/metadata_test.go +++ b/modules/packages/debian/metadata_test.go @@ -69,57 +69,71 @@ func TestParsePackage(t *testing.T) { tw.Write([]byte("Package: gitea\nVersion: 1.0.0\nArchitecture: amd64\n")) tw.Close() - t.Run("None", func(t *testing.T) { - data := createArchive(map[string][]byte{"control.tar": buf.Bytes()}) - - p, err := ParsePackage(data) - assert.NotNil(t, p) - assert.NoError(t, err) - assert.Equal(t, "gitea", p.Name) - }) - - t.Run("gz", func(t *testing.T) { - 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) - }) - - t.Run("xz", func(t *testing.T) { - var xbuf bytes.Buffer - xw, _ := xz.NewWriter(&xbuf) - xw.Write(buf.Bytes()) - 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) - }) + cases := []struct { + 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 + }, + }, + } - t.Run("zst", func(t *testing.T) { - var zbuf bytes.Buffer - zw, _ := zstd.NewWriter(&zbuf) - zw.Write(buf.Bytes()) - zw.Close() + for _, c := range cases { + t.Run(c.Extension, func(t *testing.T) { + var cbuf bytes.Buffer + w := c.WriterFactory(&cbuf) + w.Write(buf.Bytes()) + w.Close() + + data := createArchive(map[string][]byte{"control.tar" + c.Extension: cbuf.Bytes()}) + + p, err := ParsePackage(data) + assert.NotNil(t, p) + assert.NoError(t, err) + assert.Equal(t, "gitea", p.Name) + + t.Run("TrailingSlash", func(t *testing.T) { + data := createArchive(map[string][]byte{"control.tar" + c.Extension + "/": cbuf.Bytes()}) + + p, err := ParsePackage(data) + assert.NotNil(t, p) + assert.NoError(t, err) + assert.Equal(t, "gitea", p.Name) + }) + }) + } + }) +} - data := createArchive(map[string][]byte{"control.tar.zst": zbuf.Bytes()}) +type nopCloser struct { + io.Writer +} - p, err := ParsePackage(data) - assert.NotNil(t, p) - assert.NoError(t, err) - assert.Equal(t, "gitea", p.Name) - }) - }) +func (nopCloser) Close() error { + return nil } func TestParseControlFile(t *testing.T) { diff --git a/tests/integration/api_packages_debian_test.go b/tests/integration/api_packages_debian_test.go index 9725eff0a8a76..2d92b93159943 100644 --- a/tests/integration/api_packages_debian_test.go +++ b/tests/integration/api_packages_debian_test.go @@ -33,7 +33,7 @@ func TestPackageDebian(t *testing.T) { packageVersion := "1.0.3" packageDescription := "Package Description" - createArchive := func(name, version, architecture string, appendSlash bool) io.Reader { + createArchive := func(name, version, architecture string) io.Reader { var cbuf bytes.Buffer zw := gzip.NewWriter(&cbuf) tw := tar.NewWriter(zw) @@ -54,9 +54,6 @@ func TestPackageDebian(t *testing.T) { Mode: 0o600, Size: int64(cbuf.Len()), } - if appendSlash { - hdr.Name += "/" - } aw.WriteHeader(hdr) aw.Write(cbuf.Bytes()) return &buf @@ -95,11 +92,11 @@ func TestPackageDebian(t *testing.T) { AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusBadRequest) - req = NewRequestWithBody(t, "PUT", uploadURL, createArchive("", "", "", false)) + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive("", "", "")) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusBadRequest) - req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture, false)) + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture)) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusCreated) @@ -148,11 +145,7 @@ func TestPackageDebian(t *testing.T) { return seen }) - req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture, false)) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusBadRequest) - - req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture, true)) + req = NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion, architecture)) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusBadRequest) })