Last active
February 14, 2018 14:03
-
-
Save kyokomi/5a500e88e9be55a4e694f30759d0aa76 to your computer and use it in GitHub Desktop.
Authenticating Requests in Browser-Based Uploads Using POST (AWS Signature Version 2) for golang http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UsingHTTPPOST.html
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 ( | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"io/ioutil" | |
"mime/multipart" | |
"github.com/k0kubun/pp" | |
"github.com/pborman/uuid" | |
"bytes" | |
"io" | |
"net/http" | |
) | |
func postFile(filename string, url string, formData map[string]string) error { | |
bodyBuf := &bytes.Buffer{} | |
bodyWriter := multipart.NewWriter(bodyBuf) | |
for k, v := range formData { | |
bodyWriter.WriteField(k, v) | |
} | |
fileWriter, err := bodyWriter.CreateFormFile("file", filename) | |
if err != nil { | |
return err | |
} | |
fh, err := os.Open(filename) | |
if err != nil { | |
return err | |
} | |
defer fh.Close() | |
if _, err = io.Copy(fileWriter, fh); err != nil { | |
return err | |
} | |
contentType := bodyWriter.FormDataContentType() | |
bodyWriter.Close() | |
resp, err := http.Post(url, contentType, bodyBuf) | |
if err != nil { | |
return err | |
} | |
defer resp.Body.Close() | |
resp_body, err := ioutil.ReadAll(resp.Body) | |
if err != nil { | |
return err | |
} | |
fmt.Println(resp.Status) | |
fmt.Println(string(resp_body)) | |
return nil | |
} | |
func main() { | |
awsAccessKeyID := flag.String("aid", "", "AWS_ACCESS_KEY_ID") | |
awsSecretKeyID := flag.String("sid", "", "AWS_SECRET_KEY_ID") | |
s3BucketName := flag.String("b", "", "S3_BUCKET_NAME") | |
filePath := flag.String("f", "", "Upload file path") | |
flag.Parse() | |
f, err := os.Open(filePath) | |
if err != nil { | |
log.Fatalln(err) | |
} | |
fileID := uuid.New() | |
userID := 111111 // TODO: | |
// input data | |
fi, err := f.Stat() | |
if err != nil { | |
log.Fatalln(err) | |
} | |
uploadObjectKey := fmt.Sprintf("files/%d/%s.%s", userID, fileID, "png") | |
policies, err := CreatePolicies(AWSCredentials{ | |
AWSAccessKeyID: awsAccessKeyID, | |
AWSSecretKeyID: awsSecretKeyID, | |
}, UploadConfig{ | |
BucketName: s3BucketName, | |
FileSize: fi.Size(), | |
ContentType: "image/png", // TODO: | |
ObjectKey: uploadObjectKey, | |
}) | |
if err != nil { | |
log.Fatalln(err) | |
} | |
pp.Print(policies) | |
if err := postFile(filePath, policies.URL, policies.Form); err != nil { | |
log.Fatalln(err) | |
} | |
} |
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 ( | |
"encoding/base64" | |
"crypto/hmac" | |
"crypto/sha1" | |
"fmt" | |
"time" | |
"encoding/json" | |
"strings" | |
) | |
// AWSCredentials Amazon Credentials | |
type AWSCredentials struct { | |
AWSSecretKeyID string | |
AWSAccessKeyID string | |
} | |
// UploadConfig generate policies from config | |
type UploadConfig struct { | |
BucketName string | |
ObjectKey string | |
ContentType string | |
FileSize int64 | |
} | |
// UploadPolicies Amazon s3 upload policies | |
type UploadPolicies struct { | |
URL string | |
Form map[string]string | |
} | |
// PolicyJSON is policy rule | |
type PolicyJSON struct { | |
Expiration string `json:"expiration"` | |
Conditions []interface{} `json:"conditions"` | |
} | |
const expirationTimeFormat = "2006-01-02T15:04:05ZZ07:00" | |
const expirationHour = 1 * time.Hour | |
const uploadURLFormat = "http://%s.s3.amazonaws.com/" // <bucketName> | |
// CreatePolicies create amazon s3 to upload policies return | |
func CreatePolicies(awsCredentials AWSCredentials, fileInfo UploadConfig) (UploadPolicies, error) { | |
data, err := json.Marshal(&PolicyJSON{ | |
Expiration: time.Now().Add(expirationHour).Format(expirationTimeFormat), | |
Conditions: []interface{}{ | |
map[string]string{"bucket": fileInfo.BucketName}, | |
map[string]string{"key": fileInfo.ObjectKey}, | |
map[string]string{"Content-Type": fileInfo.ContentType}, | |
[]interface{}{"content-length-range", fileInfo.FileSize, fileInfo.FileSize}, | |
}, | |
}) | |
if err != nil { | |
return UploadPolicies{}, err | |
} | |
policy := strings.Replace(base64.StdEncoding.EncodeToString(data), "\n", "", -1) | |
mac := hmac.New(sha1.New, []byte(awsCredentials.AWSSecretKeyID)) | |
mac.Write([]byte(policy)) | |
expectedMAC := mac.Sum(nil) | |
signature := strings.Replace(base64.StdEncoding.EncodeToString(expectedMAC), "\n", "", -1) | |
uploadURL := fmt.Sprintf(uploadURLFormat, fileInfo.BucketName) | |
return UploadPolicies{ | |
URL: uploadURL, | |
Form: map[string]string{ | |
"AWSAccessKeyId": awsCredentials.AWSAccessKeyID, | |
"key": fileInfo.ObjectKey, | |
"Content-Type": fileInfo.ContentType, | |
"signature": signature, | |
"policy": policy, | |
}, | |
}, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
v4も対応したので、このライブラリを使った方が良い
https://github.com/kyokomi/s3gopolicy