internal/artifact/checksum.go (54 lines of code) (raw):

package artifact import ( "bytes" "encoding/hex" "errors" "fmt" "hash" "strings" ) type checksumVerifier struct { expect []byte digest hash.Hash } type nopChecksumVerifier struct{} type ChecksumError struct { Expect []byte Actual []byte } // ParseGNUChecksum parses r as GNU checksum format and returns the checksum value. GNU checksums // are a space separated digest and filename: // // <digest> <filename> func ParseGNUChecksum(gnuChecksum []byte) ([]byte, error) { ch, _, found := strings.Cut(string(gnuChecksum), " ") if !found { return nil, errors.New("invalid gnu checksum") } checksum, err := hex.DecodeString(ch) if err != nil { return nil, err } return checksum, nil } // NewChecksumError creates an error of type ChecksumError. func NewChecksumError(src Source) error { return ChecksumError{ Expect: src.ExpectedChecksum(), Actual: src.ActualChecksum(), } } // Actual satisfies Checksumer. func (c checksumVerifier) ActualChecksum() []byte { return c.digest.Sum(nil) } // Expected satisfies Checksumer. func (c checksumVerifier) ExpectedChecksum() []byte { return c.expect } // VerifyChecksum satisfies Checksumer. Calling verify before the associated Source has been // completely read will cause an incomplete digest to be used and result in a false return. func (c checksumVerifier) VerifyChecksum() bool { return bytes.Equal(c.ActualChecksum(), c.ExpectedChecksum()) } // Error implements the error interface. func (ce ChecksumError) Error() string { return fmt.Sprintf("checksum mismatch (expect != actual): %s != %s", string(ce.Expect), string(ce.Actual)) } // Is implements the errors.Is interface. func (ce ChecksumError) Is(err error) bool { _, ok := err.(ChecksumError) return ok } func (nopChecksumVerifier) VerifyChecksum() bool { return true } func (nopChecksumVerifier) ExpectedChecksum() []byte { return nil } func (nopChecksumVerifier) ActualChecksum() []byte { return nil }