Skip to content
This repository has been archived by the owner on Jun 5, 2024. It is now read-only.

Use sha1 from header if it exists #78

Merged
merged 1 commit into from
Jul 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 67 additions & 16 deletions pkg/apk/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"context"
"crypto/sha1" //nolint:gosec // this is what apk tools is using
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -131,29 +132,41 @@ func (a *APK) installAPKFiles(ctx context.Context, gzipIn io.Reader, origin, rep
}

case tar.TypeReg:
// we need to calculate the checksum of the file, and then pass it to the writeOneFile,
// so we save it to a tempdir and then remove it
f, err := os.CreateTemp(tmpDir, "apk-file")
checksum, err := checksumFromHeader(header)
if err != nil {
return nil, fmt.Errorf("error creating temporary file: %w", err)
return nil, err
}

// we need to calculate the checksum of the file while reading it
w := sha1.New() //nolint:gosec // this is what apk tools is using
tee := io.TeeReader(tr, w)
if _, err := io.Copy(f, tee); err != nil {
return nil, fmt.Errorf("error copying file %s: %w", header.Name, err)
}
offset, err := f.Seek(0, io.SeekStart)
if err != nil {
return nil, fmt.Errorf("error seeking to start of temp file for %s: %w", header.Name, err)
}
if offset != 0 {
return nil, fmt.Errorf("error seeking to start of temp file for %s: offset is %d", header.Name, offset)

r := tee

if checksum == nil {
// we need to calculate the checksum of the file, and then pass it to the writeOneFile,
// so we save it to a tempdir and then remove it
f, err := os.CreateTemp(tmpDir, "apk-file")
if err != nil {
return nil, fmt.Errorf("error creating temporary file: %w", err)
}

if _, err := io.Copy(f, tee); err != nil {
return nil, fmt.Errorf("error copying file %s: %w", header.Name, err)
}
offset, err := f.Seek(0, io.SeekStart)
if err != nil {
return nil, fmt.Errorf("error seeking to start of temp file for %s: %w", header.Name, err)
}
if offset != 0 {
return nil, fmt.Errorf("error seeking to start of temp file for %s: offset is %d", header.Name, offset)
}
checksum = w.Sum(nil)
jonjohnsonjr marked this conversation as resolved.
Show resolved Hide resolved

r = f
}
checksum := w.Sum(nil)

if err := a.writeOneFile(header, f, false); err != nil {
if err := a.writeOneFile(header, r, false); err != nil {
// if the error is something other than the file exists, return the error
var fileExistsError FileExistsError
if !errors.As(err, &fileExistsError) || origin == "" {
Expand Down Expand Up @@ -197,10 +210,16 @@ func (a *APK) installAPKFiles(ctx context.Context, gzipIn io.Reader, origin, rep
// it was found in a package with the same origin, so just overwrite

// if we get here, it had the same origin so even if different, we are allowed to overwrite the file
if err := a.writeOneFile(header, f, true); err != nil {
if err := a.writeOneFile(header, r, true); err != nil {
return nil, err
}
}

// TODO: Move individual file checksum verification into ExpandAPK so we do it just once per APK.
if want, got := checksum, w.Sum(nil); !bytes.Equal(want, got) {
return nil, fmt.Errorf("checksum mismatch: header was %x, computed %x", want, got)
}

// we need to save this somewhere. The output expects []tar.Header, so we need to override that.
// Reusing a field should be good enough, provided that we know it is not getting in the way of
// anything downstream. Since we know it is not, this is good enough.
Expand Down Expand Up @@ -243,3 +262,35 @@ func (a *APK) installAPKFiles(ctx context.Context, gzipIn io.Reader, origin, rep

return files, nil
}

func checksumFromHeader(header *tar.Header) ([]byte, error) {
pax := header.PAXRecords
if pax == nil {
return nil, nil
}

hexsum, ok := pax[paxRecordsChecksumKey]
if !ok {
return nil, nil
}

if strings.HasPrefix(hexsum, "Q1") {
// This is nonstandard but something we did at one point, handle it.
// In other contexts, this Q1 prefix means "this is sha1 not md5".
b64 := strings.TrimPrefix(hexsum, "Q1")

checksum, err := base64.StdEncoding.DecodeString(b64)
if err != nil {
return nil, fmt.Errorf("decoding base64 checksum from header for %q: %w", header.Name, err)
}

return checksum, nil
}

checksum, err := hex.DecodeString(hexsum)
if err != nil {
return nil, fmt.Errorf("decoding hex checksum from header for %q: %w", header.Name, err)
}

return checksum, nil
}
Loading