11package getter
22
33import (
4+ "bytes"
5+ "crypto/md5"
6+ "crypto/sha1"
7+ "crypto/sha256"
8+ "crypto/sha512"
9+ "encoding/hex"
410 "fmt"
11+ "hash"
12+ "io"
513 "io/ioutil"
614 "os"
715 "path/filepath"
16+ "strings"
817
918 urlhelper "github.com/hashicorp/terraform/helper/url"
1019)
@@ -71,10 +80,65 @@ func (c *Client) Get() error {
7180 "download not supported for scheme '%s'" , force )
7281 }
7382
83+ // Determine if we have a checksum
84+ var checksumHash hash.Hash
85+ var checksumValue []byte
86+ q := u .Query ()
87+ if v := q .Get ("checksum" ); v != "" {
88+ // Delete the query parameter if we have it.
89+ q .Del ("checksum" )
90+ u .RawQuery = q .Encode ()
91+
92+ // If we're getting a directory, then this is an error. You cannot
93+ // checksum a directory. TODO: test
94+ if c .Dir {
95+ return fmt .Errorf (
96+ "checksum cannot be specified for directory download" )
97+ }
98+
99+ // Determine the checksum hash type
100+ checksumType := ""
101+ idx := strings .Index (v , ":" )
102+ if idx > - 1 {
103+ checksumType = v [:idx ]
104+ }
105+ switch checksumType {
106+ case "md5" :
107+ checksumHash = md5 .New ()
108+ case "sha1" :
109+ checksumHash = sha1 .New ()
110+ case "sha256" :
111+ checksumHash = sha256 .New ()
112+ case "sha512" :
113+ checksumHash = sha512 .New ()
114+ default :
115+ return fmt .Errorf (
116+ "unsupported checksum type: %s" , checksumType )
117+ }
118+
119+ // Get the remainder of the value and parse it into bytes
120+ b , err := hex .DecodeString (v [idx + 1 :])
121+ if err != nil {
122+ return fmt .Errorf ("invalid checksum: %s" , err )
123+ }
124+
125+ // Set our value
126+ checksumValue = b
127+ }
128+
74129 // If we're not downloading a directory, then just download the file
75130 // and return.
76131 if ! c .Dir {
77- return g .GetFile (dst , u )
132+ err := g .GetFile (dst , u )
133+ if err != nil {
134+ return err
135+ }
136+
137+ if checksumHash != nil {
138+ return checksum (dst , checksumHash , checksumValue )
139+ }
140+
141+ return nil
78142 }
79143
80144 // We're downloading a directory, which might require a bit more work
@@ -99,3 +163,26 @@ func (c *Client) Get() error {
99163
100164 return nil
101165}
166+
167+ // checksum is a simple method to compute the checksum of a source file
168+ // and compare it to the given expected value.
169+ func checksum (source string , h hash.Hash , v []byte ) error {
170+ f , err := os .Open (source )
171+ if err != nil {
172+ return fmt .Errorf ("Failed to open file for checksum: %s" , err )
173+ }
174+ defer f .Close ()
175+
176+ if _ , err := io .Copy (h , f ); err != nil {
177+ return fmt .Errorf ("Failed to hash: %s" , err )
178+ }
179+
180+ if actual := h .Sum (nil ); ! bytes .Equal (actual , v ) {
181+ return fmt .Errorf (
182+ "Checksums did not match.\n Expected: %s\n Got: %s" ,
183+ hex .EncodeToString (v ),
184+ hex .EncodeToString (actual ))
185+ }
186+
187+ return nil
188+ }
0 commit comments