'use strict'; var getEndpointFromConfig = require('./adaptors/getEndpointFromConfig'); var urlParser = require('@smithy/url-parser'); var core = require('@smithy/core'); var utilMiddleware = require('@smithy/util-middleware'); var middlewareSerde = require('@smithy/middleware-serde'); const resolveParamsForS3 = async (endpointParams) => { const bucket = endpointParams?.Bucket || ""; if (typeof endpointParams.Bucket === "string") { endpointParams.Bucket = bucket.replace(/#/g, encodeURIComponent("#")).replace(/\?/g, encodeURIComponent("?")); } if (isArnBucketName(bucket)) { if (endpointParams.ForcePathStyle === true) { throw new Error("Path-style addressing cannot be used with ARN buckets"); } } else if (!isDnsCompatibleBucketName(bucket) || (bucket.indexOf(".") !== -1 && !String(endpointParams.Endpoint).startsWith("http:")) || bucket.toLowerCase() !== bucket || bucket.length < 3) { endpointParams.ForcePathStyle = true; } if (endpointParams.DisableMultiRegionAccessPoints) { endpointParams.disableMultiRegionAccessPoints = true; endpointParams.DisableMRAP = true; } return endpointParams; }; const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/; const IP_ADDRESS_PATTERN = /(\d+\.){3}\d+/; const DOTS_PATTERN = /\.\./; const isDnsCompatibleBucketName = (bucketName) => DOMAIN_PATTERN.test(bucketName) && !IP_ADDRESS_PATTERN.test(bucketName) && !DOTS_PATTERN.test(bucketName); const isArnBucketName = (bucketName) => { const [arn, partition, service, , , bucket] = bucketName.split(":"); const isArn = arn === "arn" && bucketName.split(":").length >= 6; const isValidArn = Boolean(isArn && partition && service && bucket); if (isArn && !isValidArn) { throw new Error(`Invalid ARN: ${bucketName} was an invalid ARN.`); } return isValidArn; }; const createConfigValueProvider = (configKey, canonicalEndpointParamKey, config) => { const configProvider = async () => { const configValue = config[configKey] ?? config[canonicalEndpointParamKey]; if (typeof configValue === "function") { return configValue(); } return configValue; }; if (configKey === "credentialScope" || canonicalEndpointParamKey === "CredentialScope") { return async () => { const credentials = typeof config.credentials === "function" ? await config.credentials() : config.credentials; const configValue = credentials?.credentialScope ?? credentials?.CredentialScope; return configValue; }; } if (configKey === "accountId" || canonicalEndpointParamKey === "AccountId") { return async () => { const credentials = typeof config.credentials === "function" ? await config.credentials() : config.credentials; const configValue = credentials?.accountId ?? credentials?.AccountId; return configValue; }; } if (configKey === "endpoint" || canonicalEndpointParamKey === "endpoint") { return async () => { if (config.isCustomEndpoint === false) { return undefined; } const endpoint = await configProvider(); if (endpoint && typeof endpoint === "object") { if ("url" in endpoint) { return endpoint.url.href; } if ("hostname" in endpoint) { const { protocol, hostname, port, path } = endpoint; return `${protocol}//${hostname}${port ? ":" + port : ""}${path}`; } } return endpoint; }; } return configProvider; }; const toEndpointV1 = (endpoint) => { if (typeof endpoint === "object") { if ("url" in endpoint) { return urlParser.parseUrl(endpoint.url); } return endpoint; } return urlParser.parseUrl(endpoint); }; const getEndpointFromInstructions = async (commandInput, instructionsSupplier, clientConfig, context) => { if (!clientConfig.isCustomEndpoint) { let endpointFromConfig; if (clientConfig.serviceConfiguredEndpoint) { endpointFromConfig = await clientConfig.serviceConfiguredEndpoint(); } else { endpointFromConfig = await getEndpointFromConfig.getEndpointFromConfig(clientConfig.serviceId); } if (endpointFromConfig) { clientConfig.endpoint = () => Promise.resolve(toEndpointV1(endpointFromConfig)); clientConfig.isCustomEndpoint = true; } } const endpointParams = await resolveParams(commandInput, instructionsSupplier, clientConfig); if (typeof clientConfig.endpointProvider !== "function") { throw new Error("config.endpointProvider is not set."); } const endpoint = clientConfig.endpointProvider(endpointParams, context); return endpoint; }; const resolveParams = async (commandInput, instructionsSupplier, clientConfig) => { const endpointParams = {}; const instructions = instructionsSupplier?.getEndpointParameterInstructions?.() || {}; for (const [name, instruction] of Object.entries(instructions)) { switch (instruction.type) { case "staticContextParams": endpointParams[name] = instruction.value; break; case "contextParams": endpointParams[name] = commandInput[instruction.name]; break; case "clientContextParams": case "builtInParams": endpointParams[name] = await createConfigValueProvider(instruction.name, name, clientConfig)(); break; case "operationContextParams": endpointParams[name] = instruction.get(commandInput); break; default: throw new Error("Unrecognized endpoint parameter instruction: " + JSON.stringify(instruction)); } } if (Object.keys(instructions).length === 0) { Object.assign(endpointParams, clientConfig); } if (String(clientConfig.serviceId).toLowerCase() === "s3") { await resolveParamsForS3(endpointParams); } return endpointParams; }; const endpointMiddleware = ({ config, instructions, }) => { return (next, context) => async (args) => { if (config.isCustomEndpoint) { core.setFeature(context, "ENDPOINT_OVERRIDE", "N"); } const endpoint = await getEndpointFromInstructions(args.input, { getEndpointParameterInstructions() { return instructions; }, }, { ...config }, context); context.endpointV2 = endpoint; context.authSchemes = endpoint.properties?.authSchemes; const authScheme = context.authSchemes?.[0]; if (authScheme) { context["signing_region"] = authScheme.signingRegion; context["signing_service"] = authScheme.signingName; const smithyContext = utilMiddleware.getSmithyContext(context); const httpAuthOption = smithyContext?.selectedHttpAuthScheme?.httpAuthOption; if (httpAuthOption) { httpAuthOption.signingProperties = Object.assign(httpAuthOption.signingProperties || {}, { signing_region: authScheme.signingRegion, signingRegion: authScheme.signingRegion, signing_service: authScheme.signingName, signingName: authScheme.signingName, signingRegionSet: authScheme.signingRegionSet, }, authScheme.properties); } } return next({ ...args, }); }; }; const endpointMiddlewareOptions = { step: "serialize", tags: ["ENDPOINT_PARAMETERS", "ENDPOINT_V2", "ENDPOINT"], name: "endpointV2Middleware", override: true, relation: "before", toMiddleware: middlewareSerde.serializerMiddlewareOption.name, }; const getEndpointPlugin = (config, instructions) => ({ applyToStack: (clientStack) => { clientStack.addRelativeTo(endpointMiddleware({ config, instructions, }), endpointMiddlewareOptions); }, }); const resolveEndpointConfig = (input) => { const tls = input.tls ?? true; const { endpoint, useDualstackEndpoint, useFipsEndpoint } = input; const customEndpointProvider = endpoint != null ? async () => toEndpointV1(await utilMiddleware.normalizeProvider(endpoint)()) : undefined; const isCustomEndpoint = !!endpoint; const resolvedConfig = Object.assign(input, { endpoint: customEndpointProvider, tls, isCustomEndpoint, useDualstackEndpoint: utilMiddleware.normalizeProvider(useDualstackEndpoint ?? false), useFipsEndpoint: utilMiddleware.normalizeProvider(useFipsEndpoint ?? false), }); let configuredEndpointPromise = undefined; resolvedConfig.serviceConfiguredEndpoint = async () => { if (input.serviceId && !configuredEndpointPromise) { configuredEndpointPromise = getEndpointFromConfig.getEndpointFromConfig(input.serviceId); } return configuredEndpointPromise; }; return resolvedConfig; }; const resolveEndpointRequiredConfig = (input) => { const { endpoint } = input; if (endpoint === undefined) { input.endpoint = async () => { throw new Error("@smithy/middleware-endpoint: (default endpointRuleSet) endpoint is not set - you must configure an endpoint."); }; } return input; }; exports.endpointMiddleware = endpointMiddleware; exports.endpointMiddlewareOptions = endpointMiddlewareOptions; exports.getEndpointFromInstructions = getEndpointFromInstructions; exports.getEndpointPlugin = getEndpointPlugin; exports.resolveEndpointConfig = resolveEndpointConfig; exports.resolveEndpointRequiredConfig = resolveEndpointRequiredConfig; exports.resolveParams = resolveParams; exports.toEndpointV1 = toEndpointV1;