Update readme and docstrings, minor refactors.
This commit is contained in:
+34
-21
@@ -16,6 +16,7 @@ const (
|
||||
defaultPresignedURLFormat = "%s.s3.amazonaws.com" // <bucket>
|
||||
)
|
||||
|
||||
// PresignedInput is passed to GeneratePresignedURL as a parameter.
|
||||
type PresignedInput struct {
|
||||
Bucket string
|
||||
ObjectKey string
|
||||
@@ -25,10 +26,13 @@ type PresignedInput struct {
|
||||
ExpirySeconds int
|
||||
}
|
||||
|
||||
// GeneratePresignedURL creates a Presigned URL that can be used
|
||||
// for Authentication using Query Parameters.
|
||||
// (https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html)
|
||||
func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
||||
var (
|
||||
nowTime = in.Timestamp.UTC()
|
||||
cred = s3.buildCredential(nowTime)
|
||||
cred = fmt.Sprintf("%s/"+s3.buildCredentialWithoutKey(nowTime), s3.AccessKey)
|
||||
amzdate = nowTime.Format(amzDateISO8601TimeFormat)
|
||||
expiry = strconv.Itoa(in.ExpirySeconds)
|
||||
)
|
||||
@@ -41,7 +45,7 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
||||
signedHeaders["host"] = fmt.Sprintf(defaultPresignedURLFormat, in.Bucket)
|
||||
|
||||
// Start Canonical Request Formation
|
||||
h := sha256.New()
|
||||
h := sha256.New() // We write the canonical request directly to the SHA256 hash.
|
||||
fmt.Fprintf(h, "%s\n", in.Method) // HTTP Verb
|
||||
fmt.Fprintf(h, "/%s\n", in.ObjectKey) // CanonicalURL
|
||||
|
||||
@@ -54,44 +58,53 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
||||
}
|
||||
|
||||
// We need to have a sorted order,
|
||||
keysQS := make([]string, 0, len(queryString))
|
||||
// for QueryStrings and SignedHeaders
|
||||
sortedQS := make([]string, 0, len(queryString))
|
||||
for name := range queryString {
|
||||
keysQS = append(keysQS, name)
|
||||
sortedQS = append(sortedQS, name)
|
||||
}
|
||||
sort.Strings(keysQS) //sort by key
|
||||
for _, k := range keysQS {
|
||||
sort.Strings(sortedQS) //sort by key
|
||||
|
||||
sortedSH := make([]string, 0, len(signedHeaders))
|
||||
for name := range signedHeaders {
|
||||
sortedSH = append(sortedSH, name)
|
||||
}
|
||||
sort.Strings(sortedSH) //sort by key
|
||||
|
||||
// Proceed to write canonical query params
|
||||
for _, k := range sortedQS {
|
||||
fmt.Fprintf(h, "%s=%s&", url.QueryEscape(k), url.QueryEscape(queryString[k])) // HTTP Verb
|
||||
}
|
||||
|
||||
fmt.Fprintf(h, "X-Amz-SignedHeaders=")
|
||||
// Add Signed Headers to Query String
|
||||
first := true
|
||||
for k := range signedHeaders {
|
||||
for k := range sortedSH {
|
||||
if first {
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(k))
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(sortedSH[k]))
|
||||
first = false
|
||||
} else {
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(";"+k))
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(";"+sortedSH[k]))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(h, "\n")
|
||||
// End QueryString Params
|
||||
|
||||
// Start Canonical Headers
|
||||
for k, v := range signedHeaders {
|
||||
fmt.Fprintf(h, "%s:%s\n", strings.ToLower(k), strings.TrimSpace(v))
|
||||
for _, k := range sortedSH {
|
||||
fmt.Fprintf(h, "%s:%s\n", strings.ToLower(k), strings.TrimSpace(signedHeaders[k]))
|
||||
}
|
||||
fmt.Fprintf(h, "\n")
|
||||
// End Canonical Headers
|
||||
|
||||
// Start Signed Headers
|
||||
first = true
|
||||
for k := range signedHeaders {
|
||||
for k := range sortedSH {
|
||||
if first {
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(k))
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(sortedSH[k]))
|
||||
first = false
|
||||
} else {
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(";"+k))
|
||||
fmt.Fprintf(h, "%s", url.QueryEscape(";"+sortedSH[k]))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(h, "\n")
|
||||
@@ -126,7 +139,8 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
||||
[]byte("s3")),
|
||||
[]byte("aws4_request"),
|
||||
)
|
||||
// sigKey gen verified using https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-other
|
||||
// sigKey gen verified using
|
||||
// https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-other
|
||||
// (TODO: add a test using the same, consolidate with signKeys())
|
||||
|
||||
signedStrToSign := makeHMac(sigKey, stringToSign)
|
||||
@@ -142,21 +156,20 @@ func (s3 *S3) GeneratePresignedURL(in PresignedInput) string {
|
||||
|
||||
// We don't need to have a sorted order here,
|
||||
// but just to preserve tests.
|
||||
for _, k := range keysQS {
|
||||
for _, k := range sortedQS {
|
||||
fmt.Fprintf(&b, "%s=%s&", url.QueryEscape(k), url.QueryEscape(queryString[k])) // HTTP Verb
|
||||
}
|
||||
fmt.Fprintf(&b, "%s=", "X-Amz-SignedHeaders")
|
||||
first = true
|
||||
for k := range signedHeaders {
|
||||
for k := range sortedSH {
|
||||
if first {
|
||||
fmt.Fprintf(&b, "%s", url.QueryEscape(k))
|
||||
fmt.Fprintf(&b, "%s", url.QueryEscape(sortedSH[k]))
|
||||
first = false
|
||||
} else {
|
||||
fmt.Fprintf(&b, "%s", url.QueryEscape(";"+k))
|
||||
fmt.Fprintf(&b, "%s", url.QueryEscape(";"+sortedSH[k]))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(&b, "&X-Amz-Signature=%s", signature)
|
||||
resultURL := b.String()
|
||||
|
||||
return resultURL
|
||||
return b.String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user