package actions import ( "flow/services/internal/bundle" "fmt" "io" "net/http" "os" "path/filepath" "github.com/magefile/mage/sh" ) // Download downloads all the files in the download pack, // verifies all the GPG signatures (if enabled) and // verifies the checksums (if enabled). func Download(b bundle.Bundle) error { if err := os.MkdirAll(b.DestinationDir, 0o750); err != nil { return fmt.Errorf("unable to make '%s'; %w", b.DestinationDir, err) } var objects []bundle.Object for i := range b.Packages { objects = append(objects, b.Packages[i].File) if b.ValidateGPGSignature { objects = append(objects, b.Packages[i].GPGSignature) } } if b.Checksum.Validate { objects = append(objects, b.Checksum.File) } for _, object := range objects { if err := func() error { _, err := os.Stat(object.Destination) if err == nil { fmt.Printf("%s is already downloaded.\n", object.Destination) return nil } file, err := os.Create(object.Destination) if err != nil { return fmt.Errorf("unable to create %s; %w", object.Destination, err) } defer file.Close() client := http.Client{ CheckRedirect: func(r *http.Request, _ []*http.Request) error { r.URL.Opaque = r.URL.Path return nil }, } resp, err := client.Get(object.Source) if err != nil { return err } defer resp.Body.Close() size, err := io.Copy(file, resp.Body) if err != nil { return err } fmt.Printf("Downloaded %s with size %d.\n", object.Destination, size) return nil }(); err != nil { return err } } if b.ValidateGPGSignature { for i := range b.Packages { if err := sh.RunV("gpg", "--verify", b.Packages[i].GPGSignature.Destination, b.Packages[i].File.Destination); err != nil { return fmt.Errorf("GPG verification failed for '%s'; %w", b.Packages[i].File.Destination, err) } } } if b.Checksum.Validate { var err error if b.Checksum.ValidateFunc != nil { err = b.Checksum.ValidateFunc() } else { err = validateChecksum(b.DestinationDir, b.Checksum.File.Destination) } if err != nil { return fmt.Errorf("checksum validation failed; %w", err) } } return nil } func validateChecksum(destinationDir, checksumPath string) error { startDir, err := os.Getwd() if err != nil { return err } if err := os.Chdir(destinationDir); err != nil { return err } checksum := filepath.Base(checksumPath) if err := sh.RunV("sha256sum", "--check", "--ignore-missing", checksum); err != nil { return err } if err := os.Chdir(startDir); err != nil { return err } return nil }