mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Fix handling of Debian files with trailing slash (#26087)
Fixes #26022 - Fix handling of files with trailing slash - Fix handling of duplicate package file errors - Added test for both
This commit is contained in:
		@@ -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":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,7 +187,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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user