PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/@bitgo/sdk-core/dist/src/bitgo/keychain

Просмотр файла: keychains.js

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Keychains = void 0;
const assert_1 = __importDefault(require("assert"));
const _ = __importStar(require("lodash"));
const common = __importStar(require("../../common"));
const utils_1 = require("../utils");
const ovcJsonCodec_1 = require("./ovcJsonCodec");
class Keychains {
    constructor(bitgo, baseCoin) {
        this.bitgo = bitgo;
        this.baseCoin = baseCoin;
    }
    /**
     * Get a keychain by ID
     * @param params
     * @param params.id
     * @param params.xpub (optional)
     * @param params.ethAddress (optional)
     * @param params.reqId (optional)
     */
    async get(params) {
        common.validateParams(params, [], ['xpub', 'ethAddress']);
        if (_.isUndefined(params.id)) {
            throw new Error('id must be defined');
        }
        const id = params.id;
        if (params.reqId) {
            this.bitgo.setRequestTracer(params.reqId);
        }
        return await this.bitgo.get(this.baseCoin.url('/key/' + encodeURIComponent(id))).result();
    }
    /**
     * list the users keychains
     * @param params
     * @param params.limit - Max number of results in a single call.
     * @param params.prevId - Continue iterating (provided by nextBatchPrevId in the previous list)
     * @returns {*}
     */
    async list(params = {}) {
        const queryObject = {};
        if (!_.isUndefined(params.limit)) {
            if (!_.isNumber(params.limit)) {
                throw new Error('invalid limit argument, expecting number');
            }
            queryObject.limit = params.limit;
        }
        if (!_.isUndefined(params.prevId)) {
            if (!_.isString(params.prevId)) {
                throw new Error('invalid prevId argument, expecting string');
            }
            queryObject.prevId = params.prevId;
        }
        return this.bitgo.get(this.baseCoin.url('/key')).query(queryObject).result();
    }
    /**
     * Change the decryption password for all possible keychains associated with a user.
     *
     * This function iterates through all keys associated with the user, decrypts
     * them with the old password and re-encrypts them with the new password.
     *
     * This should be called when a user changes their login password, and are expecting
     * that their wallet passwords are changed to match the new login password.
     *
     * @param params
     * @param params.oldPassword - The old password used for encrypting the key
     * @param params.newPassword - The new password to be used for encrypting the key
     * @returns changedKeys Object - e.g.:
     *  {
     *    xpub1: encryptedPrv,
     *    ...
     *  }
     */
    async updatePassword(params) {
        common.validateParams(params, ['oldPassword', 'newPassword'], []);
        const changedKeys = {};
        let prevId;
        let keysLeft = true;
        while (keysLeft) {
            const result = await this.list({ limit: 500, prevId });
            for (const key of result.keys) {
                const oldEncryptedPrv = key.encryptedPrv;
                if (_.isUndefined(oldEncryptedPrv)) {
                    continue;
                }
                try {
                    const updatedKeychain = this.updateSingleKeychainPassword({
                        keychain: key,
                        oldPassword: params.oldPassword,
                        newPassword: params.newPassword,
                    });
                    if (updatedKeychain.encryptedPrv) {
                        const changedKeyIdentifier = updatedKeychain.type === 'tss' ? updatedKeychain.id : updatedKeychain.pub;
                        if (changedKeyIdentifier) {
                            changedKeys[changedKeyIdentifier] = updatedKeychain.encryptedPrv;
                        }
                    }
                }
                catch (e) {
                    // if the password was incorrect, silence the error, throw otherwise
                    if (!e.message.includes('private key is incorrect')) {
                        throw e;
                    }
                }
            }
            if (result.nextBatchPrevId) {
                prevId = result.nextBatchPrevId;
            }
            else {
                keysLeft = false;
            }
        }
        return changedKeys;
    }
    /**
     * Update the password used to decrypt a single keychain
     * @param params
     * @param params.keychain - The keychain whose password should be updated
     * @param params.oldPassword - The old password used for encrypting the key
     * @param params.newPassword - The new password to be used for encrypting the key
     * @returns {object}
     */
    updateSingleKeychainPassword(params = {}) {
        if (!_.isString(params.oldPassword)) {
            throw new Error('expected old password to be a string');
        }
        if (!_.isString(params.newPassword)) {
            throw new Error('expected new password to be a string');
        }
        if (!_.isObject(params.keychain) || !_.isString(params.keychain.encryptedPrv)) {
            throw new Error('expected keychain to be an object with an encryptedPrv property');
        }
        const oldEncryptedPrv = params.keychain.encryptedPrv;
        try {
            const decryptedPrv = this.bitgo.decrypt({ input: oldEncryptedPrv, password: params.oldPassword });
            const newEncryptedPrv = this.bitgo.encrypt({ input: decryptedPrv, password: params.newPassword });
            return _.assign({}, params.keychain, { encryptedPrv: newEncryptedPrv });
        }
        catch (e) {
            // catching an error here means that the password was incorrect or, less likely, the input to decrypt is corrupted
            throw new Error('password used to decrypt keychain private key is incorrect');
        }
    }
    /**
     * Create a public/private key pair
     * @param params - optional params
     * @param params.seed optional - seed to use for keypair generation
     * @param params.isRootKey optional - whether the resulting keypair should be a root key
     * @returns {KeyPair} - the generated keypair
     */
    create(params = {}) {
        if (params?.isRootKey) {
            return this.baseCoin.generateRootKeyPair(params.seed);
        }
        return this.baseCoin.generateKeyPair(params.seed);
    }
    /**
     * Add a keychain to BitGo's records
     * @param params
     */
    async add(params = {}) {
        params = params || {};
        common.validateParams(params, [], [
            'pub',
            'encryptedPrv',
            'keyType',
            'type',
            'source',
            'originalPasscodeEncryptionCode',
            'enterprise',
            'derivedFromParentWithSeed',
        ]);
        if (!_.isUndefined(params.disableKRSEmail)) {
            if (!_.isBoolean(params.disableKRSEmail)) {
                throw new Error('invalid disableKRSEmail argument, expecting boolean');
            }
        }
        if (params.reqId) {
            this.bitgo.setRequestTracer(params.reqId);
        }
        return await this.bitgo
            .post(this.baseCoin.url('/key'))
            .send({
            pub: params.pub,
            commonPub: params.commonPub,
            commonKeychain: params.commonKeychain,
            encryptedPrv: params.encryptedPrv,
            type: params.type,
            keyType: params.keyType,
            source: params.source,
            provider: params.provider,
            originalPasscodeEncryptionCode: params.originalPasscodeEncryptionCode,
            enterprise: params.enterprise,
            derivedFromParentWithSeed: params.derivedFromParentWithSeed,
            disableKRSEmail: params.disableKRSEmail,
            krsSpecific: params.krsSpecific,
            keyShares: params.keyShares,
            userGPGPublicKey: params.userGPGPublicKey,
            backupGPGPublicKey: params.backupGPGPublicKey,
            algoUsed: params.algoUsed,
            isDistributedCustody: params.isDistributedCustody,
            isMPCv2: params.isMPCv2,
            coinSpecific: params.coinSpecific,
        })
            .result();
    }
    /**
     * Create a BitGo key
     * @param params (empty)
     */
    async createBitGo(params = {}) {
        params.source = 'bitgo';
        this.baseCoin.preCreateBitGo(params);
        return await this.add(params);
    }
    /**
     * Create a backup key
     * @param params
     * @param params.provider (optional)
     */
    async createBackup(params = {}) {
        params.source = 'backup';
        const isTssBackupKey = params.prv && (params.commonKeychain || params.commonPub);
        if (_.isUndefined(params.provider) && !isTssBackupKey) {
            // if the provider is undefined, we generate a local key and add the source details
            const key = this.create();
            _.extend(params, key);
            if (params.passphrase !== undefined) {
                _.extend(params, { encryptedPrv: this.bitgo.encrypt({ input: key.prv, password: params.passphrase }) });
            }
        }
        const serverResponse = await this.add(params);
        return _.extend({}, serverResponse, _.pick(params, ['prv', 'encryptedPrv', 'provider', 'source']));
    }
    /**
     * Gets keys for signing from a wallet
     * @param params
     * @returns {Promise<Keychain[]>}
     */
    async getKeysForSigning(params = {}) {
        if (!_.isObject(params.wallet)) {
            throw new Error('missing required param wallet');
        }
        const wallet = params.wallet;
        const reqId = params.reqId || new utils_1.RequestTracer();
        const ids = wallet.baseCoin.keyIdsForSigning();
        const keychainQueriesBluebirds = ids.map((id) => this.get({ id: wallet.keyIds()[id], reqId }));
        return Promise.all(keychainQueriesBluebirds);
    }
    /**
     * Convenience function to create and store MPC keychains with BitGo.
     * @param params passphrase used to encrypt secret materials
     * @return {Promise<KeychainsTriplet>} newly created User, Backup, and BitGo keys
     */
    async createMpc(params) {
        let MpcUtils;
        let multisigTypeVersion = undefined;
        if (params.multisigType === 'tss' && this.baseCoin.getMPCAlgorithm() === 'ecdsa') {
            const tssSettings = await this.bitgo
                .get(this.bitgo.microservicesUrl('/api/v2/tss/settings'))
                .result();
            multisigTypeVersion =
                tssSettings.coinSettings[this.baseCoin.getFamily()]?.walletCreationSettings?.multiSigTypeVersion;
        }
        switch (params.multisigType) {
            case 'tss':
                MpcUtils =
                    this.baseCoin.getMPCAlgorithm() === 'eddsa'
                        ? utils_1.EDDSAUtils.default
                        : multisigTypeVersion === 'MPCv2'
                            ? utils_1.ECDSAUtils.EcdsaMPCv2Utils
                            : utils_1.ECDSAUtils.EcdsaUtils;
                break;
            default:
                throw new Error('Unsupported multi-sig type');
        }
        const mpcUtils = new MpcUtils(this.bitgo, this.baseCoin);
        return await mpcUtils.createKeychains({
            passphrase: params.passphrase,
            enterprise: params.enterprise,
            originalPasscodeEncryptionCode: params.originalPasscodeEncryptionCode,
            retrofit: params.retrofit,
        });
    }
    async recreateMpc(params) {
        (0, assert_1.default)(params.coin, new Error('missing required param coin'));
        (0, assert_1.default)(params.walletId, new Error('missing required param walletId'));
        (0, assert_1.default)(params.otp, new Error('missing required param otp'));
        (0, assert_1.default)(params.passphrase, new Error('missing required param passphrase'));
        (0, assert_1.default)(params.encryptedMaterial.encryptedWalletPassphrase, new Error('missing required param encryptedWalletPassphrase'));
        (0, assert_1.default)(params.encryptedMaterial.encryptedUserKey, new Error('missing required param encryptedUserKey'));
        (0, assert_1.default)(params.encryptedMaterial.encryptedBackupKey, new Error('missing required param encryptedBackupKey'));
        await this.bitgo.post(this.bitgo.microservicesUrl('/api/v1/user/unlock')).send({ otp: params.otp }).result();
        const { recoveryInfo } = await this.bitgo
            .post(this.bitgo.microservicesUrl(`/api/v2/${params.coin}/wallet/${params.walletId}/passcoderecovery`))
            .result();
        if (!recoveryInfo || !('passcodeEncryptionCode' in recoveryInfo)) {
            throw new Error('failed to get recovery info');
        }
        const decryptedWalletPassphrase = this.bitgo.decrypt({
            input: params.encryptedMaterial.encryptedWalletPassphrase,
            password: recoveryInfo.passcodeEncryptionCode,
        });
        const decryptedUserKey = this.bitgo.decrypt({
            input: params.encryptedMaterial.encryptedUserKey,
            password: decryptedWalletPassphrase,
        });
        const decryptedBackupKey = this.bitgo.decrypt({
            input: params.encryptedMaterial.encryptedBackupKey,
            password: decryptedWalletPassphrase,
        });
        return this.createMpc({
            ...params,
            multisigType: 'tss',
            retrofit: {
                decryptedUserKey,
                decryptedBackupKey,
                walletId: params.walletId,
            },
        });
    }
    /**
     * It parses the JSON downloaded from the OVC for platform (BitGo),
     * and creates a corresponding TSS BitGo key. It also returns the JSON that needs
     * to be uploaded back to the OVCs containing the BitGo -> OVC shares.
     * @param ovcOutputJson JSON format of the file downloaded from the OVC for platform
     * @param enterprise Optional enterprise ID associated with the key
     * @returns {BitGoKeyFromOvcShares}
     */
    async createTssBitGoKeyFromOvcShares(ovcOutputJson, enterprise) {
        const decodedOvcOutput = (0, utils_1.decodeOrElse)(ovcJsonCodec_1.OvcToBitGoJSON.name, ovcJsonCodec_1.OvcToBitGoJSON, ovcOutputJson, (errors) => {
            throw new Error(`Error(s) parsing OVC JSON: ${errors}`);
        });
        if (decodedOvcOutput.state !== 1) {
            throw new Error('State expected to be "1". Please complete the first two OVC operations');
        }
        // OVC-1 is responsible for the User key
        const ovc1 = decodedOvcOutput.ovc[1];
        // OVC-2 is responsible for the Backup key
        const ovc2 = decodedOvcOutput.ovc[2];
        const keyShares = [
            {
                from: 'user',
                to: 'bitgo',
                publicShare: ovc1.ovcToBitgoShare.publicShare,
                privateShare: ovc1.ovcToBitgoShare.privateShare,
                privateShareProof: ovc1.ovcToBitgoShare.uSig.toString() ?? '',
                vssProof: ovc1.ovcToBitgoShare.vssProof ?? '',
            },
            {
                from: 'backup',
                to: 'bitgo',
                publicShare: ovc2.ovcToBitgoShare.publicShare,
                privateShare: ovc2.ovcToBitgoShare.privateShare,
                privateShareProof: ovc2.ovcToBitgoShare.uSig.toString() ?? '',
                vssProof: ovc2.ovcToBitgoShare.vssProof ?? '',
            },
        ];
        const key = await this.baseCoin.keychains().add({
            source: 'bitgo',
            keyShares,
            keyType: 'tss',
            userGPGPublicKey: ovc1.gpgPubKey,
            backupGPGPublicKey: ovc2.gpgPubKey,
            enterprise,
        });
        (0, assert_1.default)(key.keyShares);
        (0, assert_1.default)(key.commonKeychain);
        (0, assert_1.default)(key.walletHSMGPGPublicKeySigs);
        const bitgoToUserShare = key.keyShares.find((value) => value.from === 'bitgo' && value.to === 'user');
        (0, assert_1.default)(bitgoToUserShare);
        (0, assert_1.default)(bitgoToUserShare.vssProof);
        (0, assert_1.default)(bitgoToUserShare.paillierPublicKey);
        const bitgoToBackupShare = key.keyShares.find((value) => value.from === 'bitgo' && value.to === 'backup');
        (0, assert_1.default)(bitgoToBackupShare);
        (0, assert_1.default)(bitgoToBackupShare.vssProof);
        (0, assert_1.default)(bitgoToBackupShare.paillierPublicKey);
        // Create JSON data with platform shares for OVC-1 and OVC-2
        const bitgoToOvcOutput = {
            wallet: {
                ...decodedOvcOutput,
                platform: {
                    commonKeychain: key.commonKeychain,
                    walletGpgPubKeySigs: key.walletHSMGPGPublicKeySigs,
                    ovc: {
                        // BitGo to User (OVC-1)
                        1: {
                            bitgoToOvcShare: {
                                i: 1,
                                j: 3,
                                publicShare: bitgoToUserShare.publicShare,
                                privateShare: bitgoToUserShare.privateShare,
                                paillierPublicKey: bitgoToUserShare.paillierPublicKey,
                                vssProof: bitgoToUserShare.vssProof,
                            },
                        },
                        // BitGo to Backup (OVC-2)
                        2: {
                            bitgoToOvcShare: {
                                i: 2,
                                j: 3,
                                publicShare: bitgoToBackupShare.publicShare,
                                privateShare: bitgoToBackupShare.privateShare,
                                paillierPublicKey: bitgoToBackupShare.paillierPublicKey,
                                vssProof: bitgoToBackupShare.vssProof,
                            },
                        },
                    },
                },
            },
        };
        // Mark it ready for next operation, should be 2
        bitgoToOvcOutput.wallet.state += 1;
        const output = {
            bitGoKeyId: key.id,
            bitGoOutputJsonForOvc: bitgoToOvcOutput,
        };
        return (0, utils_1.decodeOrElse)(ovcJsonCodec_1.BitGoKeyFromOvcShares.name, ovcJsonCodec_1.BitGoKeyFromOvcShares, output, (errors) => {
            throw new Error(`Error producing the output: ${errors}`);
        });
    }
    /**
     * Create user keychain, encrypt the private key with the wallet passphrase and store it in BitGo.
     * @param walletPassphrase
     * @returns Keychain including the decrypted private key
     */
    async createUserKeychain(walletPassphrase) {
        const keychains = this.baseCoin.keychains();
        const newKeychain = keychains.create();
        const originalPasscodeEncryptionCode = (0, utils_1.generateRandomPassword)(5);
        const encryptedPrv = this.bitgo.encrypt({
            password: walletPassphrase,
            input: newKeychain.prv,
        });
        return {
            ...(await keychains.add({
                encryptedPrv,
                originalPasscodeEncryptionCode,
                pub: newKeychain.pub,
                source: 'user',
            })),
            prv: newKeychain.prv,
        };
    }
}
exports.Keychains = Keychains;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Y2hhaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2JpdGdvL2tleWNoYWluL2tleWNoYWlucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSxvREFBNEI7QUFDNUIsMENBQTRCO0FBQzVCLHFEQUF1QztBQUd2QyxvQ0FBdUc7QUFrQnZHLGlEQUF1RjtBQUV2RixNQUFhLFNBQVM7SUFJcEIsWUFBWSxLQUFnQixFQUFFLFFBQW1CO1FBQy9DLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBQyxNQUEwQjtRQUNsQyxNQUFNLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUUxRCxJQUFJLENBQUMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFFRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ3JCLElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFDRCxPQUFPLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxHQUFHLGtCQUFrQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUM1RixD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Q0FBQztJQUNMLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGtCQUFrQixDQUFDLGdCQUF3QjtRQUMvQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQzVDLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN2QyxNQUFNLDhCQUE4QixHQUFHLElBQUEsOEJBQXNCLEVBQUMsQ0FBQyxDQUFDLENBQUM7UUFFakUsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7WUFDdEMsUUFBUSxFQUFFLGdCQUFnQjtZQUMxQixLQUFLLEVBQUUsV0FBVyxDQUFDLEdBQUc7U0FDdkIsQ0FBQyxDQUFDO1FBRUgsT0FBTztZQUNMLEdBQUcsQ0FBQyxNQUFNLFNBQVMsQ0FBQyxHQUFHLENBQUM7Z0JBQ3RCLFlBQVk7Z0JBQ1osOEJBQThCO2dCQUM5QixHQUFHLEVBQUUsV0FBVyxDQUFDLEdBQUc7Z0JBQ3BCLE1BQU0sRUFBRSxNQUFNO2FBQ2YsQ0FBQyxDQUFDO1lBQ0gsR0FBRyxFQUFFLFdBQVcsQ0FBQyxHQUFHO1NBQ3JCLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUE3ZUQsOEJBNmVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVHNzU2V0dGluZ3MgfSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCAqIGFzIGNvbW1vbiBmcm9tICcuLi8uLi9jb21tb24nO1xuaW1wb3J0IHsgSUJhc2VDb2luLCBLZXljaGFpbnNUcmlwbGV0LCBLZXlQYWlyIH0gZnJvbSAnLi4vYmFzZUNvaW4nO1xuaW1wb3J0IHsgQml0R29CYXNlIH0gZnJvbSAnLi4vYml0Z29CYXNlJztcbmltcG9ydCB7IGRlY29kZU9yRWxzZSwgRUNEU0FVdGlscywgRUREU0FVdGlscywgZ2VuZXJhdGVSYW5kb21QYXNzd29yZCwgUmVxdWVzdFRyYWNlciB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7XG4gIEFkZEtleWNoYWluT3B0aW9ucyxcbiAgQXBpS2V5U2hhcmUsXG4gIENoYW5nZWRLZXljaGFpbnMsXG4gIENyZWF0ZUJhY2t1cE9wdGlvbnMsXG4gIENyZWF0ZUJpdEdvT3B0aW9ucyxcbiAgQ3JlYXRlTXBjT3B0aW9ucyxcbiAgR2V0S2V5Y2hhaW5PcHRpb25zLFxuICBHZXRLZXlzRm9yU2lnbmluZ09wdGlvbnMsXG4gIElLZXljaGFpbnMsXG4gIEtleWNoYWluLFxuICBMaXN0S2V5Y2hhaW5PcHRpb25zLFxuICBMaXN0S2V5Y2hhaW5zUmVzdWx0LFxuICBSZWNyZWF0ZU1wY09wdGlvbnMsXG4gIFVwZGF0ZVBhc3N3b3JkT3B0aW9ucyxcbiAgVXBkYXRlU2luZ2xlS2V5Y2hhaW5QYXNzd29yZE9wdGlvbnMsXG59IGZyb20gJy4vaUtleWNoYWlucyc7XG5pbXBvcnQgeyBCaXRHb0tleUZyb21PdmNTaGFyZXMsIEJpdEdvVG9PdmNKU09OLCBPdmNUb0JpdEdvSlNPTiB9IGZyb20gJy4vb3ZjSnNvbkNvZGVjJztcblxuZXhwb3J0IGNsYXNzIEtleWNoYWlucyBpbXBsZW1lbnRzIElLZXljaGFpbnMge1xuICBwcml2YXRlIHJlYWRvbmx5IGJpdGdvOiBCaXRHb0Jhc2U7XG4gIHByaXZhdGUgcmVhZG9ubHkgYmFzZUNvaW46IElCYXNlQ29pbjtcblxuICBjb25zdHJ1Y3RvcihiaXRnbzogQml0R29CYXNlLCBiYXNlQ29pbjogSUJhc2VDb2luKSB7XG4gICAgdGhpcy5iaXRnbyA9IGJpdGdvO1xuICAgIHRoaXMuYmFzZUNvaW4gPSBiYXNlQ29pbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSBrZXljaGFpbiBieSBJRFxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMuaWRcbiAgICogQHBhcmFtIHBhcmFtcy54cHViIChvcHRpb25hbClcbiAgICogQHBhcmFtIHBhcmFtcy5ldGhBZGRyZXNzIChvcHRpb25hbClcbiAgICogQHBhcmFtIHBhcmFtcy5yZXFJZCAob3B0aW9uYWwpXG4gICAqL1xuICBhc3luYyBnZXQocGFyYW1zOiBHZXRLZXljaGFpbk9wdGlvbnMpOiBQcm9taXNlPEtleWNoYWluPiB7XG4gICAgY29tbW9uLnZhbGlkYXRlUGFyYW1zKHBhcmFtcywgW10sIFsneHB1YicsICdldGhBZGRyZXNzJ10pO1xuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQocGFyYW1zLmlkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpZCBtdXN0IGJlIGRlZmluZWQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBpZCA9IHBhcmFtcy5pZDtcbiAgICBpZiAocGFyYW1zLnJlcUlkKSB7XG4gICAgICB0aGlzLmJpdGdvLnNldFJlcXVlc3RUcmFjZXIocGFyYW1zLnJlcUlkKTtcbiAgICB9XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuYml0Z28uZ2V0KHRoaXMuYmFzZUNvaW4udXJsKCcva2V5LycgKyBlbmNvZGVVUklDb21wb25lbnQoaWQpKSkucmVzdWx0KCk7XG4gIH1cblxuICAvKipcbiAgICogbGlzdCB0aGUgdXNlcnMga2V5Y2hhaW5zXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHBhcmFtIHBhcmFtcy5saW1pdCAtIE1heCBudW1iZXIgb2YgcmVzdWx0cyBpbiBhIHNpbmdsZSBjYWxsLlxuICAgKiBAcGFyYW0gcGFyYW1zLnByZXZJZCAtIENvbnRpbnVlIGl0ZXJhdGluZyAocHJvdmlkZWQgYnkgbmV4dEJhdGNoUHJldklkIGluIHRoZSBwcmV2aW91cyBsaXN0KVxuICAgKiBAcmV0dXJucyB7Kn1cbiAgICovXG4gIGFzeW5jIGxpc3QocGFyYW1zOiBMaXN0S2V5Y2hhaW5PcHRpb25zID0ge30pOiBQcm9taXNlPExpc3RLZXljaGFpbnNSZXN1bHQ+IHtcbiAgICBjb25zdCBxdWVyeU9iamVjdDogYW55ID0ge307XG5cbiAgICBpZiAoIV8uaXNVbmRlZmluZWQocGFyYW1zLmxpbWl0KSkge1xuICAgICAgaWYgKCFfLmlzTnVtYmVyKHBhcmFtcy5saW1pdCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGxpbWl0IGFyZ3VtZW50LCBleHBlY3RpbmcgbnVtYmVyJyk7XG4gICAgICB9XG4gICAgICBxdWVyeU9iamVjdC5saW1pdCA9IHBhcmFtcy5saW1pdDtcbiAgICB9XG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKHBhcmFtcy5wcmV2SWQpKSB7XG4gICAgICBpZiAoIV8uaXNTdHJpbmcocGFyYW1zLnByZXZJZCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHByZXZJZCBhcmd1bWVudCwgZXhwZWN0aW5nIHN0cmluZycpO1xuICAgICAgfVxuICAgICAgcXVlcnlPYmplY3QucHJldklkID0gcGFyYW1zLnByZXZJZDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5iaXRnby5nZXQodGhpcy5iYXNlQ29pbi51cmwoJy9rZXknKSkucXVlcnkocXVlcnlPYmplY3QpLnJlc3VsdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgZGVjcnlwdGlvbiBwYXNzd29yZCBmb3IgYWxsIHBvc3NpYmxlIGtleWNoYWlucyBhc3NvY2lhdGVkIHdpdGggYSB1c2VyLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGl0ZXJhdGVzIHRocm91Z2ggYWxsIGtleXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB1c2VyLCBkZWNyeXB0c1xuICAgKiB0aGVtIHdpdGggdGhlIG9sZCBwYXNzd29yZCBhbmQgcmUtZW5jcnlwdHMgdGhlbSB3aXRoIHRoZSBuZXcgcGFzc3dvcmQuXG4gICAqXG4gICAqIFRoaXMgc2hvdWxkIGJlIGNhbGxlZCB3aGVuIGEgdXNlciBjaGFuZ2VzIHRoZWlyIGxvZ2luIHBhc3N3b3JkLCBhbmQgYXJlIGV4cGVjdGluZ1xuICAgKiB0aGF0IHRoZWlyIHdhbGxldCBwYXNzd29yZHMgYXJlIGNoYW5nZWQgdG8gbWF0Y2ggdGhlIG5ldyBsb2dpbiBwYXNzd29yZC5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0gcGFyYW1zLm9sZFBhc3N3b3JkIC0gVGhlIG9sZCBwYXNzd29yZCB1c2VkIGZvciBlbmNyeXB0aW5nIHRoZSBrZXlcbiAgICogQHBhcmFtIHBhcmFtcy5uZXdQYXNzd29yZCAtIFRoZSBuZXcgcGFzc3dvcmQgdG8gYmUgdXNlZCBmb3IgZW5jcnlwdGluZyB0aGUga2V5XG4gICAqIEByZXR1cm5zIGNoYW5nZWRLZXlzIE9iamVjdCAtIGUuZy46XG4gICAqICB7XG4gICAqICAgIHhwdWIxOiBlbmNyeXB0ZWRQcnYsXG4gICAqICAgIC4uLlxuICAgKiAgfVxuICAgKi9cbiAgYXN5bmMgdXBkYXRlUGFzc3dvcmQocGFyYW1zOiBVcGRhdGVQYXNzd29yZE9wdGlvbnMpOiBQcm9taXNlPENoYW5nZWRLZXljaGFpbnM+IHtcbiAgICBjb21tb24udmFsaWRhdGVQYXJhbXMocGFyYW1zLCBbJ29sZFBhc3N3b3JkJywgJ25ld1Bhc3N3b3JkJ10sIFtdKTtcbiAgICBjb25zdCBjaGFuZ2VkS2V5czogQ2hhbmdlZEtleWNoYWlucyA9IHt9O1xuICAgIGxldCBwcmV2SWQ7XG4gICAgbGV0IGtleXNMZWZ0ID0gdHJ1ZTtcbiAgICB3aGlsZSAoa2V5c0xlZnQpIHtcbiAgICAgIGNvbnN0IHJlc3VsdDogTGlzdEtleWNoYWluc1Jlc3VsdCA9IGF3YWl0IHRoaXMubGlzdCh7IGxpbWl0OiA1MDAsIHByZXZJZCB9KTtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIHJlc3VsdC5rZXlzKSB7XG4gICAgICAgIGNvbnN0IG9sZEVuY3J5cHRlZFBydiA9IGtleS5lbmNyeXB0ZWRQcnY7XG4gICAgICAgIGlmIChfLmlzVW5kZWZpbmVkKG9sZEVuY3J5cHRlZFBydikpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHVwZGF0ZWRLZXljaGFpbiA9IHRoaXMudXBkYXRlU2luZ2xlS2V5Y2hhaW5QYXNzd29yZCh7XG4gICAgICAgICAgICBrZXljaGFpbjoga2V5LFxuICAgICAgICAgICAgb2xkUGFzc3dvcmQ6IHBhcmFtcy5vbGRQYXNzd29yZCxcbiAgICAgICAgICAgIG5ld1Bhc3N3b3JkOiBwYXJhbXMubmV3UGFzc3dvcmQsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHVwZGF0ZWRLZXljaGFpbi5lbmNyeXB0ZWRQcnYpIHtcbiAgICAgICAgICAgIGNvbnN0IGNoYW5nZWRLZXlJZGVudGlmaWVyID0gdXBkYXRlZEtleWNoYWluLnR5cGUgPT09ICd0c3MnID8gdXBkYXRlZEtleWNoYWluLmlkIDogdXBkYXRlZEtleWNoYWluLnB1YjtcbiAgICAgICAgICAgIGlmIChjaGFuZ2VkS2V5SWRlbnRpZmllcikge1xuICAgICAgICAgICAgICBjaGFuZ2VkS2V5c1tjaGFuZ2VkS2V5SWRlbnRpZmllcl0gPSB1cGRhdGVkS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIC8vIGlmIHRoZSBwYXNzd29yZCB3YXMgaW5jb3JyZWN0LCBzaWxlbmNlIHRoZSBlcnJvciwgdGhyb3cgb3RoZXJ3aXNlXG4gICAgICAgICAgaWYgKCFlLm1lc3NhZ2UuaW5jbHVkZXMoJ3ByaXZhdGUga2V5IGlzIGluY29ycmVjdCcpKSB7XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHJlc3VsdC5uZXh0QmF0Y2hQcmV2SWQpIHtcbiAgICAgICAgcHJldklkID0gcmVzdWx0Lm5leHRCYXRjaFByZXZJZDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGtleXNMZWZ0ID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjaGFuZ2VkS2V5cztcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIHBhc3N3b3JkIHVzZWQgdG8gZGVjcnlwdCBhIHNpbmdsZSBrZXljaGFpblxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMua2V5Y2hhaW4gLSBUaGUga2V5Y2hhaW4gd2hvc2UgcGFzc3dvcmQgc2hvdWxkIGJlIHVwZGF0ZWRcbiAgICogQHBhcmFtIHBhcmFtcy5vbGRQYXNzd29yZCAtIFRoZSBvbGQgcGFzc3dvcmQgdXNlZCBmb3IgZW5jcnlwdGluZyB0aGUga2V5XG4gICAqIEBwYXJhbSBwYXJhbXMubmV3UGFzc3dvcmQgLSBUaGUgbmV3IHBhc3N3b3JkIHRvIGJlIHVzZWQgZm9yIGVuY3J5cHRpbmcgdGhlIGtleVxuICAgKiBAcmV0dXJucyB7b2JqZWN0fVxuICAgKi9cbiAgdXBkYXRlU2luZ2xlS2V5Y2hhaW5QYXNzd29yZChwYXJhbXM6IFVwZGF0ZVNpbmdsZUtleWNoYWluUGFzc3dvcmRPcHRpb25zID0ge30pOiBLZXljaGFpbiB7XG4gICAgaWYgKCFfLmlzU3RyaW5nKHBhcmFtcy5vbGRQYXNzd29yZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0ZWQgb2xkIHBhc3N3b3JkIHRvIGJlIGEgc3RyaW5nJyk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzU3RyaW5nKHBhcmFtcy5uZXdQYXNzd29yZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0ZWQgbmV3IHBhc3N3b3JkIHRvIGJlIGEgc3RyaW5nJyk7XG4gICAgfVxuXG4gICAgaWYgKCFfLmlzT2JqZWN0KHBhcmFtcy5rZXljaGFpbikgfHwgIV8uaXNTdHJpbmcocGFyYW1zLmtleWNoYWluLmVuY3J5cHRlZFBydikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0ZWQga2V5Y2hhaW4gdG8gYmUgYW4gb2JqZWN0IHdpdGggYW4gZW5jcnlwdGVkUHJ2IHByb3BlcnR5Jyk7XG4gICAgfVxuXG4gICAgY29uc3Qgb2xkRW5jcnlwdGVkUHJ2ID0gcGFyYW1zLmtleWNoYWluLmVuY3J5cHRlZFBydjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZGVjcnlwdGVkUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHsgaW5wdXQ6IG9sZEVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6IHBhcmFtcy5vbGRQYXNzd29yZCB9KTtcbiAgICAgIGNvbnN0IG5ld0VuY3J5cHRlZFBydiA9IHRoaXMuYml0Z28uZW5jcnlwdCh7IGlucHV0OiBkZWNyeXB0ZWRQcnYsIHBhc3N3b3JkOiBwYXJhbXMubmV3UGFzc3dvcmQgfSk7XG4gICAgICByZXR1cm4gXy5hc3NpZ24oe30sIHBhcmFtcy5rZXljaGFpbiwgeyBlbmNyeXB0ZWRQcnY6IG5ld0VuY3J5cHRlZFBydiB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBjYXRjaGluZyBhbiBlcnJvciBoZXJlIG1lYW5zIHRoYXQgdGhlIHBhc3N3b3JkIHdhcyBpbmNvcnJlY3Qgb3IsIGxlc3MgbGlrZWx5LCB0aGUgaW5wdXQgdG8gZGVjcnlwdCBpcyBjb3JydXB0ZWRcbiAgICAgIHRocm93IG5ldyBFcnJvcigncGFzc3dvcmQgdXNlZCB0byBkZWNyeXB0IGtleWNoYWluIHByaXZhdGUga2V5IGlzIGluY29ycmVjdCcpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBwdWJsaWMvcHJpdmF0ZSBrZXkgcGFpclxuICAgKiBAcGFyYW0gcGFyYW1zIC0gb3B0aW9uYWwgcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMuc2VlZCBvcHRpb25hbCAtIHNlZWQgdG8gdXNlIGZvciBrZXlwYWlyIGdlbmVyYXRpb25cbiAgICogQHBhcmFtIHBhcmFtcy5pc1Jvb3RLZXkgb3B0aW9uYWwgLSB3aGV0aGVyIHRoZSByZXN1bHRpbmcga2V5cGFpciBzaG91bGQgYmUgYSByb290IGtleVxuICAgKiBAcmV0dXJucyB7S2V5UGFpcn0gLSB0aGUgZ2VuZXJhdGVkIGtleXBhaXJcbiAgICovXG4gIGNyZWF0ZShwYXJhbXM6IHsgc2VlZD86IEJ1ZmZlcjsgaXNSb290S2V5PzogYm9vbGVhbiB9ID0ge30pOiBLZXlQYWlyIHtcbiAgICBpZiAocGFyYW1zPy5pc1Jvb3RLZXkpIHtcbiAgICAgIHJldHVybiB0aGlzLmJhc2VDb2luLmdlbmVyYXRlUm9vdEtleVBhaXIocGFyYW1zLnNlZWQpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5iYXNlQ29pbi5nZW5lcmF0ZUtleVBhaXIocGFyYW1zLnNlZWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIGtleWNoYWluIHRvIEJpdEdvJ3MgcmVjb3Jkc1xuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqL1xuICBhc3luYyBhZGQocGFyYW1zOiBBZGRLZXljaGFpbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8S2V5Y2hhaW4+IHtcbiAgICBwYXJhbXMgPSBwYXJhbXMgfHwge307XG4gICAgY29tbW9uLnZhbGlkYXRlUGFyYW1zKFxuICAgICAgcGFyYW1zLFxuICAgICAgW10sXG4gICAgICBbXG4gICAgICAgICdwdWInLFxuICAgICAgICAnZW5jcnlwdGVkUHJ2JyxcbiAgICAgICAgJ2tleVR5cGUnLFxuICAgICAgICAndHlwZScsXG4gICAgICAgICdzb3VyY2UnLFxuICAgICAgICAnb3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlJyxcbiAgICAgICAgJ2VudGVycHJpc2UnLFxuICAgICAgICAnZGVyaXZlZEZyb21QYXJlbnRXaXRoU2VlZCcsXG4gICAgICBdXG4gICAgKTtcblxuICAgIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMuZGlzYWJsZUtSU0VtYWlsKSkge1xuICAgICAgaWYgKCFfLmlzQm9vbGVhbihwYXJhbXMuZGlzYWJsZUtSU0VtYWlsKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgZGlzYWJsZUtSU0VtYWlsIGFyZ3VtZW50LCBleHBlY3RpbmcgYm9vbGVhbicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChwYXJhbXMucmVxSWQpIHtcbiAgICAgIHRoaXMuYml0Z28uc2V0UmVxdWVzdFRyYWNlcihwYXJhbXMucmVxSWQpO1xuICAgIH1cblxuICAgIHJldHVybiBhd2FpdCB0aGlzLmJpdGdvXG4gICAgICAucG9zdCh0aGlzLmJhc2VDb2luLnVybCgnL2tleScpKVxuICAgICAgLnNlbmQoe1xuICAgICAgICBwdWI6IHBhcmFtcy5wdWIsXG4gICAgICAgIGNvbW1vblB1YjogcGFyYW1zLmNvbW1vblB1YixcbiAgICAgICAgY29tbW9uS2V5Y2hhaW46IHBhcmFtcy5jb21tb25LZXljaGFpbixcbiAgICAgICAgZW5jcnlwdGVkUHJ2OiBwYXJhbXMuZW5jcnlwdGVkUHJ2LFxuICAgICAgICB0eXBlOiBwYXJhbXMudHlwZSxcbiAgICAgICAga2V5VHlwZTogcGFyYW1zLmtleVR5cGUsXG4gICAgICAgIHNvdXJjZTogcGFyYW1zLnNvdXJjZSxcbiAgICAgICAgcHJvdmlkZXI6IHBhcmFtcy5wcm92aWRlcixcbiAgICAgICAgb3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlOiBwYXJhbXMub3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlLFxuICAgICAgICBlbnRlcnByaXNlOiBwYXJhbXMuZW50ZXJwcmlzZSxcbiAgICAgICAgZGVyaXZlZEZyb21QYXJlbnRXaXRoU2VlZDogcGFyYW1zLmRlcml2ZWRGcm9tUGFyZW50V2l0aFNlZWQsXG4gICAgICAgIGRpc2FibGVLUlNFbWFpbDogcGFyYW1zLmRpc2FibGVLUlNFbWFpbCxcbiAgICAgICAga3JzU3BlY2lmaWM6IHBhcmFtcy5rcnNTcGVjaWZpYyxcbiAgICAgICAga2V5U2hhcmVzOiBwYXJhbXMua2V5U2hhcmVzLFxuICAgICAgICB1c2VyR1BHUHVibGljS2V5OiBwYXJhbXMudXNlckdQR1B1YmxpY0tleSxcbiAgICAgICAgYmFja3VwR1BHUHVibGljS2V5OiBwYXJhbXMuYmFja3VwR1BHUHVibGljS2V5LFxuICAgICAgICBhbGdvVXNlZDogcGFyYW1zLmFsZ29Vc2VkLFxuICAgICAgICBpc0Rpc3RyaWJ1dGVkQ3VzdG9keTogcGFyYW1zLmlzRGlzdHJpYnV0ZWRDdXN0b2R5LFxuICAgICAgICBpc01QQ3YyOiBwYXJhbXMuaXNNUEN2MixcbiAgICAgICAgY29pblNwZWNpZmljOiBwYXJhbXMuY29pblNwZWNpZmljLFxuICAgICAgfSlcbiAgICAgIC5yZXN1bHQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBCaXRHbyBrZXlcbiAgICogQHBhcmFtIHBhcmFtcyAoZW1wdHkpXG4gICAqL1xuICBhc3luYyBjcmVhdGVCaXRHbyhwYXJhbXM6IENyZWF0ZUJpdEdvT3B0aW9ucyA9IHt9KTogUHJvbWlzZTxLZXljaGFpbj4ge1xuICAgIHBhcmFtcy5zb3VyY2UgPSAnYml0Z28nO1xuXG4gICAgdGhpcy5iYXNlQ29pbi5wcmVDcmVhdGVCaXRHbyhwYXJhbXMgYXMgYW55KTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5hZGQocGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBiYWNrdXAga2V5XG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICogQHBhcmFtIHBhcmFtcy5wcm92aWRlciAob3B0aW9uYWwpXG4gICAqL1xuICBhc3luYyBjcmVhdGVCYWNrdXAocGFyYW1zOiBDcmVhdGVCYWNrdXBPcHRpb25zID0ge30pOiBQcm9taXNlPEtleWNoYWluPiB7XG4gICAgcGFyYW1zLnNvdXJjZSA9ICdiYWNrdXAnO1xuXG4gICAgY29uc3QgaXNUc3NCYWNrdXBLZXkgPSBwYXJhbXMucHJ2ICYmIChwYXJhbXMuY29tbW9uS2V5Y2hhaW4gfHwgcGFyYW1zLmNvbW1vblB1Yik7XG5cbiAgICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMucHJvdmlkZXIpICYmICFpc1Rzc0JhY2t1cEtleSkge1xuICAgICAgLy8gaWYgdGhlIHByb3ZpZGVyIGlzIHVuZGVmaW5lZCwgd2UgZ2VuZXJhdGUgYSBsb2NhbCBrZXkgYW5kIGFkZCB0aGUgc291cmNlIGRldGFpbHNcbiAgICAgIGNvbnN0IGtleSA9IHRoaXMuY3JlYXRlKCk7XG4gICAgICBfLmV4dGVuZChwYXJhbXMsIGtleSk7XG4gICAgICBpZiAocGFyYW1zLnBhc3NwaHJhc2UgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBfLmV4dGVuZChwYXJhbXMsIHsgZW5jcnlwdGVkUHJ2OiB0aGlzLmJpdGdvLmVuY3J5cHQoeyBpbnB1dDoga2V5LnBydiwgcGFzc3dvcmQ6IHBhcmFtcy5wYXNzcGhyYXNlIH0pIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHNlcnZlclJlc3BvbnNlID0gYXdhaXQgdGhpcy5hZGQocGFyYW1zKTtcbiAgICByZXR1cm4gXy5leHRlbmQoe30sIHNlcnZlclJlc3BvbnNlLCBfLnBpY2socGFyYW1zLCBbJ3BydicsICdlbmNyeXB0ZWRQcnYnLCAncHJvdmlkZXInLCAnc291cmNlJ10pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGtleXMgZm9yIHNpZ25pbmcgZnJvbSBhIHdhbGxldFxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEtleWNoYWluW10+fVxuICAgKi9cbiAgYXN5bmMgZ2V0S2V5c0ZvclNpZ25pbmcocGFyYW1zOiBHZXRLZXlzRm9yU2lnbmluZ09wdGlvbnMgPSB7fSk6IFByb21pc2U8S2V5Y2hhaW5bXT4ge1xuICAgIGlmICghXy5pc09iamVjdChwYXJhbXMud2FsbGV0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHBhcmFtIHdhbGxldCcpO1xuICAgIH1cbiAgICBjb25zdCB3YWxsZXQgPSBwYXJhbXMud2FsbGV0O1xuICAgIGNvbnN0IHJlcUlkID0gcGFyYW1zLnJlcUlkIHx8IG5ldyBSZXF1ZXN0VHJhY2VyKCk7XG4gICAgY29uc3QgaWRzID0gd2FsbGV0LmJhc2VDb2luLmtleUlkc0ZvclNpZ25pbmcoKTtcbiAgICBjb25zdCBrZXljaGFpblF1ZXJpZXNCbHVlYmlyZHMgPSBpZHMubWFwKChpZCkgPT4gdGhpcy5nZXQoeyBpZDogd2FsbGV0LmtleUlkcygpW2lkXSwgcmVxSWQgfSkpO1xuICAgIHJldHVybiBQcm9taXNlLmFsbChrZXljaGFpblF1ZXJpZXNCbHVlYmlyZHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlbmllbmNlIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhbmQgc3RvcmUgTVBDIGtleWNoYWlucyB3aXRoIEJpdEdvLlxuICAgKiBAcGFyYW0gcGFyYW1zIHBhc3NwaHJhc2UgdXNlZCB0byBlbmNyeXB0IHNlY3JldCBtYXRlcmlhbHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxLZXljaGFpbnNUcmlwbGV0Pn0gbmV3bHkgY3JlYXRlZCBVc2VyLCBCYWNrdXAsIGFuZCBCaXRHbyBrZXlzXG4gICAqL1xuICBhc3luYyBjcmVhdGVNcGMocGFyYW1zOiBDcmVhdGVNcGNPcHRpb25zKTogUHJvbWlzZTxLZXljaGFpbnNUcmlwbGV0PiB7XG4gICAgbGV0IE1wY1V0aWxzO1xuICAgIGxldCBtdWx0aXNpZ1R5cGVWZXJzaW9uOiAnTVBDdjInIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgIGlmIChwYXJhbXMubXVsdGlzaWdUeXBlID09PSAndHNzJyAmJiB0aGlzLmJhc2VDb2luLmdldE1QQ0FsZ29yaXRobSgpID09PSAnZWNkc2EnKSB7XG4gICAgICBjb25zdCB0c3NTZXR0aW5nczogVHNzU2V0dGluZ3MgPSBhd2FpdCB0aGlzLmJpdGdvXG4gICAgICAgIC5nZXQodGhpcy5iaXRnby5taWNyb3NlcnZpY2VzVXJsKCcvYXBpL3YyL3Rzcy9zZXR0aW5ncycpKVxuICAgICAgICAucmVzdWx0KCk7XG4gICAgICBtdWx0aXNpZ1R5cGVWZXJzaW9uID1cbiAgICAgICAgdHNzU2V0dGluZ3MuY29pblNldHRpbmdzW3RoaXMuYmFzZUNvaW4uZ2V0RmFtaWx5KCldPy53YWxsZXRDcmVhdGlvblNldHRpbmdzPy5tdWx0aVNpZ1R5cGVWZXJzaW9uO1xuICAgIH1cblxuICAgIHN3aXRjaCAocGFyYW1zLm11bHRpc2lnVHlwZSkge1xuICAgICAgY2FzZSAndHNzJzpcbiAgICAgICAgTXBjVXRpbHMgPVxuICAgICAgICAgIHRoaXMuYmFzZUNvaW4uZ2V0TVBDQWxnb3JpdGhtKCkgPT09ICdlZGRzYSdcbiAgICAgICAgICAgID8gRUREU0FVdGlscy5kZWZhdWx0XG4gICAgICAgICAgICA6IG11bHRpc2lnVHlwZVZlcnNpb24gPT09ICdNUEN2MidcbiAgICAgICAgICAgID8gRUNEU0FVdGlscy5FY2RzYU1QQ3YyVXRpbHNcbiAgICAgICAgICAgIDogRUNEU0FVdGlscy5FY2RzYVV0aWxzO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVW5zdXBwb3J0ZWQgbXVsdGktc2lnIHR5cGUnKTtcbiAgICB9XG4gICAgY29uc3QgbXBjVXRpbHMgPSBuZXcgTXBjVXRpbHModGhpcy5iaXRnbywgdGhpcy5iYXNlQ29pbik7XG4gICAgcmV0dXJuIGF3YWl0IG1wY1V0aWxzLmNyZWF0ZUtleWNoYWlucyh7XG4gICAgICBwYXNzcGhyYXNlOiBwYXJhbXMucGFzc3BocmFzZSxcbiAgICAgIGVudGVycHJpc2U6IHBhcmFtcy5lbnRlcnByaXNlLFxuICAgICAgb3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlOiBwYXJhbXMub3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlLFxuICAgICAgcmV0cm9maXQ6IHBhcmFtcy5yZXRyb2ZpdCxcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIHJlY3JlYXRlTXBjKHBhcmFtczogUmVjcmVhdGVNcGNPcHRpb25zKTogUHJvbWlzZTxLZXljaGFpbnNUcmlwbGV0PiB7XG4gICAgYXNzZXJ0KHBhcmFtcy5jb2luLCBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcGFyYW0gY29pbicpKTtcbiAgICBhc3NlcnQocGFyYW1zLndhbGxldElkLCBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcGFyYW0gd2FsbGV0SWQnKSk7XG4gICAgYXNzZXJ0KHBhcmFtcy5vdHAsIG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCBwYXJhbSBvdHAnKSk7XG4gICAgYXNzZXJ0KHBhcmFtcy5wYXNzcGhyYXNlLCBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcGFyYW0gcGFzc3BocmFzZScpKTtcblxuICAgIGFzc2VydChcbiAgICAgIHBhcmFtcy5lbmNyeXB0ZWRNYXRlcmlhbC5lbmNyeXB0ZWRXYWxsZXRQYXNzcGhyYXNlLFxuICAgICAgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHBhcmFtIGVuY3J5cHRlZFdhbGxldFBhc3NwaHJhc2UnKVxuICAgICk7XG4gICAgYXNzZXJ0KHBhcmFtcy5lbmNyeXB0ZWRNYXRlcmlhbC5lbmNyeXB0ZWRVc2VyS2V5LCBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgcGFyYW0gZW5jcnlwdGVkVXNlcktleScpKTtcbiAgICBhc3NlcnQocGFyYW1zLmVuY3J5cHRlZE1hdGVyaWFsLmVuY3J5cHRlZEJhY2t1cEtleSwgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHBhcmFtIGVuY3J5cHRlZEJhY2t1cEtleScpKTtcblxuICAgIGF3YWl0IHRoaXMuYml0Z28ucG9zdCh0aGlzLmJpdGdvLm1pY3Jvc2VydmljZXNVcmwoJy9hcGkvdjEvdXNlci91bmxvY2snKSkuc2VuZCh7IG90cDogcGFyYW1zLm90cCB9KS5yZXN1bHQoKTtcbiAgICBjb25zdCB7IHJlY292ZXJ5SW5mbyB9ID0gYXdhaXQgdGhpcy5iaXRnb1xuICAgICAgLnBvc3QodGhpcy5iaXRnby5taWNyb3NlcnZpY2VzVXJsKGAvYXBpL3YyLyR7cGFyYW1zLmNvaW59L3dhbGxldC8ke3BhcmFtcy53YWxsZXRJZH0vcGFzc2NvZGVyZWNvdmVyeWApKVxuICAgICAgLnJlc3VsdCgpO1xuXG4gICAgaWYgKCFyZWNvdmVyeUluZm8gfHwgISgncGFzc2NvZGVFbmNyeXB0aW9uQ29kZScgaW4gcmVjb3ZlcnlJbmZvKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdmYWlsZWQgdG8gZ2V0IHJlY292ZXJ5IGluZm8nKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWNyeXB0ZWRXYWxsZXRQYXNzcGhyYXNlID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgIGlucHV0OiBwYXJhbXMuZW5jcnlwdGVkTWF0ZXJpYWwuZW5jcnlwdGVkV2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIHBhc3N3b3JkOiByZWNvdmVyeUluZm8ucGFzc2NvZGVFbmNyeXB0aW9uQ29kZSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGRlY3J5cHRlZFVzZXJLZXkgPSB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgaW5wdXQ6IHBhcmFtcy5lbmNyeXB0ZWRNYXRlcmlhbC5lbmNyeXB0ZWRVc2VyS2V5LFxuICAgICAgcGFzc3dvcmQ6IGRlY3J5cHRlZFdhbGxldFBhc3NwaHJhc2UsXG4gICAgfSk7XG5cbiAgICBjb25zdCBkZWNyeXB0ZWRCYWNrdXBLZXkgPSB0aGlzLmJpdGdvLmRlY3J5cHQoe1xuICAgICAgaW5wdXQ6IHBhcmFtcy5lbmNyeXB0ZWRNYXRlcmlhbC5lbmNyeXB0ZWRCYWNrdXBLZXksXG4gICAgICBwYXNzd29yZDogZGVjcnlwdGVkV2FsbGV0UGFzc3BocmFzZSxcbiAgICB9KTtcblxuICAgIHJldHVybiB0aGlzLmNyZWF0ZU1wYyh7XG4gICAgICAuLi5wYXJhbXMsXG4gICAgICBtdWx0aXNpZ1R5cGU6ICd0c3MnLFxuICAgICAgcmV0cm9maXQ6IHtcbiAgICAgICAgZGVjcnlwdGVkVXNlcktleSxcbiAgICAgICAgZGVjcnlwdGVkQmFja3VwS2V5LFxuICAgICAgICB3YWxsZXRJZDogcGFyYW1zLndhbGxldElkLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJdCBwYXJzZXMgdGhlIEpTT04gZG93bmxvYWRlZCBmcm9tIHRoZSBPVkMgZm9yIHBsYXRmb3JtIChCaXRHbyksXG4gICAqIGFuZCBjcmVhdGVzIGEgY29ycmVzcG9uZGluZyBUU1MgQml0R28ga2V5LiBJdCBhbHNvIHJldHVybnMgdGhlIEpTT04gdGhhdCBuZWVkc1xuICAgKiB0byBiZSB1cGxvYWRlZCBiYWNrIHRvIHRoZSBPVkNzIGNvbnRhaW5pbmcgdGhlIEJpdEdvIC0+IE9WQyBzaGFyZXMuXG4gICAqIEBwYXJhbSBvdmNPdXRwdXRKc29uIEpTT04gZm9ybWF0IG9mIHRoZSBmaWxlIGRvd25sb2FkZWQgZnJvbSB0aGUgT1ZDIGZvciBwbGF0Zm9ybVxuICAgKiBAcGFyYW0gZW50ZXJwcmlzZSBPcHRpb25hbCBlbnRlcnByaXNlIElEIGFzc29jaWF0ZWQgd2l0aCB0aGUga2V5XG4gICAqIEByZXR1cm5zIHtCaXRHb0tleUZyb21PdmNTaGFyZXN9XG4gICAqL1xuICBhc3luYyBjcmVhdGVUc3NCaXRHb0tleUZyb21PdmNTaGFyZXMob3ZjT3V0cHV0SnNvbjogdW5rbm93biwgZW50ZXJwcmlzZT86IHN0cmluZyk6IFByb21pc2U8Qml0R29LZXlGcm9tT3ZjU2hhcmVzPiB7XG4gICAgY29uc3QgZGVjb2RlZE92Y091dHB1dCA9IGRlY29kZU9yRWxzZShPdmNUb0JpdEdvSlNPTi5uYW1lLCBPdmNUb0JpdEdvSlNPTiwgb3ZjT3V0cHV0SnNvbiwgKGVycm9ycykgPT4ge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvcihzKSBwYXJzaW5nIE9WQyBKU09OOiAke2Vycm9yc31gKTtcbiAgICB9KTtcblxuICAgIGlmIChkZWNvZGVkT3ZjT3V0cHV0LnN0YXRlICE9PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1N0YXRlIGV4cGVjdGVkIHRvIGJlIFwiMVwiLiBQbGVhc2UgY29tcGxldGUgdGhlIGZpcnN0IHR3byBPVkMgb3BlcmF0aW9ucycpO1xuICAgIH1cblxuICAgIC8vIE9WQy0xIGlzIHJlc3BvbnNpYmxlIGZvciB0aGUgVXNlciBrZXlcbiAgICBjb25zdCBvdmMxID0gZGVjb2RlZE92Y091dHB1dC5vdmNbMV07XG4gICAgLy8gT1ZDLTIgaXMgcmVzcG9uc2libGUgZm9yIHRoZSBCYWNrdXAga2V5XG4gICAgY29uc3Qgb3ZjMiA9IGRlY29kZWRPdmNPdXRwdXQub3ZjWzJdO1xuXG4gICAgY29uc3Qga2V5U2hhcmVzOiBBcGlLZXlTaGFyZVtdID0gW1xuICAgICAge1xuICAgICAgICBmcm9tOiAndXNlcicsXG4gICAgICAgIHRvOiAnYml0Z28nLFxuICAgICAgICBwdWJsaWNTaGFyZTogb3ZjMS5vdmNUb0JpdGdvU2hhcmUucHVibGljU2hhcmUsXG4gICAgICAgIHByaXZhdGVTaGFyZTogb3ZjMS5vdmNUb0JpdGdvU2hhcmUucHJpdmF0ZVNoYXJlLFxuICAgICAgICBwcml2YXRlU2hhcmVQcm9vZjogb3ZjMS5vdmNUb0JpdGdvU2hhcmUudVNpZy50b1N0cmluZygpID8/ICcnLFxuICAgICAgICB2c3NQcm9vZjogb3ZjMS5vdmNUb0JpdGdvU2hhcmUudnNzUHJvb2YgPz8gJycsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBmcm9tOiAnYmFja3VwJyxcbiAgICAgICAgdG86ICdiaXRnbycsXG4gICAgICAgIHB1YmxpY1NoYXJlOiBvdmMyLm92Y1RvQml0Z29TaGFyZS5wdWJsaWNTaGFyZSxcbiAgICAgICAgcHJpdmF0ZVNoYXJlOiBvdmMyLm92Y1RvQml0Z29TaGFyZS5wcml2YXRlU2hhcmUsXG4gICAgICAgIHByaXZhdGVTaGFyZVByb29mOiBvdmMyLm92Y1RvQml0Z29TaGFyZS51U2lnLnRvU3RyaW5nKCkgPz8gJycsXG4gICAgICAgIHZzc1Byb29mOiBvdmMyLm92Y1RvQml0Z29TaGFyZS52c3NQcm9vZiA/PyAnJyxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGNvbnN0IGtleSA9IGF3YWl0IHRoaXMuYmFzZUNvaW4ua2V5Y2hhaW5zKCkuYWRkKHtcbiAgICAgIHNvdXJjZTogJ2JpdGdvJyxcbiAgICAgIGtleVNoYXJlcyxcbiAgICAgIGtleVR5cGU6ICd0c3MnLFxuICAgICAgdXNlckdQR1B1YmxpY0tleTogb3ZjMS5ncGdQdWJLZXksXG4gICAgICBiYWNrdXBHUEdQdWJsaWNLZXk6IG92YzIuZ3BnUHViS2V5LFxuICAgICAgZW50ZXJwcmlzZSxcbiAgICB9KTtcbiAgICBhc3NlcnQoa2V5LmtleVNoYXJlcyk7XG4gICAgYXNzZXJ0KGtleS5jb21tb25LZXljaGFpbik7XG4gICAgYXNzZXJ0KGtleS53YWxsZXRIU01HUEdQdWJsaWNLZXlTaWdzKTtcblxuICAgIGNvbnN0IGJpdGdvVG9Vc2VyU2hhcmUgPSBrZXkua2V5U2hhcmVzLmZpbmQoXG4gICAgICAodmFsdWU6IHsgZnJvbTogc3RyaW5nOyB0bzogc3RyaW5nIH0pID0+IHZhbHVlLmZyb20gPT09ICdiaXRnbycgJiYgdmFsdWUudG8gPT09ICd1c2VyJ1xuICAgICk7XG4gICAgYXNzZXJ0KGJpdGdvVG9Vc2VyU2hhcmUpO1xuICAgIGFzc2VydChiaXRnb1RvVXNlclNoYXJlLnZzc1Byb29mKTtcbiAgICBhc3NlcnQoYml0Z29Ub1VzZXJTaGFyZS5wYWlsbGllclB1YmxpY0tleSk7XG4gICAgY29uc3QgYml0Z29Ub0JhY2t1cFNoYXJlID0ga2V5LmtleVNoYXJlcy5maW5kKFxuICAgICAgKHZhbHVlOiB7IGZyb206IHN0cmluZzsgdG86IHN0cmluZyB9KSA9PiB2YWx1ZS5mcm9tID09PSAnYml0Z28nICYmIHZhbHVlLnRvID09PSAnYmFja3VwJ1xuICAgICk7XG4gICAgYXNzZXJ0KGJpdGdvVG9CYWNrdXBTaGFyZSk7XG4gICAgYXNzZXJ0KGJpdGdvVG9CYWNrdXBTaGFyZS52c3NQcm9vZik7XG4gICAgYXNzZXJ0KGJpdGdvVG9CYWNrdXBTaGFyZS5wYWlsbGllclB1YmxpY0tleSk7XG5cbiAgICAvLyBDcmVhdGUgSlNPTiBkYXRhIHdpdGggcGxhdGZvcm0gc2hhcmVzIGZvciBPVkMtMSBhbmQgT1ZDLTJcbiAgICBjb25zdCBiaXRnb1RvT3ZjT3V0cHV0OiBCaXRHb1RvT3ZjSlNPTiA9IHtcbiAgICAgIHdhbGxldDoge1xuICAgICAgICAuLi5kZWNvZGVkT3ZjT3V0cHV0LFxuICAgICAgICBwbGF0Zm9ybToge1xuICAgICAgICAgIGNvbW1vbktleWNoYWluOiBrZXkuY29tbW9uS2V5Y2hhaW4sXG4gICAgICAgICAgd2FsbGV0R3BnUHViS2V5U2lnczoga2V5LndhbGxldEhTTUdQR1B1YmxpY0tleVNpZ3MsXG4gICAgICAgICAgb3ZjOiB7XG4gICAgICAgICAgICAvLyBCaXRHbyB0byBVc2VyIChPVkMtMSlcbiAgICAgICAgICAgIDE6IHtcbiAgICAgICAgICAgICAgYml0Z29Ub092Y1NoYXJlOiB7XG4gICAgICAgICAgICAgICAgaTogMSxcbiAgICAgICAgICAgICAgICBqOiAzLFxuICAgICAgICAgICAgICAgIHB1YmxpY1NoYXJlOiBiaXRnb1RvVXNlclNoYXJlLnB1YmxpY1NoYXJlLFxuICAgICAgICAgICAgICAgIHByaXZhdGVTaGFyZTogYml0Z29Ub1VzZXJTaGFyZS5wcml2YXRlU2hhcmUsXG4gICAgICAgICAgICAgICAgcGFpbGxpZXJQdWJsaWNLZXk6IGJpdGdvVG9Vc2VyU2hhcmUucGFpbGxpZXJQdWJsaWNLZXksXG4gICAgICAgICAgICAgICAgdnNzUHJvb2Y6IGJpdGdvVG9Vc2VyU2hhcmUudnNzUHJvb2YsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgLy8gQml0R28gdG8gQmFja3VwIChPVkMtMilcbiAgICAgICAgICAgIDI6IHtcbiAgICAgICAgICAgICAgYml0Z29Ub092Y1NoYXJlOiB7XG4gICAgICAgICAgICAgICAgaTogMixcbiAgICAgICAgICAgICAgICBqOiAzLFxuICAgICAgICAgICAgICAgIHB1YmxpY1NoYXJlOiBiaXRnb1RvQmFja3VwU2hhcmUucHVibGljU2hhcmUsXG4gICAgICAgICAgICAgICAgcHJpdmF0ZVNoYXJlOiBiaXRnb1RvQmFja3VwU2hhcmUucHJpdmF0ZVNoYXJlLFxuICAgICAgICAgICAgICAgIHBhaWxsaWVyUHVibGljS2V5OiBiaXRnb1RvQmFja3VwU2hhcmUucGFpbGxpZXJQdWJsaWNLZXksXG4gICAgICAgICAgICAgICAgdnNzUHJvb2Y6IGJpdGdvVG9CYWNrdXBTaGFyZS52c3NQcm9vZixcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIC8vIE1hcmsgaXQgcmVhZHkgZm9yIG5leHQgb3BlcmF0aW9uLCBzaG91bGQgYmUgMlxuICAgIGJpdGdvVG9PdmNPdXRwdXQud2FsbGV0LnN0YXRlICs9IDE7XG5cbiAgICBjb25zdCBvdXRwdXQ6IEJpdEdvS2V5RnJvbU92Y1NoYXJlcyA9IHtcbiAgICAgIGJpdEdvS2V5SWQ6IGtleS5pZCxcbiAgICAgIGJpdEdvT3V0cHV0SnNvbkZvck92YzogYml0Z29Ub092Y091dHB1dCxcbiAgICB9O1xuXG4gICAgcmV0dXJuIGRlY29kZU9yRWxzZShCaXRHb0tleUZyb21PdmNTaGFyZXMubmFtZSwgQml0R29LZXlGcm9tT3ZjU2hhcmVzLCBvdXRwdXQsIChlcnJvcnMpID0+IHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgcHJvZHVjaW5nIHRoZSBvdXRwdXQ6ICR7ZXJyb3JzfWApO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSB1c2VyIGtleWNoYWluLCBlbmNyeXB0IHRoZSBwcml2YXRlIGtleSB3aXRoIHRoZSB3YWxsZXQgcGFzc3BocmFzZSBhbmQgc3RvcmUgaXQgaW4gQml0R28uXG4gICAqIEBwYXJhbSB3YWxsZXRQYXNzcGhyYXNlXG4gICAqIEByZXR1cm5zIEtleWNoYWluIGluY2x1ZGluZyB0aGUgZGVjcnlwdGVkIHByaXZhdGUga2V5XG4gICAqL1xuICBhc3luYyBjcmVhdGVVc2VyS2V5Y2hhaW4od2FsbGV0UGFzc3BocmFzZTogc3RyaW5nKTogUHJvbWlzZTxLZXljaGFpbj4ge1xuICAgIGNvbnN0IGtleWNoYWlucyA9IHRoaXMuYmFzZUNvaW4ua2V5Y2hhaW5zKCk7XG4gICAgY29uc3QgbmV3S2V5Y2hhaW4gPSBrZXljaGFpbnMuY3JlYXRlKCk7XG4gICAgY29uc3Qgb3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlID0gZ2VuZXJhdGVSYW5kb21QYXNzd29yZCg1KTtcblxuICAgIGNvbnN0IGVuY3J5cHRlZFBydiA9IHRoaXMuYml0Z28uZW5jcnlwdCh7XG4gICAgICBwYXNzd29yZDogd2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIGlucHV0OiBuZXdLZXljaGFpbi5wcnYsXG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uKGF3YWl0IGtleWNoYWlucy5hZGQoe1xuICAgICAgICBlbmNyeXB0ZWRQcnYsXG4gICAgICAgIG9yaWdpbmFsUGFzc2NvZGVFbmNyeXB0aW9uQ29kZSxcbiAgICAgICAgcHViOiBuZXdLZXljaGFpbi5wdWIsXG4gICAgICAgIHNvdXJjZTogJ3VzZXInLFxuICAgICAgfSkpLFxuICAgICAgcHJ2OiBuZXdLZXljaGFpbi5wcnYsXG4gICAgfTtcbiAgfVxufVxuIl19

Выполнить команду


Для локальной разработки. Не используйте в интернете!