Skip to content

Instantly share code, notes, and snippets.

@justincormack
Created July 8, 2018 13:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justincormack/496500a5bb1b0dd31f12f49b81ff931a to your computer and use it in GitHub Desktop.
Save justincormack/496500a5bb1b0dd31f12f49b81ff931a to your computer and use it in GitHub Desktop.
Enforcing content addressed storage on S3 with signed URLs and sha256 hashes
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