// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { immutableClass, readOnlyProperty } from './immutable_class';
import { KeyringNode, KeyringWebCrypto } from './keyring';
import { needs } from './needs';
export class MultiKeyringNode extends KeyringNode {
    generator;
    children;
    constructor(input) {
        super();
        decorateProperties(this, KeyringNode, input);
    }
    _onEncrypt = buildPrivateOnEncrypt();
    _onDecrypt = buildPrivateOnDecrypt();
}
immutableClass(MultiKeyringNode);
export class MultiKeyringWebCrypto extends KeyringWebCrypto {
    constructor(input) {
        super();
        decorateProperties(this, KeyringWebCrypto, input);
    }
    _onEncrypt = buildPrivateOnEncrypt();
    _onDecrypt = buildPrivateOnDecrypt();
}
immutableClass(MultiKeyringWebCrypto);
function decorateProperties(obj, BaseKeyring, { generator, children = [] }) {
    /* Precondition: MultiKeyring must have keyrings. */
    needs(generator || children.length, 'Noop MultiKeyring is not supported.');
    /* Precondition: generator must be a Keyring. */
    needs(!!generator === generator instanceof BaseKeyring, 'Generator must be a Keyring');
    /* Precondition: All children must be Keyrings. */
    needs(children.every((kr) => kr instanceof BaseKeyring), 'Child must be a Keyring');
    readOnlyProperty(obj, 'children', Object.freeze(children.slice()));
    readOnlyProperty(obj, 'generator', generator);
}
function buildPrivateOnEncrypt() {
    return async function _onEncrypt(material) {
        /* Precondition: Only Keyrings explicitly designated as generators can generate material.
         * Technically, the precondition below will handle this.
         * Since if I do not have an unencrypted data key,
         * and I do not have a generator,
         * then generated.hasUnencryptedDataKey === false will throw.
         * But this is a much more meaningful error.
         */
        needs(!material.hasUnencryptedDataKey ? this.generator : true, 'Only Keyrings explicitly designated as generators can generate material.');
        const generated = this.generator
            ? await this.generator.onEncrypt(material)
            : material;
        /* Precondition: A Generator Keyring *must* ensure generated material. */
        needs(generated.hasUnencryptedDataKey, 'Generator Keyring has not generated material.');
        /* By default this is a serial operation.  A keyring _may_ perform an expensive operation
         * or create resource constraints such that encrypting with multiple keyrings could
         * fail in unexpected ways.
         * Additionally, "downstream" keyrings may make choices about the EncryptedDataKeys they
         * append based on already appended EDK's.
         */
        for (const keyring of this.children) {
            await keyring.onEncrypt(generated);
        }
        // Keyrings are required to not create new EncryptionMaterial instances, but
        // only append EncryptedDataKey.  Therefore the generated material has all
        // the data I want.
        return generated;
    };
}
function buildPrivateOnDecrypt() {
    return async function _onDecrypt(material, encryptedDataKeys) {
        const children = this.children.slice();
        if (this.generator)
            children.unshift(this.generator);
        const childKeyringErrors = [];
        for (const keyring of children) {
            /* Check for early return (Postcondition): Do not attempt to decrypt once I have a valid key. */
            if (material.hasValidKey())
                return material;
            try {
                await keyring.onDecrypt(material, encryptedDataKeys);
            }
            catch (e) {
                /* Failures onDecrypt should not short-circuit the process
                 * If the caller does not have access they may have access
                 * through another Keyring.
                 */
                childKeyringErrors.push({ errPlus: e });
            }
        }
        /* Postcondition: A child keyring must provide a valid data key or no child keyring must have raised an error.
         * If I have a data key,
         * decrypt errors can be ignored.
         * However, if I was unable to decrypt a data key AND I have errors,
         * these errors should bubble up.
         * Otherwise, the only error customers will see is that
         * the material does not have an unencrypted data key.
         * So I return a concatenated Error message
         */
        needs(material.hasValidKey() ||
            (!material.hasValidKey() && !childKeyringErrors.length), childKeyringErrors.reduce((m, e, i) => `${m} Error #${i + 1} \n ${e.errPlus.stack} \n`, 'Unable to decrypt data key and one or more child keyrings had an error. \n '));
        return material;
    };
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXVsdGlfa2V5cmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tdWx0aV9rZXlyaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9FQUFvRTtBQUNwRSxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ3BFLE9BQU8sRUFBVyxXQUFXLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFPbEUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUsvQixNQUFNLE9BQU8sZ0JBQ1gsU0FBUSxXQUFXO0lBR0gsU0FBUyxDQUFjO0lBQ3ZCLFFBQVEsQ0FBNkI7SUFDckQsWUFBWSxLQUE0QztRQUN0RCxLQUFLLEVBQUUsQ0FBQTtRQUNQLGtCQUFrQixDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsS0FBSyxDQUFDLENBQUE7SUFDOUMsQ0FBQztJQUNELFVBQVUsR0FBRyxxQkFBcUIsRUFBc0IsQ0FBQTtJQUN4RCxVQUFVLEdBQUcscUJBQXFCLEVBQXNCLENBQUE7Q0FDekQ7QUFDRCxjQUFjLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtBQUVoQyxNQUFNLE9BQU8scUJBQ1gsU0FBUSxnQkFBZ0I7SUFNeEIsWUFBWSxLQUFpRDtRQUMzRCxLQUFLLEVBQUUsQ0FBQTtRQUNQLGtCQUFrQixDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsQ0FBQTtJQUNuRCxDQUFDO0lBQ0QsVUFBVSxHQUFHLHFCQUFxQixFQUEyQixDQUFBO0lBQzdELFVBQVUsR0FBRyxxQkFBcUIsRUFBMkIsQ0FBQTtDQUM5RDtBQUNELGNBQWMsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO0FBRXJDLFNBQVMsa0JBQWtCLENBQ3pCLEdBQW9CLEVBQ3BCLFdBQWdCLEVBQ2hCLEVBQUUsU0FBUyxFQUFFLFFBQVEsR0FBRyxFQUFFLEVBQXdCO0lBRWxELG9E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