Created
July 8, 2018 13:48
-
-
Save justincormack/496500a5bb1b0dd31f12f49b81ff931a to your computer and use it in GitHub Desktop.
Enforcing content addressed storage on S3 with signed URLs and sha256 hashes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/sha256" | |
"encoding/hex" | |
"flag" | |
"fmt" | |
"io" | |
"net/http" | |
"os" | |
"time" | |
"github.com/aws/aws-sdk-go/aws" | |
"github.com/aws/aws-sdk-go/aws/session" | |
"github.com/aws/aws-sdk-go/service/s3" | |
) | |
func main() { | |
bucket := "tmp.myriabit.eu" | |
flag.StringVar(&bucket, "bucket", bucket, "Bucket to use") | |
flag.Parse() | |
if len(flag.Args()) != 1 { | |
fmt.Println("Expect a filename") | |
os.Exit(1) | |
} | |
filename := flag.Args()[0] | |
fileReader, err := os.Open(filename) | |
if err != nil { | |
fmt.Println("Cannot open file:", err) | |
os.Exit(1) | |
} | |
defer fileReader.Close() | |
hf := sha256.New() | |
if _, err := io.Copy(hf, fileReader); err != nil { | |
fmt.Println("%v", err) | |
os.Exit(1) | |
} | |
if _, err := fileReader.Seek(0, 0); err != nil { | |
fmt.Println("%v", err) | |
os.Exit(1) | |
} | |
h := hex.EncodeToString(hf.Sum(nil)) | |
fmt.Printf("sha256 hash is %s\n", h) | |
url, err := vURL(bucket, h) | |
if err != nil { | |
fmt.Println("%v", err) | |
os.Exit(1) | |
} | |
fmt.Println("URL", url) | |
st, err := fileReader.Stat() | |
if err != nil { | |
fmt.Println("Cannot stat file:", err) | |
os.Exit(1) | |
} | |
req, err := http.NewRequest("PUT", url, fileReader) | |
if err != nil { | |
fmt.Println("error creating request", url) | |
os.Exit(1) | |
} | |
req.ContentLength = st.Size() | |
req.Header.Add("x-amz-content-sha256", h) | |
resp, err := http.DefaultClient.Do(req) | |
if err != nil { | |
fmt.Println("failed making request") | |
os.Exit(1) | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode > 299 { | |
fmt.Printf("Bad response code: %d\n", resp.StatusCode) | |
io.Copy(os.Stdout, resp.Body) | |
os.Exit(1) | |
} | |
fmt.Printf("%s\n", resp.Status) | |
} | |
func vURL(bucket, h string) (string, error) { | |
svc := s3.New(session.New()) | |
r, _ := svc.PutObjectRequest(&s3.PutObjectInput{ | |
Bucket: aws.String(bucket), | |
Key: aws.String(h), | |
}) | |
r.HTTPRequest.Header.Set("x-amz-content-sha256", h) | |
url, err := r.Presign(15 * time.Minute) | |
if err != nil { | |
fmt.Println("error presigning request", err) | |
return "", err | |
} | |
return url, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment