mirror of
https://github.com/binwiederhier/ntfy.git
synced 2026-05-15 07:35:49 -06:00
71 lines
2.1 KiB
Go
71 lines
2.1 KiB
Go
package s3
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// signV4 signs req in place using AWS Signature V4. payloadHash is the hex-encoded SHA-256
|
|
// of the request body, or the literal string "UNSIGNED-PAYLOAD" for streaming uploads.
|
|
//
|
|
// See https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
|
func (c *Client) signV4(req *http.Request, hash string) {
|
|
now := time.Now().UTC()
|
|
datestamp := now.Format("20060102")
|
|
amzDate := now.Format("20060102T150405Z")
|
|
|
|
// Required headers
|
|
req.Header.Set("Host", c.config.HostHeader())
|
|
req.Header.Set("X-Amz-Date", amzDate)
|
|
req.Header.Set("X-Amz-Content-Sha256", hash)
|
|
|
|
// Canonical headers (all headers we set, sorted by lowercase key)
|
|
signedKeys := make([]string, 0, len(req.Header))
|
|
canonHeaders := make(map[string]string, len(req.Header))
|
|
for k := range req.Header {
|
|
lk := strings.ToLower(k)
|
|
signedKeys = append(signedKeys, lk)
|
|
canonHeaders[lk] = strings.TrimSpace(req.Header.Get(k))
|
|
}
|
|
sort.Strings(signedKeys)
|
|
signedHeadersStr := strings.Join(signedKeys, ";")
|
|
var chBuf strings.Builder
|
|
for _, k := range signedKeys {
|
|
chBuf.WriteString(k)
|
|
chBuf.WriteByte(':')
|
|
chBuf.WriteString(canonHeaders[k])
|
|
chBuf.WriteByte('\n')
|
|
}
|
|
|
|
// Canonical request
|
|
canonicalRequest := strings.Join([]string{
|
|
req.Method,
|
|
canonicalURI(req.URL),
|
|
canonicalQueryString(req.URL.Query()),
|
|
chBuf.String(),
|
|
signedHeadersStr,
|
|
hash,
|
|
}, "\n")
|
|
|
|
// String to sign
|
|
credentialScope := datestamp + "/" + c.config.Region + "/s3/aws4_request"
|
|
stringToSign := "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" + sha256Hex([]byte(canonicalRequest))
|
|
|
|
// Signing key
|
|
signingKey := hmacSHA256(hmacSHA256(hmacSHA256(hmacSHA256(
|
|
[]byte("AWS4"+c.config.SecretKey), []byte(datestamp)),
|
|
[]byte(c.config.Region)),
|
|
[]byte("s3")),
|
|
[]byte("aws4_request"))
|
|
|
|
signature := hex.EncodeToString(hmacSHA256(signingKey, []byte(stringToSign)))
|
|
header := fmt.Sprintf(
|
|
"AWS4-HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s",
|
|
c.config.AccessKey, credentialScope, signedHeadersStr, signature,
|
|
)
|
|
req.Header.Set("Authorization", header)
|
|
}
|