UNPKG

open-next-cdk

Version:

Deploy a NextJS app using OpenNext packaging to serverless AWS using CDK

195 lines (193 loc) 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SignatureV4 = void 0; const eventstream_codec_1 = require("@smithy/eventstream-codec"); const util_hex_encoding_1 = require("@smithy/util-hex-encoding"); const util_middleware_1 = require("@smithy/util-middleware"); const util_utf8_1 = require("@smithy/util-utf8"); const constants_1 = require("./constants"); const credentialDerivation_1 = require("./credentialDerivation"); const getCanonicalHeaders_1 = require("./getCanonicalHeaders"); const getCanonicalQuery_1 = require("./getCanonicalQuery"); const getPayloadHash_1 = require("./getPayloadHash"); const headerUtil_1 = require("./headerUtil"); const moveHeadersToQuery_1 = require("./moveHeadersToQuery"); const prepareRequest_1 = require("./prepareRequest"); const utilDate_1 = require("./utilDate"); class SignatureV4 { constructor({ applyChecksum, credentials, region, service, sha256, uriEscapePath = true, }) { this.headerMarshaller = new eventstream_codec_1.HeaderMarshaller(util_utf8_1.toUtf8, util_utf8_1.fromUtf8); this.service = service; this.sha256 = sha256; this.uriEscapePath = uriEscapePath; this.applyChecksum = typeof applyChecksum === "boolean" ? applyChecksum : true; this.regionProvider = (0, util_middleware_1.normalizeProvider)(region); this.credentialProvider = (0, util_middleware_1.normalizeProvider)(credentials); } async presign(originalRequest, options = {}) { const { signingDate = new Date(), expiresIn = 3600, unsignableHeaders, unhoistableHeaders, signableHeaders, signingRegion, signingService, } = options; const credentials = await this.credentialProvider(); this.validateResolvedCredentials(credentials); const region = signingRegion !== null && signingRegion !== void 0 ? signingRegion : (await this.regionProvider()); const { longDate, shortDate } = formatDate(signingDate); if (expiresIn > constants_1.MAX_PRESIGNED_TTL) { return Promise.reject("Signature version 4 presigned URLs" + " must have an expiration date less than one week in" + " the future"); } const scope = (0, credentialDerivation_1.createScope)(shortDate, region, signingService !== null && signingService !== void 0 ? signingService : this.service); const request = (0, moveHeadersToQuery_1.moveHeadersToQuery)((0, prepareRequest_1.prepareRequest)(originalRequest), { unhoistableHeaders }); if (credentials.sessionToken) { request.query[constants_1.TOKEN_QUERY_PARAM] = credentials.sessionToken; } request.query[constants_1.ALGORITHM_QUERY_PARAM] = constants_1.ALGORITHM_IDENTIFIER; request.query[constants_1.CREDENTIAL_QUERY_PARAM] = `${credentials.accessKeyId}/${scope}`; request.query[constants_1.AMZ_DATE_QUERY_PARAM] = longDate; request.query[constants_1.EXPIRES_QUERY_PARAM] = expiresIn.toString(10); const canonicalHeaders = (0, getCanonicalHeaders_1.getCanonicalHeaders)(request, unsignableHeaders, signableHeaders); request.query[constants_1.SIGNED_HEADERS_QUERY_PARAM] = getCanonicalHeaderList(canonicalHeaders); request.query[constants_1.SIGNATURE_QUERY_PARAM] = await this.getSignature(longDate, scope, this.getSigningKey(credentials, region, shortDate, signingService), this.createCanonicalRequest(request, canonicalHeaders, await (0, getPayloadHash_1.getPayloadHash)(originalRequest, this.sha256))); return request; } async sign(toSign, options) { if (typeof toSign === "string") { return this.signString(toSign, options); } else if (toSign.headers && toSign.payload) { return this.signEvent(toSign, options); } else if (toSign.message) { return this.signMessage(toSign, options); } else { return this.signRequest(toSign, options); } } async signEvent({ headers, payload }, { signingDate = new Date(), priorSignature, signingRegion, signingService }) { const region = signingRegion !== null && signingRegion !== void 0 ? signingRegion : (await this.regionProvider()); const { shortDate, longDate } = formatDate(signingDate); const scope = (0, credentialDerivation_1.createScope)(shortDate, region, signingService !== null && signingService !== void 0 ? signingService : this.service); const hashedPayload = await (0, getPayloadHash_1.getPayloadHash)({ headers: {}, body: payload }, this.sha256); const hash = new this.sha256(); hash.update(headers); const hashedHeaders = (0, util_hex_encoding_1.toHex)(await hash.digest()); const stringToSign = [ constants_1.EVENT_ALGORITHM_IDENTIFIER, longDate, scope, priorSignature, hashedHeaders, hashedPayload, ].join("\n"); return this.signString(stringToSign, { signingDate, signingRegion: region, signingService }); } async signMessage(signableMessage, { signingDate = new Date(), signingRegion, signingService }) { const promise = this.signEvent({ headers: this.headerMarshaller.format(signableMessage.message.headers), payload: signableMessage.message.body, }, { signingDate, signingRegion, signingService, priorSignature: signableMessage.priorSignature, }); return promise.then((signature) => { return { message: signableMessage.message, signature }; }); } async signString(stringToSign, { signingDate = new Date(), signingRegion, signingService } = {}) { const credentials = await this.credentialProvider(); this.validateResolvedCredentials(credentials); const region = signingRegion !== null && signingRegion !== void 0 ? signingRegion : (await this.regionProvider()); const { shortDate } = formatDate(signingDate); const hash = new this.sha256(await this.getSigningKey(credentials, region, shortDate, signingService)); hash.update((0, util_utf8_1.toUint8Array)(stringToSign)); return (0, util_hex_encoding_1.toHex)(await hash.digest()); } async signRequest(requestToSign, { signingDate = new Date(), signableHeaders, unsignableHeaders, signingRegion, signingService, } = {}) { const credentials = await this.credentialProvider(); this.validateResolvedCredentials(credentials); const region = signingRegion !== null && signingRegion !== void 0 ? signingRegion : (await this.regionProvider()); const request = (0, prepareRequest_1.prepareRequest)(requestToSign); const { longDate, shortDate } = formatDate(signingDate); const scope = (0, credentialDerivation_1.createScope)(shortDate, region, signingService !== null && signingService !== void 0 ? signingService : this.service); request.headers[constants_1.AMZ_DATE_HEADER] = longDate; if (credentials.sessionToken) { request.headers[constants_1.TOKEN_HEADER] = credentials.sessionToken; } const payloadHash = await (0, getPayloadHash_1.getPayloadHash)(request, this.sha256); if (!(0, headerUtil_1.hasHeader)(constants_1.SHA256_HEADER, request.headers) && this.applyChecksum) { request.headers[constants_1.SHA256_HEADER] = payloadHash; } const canonicalHeaders = (0, getCanonicalHeaders_1.getCanonicalHeaders)(request, unsignableHeaders, signableHeaders); const signature = await this.getSignature(longDate, scope, this.getSigningKey(credentials, region, shortDate, signingService), this.createCanonicalRequest(request, canonicalHeaders, payloadHash)); request.headers[constants_1.AUTH_HEADER] = `${constants_1.ALGORITHM_IDENTIFIER} ` + `Credential=${credentials.accessKeyId}/${scope}, ` + `SignedHeaders=${getCanonicalHeaderList(canonicalHeaders)}, ` + `Signature=${signature}`; return request; } createCanonicalRequest(request, canonicalHeaders, payloadHash) { const sortedHeaders = Object.keys(canonicalHeaders).sort(); return `${request.method} ${this.getCanonicalPath(request)} ${(0, getCanonicalQuery_1.getCanonicalQuery)(request)} ${sortedHeaders.map((name) => `${name}:${canonicalHeaders[name]}`).join("\n")} ${sortedHeaders.join(";")} ${payloadHash}`; } async createStringToSign(longDate, credentialScope, canonicalRequest) { const hash = new this.sha256(); hash.update((0, util_utf8_1.toUint8Array)(canonicalRequest)); const hashedRequest = await hash.digest(); return `${constants_1.ALGORITHM_IDENTIFIER} ${longDate} ${credentialScope} ${(0, util_hex_encoding_1.toHex)(hashedRequest)}`; } getCanonicalPath({ path }) { if (this.uriEscapePath) { const normalizedPathSegments = []; for (const pathSegment of path.split("/")) { if ((pathSegment === null || pathSegment === void 0 ? void 0 : pathSegment.length) === 0) continue; if (pathSegment === ".") continue; if (pathSegment === "..") { normalizedPathSegments.pop(); } else { normalizedPathSegments.push(pathSegment); } } const normalizedPath = `${(path === null || path === void 0 ? void 0 : path.startsWith("/")) ? "/" : ""}${normalizedPathSegments.join("/")}${normalizedPathSegments.length > 0 && (path === null || path === void 0 ? void 0 : path.endsWith("/")) ? "/" : ""}`; const doubleEncoded = encodeURIComponent(normalizedPath); return doubleEncoded.replace(/%2F/g, "/"); } return path; } async getSignature(longDate, credentialScope, keyPromise, canonicalRequest) { const stringToSign = await this.createStringToSign(longDate, credentialScope, canonicalRequest); const hash = new this.sha256(await keyPromise); hash.update((0, util_utf8_1.toUint8Array)(stringToSign)); return (0, util_hex_encoding_1.toHex)(await hash.digest()); } getSigningKey(credentials, region, shortDate, service) { return (0, credentialDerivation_1.getSigningKey)(this.sha256, credentials, shortDate, region, service || this.service); } validateResolvedCredentials(credentials) { if (typeof credentials !== "object" || typeof credentials.accessKeyId !== "string" || typeof credentials.secretAccessKey !== "string") { throw new Error("Resolved credential object is not valid"); } } } exports.SignatureV4 = SignatureV4; const formatDate = (now) => { const longDate = (0, utilDate_1.iso8601)(now).replace(/[\-:]/g, ""); return { longDate, shortDate: longDate.slice(0, 8), }; }; const getCanonicalHeaderList = (headers) => Object.keys(headers).sort().join(";");