backend requirements onthe xustomer app

This commit is contained in:
2026-09-07 10:55:11 +05:30
parent 35675d8a9b
commit 1b2690b21a
56 changed files with 13342 additions and 1071 deletions

View File

@@ -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
}