// NewDigestVerifier returns a verifier that compares the written bytes // against a passed in digest. func NewDigestVerifier(d Digest) (Verifier, error) { if err := d.Validate(); err != nil { return nil, err } alg := d.Algorithm() switch alg { case "sha256", "sha384", "sha512": return hashVerifier{ hash: alg.Hash(), digest: d, }, nil default: // Assume we have a tarsum. version, err := tarsum.GetVersionFromTarsum(string(d)) if err != nil { return nil, err } pr, pw := io.Pipe() // TODO(stevvooe): We may actually want to ban the earlier versions of // tarsum. That decision may not be the place of the verifier. ts, err := tarsum.NewTarSum(pr, true, version) if err != nil { return nil, err } // TODO(sday): Ick! A goroutine per digest verification? We'll have to // get the tarsum library to export an io.Writer variant. go func() { if _, err := io.Copy(ioutil.Discard, ts); err != nil { pr.CloseWithError(err) } else { pr.Close() } }() return &tarsumVerifier{ digest: d, ts: ts, pr: pr, pw: pw, }, nil } }
// ReadChecks takes the input and loads the hash/id to be checked func ReadChecks(input io.Reader) (Checks, error) { rdr := bufio.NewReader(input) checks := Checks{} for { line, err := rdr.ReadString('\n') if err != nil { if err == io.EOF { break } return checks, err } v, err := tarsum.GetVersionFromTarsum(line) if err != nil { continue } // tarsum+sha256:7b0ade22d5bba35d1e88389c005376f441e7d83bf5f363f2d7c70be9286163aa ./busybox.tar:120e218dd395ec314e7b6249f39d2853911b3d6def6ea164ae05722649f34b16 chunks := strings.SplitN(line, DefaultSpacer, 2) sum, source := chunks[0], chunks[1] i := strings.LastIndex(source, ":") checks = append(checks, Check{Hash: sum, Source: source[:i], Id: strings.TrimSpace(source[i+1:]), Version: v}) } return checks, nil }
func main() { var jobs []job flag.Usage = usage flag.Parse() if showVersion { version.PrintVersion() return } var fail bool // if we fail on one item, foul the exit code if flag.NArg() > 0 { for _, path := range flag.Args() { fp, err := os.Open(path) if err != nil { log.Printf("%s: %v", path, err) fail = true continue } defer fp.Close() jobs = append(jobs, job{name: path, reader: fp}) } } else { // just read stdin jobs = append(jobs, job{name: "-", reader: os.Stdin}) } digestFn := algorithm.FromReader if !algorithm.Available() { // we cannot digest if is not available. An exception is made for // tarsum. if !strings.HasPrefix(algorithm.String(), "tarsum") { unsupported() } var version tarsum.Version if algorithm == "tarsum" { // small hack: if we just have tarsum, use latest version = tarsum.Version1 } else { var err error version, err = tarsum.GetVersionFromTarsum(algorithm.String()) if err != nil { unsupported() } } digestFn = func(rd io.Reader) (digest.Digest, error) { ts, err := tarsum.NewTarSum(rd, true, version) if err != nil { return "", err } if _, err := io.Copy(ioutil.Discard, ts); err != nil { return "", err } return digest.Digest(ts.Sum(nil)), nil } } for _, job := range jobs { dgst, err := digestFn(job.reader) if err != nil { log.Printf("%s: %v", job.name, err) fail = true continue } fmt.Printf("%v\t%s\n", dgst, job.name) } if fail { os.Exit(1) } }