AWS Signature V4 签名
(
method: string,
bucket: string,
key: string | undefined,
queryParams: Record<string, string>,
headers: Record<string, string>,
payloadHash: string
)
| 199 | |
| 200 | /** AWS Signature V4 签名 */ |
| 201 | private async signRequest( |
| 202 | method: string, |
| 203 | bucket: string, |
| 204 | key: string | undefined, |
| 205 | queryParams: Record<string, string>, |
| 206 | headers: Record<string, string>, |
| 207 | payloadHash: string |
| 208 | ): Promise<void> { |
| 209 | const now = new Date(); |
| 210 | // ISO 8601 基本格式: 20210101T000000Z |
| 211 | const amzDate = now |
| 212 | .toISOString() |
| 213 | .replace(/[-:]/g, "") |
| 214 | .replace(/\.\d{3}/, ""); |
| 215 | const dateStamp = amzDate.substring(0, 8); |
| 216 | |
| 217 | headers["host"] = this.getHost(bucket); |
| 218 | headers["x-amz-date"] = amzDate; |
| 219 | headers["x-amz-content-sha256"] = payloadHash; |
| 220 | |
| 221 | // 构建 Canonical Request |
| 222 | const canonicalUri = this.getCanonicalUri(bucket, key); |
| 223 | const canonicalQueryString = Object.entries(queryParams) |
| 224 | .sort(([a], [b]) => a.localeCompare(b)) |
| 225 | .map(([k, v]) => `${awsUriEncode(k)}=${awsUriEncode(v)}`) |
| 226 | .join("&"); |
| 227 | |
| 228 | const signedHeaderKeys = Object.keys(headers) |
| 229 | .map((k) => k.toLowerCase()) |
| 230 | .sort(); |
| 231 | const canonicalHeaders = signedHeaderKeys.map((k) => `${k}:${(headers[k] ?? "").trim()}\n`).join(""); |
| 232 | const signedHeaders = signedHeaderKeys.join(";"); |
| 233 | |
| 234 | const canonicalRequest = [ |
| 235 | method, |
| 236 | canonicalUri, |
| 237 | canonicalQueryString, |
| 238 | canonicalHeaders, |
| 239 | signedHeaders, |
| 240 | payloadHash, |
| 241 | ].join("\n"); |
| 242 | |
| 243 | // 构建 String to Sign |
| 244 | const credentialScope = `${dateStamp}/${this.config.region}/s3/aws4_request`; |
| 245 | const canonicalRequestHash = await sha256Hex(canonicalRequest); |
| 246 | const stringToSign = ["AWS4-HMAC-SHA256", amzDate, credentialScope, canonicalRequestHash].join("\n"); |
| 247 | |
| 248 | // 计算签名 |
| 249 | const signingKey = await deriveSigningKey( |
| 250 | this.config.credentials.secretAccessKey, |
| 251 | dateStamp, |
| 252 | this.config.region, |
| 253 | "s3" |
| 254 | ); |
| 255 | const signature = toHex(await hmacSha256(signingKey, stringToSign)); |
| 256 | |
| 257 | // 添加 Authorization 头 |
| 258 | headers["authorization"] = |
no test coverage detected