From b38771f0162e6ef445f793c8c62efc31d56d4297 Mon Sep 17 00:00:00 2001 From: Seth Hoenig Date: Thu, 9 Feb 2023 17:10:25 +0000 Subject: [PATCH] decompressors: add LimitedDecompressors helper This PR adds helper function LimitedDecompressors(filesLimit, fileSizeLimit) for creating the same suite of decompressors as Decompressors, but all configured with the given filesLimit and fileSizeLimit (where applicable). --- decompress.go | 47 ++++++++++++++++++++++++++++--------------- decompress_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 decompress_test.go diff --git a/decompress.go b/decompress.go index 9db9e15c0..c0ca99bef 100644 --- a/decompress.go +++ b/decompress.go @@ -18,21 +18,24 @@ type Decompressor interface { Decompress(dst, src string, dir bool, umask os.FileMode) error } -// Decompressors is the mapping of extension to the Decompressor implementation -// that will decompress that extension/type. -var Decompressors map[string]Decompressor - -func init() { - tarDecompressor := new(TarDecompressor) - tbzDecompressor := new(TarBzip2Decompressor) - tgzDecompressor := new(TarGzipDecompressor) - txzDecompressor := new(TarXzDecompressor) - tzstDecompressor := new(TarZstdDecompressor) +// LimitedDecompressors creates the set of Decompressors, but with each compressor configured +// with the given filesLimit and/or fileSizeLimit where applicable. +func LimitedDecompressors(filesLimit int, fileSizeLimit int64) map[string]Decompressor { + tarDecompressor := &TarDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit} + tbzDecompressor := &TarBzip2Decompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit} + tgzDecompressor := &TarGzipDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit} + txzDecompressor := &TarXzDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit} + tzstDecompressor := &TarZstdDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit} + bzipDecompressor := &Bzip2Decompressor{FileSizeLimit: fileSizeLimit} + gzipDecompressor := &GzipDecompressor{FileSizeLimit: fileSizeLimit} + xzDecompressor := &XzDecompressor{FileSizeLimit: fileSizeLimit} + zipDecompressor := &ZipDecompressor{FilesLimit: filesLimit, FileSizeLimit: fileSizeLimit} + zstDecompressor := &ZstdDecompressor{FileSizeLimit: fileSizeLimit} - Decompressors = map[string]Decompressor{ - "bz2": new(Bzip2Decompressor), - "gz": new(GzipDecompressor), - "xz": new(XzDecompressor), + return map[string]Decompressor{ + "bz2": bzipDecompressor, + "gz": gzipDecompressor, + "xz": xzDecompressor, "tar": tarDecompressor, "tar.bz2": tbzDecompressor, "tar.gz": tgzDecompressor, @@ -42,11 +45,23 @@ func init() { "tgz": tgzDecompressor, "txz": txzDecompressor, "tzst": tzstDecompressor, - "zip": new(ZipDecompressor), - "zst": new(ZstdDecompressor), + "zip": zipDecompressor, + "zst": zstDecompressor, } } +const ( + noFilesLimit = 0 + noFileSizeLimit = 0 +) + +// Decompressors is the mapping of extension to the Decompressor implementation +// configured with default settings that will decompress that extension/type. +// +// Note: these decompressors by default do not limit the number of files or the +// maximum file size created by the decompressed payload. +var Decompressors = LimitedDecompressors(noFilesLimit, noFileSizeLimit) + // containsDotDot checks if the filepath value v contains a ".." entry. // This will check filepath components by splitting along / or \. This // function is copied directly from the Go net/http implementation. diff --git a/decompress_test.go b/decompress_test.go new file mode 100644 index 000000000..5a0015b0e --- /dev/null +++ b/decompress_test.go @@ -0,0 +1,50 @@ +package getter + +import ( + "testing" +) + +func TestLimitedDecompressors(t *testing.T) { + const ( + maxFiles = 111 + maxSize = 222 + ) + + checkFileSizeLimit := func(limit int64) { + if limit != maxSize { + t.Fatalf("expected FileSizeLimit of %d, got %d", maxSize, limit) + } + } + + checkFilesLimit := func(limit int) { + if limit != maxFiles { + t.Fatalf("expected FilesLimit of %d, got %d", maxFiles, limit) + } + } + + decompressors := LimitedDecompressors(maxFiles, maxSize) + + checkFilesLimit(decompressors["tar"].(*TarDecompressor).FilesLimit) + checkFileSizeLimit(decompressors["tar"].(*TarDecompressor).FileSizeLimit) + + checkFilesLimit(decompressors["tar.bz2"].(*TarBzip2Decompressor).FilesLimit) + checkFileSizeLimit(decompressors["tar.bz2"].(*TarBzip2Decompressor).FileSizeLimit) + + checkFilesLimit(decompressors["tar.gz"].(*TarGzipDecompressor).FilesLimit) + checkFileSizeLimit(decompressors["tar.gz"].(*TarGzipDecompressor).FileSizeLimit) + + checkFilesLimit(decompressors["tar.xz"].(*TarXzDecompressor).FilesLimit) + checkFileSizeLimit(decompressors["tar.xz"].(*TarXzDecompressor).FileSizeLimit) + + checkFilesLimit(decompressors["tar.zst"].(*TarZstdDecompressor).FilesLimit) + checkFileSizeLimit(decompressors["tar.zst"].(*TarZstdDecompressor).FileSizeLimit) + + checkFilesLimit(decompressors["zip"].(*ZipDecompressor).FilesLimit) + checkFileSizeLimit(decompressors["zip"].(*ZipDecompressor).FileSizeLimit) + + // ones with file size limit only + checkFileSizeLimit(decompressors["bz2"].(*Bzip2Decompressor).FileSizeLimit) + checkFileSizeLimit(decompressors["gz"].(*GzipDecompressor).FileSizeLimit) + checkFileSizeLimit(decompressors["xz"].(*XzDecompressor).FileSizeLimit) + checkFileSizeLimit(decompressors["zst"].(*ZstdDecompressor).FileSizeLimit) +}