Buckets:
| ; | |
| // Copyright 2021 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.AwsRequestSigner = void 0; | |
| const gaxios_1 = require("gaxios"); | |
| const crypto_1 = require("../crypto/crypto"); | |
| /** AWS Signature Version 4 signing algorithm identifier. */ | |
| const AWS_ALGORITHM = 'AWS4-HMAC-SHA256'; | |
| /** | |
| * The termination string for the AWS credential scope value as defined in | |
| * https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html | |
| */ | |
| const AWS_REQUEST_TYPE = 'aws4_request'; | |
| /** | |
| * Implements an AWS API request signer based on the AWS Signature Version 4 | |
| * signing process. | |
| * https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html | |
| */ | |
| class AwsRequestSigner { | |
| getCredentials; | |
| region; | |
| crypto; | |
| /** | |
| * Instantiates an AWS API request signer used to send authenticated signed | |
| * requests to AWS APIs based on the AWS Signature Version 4 signing process. | |
| * This also provides a mechanism to generate the signed request without | |
| * sending it. | |
| * @param getCredentials A mechanism to retrieve AWS security credentials | |
| * when needed. | |
| * @param region The AWS region to use. | |
| */ | |
| constructor(getCredentials, region) { | |
| this.getCredentials = getCredentials; | |
| this.region = region; | |
| this.crypto = (0, crypto_1.createCrypto)(); | |
| } | |
| /** | |
| * Generates the signed request for the provided HTTP request for calling | |
| * an AWS API. This follows the steps described at: | |
| * https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html | |
| * @param amzOptions The AWS request options that need to be signed. | |
| * @return A promise that resolves with the GaxiosOptions containing the | |
| * signed HTTP request parameters. | |
| */ | |
| async getRequestOptions(amzOptions) { | |
| if (!amzOptions.url) { | |
| throw new RangeError('"url" is required in "amzOptions"'); | |
| } | |
| // Stringify JSON requests. This will be set in the request body of the | |
| // generated signed request. | |
| const requestPayloadData = typeof amzOptions.data === 'object' | |
| ? JSON.stringify(amzOptions.data) | |
| : amzOptions.data; | |
| const url = amzOptions.url; | |
| const method = amzOptions.method || 'GET'; | |
| const requestPayload = amzOptions.body || requestPayloadData; | |
| const additionalAmzHeaders = amzOptions.headers; | |
| const awsSecurityCredentials = await this.getCredentials(); | |
| const uri = new URL(url); | |
| if (typeof requestPayload !== 'string' && requestPayload !== undefined) { | |
| throw new TypeError(`'requestPayload' is expected to be a string if provided. Got: ${requestPayload}`); | |
| } | |
| const headerMap = await generateAuthenticationHeaderMap({ | |
| crypto: this.crypto, | |
| host: uri.host, | |
| canonicalUri: uri.pathname, | |
| canonicalQuerystring: uri.search.slice(1), | |
| method, | |
| region: this.region, | |
| securityCredentials: awsSecurityCredentials, | |
| requestPayload, | |
| additionalAmzHeaders, | |
| }); | |
| // Append additional optional headers, eg. X-Amz-Target, Content-Type, etc. | |
| const headers = gaxios_1.Gaxios.mergeHeaders( | |
| // Add x-amz-date if available. | |
| headerMap.amzDate ? { 'x-amz-date': headerMap.amzDate } : {}, { | |
| authorization: headerMap.authorizationHeader, | |
| host: uri.host, | |
| }, additionalAmzHeaders || {}); | |
| if (awsSecurityCredentials.token) { | |
| gaxios_1.Gaxios.mergeHeaders(headers, { | |
| 'x-amz-security-token': awsSecurityCredentials.token, | |
| }); | |
| } | |
| const awsSignedReq = { | |
| url, | |
| method: method, | |
| headers, | |
| }; | |
| if (requestPayload !== undefined) { | |
| awsSignedReq.body = requestPayload; | |
| } | |
| return awsSignedReq; | |
| } | |
| } | |
| exports.AwsRequestSigner = AwsRequestSigner; | |
| /** | |
| * Creates the HMAC-SHA256 hash of the provided message using the | |
| * provided key. | |
| * | |
| * @param crypto The crypto instance used to facilitate cryptographic | |
| * operations. | |
| * @param key The HMAC-SHA256 key to use. | |
| * @param msg The message to hash. | |
| * @return The computed hash bytes. | |
| */ | |
| async function sign(crypto, key, msg) { | |
| return await crypto.signWithHmacSha256(key, msg); | |
| } | |
| /** | |
| * Calculates the signing key used to calculate the signature for | |
| * AWS Signature Version 4 based on: | |
| * https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html | |
| * | |
| * @param crypto The crypto instance used to facilitate cryptographic | |
| * operations. | |
| * @param key The AWS secret access key. | |
| * @param dateStamp The '%Y%m%d' date format. | |
| * @param region The AWS region. | |
| * @param serviceName The AWS service name, eg. sts. | |
| * @return The signing key bytes. | |
| */ | |
| async function getSigningKey(crypto, key, dateStamp, region, serviceName) { | |
| const kDate = await sign(crypto, `AWS4${key}`, dateStamp); | |
| const kRegion = await sign(crypto, kDate, region); | |
| const kService = await sign(crypto, kRegion, serviceName); | |
| const kSigning = await sign(crypto, kService, 'aws4_request'); | |
| return kSigning; | |
| } | |
| /** | |
| * Generates the authentication header map needed for generating the AWS | |
| * Signature Version 4 signed request. | |
| * | |
| * @param option The options needed to compute the authentication header map. | |
| * @return The AWS authentication header map which constitutes of the following | |
| * components: amz-date, authorization header and canonical query string. | |
| */ | |
| async function generateAuthenticationHeaderMap(options) { | |
| const additionalAmzHeaders = gaxios_1.Gaxios.mergeHeaders(options.additionalAmzHeaders); | |
| const requestPayload = options.requestPayload || ''; | |
| // iam.amazonaws.com host => iam service. | |
| // sts.us-east-2.amazonaws.com => sts service. | |
| const serviceName = options.host.split('.')[0]; | |
| const now = new Date(); | |
| // Format: '%Y%m%dT%H%M%SZ'. | |
| const amzDate = now | |
| .toISOString() | |
| .replace(/[-:]/g, '') | |
| .replace(/\.[0-9]+/, ''); | |
| // Format: '%Y%m%d'. | |
| const dateStamp = now.toISOString().replace(/[-]/g, '').replace(/T.*/, ''); | |
| // Add AWS token if available. | |
| if (options.securityCredentials.token) { | |
| additionalAmzHeaders.set('x-amz-security-token', options.securityCredentials.token); | |
| } | |
| // Header keys need to be sorted alphabetically. | |
| const amzHeaders = gaxios_1.Gaxios.mergeHeaders({ | |
| host: options.host, | |
| }, | |
| // Previously the date was not fixed with x-amz- and could be provided manually. | |
| // https://github.com/boto/botocore/blob/879f8440a4e9ace5d3cf145ce8b3d5e5ffb892ef/tests/unit/auth/aws4_testsuite/get-header-value-trim.req | |
| additionalAmzHeaders.has('date') ? {} : { 'x-amz-date': amzDate }, additionalAmzHeaders); | |
| let canonicalHeaders = ''; | |
| // TypeScript is missing `Headers#keys` at the time of writing | |
| const signedHeadersList = [ | |
| ...amzHeaders.keys(), | |
| ].sort(); | |
| signedHeadersList.forEach(key => { | |
| canonicalHeaders += `${key}:${amzHeaders.get(key)}\n`; | |
| }); | |
| const signedHeaders = signedHeadersList.join(';'); | |
| const payloadHash = await options.crypto.sha256DigestHex(requestPayload); | |
| // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html | |
| const canonicalRequest = `${options.method.toUpperCase()}\n` + | |
| `${options.canonicalUri}\n` + | |
| `${options.canonicalQuerystring}\n` + | |
| `${canonicalHeaders}\n` + | |
| `${signedHeaders}\n` + | |
| `${payloadHash}`; | |
| const credentialScope = `${dateStamp}/${options.region}/${serviceName}/${AWS_REQUEST_TYPE}`; | |
| // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html | |
| const stringToSign = `${AWS_ALGORITHM}\n` + | |
| `${amzDate}\n` + | |
| `${credentialScope}\n` + | |
| (await options.crypto.sha256DigestHex(canonicalRequest)); | |
| // https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html | |
| const signingKey = await getSigningKey(options.crypto, options.securityCredentials.secretAccessKey, dateStamp, options.region, serviceName); | |
| const signature = await sign(options.crypto, signingKey, stringToSign); | |
| // https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html | |
| const authorizationHeader = `${AWS_ALGORITHM} Credential=${options.securityCredentials.accessKeyId}/` + | |
| `${credentialScope}, SignedHeaders=${signedHeaders}, ` + | |
| `Signature=${(0, crypto_1.fromArrayBufferToHex)(signature)}`; | |
| return { | |
| // Do not return x-amz-date if date is available. | |
| amzDate: additionalAmzHeaders.has('date') ? undefined : amzDate, | |
| authorizationHeader, | |
| canonicalQuerystring: options.canonicalQuerystring, | |
| }; | |
| } | |
| //# sourceMappingURL=awsrequestsigner.js.map |
Xet Storage Details
- Size:
- 9.44 kB
- Xet hash:
- b8a67599344c6155a4b382468f694e46860ba76e09679b4b8f425a15966c0339
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.