From a1a5de910beff42b9715b22f6d30db3829186d54 Mon Sep 17 00:00:00 2001 From: Nate Walck Date: Wed, 3 Jun 2020 14:47:41 -0400 Subject: [PATCH] Add hashing support to the http source type --- examples/config_install_pkg.json | 5 +++-- plugin/source/http/http.go | 19 +++++++++++++++++++ util/hashfile/hashfile.go | 26 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 util/hashfile/hashfile.go diff --git a/examples/config_install_pkg.json b/examples/config_install_pkg.json index a043aae..42a85e3 100644 --- a/examples/config_install_pkg.json +++ b/examples/config_install_pkg.json @@ -15,8 +15,9 @@ "is_dmg": true, "source": { "type": "go2chef.source.http", - "url": "https://packages.chef.io/files/stable/chef/15.2.20/mac_os_x/10.14/chef-15.2.20-1.dmg" + "url": "https://packages.chef.io/files/stable/chef/16.1.16/mac_os_x/10.15/chef-16.1.16-1.dmg", + "sha256": "95e62c5824e361b12a30981cab677da1010d2f05b7e3f0c538d885881a4daf4a" } } ] -} \ No newline at end of file +} diff --git a/plugin/source/http/http.go b/plugin/source/http/http.go index ce3a330..f2a3836 100644 --- a/plugin/source/http/http.go +++ b/plugin/source/http/http.go @@ -5,6 +5,7 @@ package http */ import ( + "errors" "fmt" "io" "mime" @@ -15,6 +16,7 @@ import ( "github.com/facebookincubator/go2chef/plugin/lib/certs" + "github.com/facebookincubator/go2chef/util/hashfile" "github.com/facebookincubator/go2chef/util/temp" "github.com/facebookincubator/go2chef" @@ -34,6 +36,7 @@ type Source struct { ValidStatusCodes []int `mapstructure:"valid_status_codes"` Archive bool `mapstructure:"archive"` OutputFilename string `mapstructure:"output_filename"` + SHA256 string `mapstructure:"sha256"` } // String returns a string representation of this @@ -137,6 +140,21 @@ func (s *Source) DownloadToPath(dlPath string) (err error) { } outputPath := filepath.Join(dlPath, outputFilename) + if s.SHA256 != "" { + s.logger.Debugf(1, "%s: sha256 was provided, validating %s", s.Name(), outputPath) + fileHash, err := hashfile.SHA256(tmpfile.Name()) + if err != nil { + return err + } + + s.logger.Debugf(1, "Calcluated hash is %s: ", fileHash) + s.logger.Debugf(1, "Provided hash: %s", s.SHA256) + // If the hash doesn't match what is provided, return an error. + if fileHash != s.SHA256 { + return errors.New("sha256 hashes do not match") + } + } + if s.Archive { /* ARCHIVE MODE: If the request is for an archive (using `{"archive": true}` in config) then @@ -189,6 +207,7 @@ func Loader(config map[string]interface{}) (go2chef.Source, error) { make([]int, 0), false, "", + "", } if err := mapstructure.Decode(config, s); err != nil { return nil, err diff --git a/util/hashfile/hashfile.go b/util/hashfile/hashfile.go new file mode 100644 index 0000000..13c9982 --- /dev/null +++ b/util/hashfile/hashfile.go @@ -0,0 +1,26 @@ +package hashfile + +import ( + "crypto/sha256" + "encoding/hex" + "io" + "os" +) + +// SHA256 returns a sha256 hash of the file at the given filepath. +func SHA256(filePath string) (string, error) { + f, err := os.Open(filePath) + if err != nil { + return "", err + } + defer f.Close() + + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + return "", err + } + + hString := hex.EncodeToString(h.Sum(nil)) + + return hString, nil +}