package image import ( "crypto/sha256" "encoding/hex" "errors" "fmt" "io" "net/http" "os" "path/filepath" "strings" ) // Download fetches url into dest if dest does not exist. func Download(url, dest string) error { if _, err := os.Stat(dest); err == nil { return nil } if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { return err } if strings.HasPrefix(url, "file://") { src := strings.TrimPrefix(url, "file://") in, err := os.Open(src) if err != nil { return err } defer in.Close() out, err := os.Create(dest) if err != nil { return err } defer out.Close() _, err = io.Copy(out, in) return err } resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("download failed: %s", resp.Status) } out, err := os.Create(dest) if err != nil { return err } defer out.Close() _, err = io.Copy(out, resp.Body) return err } // VerifyChecksum checks sha256 in the form "sha256:". func VerifyChecksum(path, checksum string) error { if checksum == "" { return nil } parts := strings.SplitN(checksum, ":", 2) if len(parts) != 2 || parts[0] != "sha256" { return errors.New("unsupported checksum format; use sha256:") } expected := strings.ToLower(parts[1]) f, err := os.Open(path) if err != nil { return err } defer f.Close() h := sha256.New() if _, err := io.Copy(h, f); err != nil { return err } sum := hex.EncodeToString(h.Sum(nil)) if sum != expected { return fmt.Errorf("checksum mismatch: expected %s got %s", expected, sum) } return nil }