Preflight ZIP central directory metadata (T-612)

This commit is contained in:
ila
2026-07-18 15:40:44 +08:00
parent 65ff7a3f23
commit 0f69fa330e
14 changed files with 702 additions and 68 deletions
+28 -18
View File
@@ -14,20 +14,23 @@ import (
)
var (
ErrInvalidArchive = errors.New("invalid ZIP archive")
ErrPathEscape = errors.New("ZIP path escapes payload")
ErrUnsupportedEntry = errors.New("unsupported ZIP entry")
ErrUnexpectedEntry = errors.New("unexpected ZIP package entry")
ErrDuplicateEntry = errors.New("duplicate ZIP entry")
ErrEncryptedEntry = errors.New("encrypted ZIP entry is unsupported")
ErrTooManyEntries = errors.New("ZIP entry limit exceeded")
ErrExpandedTooLarge = errors.New("ZIP expanded size limit exceeded")
ErrCompressionRatio = errors.New("ZIP compression ratio limit exceeded")
ErrEntrypointInvalid = errors.New("invalid package entrypoint")
ErrEntrypointMissing = errors.New("package entrypoint is missing")
ErrAppManifestMissing = errors.New("package app.json is missing")
ErrDestinationExists = errors.New("staging destination already exists")
ErrArchiveCorrupt = errors.New("ZIP archive data is corrupt")
ErrInvalidArchive = errors.New("invalid ZIP archive")
ErrPathEscape = errors.New("ZIP path escapes payload")
ErrUnsupportedEntry = errors.New("unsupported ZIP entry")
ErrUnexpectedEntry = errors.New("unexpected ZIP package entry")
ErrDuplicateEntry = errors.New("duplicate ZIP entry")
ErrEncryptedEntry = errors.New("encrypted ZIP entry is unsupported")
ErrArchiveSizeMismatch = errors.New("ZIP archive size does not match expected package size")
ErrArchiveTooLarge = errors.New("ZIP archive size limit exceeded")
ErrCentralDirectoryTooLarge = errors.New("ZIP central directory size limit exceeded")
ErrTooManyEntries = errors.New("ZIP entry limit exceeded")
ErrExpandedTooLarge = errors.New("ZIP expanded size limit exceeded")
ErrCompressionRatio = errors.New("ZIP compression ratio limit exceeded")
ErrEntrypointInvalid = errors.New("invalid package entrypoint")
ErrEntrypointMissing = errors.New("package entrypoint is missing")
ErrAppManifestMissing = errors.New("package app.json is missing")
ErrDestinationExists = errors.New("staging destination already exists")
ErrArchiveCorrupt = errors.New("ZIP archive data is corrupt")
)
// Extractor writes only payload/ contents from a pre-verified package ZIP.
@@ -56,18 +59,25 @@ func NewExtractor(limits Limits) (Extractor, error) {
return Extractor{limits: limits}, nil
}
// ExtractFile assumes zipPath already passed Catalog signature and SHA-256 checks.
// ExtractFile requires expectedPackageSize from the verified Catalog package.
// The completed download file must have precisely that size before any ZIP data is parsed.
func (extractor Extractor) ExtractFile(
zipPath string,
destination string,
entrypoint string,
expectedPackageSize int64,
) (ExtractResult, error) {
archive, err := zip.OpenReader(zipPath)
file, size, err := extractor.openAndScanArchive(zipPath, expectedPackageSize)
if err != nil {
return ExtractResult{}, err
}
defer file.Close()
archive, err := zip.NewReader(file, size)
if err != nil {
return ExtractResult{}, fmt.Errorf("%w: %v", ErrInvalidArchive, err)
}
defer archive.Close()
return extractor.extract(&archive.Reader, destination, entrypoint)
return extractor.extract(archive, destination, entrypoint)
}
func (extractor Extractor) extract(