Integrate verified installation flow (T-302)
This commit is contained in:
@@ -33,6 +33,24 @@ type endOfCentralDirectory struct {
|
||||
func (extractor Extractor) openAndScanArchive(
|
||||
zipPath string,
|
||||
expectedPackageSize int64,
|
||||
) (*os.File, int64, error) {
|
||||
file, size, err := extractor.openArchiveFile(zipPath, expectedPackageSize)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if err := extractor.scanOpenedArchive(file, size); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, 0, err
|
||||
}
|
||||
return file, size, nil
|
||||
}
|
||||
|
||||
// openArchiveFile opens the completed package once and proves the path still
|
||||
// names that same ordinary file. Later verification and parsing must retain
|
||||
// this handle rather than reopening zipPath.
|
||||
func (extractor Extractor) openArchiveFile(
|
||||
zipPath string,
|
||||
expectedPackageSize int64,
|
||||
) (*os.File, int64, error) {
|
||||
if err := extractor.limits.validate(); err != nil {
|
||||
return nil, 0, err
|
||||
@@ -64,6 +82,17 @@ func (extractor Extractor) openAndScanArchive(
|
||||
if !info.Mode().IsRegular() {
|
||||
return closeWithError(fmt.Errorf("%w: opened package is not a regular file", ErrInvalidArchive))
|
||||
}
|
||||
if !os.SameFile(pathInfo, info) {
|
||||
return closeWithError(fmt.Errorf("%w: package changed while opening", ErrInvalidArchive))
|
||||
}
|
||||
pathInfoAfterOpen, err := os.Lstat(zipPath)
|
||||
if err != nil {
|
||||
return closeWithError(fmt.Errorf("%w: recheck package: %v", ErrInvalidArchive, err))
|
||||
}
|
||||
if pathInfoAfterOpen.Mode()&os.ModeSymlink != 0 || !pathInfoAfterOpen.Mode().IsRegular() ||
|
||||
!os.SameFile(info, pathInfoAfterOpen) {
|
||||
return closeWithError(fmt.Errorf("%w: package changed while opening", ErrInvalidArchive))
|
||||
}
|
||||
size := info.Size()
|
||||
if size != expectedPackageSize {
|
||||
return closeWithError(fmt.Errorf(
|
||||
@@ -81,12 +110,43 @@ func (extractor Extractor) openAndScanArchive(
|
||||
extractor.limits.MaxArchiveBytes,
|
||||
))
|
||||
}
|
||||
if err := scanCentralDirectory(file, size, extractor.limits); err != nil {
|
||||
return closeWithError(err)
|
||||
}
|
||||
return file, size, nil
|
||||
}
|
||||
|
||||
func (extractor Extractor) scanOpenedArchive(file *os.File, expectedPackageSize int64) error {
|
||||
if file == nil {
|
||||
return fmt.Errorf("%w: package handle is nil", ErrInvalidArchive)
|
||||
}
|
||||
if err := extractor.limits.validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: stat package before ZIP scan: %v", ErrInvalidArchive, err)
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
return fmt.Errorf("%w: opened package is not a regular file", ErrInvalidArchive)
|
||||
}
|
||||
size := info.Size()
|
||||
if size != expectedPackageSize {
|
||||
return fmt.Errorf(
|
||||
"%w: got %d, expected %d",
|
||||
ErrArchiveSizeMismatch,
|
||||
size,
|
||||
expectedPackageSize,
|
||||
)
|
||||
}
|
||||
if size > extractor.limits.MaxArchiveBytes {
|
||||
return fmt.Errorf(
|
||||
"%w: got %d, limit %d",
|
||||
ErrArchiveTooLarge,
|
||||
size,
|
||||
extractor.limits.MaxArchiveBytes,
|
||||
)
|
||||
}
|
||||
return scanCentralDirectory(file, size, extractor.limits)
|
||||
}
|
||||
|
||||
func scanCentralDirectory(file *os.File, size int64, limits Limits) error {
|
||||
end, err := findEndOfCentralDirectory(file, size)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user