backend requirements onthe xustomer app
This commit is contained in:
@@ -223,3 +223,77 @@ func awsEncode(s string, encodeSlash bool) string {
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// PresignGet issues a short-lived, signed GET URL for one object.
|
||||
//
|
||||
// Parcel photographs are shown to the customer on the receipt, and a parcel
|
||||
// photograph frames the inside of someone's doorway. A permanent CDN link to
|
||||
// one is a permanent link anybody who ever saw it can keep, so the customer
|
||||
// surface serves these through a signature that expires instead.
|
||||
//
|
||||
// Falls back to the plain CDN URL when the bucket credentials are not
|
||||
// configured: an unsigned photo the customer can see beats a receipt with a
|
||||
// missing image, and the objects are currently written public-read anyway.
|
||||
// Once parcel photos are switched to a private ACL this becomes the only way
|
||||
// to read one — which is the point of routing them through here now.
|
||||
func PresignGet(objectKey string, expiry time.Duration) (string, error) {
|
||||
cfg := loadSpacesConfig()
|
||||
if cfg.accessKey == "" || cfg.secretKey == "" || cfg.bucket == "" {
|
||||
if cfg.cdnBase != "" {
|
||||
return cfg.cdnBase + "/" + objectKey, nil
|
||||
}
|
||||
return "", fmt.Errorf("object storage not configured")
|
||||
}
|
||||
|
||||
const (
|
||||
service = "s3"
|
||||
algorithm = "AWS4-HMAC-SHA256"
|
||||
)
|
||||
|
||||
host := cfg.bucket + "." + cfg.endpoint
|
||||
|
||||
now := time.Now().UTC()
|
||||
amzDate := now.Format("20060102T150405Z")
|
||||
dateStamp := now.Format("20060102")
|
||||
expSecs := int(expiry.Seconds())
|
||||
if expSecs <= 0 {
|
||||
expSecs = 900
|
||||
}
|
||||
|
||||
canonicalURI := "/" + encodePath(objectKey)
|
||||
credentialScope := dateStamp + "/" + cfg.region + "/" + service + "/aws4_request"
|
||||
credential := cfg.accessKey + "/" + credentialScope
|
||||
signedHeaders := "host"
|
||||
|
||||
q := [][2]string{
|
||||
{"X-Amz-Algorithm", algorithm},
|
||||
{"X-Amz-Credential", credential},
|
||||
{"X-Amz-Date", amzDate},
|
||||
{"X-Amz-Expires", fmt.Sprintf("%d", expSecs)},
|
||||
{"X-Amz-SignedHeaders", signedHeaders},
|
||||
}
|
||||
canonicalQuery := canonicalizeQuery(q)
|
||||
canonicalHeaders := "host:" + host + "\n"
|
||||
|
||||
canonicalRequest := strings.Join([]string{
|
||||
"GET",
|
||||
canonicalURI,
|
||||
canonicalQuery,
|
||||
canonicalHeaders,
|
||||
signedHeaders,
|
||||
"UNSIGNED-PAYLOAD",
|
||||
}, "\n")
|
||||
|
||||
stringToSign := strings.Join([]string{
|
||||
algorithm,
|
||||
amzDate,
|
||||
credentialScope,
|
||||
hexSHA256(canonicalRequest),
|
||||
}, "\n")
|
||||
|
||||
signingKey := deriveSigningKey(cfg.secretKey, dateStamp, cfg.region, service)
|
||||
signature := hex.EncodeToString(hmacSHA256(signingKey, stringToSign))
|
||||
|
||||
return "https://" + host + canonicalURI + "?" + canonicalQuery +
|
||||
"&X-Amz-Signature=" + signature, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user