({
method,
endpoint,
pathSegments,
queryParams = {},
body = null,
accessKeyId,
secretKey,
region,
})
| 63 | } |
| 64 | |
| 65 | async function signS3Request({ |
| 66 | method, |
| 67 | endpoint, |
| 68 | pathSegments, |
| 69 | queryParams = {}, |
| 70 | body = null, |
| 71 | accessKeyId, |
| 72 | secretKey, |
| 73 | region, |
| 74 | }) { |
| 75 | const now = new Date(); |
| 76 | const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, ''); |
| 77 | const datestamp = amzDate.slice(0, 8); |
| 78 | |
| 79 | const canonicalUri = '/' + pathSegments.map(encodeSegment).join('/'); |
| 80 | const sortedParams = Object.entries(queryParams) |
| 81 | .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0); |
| 82 | const canonicalQS = sortedParams |
| 83 | .map(([k, v]) => `${encodeSegment(k)}=${encodeSegment(v)}`) |
| 84 | .join('&'); |
| 85 | const url = `${endpoint}${canonicalUri}${canonicalQS ? `?${canonicalQS}` : ''}`; |
| 86 | const host = new URL(url).host; |
| 87 | |
| 88 | const EMPTY_HASH = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'; |
| 89 | const payloadHash = body != null ? await sha256hex(body) : EMPTY_HASH; |
| 90 | |
| 91 | const reqHeaders = { |
| 92 | host, |
| 93 | 'x-amz-content-sha256': payloadHash, |
| 94 | 'x-amz-date': amzDate, |
| 95 | }; |
| 96 | const sortedNames = Object.keys(reqHeaders).sort(); |
| 97 | const canonicalHeaders = sortedNames.map(k => `${k}:${reqHeaders[k]}\n`).join(''); |
| 98 | const signedHeaders = sortedNames.join(';'); |
| 99 | |
| 100 | const canonicalRequest = [method, canonicalUri, canonicalQS, canonicalHeaders, signedHeaders, payloadHash].join('\n'); |
| 101 | const credentialScope = `${datestamp}/${region}/s3/aws4_request`; |
| 102 | const stringToSign = ['AWS4-HMAC-SHA256', amzDate, credentialScope, await sha256hex(canonicalRequest)].join('\n'); |
| 103 | |
| 104 | const signingKey = await getSigningKey(secretKey, datestamp, region); |
| 105 | const signature = toHex(await hmacSha256(signingKey, stringToSign)); |
| 106 | |
| 107 | reqHeaders['Authorization'] = `AWS4-HMAC-SHA256 Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`; |
| 108 | return { url, headers: reqHeaders }; |
| 109 | } |
| 110 | |
| 111 | function parseListXml(xml) { |
| 112 | const doc = new DOMParser().parseFromString(xml, 'application/xml'); |
no test coverage detected