diff --git a/sign.go b/sign.go index 2ddff2c..e922c23 100644 --- a/sign.go +++ b/sign.go @@ -12,6 +12,7 @@ import ( "net/http" "sort" "strings" + "time" ) var signParams = map[string]bool{ @@ -71,6 +72,10 @@ func Sign(r *http.Request, k Keys) { DefaultService.Sign(r, k) } +func SignQuery(r *http.Request, t time.Time, k Keys) { + DefaultService.SignQuery(r, t, k) +} + // Service represents an S3-compatible service. type Service struct { Domain string // service root domain, used to extract subdomain from an http.Request and pass it to Bucket @@ -89,6 +94,17 @@ func (s *Service) Sign(r *http.Request, k Keys) { r.Header.Set("Authorization", "AWS "+k.AccessKey+":"+string(sig)) } +func (s *Service) SignQuery(r *http.Request, t time.Time, k Keys) { + if k.SecurityToken != "" { + r.Header.Set("X-Amz-Security-Token", k.SecurityToken) + } + h := hmac.New(sha1.New, []byte(k.SecretKey)) + s.writeSigQueryData(h, r, t) + sig := make([]byte, base64.StdEncoding.EncodedLen(h.Size())) + base64.StdEncoding.Encode(sig, h.Sum(nil)) + r.URL.RawQuery = "AWSAccessKeyId="+k.AccessKey+"&Signature="+string(sig)+"&Expires="+string(t.Unix()) +} + func (s *Service) writeSigData(w io.Writer, r *http.Request) { w.Write([]byte(r.Method)) w.Write([]byte{'\n'}) @@ -104,6 +120,19 @@ func (s *Service) writeSigData(w io.Writer, r *http.Request) { s.writeResource(w, r) } +func (s *Service) writeSigQueryData(w io.Writer, r *http.Request, t time.Time) { + w.Write([]byte(r.Method)) + w.Write([]byte{'\n'}) + w.Write([]byte(r.Header.Get("content-md5"))) + w.Write([]byte{'\n'}) + w.Write([]byte(r.Header.Get("content-type"))) + w.Write([]byte{'\n'}) + w.Write([]byte(string(t.Unix()))) + w.Write([]byte{'\n'}) + writeAmzHeaders(w, r) + s.writeResource(w, r) +} + func (s *Service) writeResource(w io.Writer, r *http.Request) { s.writeVhostBucket(w, strings.ToLower(r.Host)) path := r.URL.RequestURI()