"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.deferCache = exports.cacheClients = exports.excludeRegions = exports.limitRegions = exports.getClient = void 0;
const material_management_1 = require("@aws-crypto/material-management");
function getClient(KMSClient, defaultConfig) {
    return function getKmsClient(region) {
        /* a KMS alias is supported.  These do not have a region
         * in this case, the Encryption SDK should find the default region
         * or the default region needs to be supplied to this function
         */
        const config = (region ? { ...defaultConfig, region } : { ...defaultConfig });
        const client = new KMSClient(config);
        /* Postcondition: A region must be configured.
         * The AWS SDK has a process for determining the default region.
         * A user can configure a default region by setting it in `defaultConfig`
         * But KMS requires a region to operate.
         */
        // @ts-ignore the V3 client has set the config to protected, reasonable, but I need to know...
        (0, material_management_1.needs)(client.config.region, 'A region is required');
        return client;
    };
}
exports.getClient = getClient;
function limitRegions(regions, getClient) {
    /* Precondition: limitRegions requires that region be a string. */
    (0, material_management_1.needs)(regions.every((r) => !!r && typeof r === 'string'), 'Can only limit on region strings');
    return (region) => {
        if (!regions.includes(region))
            return false;
        return getClient(region);
    };
}
exports.limitRegions = limitRegions;
function excludeRegions(regions, getClient) {
    /* Precondition: excludeRegions requires region be a string. */
    (0, material_management_1.needs)(regions.every((r) => !!r && typeof r === 'string'), 'Can only exclude on region strings');
    return (region) => {
        if (regions.includes(region))
            return false;
        return getClient(region);
    };
}
exports.excludeRegions = excludeRegions;
function cacheClients(getClient) {
    const clientsCache = {};
    return (region) => {
        // Do not cache until KMS has been responded in the given region
        if (!Object.prototype.hasOwnProperty.call(clientsCache, region))
            return deferCache(clientsCache, region, getClient(region));
        return clientsCache[region];
    };
}
exports.cacheClients = cacheClients;
/* It is possible that a malicious user can attempt a local resource
 * DOS by sending ciphertext with a large number of spurious regions.
 * This will fill the cache with regions and exhaust resources.
 * To avoid this, a call succeeds in contacting KMS.
 * This does *not* mean that this call is successful,
 * only that the region is backed by a functional KMS service.
 */
function deferCache(clientsCache, region, client) {
    /* Check for early return (Postcondition): No client, then I cache false and move on. */
    if (!client) {
        clientsCache[region] = false;
        return false;
    }
    const { encrypt, decrypt, generateDataKey } = client;
    return ['encrypt', 'decrypt', 'generateDataKey'].reduce(wrapOperation, client);
    /* Wrap each of the operations to cache the client on response */
    function wrapOperation(client, name) {
        const original = client[name];
        client[name] = async function wrappedOperation(args) {
            // @ts-ignore (there should be a TypeScript solution for this)
            const v2vsV3Response = original.call(client, args);
            const v2vsV3Promise = 'promise' in v2vsV3Response ? v2vsV3Response.promise() : v2vsV3Response;
            return v2vsV3Promise
                .then((response) => {
                clientsCache[region] = Object.assign(client, {
                    encrypt,
                    decrypt,
                    generateDataKey,
                });
                return response;
            })
                .catch(async (e) => {
                /* Errors from a KMS contact mean that the region is "live".
                 * As such the client can be cached because the problem is not with the client per se,
                 * but with the request made.
                 */
                if (e.$metadata && e.$metadata.httpStatusCode) {
                    clientsCache[region] = Object.assign(client, {
                        encrypt,
                        decrypt,
                        generateDataKey,
                    });
                }
                // The request was not successful
                return Promise.reject(e);
            });
        };
        return client;
    }
}
exports.deferCache = deferCache;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia21zX2NsaWVudF9zdXBwbGllci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9rbXNfY2xpZW50X3N1cHBsaWVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxvRUFBb0U7QUFDcEUsc0NBQXNDOzs7QUFFdEMseUVBQXVEO0FBdUJ2RCxTQUFnQixTQUFTLENBQ3ZCLFNBQTJDLEVBQzNDLGFBQXNCO0lBRXRCLE9BQU8sU0FBUyxZQUFZLENBQUMsTUFBYztRQUN6Qzs7O1dBR0c7UUFDSCxNQUFNLE1BQU0sR0FBRyxDQUNiLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLGFBQWEsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLGFBQWEsRUFBRSxDQUNuRCxDQUFBO1FBQ1gsTUFBTSxNQUFNLEdBQUcsSUFBSSxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUE7UUFFcEM7Ozs7V0FJRztRQUNILDhGQUE4RjtRQUM5RixJQUFBLDJCQUFLLEVBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsc0JBQXNCLENBQUMsQ0FBQTtRQUNuRCxPQUFPLE1BQU0sQ0FBQTtJQUNmLENBQUMsQ0FBQTtBQUNILENBQUM7QUF2QkQsOEJBdUJDO0FBRUQsU0FBZ0IsWUFBWSxDQUMxQixPQUFpQixFQUNqQixTQUFvQztJQUVwQyxrRUFBa0U7SUFDbEUsSUFBQSwyQkFBSyxFQUNILE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxDQUFDLEVBQ2xELGtDQUFrQyxDQUNuQyxDQUFBO0lBRUQsT0FBTyxDQUFDLE1BQWMsRUFBRSxFQUFFO1FBQ3hCLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQztZQUFFLE9BQU8sS0FBSyxDQUFBO1FBQzNDLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQzFCLENBQUMsQ0FBQTtBQUNILENBQUM7QUFkRCxvQ0FjQztBQUVELFNBQWdCLGNBQWMsQ0FDNUIsT0FBaUIsRUFDakIsU0FBb0M7SUFFcEMsK0RBQStEO0lBQy9ELElBQUEsMkJBQUssRUFDSCxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVEsQ0FBQyxFQUNsRCxvQ0FBb0MsQ0FDckMsQ0FBQTtJQUVELE9BQU8sQ0FBQyxNQUFjLEVBQUUsRUFBRTtRQUN4QixJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFDMUMsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDMUIsQ0FBQyxDQUFBO0FBQ0gsQ0FBQztBQWRELHdDQWNDO0FBRUQsU0FBZ0IsWUFBWSxDQUMxQixTQUFvQztJQUVwQyxNQUFNLFlBQVksR0FBc0MsRUFBRSxDQUFBO0lBRTFELE9BQU8sQ0FBQyxNQUFjLEVBQUUsRUFBRTtRQUN4QixnRUFBZ0U7UUFDaEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDO1lBQzdELE9BQU8sVUFBVSxDQUFDLFlBQVksRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUE7UUFDNUQsT0FBTyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDN0IsQ0FBQyxDQUFBO0FBQ0gsQ0FBQztBQVhELG9DQVdDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsVUFBVSxDQUN4QixZQUErQyxFQUMvQyxNQUFjLEVBQ2QsTUFBc0I7SUFFdEIsd0ZBQXdGO0lBQ3hGLElBQUksQ0FBQyxNQUFNLEVBQUU7UUFDWCxZQUFZLENBQUMsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFBO1FBQzVCLE9BQU8sS0FBSyxDQUFBO0tBQ2I7SUFDRCxNQUFNLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsR0FBRyxNQUFNLENBQUE7SUFFcEQsT0FDRSxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsaUJBQWlCLENBQ3pDLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUUvQixpRUFBaUU7SUFDakUsU0FBUyxhQUFhLENBQ3BCLE1BQWMsRUFDZCxJQUErQjtRQUUvQixNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDN0IsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssVUFBVSxnQkFBZ0IsQ0FFNUMsSUFBUztZQUVULDhEQUE4RDtZQUM5RCxNQUFNLGNBQWMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQTtZQUNsRCxNQUFNLGFBQWEsR0FDakIsU0FBUyxJQUFJLGNBQWMsQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUE7WUFDekUsT0FBTyxhQUFhO2lCQUNqQixJQUFJLENBQUMsQ0FBQyxRQUFhLEVBQUUsRUFBRTtnQkFDdEIsWUFBWSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFO29CQUMzQyxPQUFPO29CQUNQLE9BQU87b0JBQ1AsZUFBZTtpQkFDaEIsQ0FBQyxDQUFBO2dCQUNGLE9BQU8sUUFBUSxDQUFBO1lBQ2pCLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsS0FBSyxFQUFFLENBQU0sRUFBRSxFQUFFO2dCQUN0Qjs7O21CQUdHO2dCQUNILElBQUksQ0FBQyxDQUFDLFNBQVMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRTtvQkFDN0MsWUFBWSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFO3dCQUMzQyxPQUFPO3dCQUNQLE9BQU87d0JBQ1AsZUFBZTtxQkFDaEIsQ0FBQyxDQUFBO2lCQUNIO2dCQUNELGlDQUFpQztnQkFDakMsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBQzFCLENBQUMsQ0FBQyxDQUFBO1FBQ04sQ0FBQyxDQUFBO1FBQ0QsT0FBTyxNQUFNLENBQUE7SUFDZixDQUFDO0FBQ0gsQ0FBQztBQXpERCxnQ0F5REMifQ==