UNPKG

serverless-spy

Version:

CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.

432 lines (404 loc) 18.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { CONFIG_REQUEST_CHECKSUM_CALCULATION: () => CONFIG_REQUEST_CHECKSUM_CALCULATION, CONFIG_RESPONSE_CHECKSUM_VALIDATION: () => CONFIG_RESPONSE_CHECKSUM_VALIDATION, ChecksumAlgorithm: () => ChecksumAlgorithm, ChecksumLocation: () => ChecksumLocation, DEFAULT_CHECKSUM_ALGORITHM: () => DEFAULT_CHECKSUM_ALGORITHM, DEFAULT_REQUEST_CHECKSUM_CALCULATION: () => DEFAULT_REQUEST_CHECKSUM_CALCULATION, DEFAULT_RESPONSE_CHECKSUM_VALIDATION: () => DEFAULT_RESPONSE_CHECKSUM_VALIDATION, ENV_REQUEST_CHECKSUM_CALCULATION: () => ENV_REQUEST_CHECKSUM_CALCULATION, ENV_RESPONSE_CHECKSUM_VALIDATION: () => ENV_RESPONSE_CHECKSUM_VALIDATION, NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS: () => NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS, NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS: () => NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS, RequestChecksumCalculation: () => RequestChecksumCalculation, ResponseChecksumValidation: () => ResponseChecksumValidation, S3_EXPRESS_DEFAULT_CHECKSUM_ALGORITHM: () => S3_EXPRESS_DEFAULT_CHECKSUM_ALGORITHM, flexibleChecksumsMiddleware: () => flexibleChecksumsMiddleware, flexibleChecksumsMiddlewareOptions: () => flexibleChecksumsMiddlewareOptions, getFlexibleChecksumsPlugin: () => getFlexibleChecksumsPlugin, resolveFlexibleChecksumsConfig: () => resolveFlexibleChecksumsConfig }); module.exports = __toCommonJS(src_exports); // src/constants.ts var RequestChecksumCalculation = { /** * When set, a checksum will be calculated for all request payloads of operations * modeled with the {@link httpChecksum} trait where `requestChecksumRequired` is `true` * AND/OR a `requestAlgorithmMember` is modeled. * {@link https://smithy.io/2.0/aws/aws-core.html#aws-protocols-httpchecksum-trait httpChecksum} */ WHEN_SUPPORTED: "WHEN_SUPPORTED", /** * When set, a checksum will only be calculated for request payloads of operations * modeled with the {@link httpChecksum} trait where `requestChecksumRequired` is `true` * OR where a `requestAlgorithmMember` is modeled and the user sets it. * {@link https://smithy.io/2.0/aws/aws-core.html#aws-protocols-httpchecksum-trait httpChecksum} */ WHEN_REQUIRED: "WHEN_REQUIRED" }; var DEFAULT_REQUEST_CHECKSUM_CALCULATION = RequestChecksumCalculation.WHEN_SUPPORTED; var ResponseChecksumValidation = { /** * When set, checksum validation MUST be performed on all response payloads of operations * modeled with the {@link httpChecksum} trait where `responseAlgorithms` is modeled, * except when no modeled checksum algorithms are supported by an SDK. * {@link https://smithy.io/2.0/aws/aws-core.html#aws-protocols-httpchecksum-trait httpChecksum} */ WHEN_SUPPORTED: "WHEN_SUPPORTED", /** * When set, checksum validation MUST NOT be performed on response payloads of operations UNLESS * the SDK supports the modeled checksum algorithms AND the user has set the `requestValidationModeMember` to `ENABLED`. * It is currently impossible to model an operation as requiring a response checksum, * but this setting leaves the door open for future updates. */ WHEN_REQUIRED: "WHEN_REQUIRED" }; var DEFAULT_RESPONSE_CHECKSUM_VALIDATION = RequestChecksumCalculation.WHEN_SUPPORTED; var ChecksumAlgorithm = /* @__PURE__ */ ((ChecksumAlgorithm3) => { ChecksumAlgorithm3["MD5"] = "MD5"; ChecksumAlgorithm3["CRC32"] = "CRC32"; ChecksumAlgorithm3["CRC32C"] = "CRC32C"; ChecksumAlgorithm3["SHA1"] = "SHA1"; ChecksumAlgorithm3["SHA256"] = "SHA256"; return ChecksumAlgorithm3; })(ChecksumAlgorithm || {}); var ChecksumLocation = /* @__PURE__ */ ((ChecksumLocation2) => { ChecksumLocation2["HEADER"] = "header"; ChecksumLocation2["TRAILER"] = "trailer"; return ChecksumLocation2; })(ChecksumLocation || {}); var DEFAULT_CHECKSUM_ALGORITHM = "MD5" /* MD5 */; var S3_EXPRESS_DEFAULT_CHECKSUM_ALGORITHM = "CRC32" /* CRC32 */; // src/stringUnionSelector.ts var stringUnionSelector = /* @__PURE__ */ __name((obj, key, union, type) => { if (!(key in obj)) return void 0; const value = obj[key].toUpperCase(); if (!Object.values(union).includes(value)) { throw new TypeError(`Cannot load ${type} '${key}'. Expected one of ${Object.values(union)}, got '${obj[key]}'.`); } return value; }, "stringUnionSelector"); // src/NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS.ts var ENV_REQUEST_CHECKSUM_CALCULATION = "AWS_REQUEST_CHECKSUM_CALCULATION"; var CONFIG_REQUEST_CHECKSUM_CALCULATION = "request_checksum_calculation"; var NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS = { environmentVariableSelector: (env) => stringUnionSelector(env, ENV_REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation, "env" /* ENV */), configFileSelector: (profile) => stringUnionSelector(profile, CONFIG_REQUEST_CHECKSUM_CALCULATION, RequestChecksumCalculation, "shared config entry" /* CONFIG */), default: DEFAULT_REQUEST_CHECKSUM_CALCULATION }; // src/NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS.ts var ENV_RESPONSE_CHECKSUM_VALIDATION = "AWS_RESPONSE_CHECKSUM_VALIDATION"; var CONFIG_RESPONSE_CHECKSUM_VALIDATION = "response_checksum_validation"; var NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS = { environmentVariableSelector: (env) => stringUnionSelector(env, ENV_RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation, "env" /* ENV */), configFileSelector: (profile) => stringUnionSelector(profile, CONFIG_RESPONSE_CHECKSUM_VALIDATION, ResponseChecksumValidation, "shared config entry" /* CONFIG */), default: DEFAULT_RESPONSE_CHECKSUM_VALIDATION }; // src/flexibleChecksumsMiddleware.ts var import_core = require("@aws-sdk/core"); var import_protocol_http = require("@smithy/protocol-http"); // src/types.ts var CLIENT_SUPPORTED_ALGORITHMS = [ "CRC32" /* CRC32 */, "CRC32C" /* CRC32C */, "SHA1" /* SHA1 */, "SHA256" /* SHA256 */ ]; var PRIORITY_ORDER_ALGORITHMS = [ "SHA256" /* SHA256 */, "SHA1" /* SHA1 */, "CRC32" /* CRC32 */, "CRC32C" /* CRC32C */ ]; // src/getChecksumAlgorithmForRequest.ts var getChecksumAlgorithmForRequest = /* @__PURE__ */ __name((input, { requestChecksumRequired, requestAlgorithmMember }, isS3Express) => { const defaultAlgorithm = isS3Express ? S3_EXPRESS_DEFAULT_CHECKSUM_ALGORITHM : DEFAULT_CHECKSUM_ALGORITHM; if (!requestAlgorithmMember || !input[requestAlgorithmMember]) { return requestChecksumRequired ? defaultAlgorithm : void 0; } const checksumAlgorithm = input[requestAlgorithmMember]; if (!CLIENT_SUPPORTED_ALGORITHMS.includes(checksumAlgorithm)) { throw new Error( `The checksum algorithm "${checksumAlgorithm}" is not supported by the client. Select one of ${CLIENT_SUPPORTED_ALGORITHMS}.` ); } return checksumAlgorithm; }, "getChecksumAlgorithmForRequest"); // src/getChecksumLocationName.ts var getChecksumLocationName = /* @__PURE__ */ __name((algorithm) => algorithm === "MD5" /* MD5 */ ? "content-md5" : `x-amz-checksum-${algorithm.toLowerCase()}`, "getChecksumLocationName"); // src/hasHeader.ts var hasHeader = /* @__PURE__ */ __name((header, headers) => { const soughtHeader = header.toLowerCase(); for (const headerName of Object.keys(headers)) { if (soughtHeader === headerName.toLowerCase()) { return true; } } return false; }, "hasHeader"); // src/isStreaming.ts var import_is_array_buffer = require("@smithy/is-array-buffer"); var isStreaming = /* @__PURE__ */ __name((body) => body !== void 0 && typeof body !== "string" && !ArrayBuffer.isView(body) && !(0, import_is_array_buffer.isArrayBuffer)(body), "isStreaming"); // src/selectChecksumAlgorithmFunction.ts var import_crc32c = require("@aws-crypto/crc32c"); var import_getCrc32ChecksumAlgorithmFunction = require("././getCrc32ChecksumAlgorithmFunction"); var selectChecksumAlgorithmFunction = /* @__PURE__ */ __name((checksumAlgorithm, config) => ({ ["MD5" /* MD5 */]: config.md5, ["CRC32" /* CRC32 */]: (0, import_getCrc32ChecksumAlgorithmFunction.getCrc32ChecksumAlgorithmFunction)(), ["CRC32C" /* CRC32C */]: import_crc32c.AwsCrc32c, ["SHA1" /* SHA1 */]: config.sha1, ["SHA256" /* SHA256 */]: config.sha256 })[checksumAlgorithm], "selectChecksumAlgorithmFunction"); // src/stringHasher.ts var import_util_utf8 = require("@smithy/util-utf8"); var stringHasher = /* @__PURE__ */ __name((checksumAlgorithmFn, body) => { const hash = new checksumAlgorithmFn(); hash.update((0, import_util_utf8.toUint8Array)(body || "")); return hash.digest(); }, "stringHasher"); // src/flexibleChecksumsMiddleware.ts var flexibleChecksumsMiddlewareOptions = { name: "flexibleChecksumsMiddleware", step: "build", tags: ["BODY_CHECKSUM"], override: true }; var flexibleChecksumsMiddleware = /* @__PURE__ */ __name((config, middlewareConfig) => (next, context) => async (args) => { if (!import_protocol_http.HttpRequest.isInstance(args.request)) { return next(args); } const { request, input } = args; const { body: requestBody, headers } = request; const { base64Encoder, streamHasher } = config; const { requestChecksumRequired, requestAlgorithmMember } = middlewareConfig; const checksumAlgorithm = getChecksumAlgorithmForRequest( input, { requestChecksumRequired, requestAlgorithmMember }, !!context.isS3ExpressBucket ); let updatedBody = requestBody; let updatedHeaders = headers; if (checksumAlgorithm) { switch (checksumAlgorithm) { case "CRC32" /* CRC32 */: (0, import_core.setFeature)(context, "FLEXIBLE_CHECKSUMS_REQ_CRC32", "U"); break; case "CRC32C" /* CRC32C */: (0, import_core.setFeature)(context, "FLEXIBLE_CHECKSUMS_REQ_CRC32C", "V"); break; case "SHA1" /* SHA1 */: (0, import_core.setFeature)(context, "FLEXIBLE_CHECKSUMS_REQ_SHA1", "X"); break; case "SHA256" /* SHA256 */: (0, import_core.setFeature)(context, "FLEXIBLE_CHECKSUMS_REQ_SHA256", "Y"); break; } const checksumLocationName = getChecksumLocationName(checksumAlgorithm); const checksumAlgorithmFn = selectChecksumAlgorithmFunction(checksumAlgorithm, config); if (isStreaming(requestBody)) { const { getAwsChunkedEncodingStream, bodyLengthChecker } = config; updatedBody = getAwsChunkedEncodingStream(requestBody, { base64Encoder, bodyLengthChecker, checksumLocationName, checksumAlgorithmFn, streamHasher }); updatedHeaders = { ...headers, "content-encoding": headers["content-encoding"] ? `${headers["content-encoding"]},aws-chunked` : "aws-chunked", "transfer-encoding": "chunked", "x-amz-decoded-content-length": headers["content-length"], "x-amz-content-sha256": "STREAMING-UNSIGNED-PAYLOAD-TRAILER", "x-amz-trailer": checksumLocationName }; delete updatedHeaders["content-length"]; } else if (!hasHeader(checksumLocationName, headers)) { const rawChecksum = await stringHasher(checksumAlgorithmFn, requestBody); updatedHeaders = { ...headers, [checksumLocationName]: base64Encoder(rawChecksum) }; } } const result = await next({ ...args, request: { ...request, headers: updatedHeaders, body: updatedBody } }); return result; }, "flexibleChecksumsMiddleware"); // src/flexibleChecksumsResponseMiddleware.ts // src/getChecksumAlgorithmListForResponse.ts var getChecksumAlgorithmListForResponse = /* @__PURE__ */ __name((responseAlgorithms = []) => { const validChecksumAlgorithms = []; for (const algorithm of PRIORITY_ORDER_ALGORITHMS) { if (!responseAlgorithms.includes(algorithm) || !CLIENT_SUPPORTED_ALGORITHMS.includes(algorithm)) { continue; } validChecksumAlgorithms.push(algorithm); } return validChecksumAlgorithms; }, "getChecksumAlgorithmListForResponse"); // src/isChecksumWithPartNumber.ts var isChecksumWithPartNumber = /* @__PURE__ */ __name((checksum) => { const lastHyphenIndex = checksum.lastIndexOf("-"); if (lastHyphenIndex !== -1) { const numberPart = checksum.slice(lastHyphenIndex + 1); if (!numberPart.startsWith("0")) { const number = parseInt(numberPart, 10); if (!isNaN(number) && number >= 1 && number <= 1e4) { return true; } } } return false; }, "isChecksumWithPartNumber"); // src/flexibleChecksumsResponseMiddleware.ts var import_create_read_stream_on_buffer = require("./streams/create-read-stream-on-buffer"); // src/validateChecksumFromResponse.ts var import_util_stream = require("@smithy/util-stream"); // src/getChecksum.ts var getChecksum = /* @__PURE__ */ __name(async (body, { checksumAlgorithmFn, base64Encoder }) => base64Encoder(await stringHasher(checksumAlgorithmFn, body)), "getChecksum"); // src/validateChecksumFromResponse.ts var validateChecksumFromResponse = /* @__PURE__ */ __name(async (response, { config, responseAlgorithms }) => { const checksumAlgorithms = getChecksumAlgorithmListForResponse(responseAlgorithms); const { body: responseBody, headers: responseHeaders } = response; for (const algorithm of checksumAlgorithms) { const responseHeader = getChecksumLocationName(algorithm); const checksumFromResponse = responseHeaders[responseHeader]; if (checksumFromResponse) { const checksumAlgorithmFn = selectChecksumAlgorithmFunction(algorithm, config); const { base64Encoder } = config; if (isStreaming(responseBody)) { response.body = (0, import_util_stream.createChecksumStream)({ expectedChecksum: checksumFromResponse, checksumSourceLocation: responseHeader, checksum: new checksumAlgorithmFn(), source: responseBody, base64Encoder }); return; } const checksum = await getChecksum(responseBody, { checksumAlgorithmFn, base64Encoder }); if (checksum === checksumFromResponse) { break; } throw new Error( `Checksum mismatch: expected "${checksum}" but received "${checksumFromResponse}" in response header "${responseHeader}".` ); } } }, "validateChecksumFromResponse"); // src/flexibleChecksumsResponseMiddleware.ts var flexibleChecksumsResponseMiddlewareOptions = { name: "flexibleChecksumsResponseMiddleware", toMiddleware: "deserializerMiddleware", relation: "after", tags: ["BODY_CHECKSUM"], override: true }; var flexibleChecksumsResponseMiddleware = /* @__PURE__ */ __name((config, middlewareConfig) => (next, context) => async (args) => { if (!import_protocol_http.HttpRequest.isInstance(args.request)) { return next(args); } const input = args.input; const result = await next(args); const response = result.response; let collectedStream = void 0; const { requestValidationModeMember, responseAlgorithms } = middlewareConfig; if (requestValidationModeMember && input[requestValidationModeMember] === "ENABLED") { const { clientName, commandName } = context; const isS3WholeObjectMultipartGetResponseChecksum = clientName === "S3Client" && commandName === "GetObjectCommand" && getChecksumAlgorithmListForResponse(responseAlgorithms).every((algorithm) => { const responseHeader = getChecksumLocationName(algorithm); const checksumFromResponse = response.headers[responseHeader]; return !checksumFromResponse || isChecksumWithPartNumber(checksumFromResponse); }); if (isS3WholeObjectMultipartGetResponseChecksum) { return result; } const isStreamingBody = isStreaming(response.body); if (isStreamingBody) { collectedStream = await config.streamCollector(response.body); response.body = (0, import_create_read_stream_on_buffer.createReadStreamOnBuffer)(collectedStream); } await validateChecksumFromResponse(result.response, { config, responseAlgorithms }); if (isStreamingBody && collectedStream) { response.body = (0, import_create_read_stream_on_buffer.createReadStreamOnBuffer)(collectedStream); } } return result; }, "flexibleChecksumsResponseMiddleware"); // src/getFlexibleChecksumsPlugin.ts var getFlexibleChecksumsPlugin = /* @__PURE__ */ __name((config, middlewareConfig) => ({ applyToStack: (clientStack) => { clientStack.add(flexibleChecksumsMiddleware(config, middlewareConfig), flexibleChecksumsMiddlewareOptions); clientStack.addRelativeTo( flexibleChecksumsResponseMiddleware(config, middlewareConfig), flexibleChecksumsResponseMiddlewareOptions ); } }), "getFlexibleChecksumsPlugin"); // src/resolveFlexibleChecksumsConfig.ts var import_util_middleware = require("@smithy/util-middleware"); var resolveFlexibleChecksumsConfig = /* @__PURE__ */ __name((input) => ({ ...input, requestChecksumCalculation: (0, import_util_middleware.normalizeProvider)( input.requestChecksumCalculation ?? DEFAULT_REQUEST_CHECKSUM_CALCULATION ), responseChecksumValidation: (0, import_util_middleware.normalizeProvider)( input.responseChecksumValidation ?? DEFAULT_RESPONSE_CHECKSUM_VALIDATION ) }), "resolveFlexibleChecksumsConfig"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ENV_REQUEST_CHECKSUM_CALCULATION, CONFIG_REQUEST_CHECKSUM_CALCULATION, NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS, ENV_RESPONSE_CHECKSUM_VALIDATION, CONFIG_RESPONSE_CHECKSUM_VALIDATION, NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS, RequestChecksumCalculation, DEFAULT_REQUEST_CHECKSUM_CALCULATION, ResponseChecksumValidation, DEFAULT_RESPONSE_CHECKSUM_VALIDATION, ChecksumAlgorithm, ChecksumLocation, DEFAULT_CHECKSUM_ALGORITHM, S3_EXPRESS_DEFAULT_CHECKSUM_ALGORITHM, flexibleChecksumsMiddlewareOptions, flexibleChecksumsMiddleware, getFlexibleChecksumsPlugin, resolveFlexibleChecksumsConfig });