bitgo
Version:
BitGo JavaScript SDK
329 lines • 59.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
const nock = require("nock");
const openpgp = require("openpgp");
const cbor_x_1 = require("cbor-x");
const sdk_test_1 = require("@bitgo/sdk-test");
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const src_1 = require("../../../../../../src");
const SAFE_ID = '6fa8537e3ef5a878fd3ae899f3ab7e5a';
const USER_ROOT_KEY_ID = 'root-user-key-id';
const DERIVATION_INDEX = 0;
const BITGO_ROOT_KEY_ID = 'root-bitgo-key-id';
const BACKUP_ROOT_KEY_ID = 'root-backup-key-id';
const PATH_M0 = new Uint8Array([0x80, 0x00, 0x00, 0x00]);
describe('TSS ECDSA safe child keychains (user/BitGo hard derive):', async function () {
const coinName = 'hteth';
const enterpriseId = '6449153a6f6bc20006d66771cdbe15d3';
let bgUrl;
let bitgo;
let tssUtils;
let wallet;
let bitGoGpgKey;
let constants;
let bitgoGpgPrvKey;
let userGpgPubKey;
let stagedBitgoMsg2;
before(async function () {
openpgp.config.rejectCurves = new Set();
bitGoGpgKey = await openpgp.generateKey({
userIDs: [{ name: 'bitgo', email: 'bitgo@test.com' }],
curve: 'secp256k1',
});
constants = {
mpc: {
bitgoPublicKey: bitGoGpgKey.publicKey,
bitgoMPCv2PublicKey: bitGoGpgKey.publicKey,
},
};
bitgoGpgPrvKey = { partyId: 2, gpgKey: bitGoGpgKey.privateKey };
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
const baseCoin = bitgo.coin(coinName);
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, {
id: '5b34252f1bf349930e34020a00000000',
enterprise: enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
});
tssUtils = new sdk_core_1.ECDSAUtils.EcdsaVrfMPCv2Utils(bitgo, baseCoin, wallet);
});
beforeEach(async function () {
nock.cleanAll();
stagedBitgoMsg2 = undefined;
await nockGetBitgoPublicKeyBasedOnFeatureFlags(coinName, enterpriseId, bitGoGpgKey);
nock(bgUrl).get('/api/v1/client/constants').times(32).reply(200, { ttl: 3600, constants });
});
after(function () {
nock.cleanAll();
});
it('should derive the user child and register the backup without encryptedPrv', async function () {
const [userRoot, , bitgoRoot] = await sdk_lib_mpc_1.DklsUtils.generateDKGKeyShares();
const [vrfUser, , vrfBitgo] = await sdk_lib_mpc_1.DklsVrfUtils.generateVrfDKGKeyShares();
const bitgoPair = new sdk_lib_mpc_1.DklsDrv.Derive(3, 2, 2, bitgoRoot.getKeyShare(), vrfBitgo.getKeyShare(), PATH_M0);
const round1Nock = await nockDeriveRound1(bitgoPair);
const round2Nock = await nockDeriveRound2(bitgoPair);
const round3Nock = await nockDeriveRound3(bitgoPair);
const addKeyNock = await nockAddChildKey(coinName);
const { userKeychain, backupKeychain, bitgoKeychain } = await tssUtils.createSafeChildKeychains({
passphrase: 'test',
enterprise: enterpriseId,
safeId: SAFE_ID,
parentKeyId: BITGO_ROOT_KEY_ID,
derivationIndex: DERIVATION_INDEX,
userRootKeyId: USER_ROOT_KEY_ID,
backupRootKeyId: BACKUP_ROOT_KEY_ID,
userRootKeyShare: userRoot.getKeyShare(),
userRootVrfKeyShare: vrfUser.getKeyShare(),
});
assert.ok(round1Nock.isDone());
assert.ok(round2Nock.isDone());
assert.ok(round3Nock.isDone());
assert.ok(addKeyNock.isDone());
assert.equal(userKeychain.commonKeychain, backupKeychain.commonKeychain);
assert.equal(bitgoKeychain.commonKeychain, userKeychain.commonKeychain);
assert.equal(bitgoKeychain.source, 'bitgo');
assert.equal(bitgoKeychain.encryptedPrv, undefined);
assert.equal(userKeychain.commonKeychain, sdk_lib_mpc_1.DklsTypes.getCommonKeychain(bitgoPair.getKeyShare()));
const encryptedUserPrv = userKeychain.encryptedPrv;
assert.ok(encryptedUserPrv);
assert.equal(backupKeychain.encryptedPrv, undefined);
const decryptedUserPrv = await bitgo.decrypt({ input: encryptedUserPrv, password: 'test' });
const userChildShare = (0, cbor_x_1.decode)(Buffer.from(decryptedUserPrv, 'base64'));
assert.equal(userChildShare.version, undefined);
assert.equal(userChildShare.vrf, undefined);
assert.equal(userChildShare.party_id, 0);
assert.ok(userChildShare.s_i);
});
it('should derive at a non-zero hardened index and agree with the server', async function () {
const idx = 7;
const path = new Uint8Array([0x80 | (idx >>> 24), 0, 0, idx]);
const [userRoot, , bitgoRoot] = await sdk_lib_mpc_1.DklsUtils.generateDKGKeyShares();
const [vrfUser, , vrfBitgo] = await sdk_lib_mpc_1.DklsVrfUtils.generateVrfDKGKeyShares();
const bitgoPair = new sdk_lib_mpc_1.DklsDrv.Derive(3, 2, 2, bitgoRoot.getKeyShare(), vrfBitgo.getKeyShare(), path);
const round1Nock = await nockDeriveRound1(bitgoPair, 1, idx);
const round2Nock = await nockDeriveRound2(bitgoPair);
const round3Nock = await nockDeriveRound3(bitgoPair);
const addKeyNock = await nockAddChildKey(coinName, 3, idx);
const { userKeychain, backupKeychain, bitgoKeychain } = await tssUtils.createSafeChildKeychains({
passphrase: 'test',
enterprise: enterpriseId,
safeId: SAFE_ID,
parentKeyId: BITGO_ROOT_KEY_ID,
derivationIndex: idx,
userRootKeyId: USER_ROOT_KEY_ID,
backupRootKeyId: BACKUP_ROOT_KEY_ID,
userRootKeyShare: userRoot.getKeyShare(),
userRootVrfKeyShare: vrfUser.getKeyShare(),
});
assert.ok(round1Nock.isDone());
assert.ok(round2Nock.isDone());
assert.ok(round3Nock.isDone());
assert.ok(addKeyNock.isDone());
assert.equal(userKeychain.commonKeychain, backupKeychain.commonKeychain);
assert.equal(bitgoKeychain.commonKeychain, userKeychain.commonKeychain);
});
it('registers the BitGo child placeholder with the hardened path and no private material', async function () {
const [userRoot, , bitgoRoot] = await sdk_lib_mpc_1.DklsUtils.generateDKGKeyShares();
const [vrfUser, , vrfBitgo] = await sdk_lib_mpc_1.DklsVrfUtils.generateVrfDKGKeyShares();
const bitgoPair = new sdk_lib_mpc_1.DklsDrv.Derive(3, 2, 2, bitgoRoot.getKeyShare(), vrfBitgo.getKeyShare(), PATH_M0);
await nockDeriveRound1(bitgoPair);
await nockDeriveRound2(bitgoPair);
await nockDeriveRound3(bitgoPair);
const addKeyBodies = [];
nock('https://bitgo.fakeurl')
.post(`/api/v2/${coinName}/key`)
.times(3)
.reply(200, (uri, requestBody) => {
addKeyBodies.push(requestBody);
return { id: requestBody.source, source: requestBody.source, commonKeychain: requestBody.commonKeychain };
});
const { bitgoKeychain } = await tssUtils.createSafeChildKeychains({
passphrase: 'test',
enterprise: enterpriseId,
safeId: SAFE_ID,
parentKeyId: BITGO_ROOT_KEY_ID,
derivationIndex: DERIVATION_INDEX,
userRootKeyId: USER_ROOT_KEY_ID,
backupRootKeyId: BACKUP_ROOT_KEY_ID,
userRootKeyShare: userRoot.getKeyShare(),
userRootVrfKeyShare: vrfUser.getKeyShare(),
});
const userBody = addKeyBodies.find((body) => body.source === 'user');
assert.ok(userBody, 'expected a user child registration');
const bitgoBody = addKeyBodies.find((body) => body.source === 'bitgo');
assert.ok(bitgoBody, 'expected a bitgo child registration');
// Same common keychain across all three child registrations.
assert.equal(bitgoBody.commonKeychain, userBody.commonKeychain);
assert.equal(bitgoBody.commonKeychain, bitgoKeychain.commonKeychain);
// All child paths are hardened.
assert.equal(userBody.derivedFromParentWithPath, "m/0'");
assert.equal(userBody.parent, USER_ROOT_KEY_ID);
const backupBody = addKeyBodies.find((body) => body.source === 'backup');
assert.ok(backupBody, 'expected a backup child registration');
assert.equal(backupBody.derivedFromParentWithPath, "m/0'");
assert.equal(backupBody.parent, BACKUP_ROOT_KEY_ID);
// Exact wire body: public-only placeholder with no private material.
assert.deepEqual(bitgoBody, {
source: 'bitgo',
keyType: 'tss',
isMPCv2: true,
commonKeychain: userBody.commonKeychain,
safeId: SAFE_ID,
parent: BITGO_ROOT_KEY_ID,
derivedFromParentWithPath: "m/0'",
});
});
it('should reject root key material that is not a valid VRF envelope', async function () {
const [, , bitgoRoot] = await sdk_lib_mpc_1.DklsUtils.generateDKGKeyShares();
const [, , vrfBitgo] = await sdk_lib_mpc_1.DklsVrfUtils.generateVrfDKGKeyShares();
const bitgoPair = new sdk_lib_mpc_1.DklsDrv.Derive(3, 2, 2, bitgoRoot.getKeyShare(), vrfBitgo.getKeyShare(), PATH_M0);
const round1Nock = await nockDeriveRound1(bitgoPair);
const round2Nock = await nockDeriveRound2(bitgoPair);
const round3Nock = await nockDeriveRound3(bitgoPair);
await assert.rejects(() => tssUtils.createSafeChildKeychains({
passphrase: 'test',
enterprise: enterpriseId,
safeId: SAFE_ID,
parentKeyId: BITGO_ROOT_KEY_ID,
derivationIndex: DERIVATION_INDEX,
userRootKeyId: USER_ROOT_KEY_ID,
backupRootKeyId: BACKUP_ROOT_KEY_ID,
userRootKeyShare: Buffer.from('garbage'),
userRootVrfKeyShare: vrfBitgo.getKeyShare(),
}), /CBOR decode|does not match root key share partyId|VRF keyshare/i);
assert.ok(!round1Nock.isDone(), 'round 1 must not be sent for invalid root material');
assert.ok(!round2Nock.isDone(), 'round 2 must not be sent for invalid root material');
assert.ok(!round3Nock.isDone(), 'round 3 must not be sent for invalid root material');
});
it('should reject a root blob with a VRF partyId mismatch', async function () {
const [userRoot, , bitgoRoot] = await sdk_lib_mpc_1.DklsUtils.generateDKGKeyShares();
const [, vrfBackup, vrfBitgo] = await sdk_lib_mpc_1.DklsVrfUtils.generateVrfDKGKeyShares();
const bitgoPair = new sdk_lib_mpc_1.DklsDrv.Derive(3, 2, 2, bitgoRoot.getKeyShare(), vrfBitgo.getKeyShare(), PATH_M0);
const round1Nock = await nockDeriveRound1(bitgoPair);
const round2Nock = await nockDeriveRound2(bitgoPair);
const round3Nock = await nockDeriveRound3(bitgoPair);
await assert.rejects(() => tssUtils.createSafeChildKeychains({
passphrase: 'test',
enterprise: enterpriseId,
safeId: SAFE_ID,
parentKeyId: BITGO_ROOT_KEY_ID,
derivationIndex: DERIVATION_INDEX,
userRootKeyId: USER_ROOT_KEY_ID,
backupRootKeyId: BACKUP_ROOT_KEY_ID,
userRootKeyShare: userRoot.getKeyShare(),
userRootVrfKeyShare: vrfBackup.getKeyShare(),
}), /does not match VRF key share partyId/);
assert.ok(!round1Nock.isDone(), 'round 1 must not be sent for mismatched VRF material');
assert.ok(!round2Nock.isDone(), 'round 2 must not be sent for mismatched VRF material');
assert.ok(!round3Nock.isDone(), 'round 3 must not be sent for mismatched VRF material');
});
async function nockGetBitgoPublicKeyBasedOnFeatureFlags(coin, enterpriseId, bitgoGpgKeyPair) {
const bitgoGPGPublicKeyResponse = {
name: 'irrelevant',
publicKey: bitgoGpgKeyPair.publicKey,
mpcv2PublicKey: bitgoGpgKeyPair.publicKey,
enterpriseId,
};
nock(bgUrl).get(`/api/v2/${coin}/tss/pubkey`).query({ enterpriseId }).reply(200, bitgoGPGPublicKeyResponse);
return bitgoGPGPublicKeyResponse;
}
async function nockDeriveRound1(bitgoPair, times = 1, index = DERIVATION_INDEX) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2Derive-R1' &&
body.safeId === SAFE_ID &&
body.payload?.parentKeyId === BITGO_ROOT_KEY_ID &&
body.payload?.derivationIndex === index &&
body.payload?.userGpgPublicKey &&
body.payload?.userMsg1 &&
body.payload?.backupGpgPublicKey === undefined &&
body.payload?.backupMsg1 === undefined)
.times(times)
.reply(200, async (uri, requestBody) => {
const { userGpgPublicKey, userMsg1 } = requestBody.payload;
userGpgPubKey = { partyId: 0, gpgKey: userGpgPublicKey };
await sdk_lib_mpc_1.DklsComms.decryptAndVerifyIncomingMessages({
p2pMessages: [],
broadcastMessages: [{ from: 0, payload: { message: userMsg1.message, signature: userMsg1.signature } }],
}, [userGpgPubKey], []);
const bitgoMsg1Unsigned = await bitgoPair.initDerive();
const bitgoMsg2 = bitgoPair.handleIncomingMessages({
p2pMessages: [],
broadcastMessages: [{ payload: Buffer.from(userMsg1.message, 'base64'), from: 0 }],
});
const signedStagedMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages({
broadcastMessages: [sdk_lib_mpc_1.DklsTypes.serializeBroadcastMessage(bitgoMsg2.broadcastMessages[0])],
p2pMessages: [],
}, [], [bitgoGpgPrvKey]);
stagedBitgoMsg2 = signedStagedMessages.broadcastMessages[0].payload;
const signedMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages({
broadcastMessages: [sdk_lib_mpc_1.DklsTypes.serializeBroadcastMessage(bitgoMsg1Unsigned)],
p2pMessages: [],
}, [], [bitgoGpgPrvKey]);
const bitgoMsg1 = signedMessages.broadcastMessages[0];
assert.ok(bitgoMsg1, 'bitgoMsg1 not found');
return {
sessionId: 'testid',
bitgoMsg1: { from: 2, ...bitgoMsg1.payload },
};
});
}
async function nockDeriveRound2(bitgoPair, times = 1) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2Derive-R2' &&
body.safeId === SAFE_ID &&
body.payload?.sessionId === 'testid' &&
body.payload?.userMsg2 &&
body.payload?.backupMsg2 === undefined)
.times(times)
.reply(200, async (uri, requestBody) => {
const { sessionId, userMsg2 } = requestBody.payload;
await sdk_lib_mpc_1.DklsComms.decryptAndVerifyIncomingMessages({
p2pMessages: [],
broadcastMessages: [{ from: 0, payload: { message: userMsg2.message, signature: userMsg2.signature } }],
}, [userGpgPubKey], []);
bitgoPair.handleIncomingMessages({
p2pMessages: [],
broadcastMessages: [{ payload: Buffer.from(userMsg2.message, 'base64'), from: 0 }],
});
assert.ok(stagedBitgoMsg2, 'staged BitGo msg2 missing');
return { sessionId, bitgoMsg2: { from: 2, ...stagedBitgoMsg2 } };
});
}
async function nockDeriveRound3(bitgoPair, times = 1) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2Derive-R3' && body.safeId === SAFE_ID && body.payload?.sessionId === 'testid')
.times(times)
.reply(200, async (uri, requestBody) => {
const { sessionId } = requestBody.payload;
return {
sessionId,
commonKeychain: sdk_lib_mpc_1.DklsTypes.getCommonKeychain(bitgoPair.getKeyShare()),
};
});
}
/**
* Nocks the hardened child key registrations.
*/
async function nockAddChildKey(coin, times = 3, index = DERIVATION_INDEX) {
return nock('https://bitgo.fakeurl')
.post(`/api/v2/${coin}/key`, (body) => body.keyType === 'tss' &&
body.isMPCv2 === true &&
body.safeId === SAFE_ID &&
!!body.parent &&
body.derivedFromParentWithPath === `m/${index}'`)
.times(times)
.reply(200, (uri, requestBody) => ({
id: requestBody.source,
source: requestBody.source,
type: requestBody.keyType,
commonKeychain: requestBody.commonKeychain,
encryptedPrv: requestBody.encryptedPrv,
}));
}
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlU2FmZUNoaWxkS2V5Y2hhaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2ludGVybmFsL3Rzc1V0aWxzL2VjZHNhVnJmTVBDdjIvY3JlYXRlU2FmZUNoaWxkS2V5Y2hhaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLDZCQUE4QjtBQUM5QixtQ0FBbUM7QUFDbkMsbUNBQWdDO0FBRWhDLDhDQUF3RDtBQUN4RCw4Q0FBaUY7QUFDakYsb0RBQTRGO0FBRzVGLCtDQUFpRTtBQUVqRSxNQUFNLE9BQU8sR0FBRyxrQ0FBa0MsQ0FBQztBQUNuRCxNQUFNLGdCQUFnQixHQUFHLGtCQUFrQixDQUFDO0FBQzVDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDO0FBQzNCLE1BQU0saUJBQWlCLEdBQUcsbUJBQW1CLENBQUM7QUFDOUMsTUFBTSxrQkFBa0IsR0FBRyxvQkFBb0IsQ0FBQztBQUNoRCxNQUFNLE9BQU8sR0FBRyxJQUFJLFVBQVUsQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7QUFFekQsUUFBUSxDQUFDLDBEQUEwRCxFQUFFLEtBQUs7SUFDeEUsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLE1BQU0sWUFBWSxHQUFHLGtDQUFrQyxDQUFDO0lBQ3hELElBQUksS0FBYSxDQUFDO0lBQ2xCLElBQUksS0FBeUIsQ0FBQztJQUM5QixJQUFJLFFBQXVDLENBQUM7SUFDNUMsSUFBSSxNQUFjLENBQUM7SUFDbkIsSUFBSSxXQUVILENBQUM7SUFDRixJQUFJLFNBQTJFLENBQUM7SUFDaEYsSUFBSSxjQUFtRCxDQUFDO0lBQ3hELElBQUksYUFBa0QsQ0FBQztJQUN2RCxJQUFJLGVBQW1FLENBQUM7SUFFeEUsTUFBTSxDQUFDLEtBQUs7UUFDVixPQUFPLENBQUMsTUFBTSxDQUFD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QUMsWUFBWTtTQUN2QyxDQUFDLENBQUMsQ0FBQztJQUNSLENBQUM7QUFDSCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0IG5vY2sgPSByZXF1aXJlKCdub2NrJyk7XG5pbXBvcnQgKiBhcyBvcGVucGdwIGZyb20gJ29wZW5wZ3AnO1xuaW1wb3J0IHsgZGVjb2RlIH0gZnJvbSAnY2Jvci14JztcblxuaW1wb3J0IHsgVGVzdGFibGVCRywgVGVzdEJpdEdvIH0gZnJvbSAnQGJpdGdvL3Nkay10ZXN0JztcbmltcG9ydCB7IEFkZEtleWNoYWluT3B0aW9ucywgY29tbW9uLCBFQ0RTQVV0aWxzLCBXYWxsZXQgfSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgRGtsc0NvbW1zLCBEa2xzRHJ2LCBEa2xzVHlwZXMsIERrbHNVdGlscywgRGtsc1ZyZlV0aWxzIH0gZnJvbSAnQGJpdGdvL3Nkay1saWItbXBjJztcbmltcG9ydCB7IE1QQ3YyRGVyaXZlUm91bmQxUmVxdWVzdCwgTVBDdjJEZXJpdmVSb3VuZDJSZXF1ZXN0LCBNUEN2MkRlcml2ZVJvdW5kM1JlcXVlc3QgfSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCB7IE5vbkVtcHR5U3RyaW5nIH0gZnJvbSAnaW8tdHMtdHlwZXMnO1xuaW1wb3J0IHsgQml0R28sIEJpdGdvR1BHUHVibGljS2V5IH0gZnJvbSAnLi4vLi4vLi4vLi4vLi4vLi4vc3JjJztcblxuY29uc3QgU0FGRV9JRCA9ICc2ZmE4NTM3ZTNlZjVhODc4ZmQzYWU4OTlmM2FiN2U1YSc7XG5jb25zdCBVU0VSX1JPT1RfS0VZX0lEID0gJ3Jvb3QtdXNlci1rZXktaWQnO1xuY29uc3QgREVSSVZBVElPTl9JTkRFWCA9IDA7XG5jb25zdCBCSVRHT19ST09UX0tFWV9JRCA9ICdyb290LWJpdGdvLWtleS1pZCc7XG5jb25zdCBCQUNLVVBfUk9PVF9LRVlfSUQgPSAncm9vdC1iYWNrdXAta2V5LWlkJztcbmNvbnN0IFBBVEhfTTAgPSBuZXcgVWludDhBcnJheShbMHg4MCwgMHgwMCwgMHgwMCwgMHgwMF0pO1xuXG5kZXNjcmliZSgnVFNTIEVDRFNBIHNhZmUgY2hpbGQga2V5Y2hhaW5zICh1c2VyL0JpdEdvIGhhcmQgZGVyaXZlKTonLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gIGNvbnN0IGNvaW5OYW1lID0gJ2h0ZXRoJztcbiAgY29uc3QgZW50ZXJwcmlzZUlkID0gJzY0NDkxNTNhNmY2YmMyMDAwNmQ2Njc3MWNkYmUxNWQzJztcbiAgbGV0IGJnVXJsOiBzdHJpbmc7XG4gIGxldCBiaXRnbzogVGVzdGFibGVCRyAmIEJpdEdvO1xuICBsZXQgdHNzVXRpbHM6IEVDRFNBVXRpbHMuRWNkc2FWcmZNUEN2MlV0aWxzO1xuICBsZXQgd2FsbGV0OiBXYWxsZXQ7XG4gIGxldCBiaXRHb0dwZ0tleTogb3BlbnBncC5TZXJpYWxpemVkS2V5UGFpcjxzdHJpbmc+ICYge1xuICAgIHJldm9jYXRpb25DZXJ0aWZpY2F0ZTogc3RyaW5nO1xuICB9O1xuICBsZXQgY29uc3RhbnRzOiB7IG1wYzogeyBiaXRnb1B1YmxpY0tleTogc3RyaW5nOyBiaXRnb01QQ3YyUHVibGljS2V5OiBzdHJpbmcgfSB9O1xuICBsZXQgYml0Z29HcGdQcnZLZXk6IHsgcGFydHlJZDogbnVtYmVyOyBncGdLZXk6IHN0cmluZyB9O1xuICBsZXQgdXNlckdwZ1B1YktleTogeyBwYXJ0eUlkOiBudW1iZXI7IGdwZ0tleTogc3RyaW5nIH07XG4gIGxldCBzdGFnZWRCaXRnb01zZzI6IHsgbWVzc2FnZTogc3RyaW5nOyBzaWduYXR1cmU6IHN0cmluZyB9IHwgdW5kZWZpbmVkO1xuXG4gIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgb3BlbnBncC5jb25maWcucmVqZWN0Q3VydmVzID0gbmV3IFNldCgpO1xuICAgIGJpdEdvR3BnS2V5ID0gYXdhaXQgb3BlbnBncC5nZW5lcmF0ZUtleSh7XG4gICAgICB1c2VySURzOiBbeyBuYW1lOiAnYml0Z28nLCBlbWFpbDogJ2JpdGdvQHRlc3QuY29tJyB9XSxcbiAgICAgIGN1cnZlOiAnc2VjcDI1NmsxJyxcbiAgICB9KTtcbiAgICBjb25zdGFudHMgPSB7XG4gICAgICBtcGM6IHtcbiAgICAgICAgYml0Z29QdWJsaWNLZXk6IGJpdEdvR3BnS2V5LnB1YmxpY0tleSxcbiAgICAgICAgYml0Z29NUEN2MlB1YmxpY0tleTogYml0R29HcGdLZXkucHVibGljS2V5LFxuICAgICAgfSxcbiAgICB9O1xuICAgIGJpdGdvR3BnUHJ2S2V5ID0geyBwYXJ0eUlkOiAyLCBncGdLZXk6IGJpdEdvR3BnS2V5LnByaXZhdGVLZXkgfTtcblxuICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvLCB7IGVudjogJ21vY2snIH0pO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGJnVXJsID0gY29tbW9uLkVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0udXJpO1xuXG4gICAgY29uc3QgYmFzZUNvaW4gPSBiaXRnby5jb2luKGNvaW5OYW1lKTtcbiAgICB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBiYXNlQ29pbiwge1xuICAgICAgaWQ6ICc1YjM0MjUyZjFiZjM0OTkzMGUzNDAyMGEwMDAwMDAwMCcsXG4gICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlSWQsXG4gICAgICBjb2luOiBjb2luTmFtZSxcbiAgICAgIGNvaW5TcGVjaWZpYzoge30sXG4gICAgICBtdWx0aXNpZ1R5cGU6ICd0c3MnLFxuICAgIH0pO1xuICAgIHRzc1V0aWxzID0gbmV3IEVDRFNBVXRpbHMuRWNkc2FWcmZNUEN2MlV0aWxzKGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0KTtcbiAgfSk7XG5cbiAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICAgIHN0YWdlZEJpdGdvTXNnMiA9IHVuZGVmaW5lZDtcbiAgICBhd2FpdCBub2NrR2V0Qml0Z29QdWJsaWNLZXlCYXNlZE9uRmVhdHVyZUZsYWdzKGNvaW5OYW1lLCBlbnRlcnByaXNlSWQsIGJpdEdvR3BnS2V5KTtcbiAgICBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjEvY2xpZW50L2NvbnN0YW50cycpLnRpbWVzKDMyKS5yZXBseSgyMDAsIHsgdHRsOiAzNjAwLCBjb25zdGFudHMgfSk7XG4gIH0pO1xuXG4gIGFmdGVyKGZ1bmN0aW9uICgpIHtcbiAgICBub2NrLmNsZWFuQWxsKCk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgZGVyaXZlIHRoZSB1c2VyIGNoaWxkIGFuZCByZWdpc3RlciB0aGUgYmFja3VwIHdpdGhvdXQgZW5jcnlwdGVkUHJ2JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IFt1c2VyUm9vdCwgLCBiaXRnb1Jvb3RdID0gYXdhaXQgRGtsc1V0aWxzLmdlbmVyYXRlREtHS2V5U2hhcmVzKCk7XG4gICAgY29uc3QgW3ZyZlVzZXIsICwgdnJmQml0Z29dID0gYXdhaXQgRGtsc1ZyZlV0aWxzLmdlbmVyYXRlVnJmREtHS2V5U2hhcmVzKCk7XG4gICAgY29uc3QgYml0Z29QYWlyID0gbmV3IERrbHNEcnYuRGVyaXZlKDMsIDIsIDIsIGJpdGdvUm9vdC5nZXRLZXlTaGFyZSgpLCB2cmZCaXRnby5nZXRLZXlTaGFyZSgpLCBQQVRIX00wKTtcblxuICAgIGNvbnN0IHJvdW5kMU5vY2sgPSBhd2FpdCBub2NrRGVyaXZlUm91bmQxKGJpdGdvUGFpcik7XG4gICAgY29uc3Qgcm91bmQyTm9jayA9IGF3YWl0IG5vY2tEZXJpdmVSb3VuZDIoYml0Z29QYWlyKTtcbiAgICBjb25zdCByb3VuZDNOb2NrID0gYXdhaXQgbm9ja0Rlcml2ZVJvdW5kMyhiaXRnb1BhaXIpO1xuICAgIGNvbnN0IGFkZEtleU5vY2sgPSBhd2FpdCBub2NrQWRkQ2hpbGRLZXkoY29pbk5hbWUpO1xuXG4gICAgY29uc3QgeyB1c2VyS2V5Y2hhaW4sIGJhY2t1cEtleWNoYWluLCBiaXRnb0tleWNoYWluIH0gPSBhd2FpdCB0c3NVdGlscy5jcmVhdGVTYWZlQ2hpbGRLZXljaGFpbnMoe1xuICAgICAgcGFzc3BocmFzZTogJ3Rlc3QnLFxuICAgICAgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkLFxuICAgICAgc2FmZUlkOiBTQUZFX0lELFxuICAgICAgcGFyZW50S2V5SWQ6IEJJVEdPX1JPT1RfS0VZX0lELFxuICAgICAgZGVyaXZhdGlvbkluZGV4OiBERVJJVkFUSU9OX0lOREVYLFxuICAgICAgdXNlclJvb3RLZXlJZDogVVNFUl9ST09UX0tFWV9JRCxcbiAgICAgIGJhY2t1cFJvb3RLZXlJZDogQkFDS1VQX1JPT1RfS0VZX0lELFxuICAgICAgdXNlclJvb3RLZXlTaGFyZTogdXNlclJvb3QuZ2V0S2V5U2hhcmUoKSxcbiAgICAgIHVzZXJSb290VnJmS2V5U2hhcmU6IHZyZlVzZXIuZ2V0S2V5U2hhcmUoKSxcbiAgICB9KTtcblxuICAgIGFzc2VydC5vayhyb3VuZDFOb2NrLmlzRG9uZSgpKTtcbiAgICBhc3NlcnQub2socm91bmQyTm9jay5pc0RvbmUoKSk7XG4gICAgYXNzZXJ0Lm9rKHJvdW5kM05vY2suaXNEb25lKCkpO1xuICAgIGFzc2VydC5vayhhZGRLZXlOb2NrLmlzRG9uZSgpKTtcbiAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLmNvbW1vbktleWNoYWluLCBiYWNrdXBLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4sIHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uc291cmNlLCAnYml0Z28nKTtcbiAgICBhc3NlcnQuZXF1YWwoYml0Z29LZXljaGFpbi5lbmNyeXB0ZWRQcnYsIHVuZGVmaW5lZCk7XG4gICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbiwgRGtsc1R5cGVzLmdldENvbW1vbktleWNoYWluKGJpdGdvUGFpci5nZXRLZXlTaGFyZSgpKSk7XG5cbiAgICBjb25zdCBlbmNyeXB0ZWRVc2VyUHJ2ID0gdXNlcktleWNoYWluLmVuY3J5cHRlZFBydjtcbiAgICBhc3NlcnQub2soZW5jcnlwdGVkVXNlclBydik7XG4gICAgYXNzZXJ0LmVxdWFsKGJhY2t1cEtleWNoYWluLmVuY3J5cHRlZFBydiwgdW5kZWZpbmVkKTtcbiAgICBjb25zdCBkZWNyeXB0ZWRVc2VyUHJ2ID0gYXdhaXQgYml0Z28uZGVjcnlwdCh7IGlucHV0OiBlbmNyeXB0ZWRVc2VyUHJ2LCBwYXNzd29yZDogJ3Rlc3QnIH0pO1xuICAgIGNvbnN0IHVzZXJDaGlsZFNoYXJlID0gZGVjb2RlKEJ1ZmZlci5mcm9tKGRlY3J5cHRlZFVzZXJQcnYsICdiYXNlNjQnKSk7XG4gICAgYXNzZXJ0LmVxdWFsKHVzZXJDaGlsZFNoYXJlLnZlcnNpb24sIHVuZGVmaW5lZCk7XG4gICAgYXNzZXJ0LmVxdWFsKHVzZXJDaGlsZFNoYXJlLnZyZiwgdW5kZWZpbmVkKTtcbiAgICBhc3NlcnQuZXF1YWwodXNlckNoaWxkU2hhcmUucGFydHlfaWQsIDApO1xuICAgIGFzc2VydC5vayh1c2VyQ2hpbGRTaGFyZS5zX2kpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGRlcml2ZSBhdCBhIG5vbi16ZXJvIGhhcmRlbmVkIGluZGV4IGFuZCBhZ3JlZSB3aXRoIHRoZSBzZXJ2ZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgaWR4ID0gNztcbiAgICBjb25zdCBwYXRoID0gbmV3IFVpbnQ4QXJyYXkoWzB4ODAgfCAoaWR4ID4+PiAyNCksIDAsIDAsIGlkeF0pO1xuICAgIGNvbnN0IFt1c2VyUm9vdCwgLCBiaXRnb1Jvb3RdID0gYXdhaXQgRGtsc1V0aWxzLmdlbmVyYXRlREtHS2V5U2hhcmVzKCk7XG4gICAgY29uc3QgW3ZyZlVzZXIsICwgdnJmQml0Z29dID0gYXdhaXQgRGtsc1ZyZlV0aWxzLmdlbmVyYXRlVnJmREtHS2V5U2hhcmVzKCk7XG4gICAgY29uc3QgYml0Z29QYWlyID0gbmV3IERrbHNEcnYuRGVyaXZlKDMsIDIsIDIsIGJpdGdvUm9vdC5nZXRLZXlTaGFyZSgpLCB2cmZCaXRnby5nZXRLZXlTaGFyZSgpLCBwYXRoKTtcblxuICAgIGNvbnN0IHJvdW5kMU5vY2sgPSBhd2FpdCBub2NrRGVyaXZlUm91bmQxKGJpdGdvUGFpciwgMSwgaWR4KTtcbiAgICBjb25zdCByb3VuZDJOb2NrID0gYXdhaXQgbm9ja0Rlcml2ZVJvdW5kMihiaXRnb1BhaXIpO1xuICAgIGNvbnN0IHJvdW5kM05vY2sgPSBhd2FpdCBub2NrRGVyaXZlUm91bmQzKGJpdGdvUGFpcik7XG4gICAgY29uc3QgYWRkS2V5Tm9jayA9IGF3YWl0IG5vY2tBZGRDaGlsZEtleShjb2luTmFtZSwgMywgaWR4KTtcblxuICAgIGNvbnN0IHsgdXNlcktleWNoYWluLCBiYWNrdXBLZXljaGFpbiwgYml0Z29LZXljaGFpbiB9ID0gYXdhaXQgdHNzVXRpbHMuY3JlYXRlU2FmZUNoaWxkS2V5Y2hhaW5zKHtcbiAgICAgIHBhc3NwaHJhc2U6ICd0ZXN0JyxcbiAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCxcbiAgICAgIHNhZmVJZDogU0FGRV9JRCxcbiAgICAgIHBhcmVudEtleUlkOiBCSVRHT19ST09UX0tFWV9JRCxcbiAgICAgIGRlcml2YXRpb25JbmRleDogaWR4LFxuICAgICAgdXNlclJvb3RLZXlJZDogVVNFUl9ST09UX0tFWV9JRCxcbiAgICAgIGJhY2t1cFJvb3RLZXlJZDogQkFDS1VQX1JPT1RfS0VZX0lELFxuICAgICAgdXNlclJvb3RLZXlTaGFyZTogdXNlclJvb3QuZ2V0S2V5U2hhcmUoKSxcbiAgICAgIHVzZXJSb290VnJmS2V5U2hhcmU6IHZyZlVzZXIuZ2V0S2V5U2hhcmUoKSxcbiAgICB9KTtcblxuICAgIGFzc2VydC5vayhyb3VuZDFOb2NrLmlzRG9uZSgpKTtcbiAgICBhc3NlcnQub2socm91bmQyTm9jay5pc0RvbmUoKSk7XG4gICAgYXNzZXJ0Lm9rKHJvdW5kM05vY2suaXNEb25lKCkpO1xuICAgIGFzc2VydC5vayhhZGRLZXlOb2NrLmlzRG9uZSgpKTtcbiAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLmNvbW1vbktleWNoYWluLCBiYWNrdXBLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4sIHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gIH0pO1xuXG4gIGl0KCdyZWdpc3RlcnMgdGhlIEJpdEdvIGNoaWxkIHBsYWNlaG9sZGVyIHdpdGggdGhlIGhhcmRlbmVkIHBhdGggYW5kIG5vIHByaXZhdGUgbWF0ZXJpYWwnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgW3VzZXJSb290LCAsIGJpdGdvUm9vdF0gPSBhd2FpdCBEa2xzVXRpbHMuZ2VuZXJhdGVES0dLZXlTaGFyZXMoKTtcbiAgICBjb25zdCBbdnJmVXNlciwgLCB2cmZCaXRnb10gPSBhd2FpdCBEa2xzVnJmVXRpbHMuZ2VuZXJhdGVWcmZES0dLZXlTaGFyZXMoKTtcbiAgICBjb25zdCBiaXRnb1BhaXIgPSBuZXcgRGtsc0Rydi5EZXJpdmUoMywgMiwgMiwgYml0Z29Sb290LmdldEtleVNoYXJlKCksIHZyZkJpdGdvLmdldEtleVNoYXJlKCksIFBBVEhfTTApO1xuXG4gICAgYXdhaXQgbm9ja0Rlcml2ZVJvdW5kMShiaXRnb1BhaXIpO1xuICAgIGF3YWl0IG5vY2tEZXJpdmVSb3VuZDIoYml0Z29QYWlyKTtcbiAgICBhd2FpdCBub2NrRGVyaXZlUm91bmQzKGJpdGdvUGFpcik7XG5cbiAgICBjb25zdCBhZGRLZXlCb2RpZXM6IEFkZEtleWNoYWluT3B0aW9uc1tdID0gW107XG4gICAgbm9jaygnaHR0cHM6Ly9iaXRnby5mYWtldXJsJylcbiAgICAgIC5wb3N0KGAvYXBpL3YyLyR7Y29pbk5hbWV9L2tleWApXG4gICAgICAudGltZXMoMylcbiAgICAgIC5yZXBseSgyMDAsICh1cmksIHJlcXVlc3RCb2R5OiBBZGRLZXljaGFpbk9wdGlvbnMpID0+IHtcbiAgICAgICAgYWRkS2V5Qm9kaWVzLnB1c2gocmVxdWVzdEJvZHkpO1xuICAgICAgICByZXR1cm4geyBpZDogcmVxdWVzdEJvZHkuc291cmNlLCBzb3VyY2U6IHJlcXVlc3RCb2R5LnNvdXJjZSwgY29tbW9uS2V5Y2hhaW46IHJlcXVlc3RCb2R5LmNvbW1vbktleWNoYWluIH07XG4gICAgICB9KTtcblxuICAgIGNvbnN0IHsgYml0Z29LZXljaGFpbiB9ID0gYXdhaXQgdHNzVXRpbHMuY3JlYXRlU2FmZUNoaWxkS2V5Y2hhaW5zKHtcbiAgICAgIHBhc3NwaHJhc2U6ICd0ZXN0JyxcbiAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCxcbiAgICAgIHNhZmVJZDogU0FGRV9JRCxcbiAgICAgIHBhcmVudEtleUlkOiBCSVRHT19ST09UX0tFWV9JRCxcbiAgICAgIGRlcml2YXRpb25JbmRleDogREVSSVZBVElPTl9JTkRFWCxcbiAgICAgIHVzZXJSb290S2V5SWQ6IFVTRVJfUk9PVF9LRVlfSUQsXG4gICAgICBiYWNrdXBSb290S2V5SWQ6IEJBQ0tVUF9ST09UX0tFWV9JRCxcbiAgICAgIHVzZXJSb290S2V5U2hhcmU6IHVzZXJSb290LmdldEtleVNoYXJlKCksXG4gICAgICB1c2VyUm9vdFZyZktleVNoYXJlOiB2cmZVc2VyLmdldEtleVNoYXJlKCksXG4gICAgfSk7XG5cbiAgICBjb25zdCB1c2VyQm9keSA9IGFkZEtleUJvZGllcy5maW5kKChib2R5KSA9PiBib2R5LnNvdXJjZSA9PT0gJ3VzZXInKTtcbiAgICBhc3NlcnQub2sodXNlckJvZHksICdleHBlY3RlZCBhIHVzZXIgY2hpbGQgcmVnaXN0cmF0aW9uJyk7XG4gICAgY29uc3QgYml0Z29Cb2R5ID0gYWRkS2V5Qm9kaWVzLmZpbmQoKGJvZHkpID0+IGJvZHkuc291cmNlID09PSAnYml0Z28nKTtcbiAgICBhc3NlcnQub2soYml0Z29Cb2R5LCAnZXhwZWN0ZWQgYSBiaXRnbyBjaGlsZCByZWdpc3RyYXRpb24nKTtcbiAgICAvLyBTYW1lIGNvbW1vbiBrZXljaGFpbiBhY3Jvc3MgYWxsIHRocmVlIGNoaWxkIHJlZ2lzdHJhdGlvbnMuXG4gICAgYXNzZXJ0LmVxdWFsKGJpdGdvQm9keS5jb21tb25LZXljaGFpbiwgdXNlckJvZHkuY29tbW9uS2V5Y2hhaW4pO1xuICAgIGFzc2VydC5lcXVhbChiaXRnb0JvZHkuY29tbW9uS2V5Y2hhaW4sIGJpdGdvS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgIC8vIEFsbCBjaGlsZCBwYXRocyBhcmUgaGFyZGVuZWQuXG4gICAgYXNzZXJ0LmVxdWFsKHVzZXJCb2R5LmRlcml2ZWRGcm9tUGFyZW50V2l0aFBhdGgsIFwibS8wJ1wiKTtcbiAgICBhc3NlcnQuZXF1YWwodXNlckJvZHkucGFyZW50LCBVU0VSX1JPT1RfS0VZX0lEKTtcbiAgICBjb25zdCBiYWNrdXBCb2R5ID0gYWRkS2V5Qm9kaWVzLmZpbmQoKGJvZHkpID0+IGJvZHkuc291cmNlID09PSAnYmFja3VwJyk7XG4gICAgYXNzZXJ0Lm9rKGJhY2t1cEJvZHksICdleHBlY3RlZCBhIGJhY2t1cCBjaGlsZCByZWdpc3RyYXRpb24nKTtcbiAgICBhc3NlcnQuZXF1YWwoYmFja3VwQm9keS5kZXJpdmVkRnJvbVBhcmVudFdpdGhQYXRoLCBcIm0vMCdcIik7XG4gICAgYXNzZXJ0LmVxdWFsKGJhY2t1cEJvZHkucGFyZW50LCBCQUNLVVBfUk9PVF9LRVlfSUQpO1xuICAgIC8vIEV4YWN0IHdpcmUgYm9keTogcHVibGljLW9ubHkgcGxhY2Vob2xkZXIgd2l0aCBubyBwcml2YXRlIG1hdGVyaWFsLlxuICAgIGFzc2VydC5kZWVwRXF1YWwoYml0Z29Cb2R5LCB7XG4gICAgICBzb3VyY2U6ICdiaXRnbycsXG4gICAgICBrZXlUeXBlOiAndHNzJyxcbiAgICAgIGlzTVBDdjI6IHRydWUsXG4gICAgICBjb21tb25LZXljaGFpbjogdXNlckJvZHkuY29tbW9uS2V5Y2hhaW4sXG4gICAgICBzYWZlSWQ6IFNBRkVfSUQsXG4gICAgICBwYXJlbnQ6IEJJVEdPX1JPT1RfS0VZX0lELFxuICAgICAgZGVyaXZlZEZyb21QYXJlbnRXaXRoUGF0aDogXCJtLzAnXCIsXG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmVqZWN0IHJvb3Qga2V5IG1hdGVyaWFsIHRoYXQgaXMgbm90IGEgdmFsaWQgVlJGIGVudmVsb3BlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IFssICwgYml0Z29Sb290XSA9IGF3YWl0IERrbHNVdGlscy5nZW5lcmF0ZURLR0tleVNoYXJlcygpO1xuICAgIGNvbnN0IFssICwgdnJmQml0Z29dID0gYXdhaXQgRGtsc1ZyZlV0aWxzLmdlbmVyYXRlVnJmREtHS2V5U2hhcmVzKCk7XG4gICAgY29uc3QgYml0Z29QYWlyID0gbmV3IERrbHNEcnYuRGVyaXZlKDMsIDIsIDIsIGJpdGdvUm9vdC5nZXRLZXlTaGFyZSgpLCB2cmZCaXRnby5nZXRLZXlTaGFyZSgpLCBQQVRIX00wKTtcbiAgICBjb25zdCByb3VuZDFOb2NrID0gYXdhaXQgbm9ja0Rlcml2ZVJvdW5kMShiaXRnb1BhaXIpO1xuICAgIGNvbnN0IHJvdW5kMk5vY2sgPSBhd2FpdCBub2NrRGVyaXZlUm91bmQyKGJpdGdvUGFpcik7XG4gICAgY29uc3Qgcm91bmQzTm9jayA9IGF3YWl0IG5vY2tEZXJpdmVSb3VuZDMoYml0Z29QYWlyKTtcblxuICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgKCkgPT5cbiAgICAgICAgdHNzVXRpbHMuY3JlYXRlU2FmZUNoaWxkS2V5Y2hhaW5zKHtcbiAgICAgICAgICBwYXNzcGhyYXNlOiAndGVzdCcsXG4gICAgICAgICAgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkLFxuICAgICAgICAgIHNhZmVJZDogU0FGRV9JRCxcbiAgICAgICAgICBwYXJlbnRLZXlJZDogQklUR09fUk9PVF9LRVlfSUQsXG4gICAgICAgICAgZGVyaXZhdGlvbkluZGV4OiBERVJJVkFUSU9OX0lOREVYLFxuICAgICAgICAgIHVzZXJSb290S2V5SWQ6IFVTRVJfUk9PVF9LRVlfSUQsXG4gICAgICAgICAgYmFja3VwUm9vdEtleUlkOiBCQUNLVVBfUk9PVF9LRVlfSUQsXG4gICAgICAgICAgdXNlclJvb3RLZXlTaGFyZTogQnVmZmVyLmZyb20oJ2dhcmJhZ2UnKSxcbiAgICAgICAgICB1c2VyUm9vdFZyZktleVNoYXJlOiB2cmZCaXRnby5nZXRLZXlTaGFyZSgpLFxuICAgICAgICB9KSxcbiAgICAgIC9DQk9SIGRlY29kZXxkb2VzIG5vdCBtYXRjaCByb290IGtleSBzaGFyZSBwYXJ0eUlkfFZSRiBrZXlzaGFyZS9pXG4gICAgKTtcbiAgICBhc3NlcnQub2soIXJvdW5kMU5vY2suaXNEb25lKCksICdyb3VuZCAxIG11c3Qgbm90IGJlIHNlbnQgZm9yIGludmFsaWQgcm9vdCBtYXRlcmlhbCcpO1xuICAgIGFzc2VydC5vayghcm91bmQyTm9jay5pc0RvbmUoKSwgJ3JvdW5kIDIgbXVzdCBub3QgYmUgc2VudCBmb3IgaW52YWxpZCByb290IG1hdGVyaWFsJyk7XG4gICAgYXNzZXJ0Lm9rKCFyb3VuZDNOb2NrLmlzRG9uZSgpLCAncm91bmQgMyBtdXN0IG5vdCBiZSBzZW50IGZvciBpbnZhbGlkIHJvb3QgbWF0ZXJpYWwnKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCByZWplY3QgYSByb290IGJsb2Igd2l0aCBhIFZSRiBwYXJ0eUlkIG1pc21hdGNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IFt1c2VyUm9vdCwgLCBiaXRnb1Jvb3RdID0gYXdhaXQgRGtsc1V0aWxzLmdlbmVyYXRlREtHS2V5U2hhcmVzKCk7XG4gICAgY29uc3QgWywgdnJmQmFja3VwLCB2cmZCaXRnb10gPSBhd2FpdCBEa2xzVnJmVXRpbHMuZ2VuZXJhdGVWcmZES0dLZXlTaGFyZXMoKTtcbiAgICBjb25zdCBiaXRnb1BhaXIgPSBuZXcgRGtsc0Rydi5EZXJpdmUoMywgMiwgMiwgYml0Z29Sb290LmdldEtleVNoYXJlKCksIHZyZkJpdGdvLmdldEtleVNoYXJlKCksIFBBVEhfTTApO1xuICAgIGNvbnN0IHJvdW5kMU5vY2sgPSBhd2FpdCBub2NrRGVyaXZlUm91bmQxKGJpdGdvUGFpcik7XG4gICAgY29uc3Qgcm91bmQyTm9jayA9IGF3YWl0IG5vY2tEZXJpdmVSb3VuZDIoYml0Z29QYWlyKTtcbiAgICBjb25zdCByb3VuZDNOb2NrID0gYXdhaXQgbm9ja0Rlcml2ZVJvdW5kMyhiaXRnb1BhaXIpO1xuXG4gICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAoKSA9PlxuICAgICAgICB0c3NVdGlscy5jcmVhdGVTYWZlQ2hpbGRLZXljaGFpbnMoe1xuICAgICAgICAgIHBhc3NwaHJhc2U6ICd0ZXN0JyxcbiAgICAgICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlSWQsXG4gICAgICAgICAgc2FmZUlkOiBTQUZFX0lELFxuICAgICAgICAgIHBhcmVudEtleUlkOiBCSVRHT19ST09UX0tFWV9JRCxcbiAgICAgICAgICBkZXJpdmF0aW9uSW5kZXg6IERFUklWQVRJT05fSU5ERVgsXG4gICAgICAgICAgdXNlclJvb3RLZXlJZDogVVNFUl9ST09UX0tFWV9JRCxcbiAgICAgICAgICBiYWNrdXBSb290S2V5SWQ6IEJBQ0tVUF9ST09UX0tFWV9JRCxcbiAgICAgICAgICB1c2VyUm9vdEtleVNoYXJlOiB1c2VyUm9vdC5nZXRLZXlTaGFyZSgpLFxuICAgICAgICAgIHVzZXJSb290VnJmS2V5U2hhcmU6IHZyZkJhY2t1cC5nZXRLZXlTaGFyZSgpLFxuICAgICAgICB9KSxcbiAgICAgIC9kb2VzIG5vdCBtYXRjaCBWUkYga2V5IHNoYXJlIHBhcnR5SWQvXG4gICAgKTtcbiAgICBhc3NlcnQub2soIXJvdW5kMU5vY2suaXNEb25lKCksICdyb3VuZCAxIG11c3Qgbm90IGJlIHNlbnQgZm9yIG1pc21hdGNoZWQgVlJGIG1hdGVyaWFsJyk7XG4gICAgYXNzZXJ0Lm9rKCFyb3VuZDJOb2NrLmlzRG9uZSgpLCAncm91bmQgMiBtdXN0IG5vdCBiZSBzZW50IGZvciBtaXNtYXRjaGVkIFZSRiBtYXRlcmlhbCcpO1xuICAgIGFzc2VydC5vayghcm91bmQzTm9jay5pc0RvbmUoKSwgJ3JvdW5kIDMgbXVzdCBub3QgYmUgc2VudCBmb3IgbWlzbWF0Y2hlZCBWUkYgbWF0ZXJpYWwnKTtcbiAgfSk7XG5cbiAgYXN5bmMgZnVuY3Rpb24gbm9ja0dldEJpdGdvUHVibGljS2V5QmFzZWRPbkZlYXR1cmVGbGFncyhcbiAgICBjb2luOiBzdHJpbmcsXG4gICAgZW50ZXJwcmlzZUlkOiBzdHJpbmcsXG4gICAgYml0Z29HcGdLZXlQYWlyOiBvcGVucGdwLlNlcmlhbGl6ZWRLZXlQYWlyPHN0cmluZz5cbiAgKTogUHJvbWlzZTxCaXRnb0dQR1B1YmxpY0tleT4ge1xuICAgIGNvbnN0IGJpdGdvR1BHUHVibGljS2V5UmVzcG9uc2U6IEJpdGdvR1BHUHVibGljS2V5ID0ge1xuICAgICAgbmFtZTogJ2lycmVsZXZhbnQnLFxuICAgICAgcHVibGljS2V5OiBiaXRnb0dwZ0tleVBhaXIucHVibGljS2V5LFxuICAgICAgbXBjdjJQdWJsaWNLZXk6IGJpdGdvR3BnS2V5UGFpci5wdWJsaWNLZXksXG4gICAgICBlbnRlcnByaXNlSWQsXG4gICAgfTtcbiAgICBub2NrKGJnVXJsKS5nZXQoYC9hcGkvdjIvJHtjb2lufS90c3MvcHVia2V5YCkucXVlcnkoeyBlbnRlcnByaXNlSWQgfSkucmVwbHkoMjAwLCBiaXRnb0dQR1B1YmxpY0tleVJlc3BvbnNlKTtcbiAgICByZXR1cm4gYml0Z29HUEdQdWJsaWNLZXlSZXNwb25zZTtcbiAgfVxuXG4gIGFzeW5jIGZ1bmN0aW9uIG5vY2tEZXJpdmVSb3VuZDEoYml0Z29QYWlyOiBEa2xzRHJ2LkRlcml2ZSwgdGltZXMgPSAxLCBpbmRleCA9IERFUklWQVRJT05fSU5ERVgpIHtcbiAgICByZXR1cm4gbm9jayhiZ1VybClcbiAgICAgIC5wb3N0KFxuICAgICAgICAnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLFxuICAgICAgICAoYm9keSkgPT5cbiAgICAgICAgICBib2R5LnJvdW5kID09PSAnTVBDdjJEZXJpdmUtUjEnICYmXG4gICAgICAgICAgYm9keS5zYWZlSWQgPT09IFNBRkVfSUQgJiZcbiAgICAgICAgICBib2R5LnBheWxvYWQ/LnBhcmVudEtleUlkID09PSBCSVRHT19ST09UX0tFWV9JRCAmJlxuICAgICAgICAgIGJvZHkucGF5bG9hZD8uZGVyaXZhdGlvbkluZGV4ID09PSBpbmRleCAmJlxuICAgICAgICAgIGJvZHkucGF5bG9hZD8udXNlckdwZ1B1YmxpY0tleSAmJlxuICAgICAgICAgIGJvZHkucGF5bG9hZD8udXNlck1zZzEgJiZcbiAgICAgICAgICBib2R5LnBheWxvYWQ/LmJhY2t1cEdwZ1B1YmxpY0tleSA9PT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgYm9keS5wYXlsb2FkPy5iYWNrdXBNc2cxID09PSB1bmRlZmluZWRcbiAgICAgIClcbiAgICAgIC50aW1lcyh0aW1lcylcbiAgICAgIC5yZXBseSgyMDAsIGFzeW5jICh1cmksIHJlcXVlc3RCb2R5OiB7IHBheWxvYWQ6IE1QQ3YyRGVyaXZlUm91bmQxUmVxdWVzdCB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgdXNlckdwZ1B1YmxpY0tleSwgdXNlck1zZzEgfSA9IHJlcXVlc3RCb2R5LnBheWxvYWQ7XG4gICAgICAgIHVzZXJHcGdQdWJLZXkgPSB7IHBhcnR5SWQ6IDAsIGdwZ0tleTogdXNlckdwZ1B1YmxpY0tleSB9O1xuICAgICAgICBhd2FpdCBEa2xzQ29tbXMuZGVjcnlwdEFuZFZlcmlmeUluY29taW5nTWVzc2FnZXMoXG4gICAgICAgICAge1xuICAgICAgICAgICAgcDJwTWVzc2FnZXM6IFtdLFxuICAgICAgICAgICAgYnJvYWRjYXN0TWVzc2FnZXM6IFt7IGZyb206IDAsIHBheWxvYWQ6IHsgbWVzc2FnZTogdXNlck1zZzEubWVzc2FnZSwgc2lnbmF0dXJlOiB1c2VyTXNnMS5zaWduYXR1cmUgfSB9XSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIFt1c2VyR3BnUHViS2V5XSxcbiAgICAgICAgICBbXVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGJpdGdvTXNnMVVuc2lnbmVkID0gYXdhaXQgYml0Z29QYWlyLmluaXREZXJpdmUoKTtcbiAgICAgICAgY29uc3QgYml0Z29Nc2cyID0gYml0Z29QYWlyLmhhbmRsZUluY29taW5nTWVzc2FnZXMoe1xuICAgICAgICAgIHAycE1lc3NhZ2VzOiBbXSxcbiAgICAgICAgICBicm9hZGNhc3RNZXNzYWdlczogW3sgcGF5bG9hZDogQnVmZmVyLmZyb20odXNlck1zZzEubWVzc2FnZSwgJ2Jhc2U2NCcpLCBmcm9tOiAwIH1dLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qgc2lnbmVkU3RhZ2VkTWVzc2FnZXMgPSBhd2FpdCBEa2xzQ29tbXMuZW5jcnlwdEFuZEF1dGhPdXRnb2luZ01lc3NhZ2VzKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGJyb2FkY2FzdE1lc3NhZ2VzOiBbRGtsc1R5cGVzLnNlcmlhbGl6ZUJyb2FkY2FzdE1lc3NhZ2UoYml0Z29Nc2cyLmJyb2FkY2FzdE1lc3NhZ2VzWzBdKV0sXG4gICAgICAgICAgICBwMnBNZXNzYWdlczogW10sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBbXSxcbiAgICAgICAgICBbYml0Z29HcGdQcnZLZXldXG4gICAgICAgICk7XG4gICAgICAgIHN0YWdlZEJpdGdvTXNnMiA9IHNpZ25lZFN0YWdlZE1lc3NhZ2VzLmJyb2FkY2FzdE1lc3NhZ2VzWzBdLnBheWxvYWQ7XG5cbiAgICAgICAgY29uc3Qgc2lnbmVkTWVzc2FnZXMgPSBhd2FpdCBEa2xzQ29tbXMuZW5jcnlwdEFuZEF1dGhPdXRnb2luZ01lc3NhZ2VzKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGJyb2FkY2FzdE1lc3NhZ2VzOiBbRGtsc1R5cGVzLnNlcmlhbGl6ZUJyb2FkY2FzdE1lc3NhZ2UoYml0Z29Nc2cxVW5zaWduZWQpXSxcbiAgICAgICAgICAgIHAycE1lc3NhZ2VzOiBbXSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIFtdLFxuICAgICAgICAgIFtiaXRnb0dwZ1BydktleV1cbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgYml0Z29Nc2cxID0gc2lnbmVkTWVzc2FnZXMuYnJvYWRjYXN0TWVzc2FnZXNbMF07XG4gICAgICAgIGFzc2VydC5vayhiaXRnb01zZzEsICdiaXRnb01zZzEgbm90IGZvdW5kJyk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc2Vzc2lvbklkOiAndGVzdGlkJyBhcyBOb25FbXB0eVN0cmluZyxcbiAgICAgICAgICBiaXRnb01zZzE6IHsgZnJvbTogMiwgLi4uYml0Z29Nc2cxLnBheWxvYWQgfSxcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gbm9ja0Rlcml2ZVJvdW5kMihiaXRnb1BhaXI6IERrbHNEcnYuRGVyaXZlLCB0aW1lcyA9IDEpIHtcbiAgICByZXR1cm4gbm9jayhiZ1VybClcbiAgICAgIC5wb3N0KFxuICAgICAgICAnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLFxuICAgICAgICAoYm9keSkgPT5cbiAgICAgICAgICBib2R5LnJvdW5kID09PSAnTVBDdjJEZXJpdmUtUjInICYmXG4gICAgICAgICAgYm9keS5zYWZlSWQgPT09IFNBRkVfSUQgJiZcbiAgICAgICAgICBib2R5LnBheWxvYWQ/LnNlc3Npb25JZCA9PT0gJ3Rlc3RpZCcgJiZcbiAgICAgICAgICBib2R5LnBheWxvYWQ/LnVzZXJNc2cyICYmXG4gICAgICAgICAgYm9keS5wYXlsb2FkPy5iYWNrdXBNc2cyID09PSB1bmRlZmluZWRcbiAgICAgIClcbiAgICAgIC50aW1lcyh0aW1lcylcbiAgICAgIC5yZXBseSgyMDAsIGFzeW5jICh1cmksIHJlcXVlc3RCb2R5OiB7IHBheWxvYWQ6IE1QQ3YyRGVyaXZlUm91bmQyUmVxdWVzdCB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2Vzc2lvbklkLCB1c2VyTXNnMiB9ID0gcmVxdWVzdEJvZHkucGF5bG9hZDtcbiAgICAgICAgYXdhaXQgRGtsc0NvbW1zLmRlY3J5cHRBbmRWZXJpZnlJbmNvbWluZ01lc3NhZ2VzKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHAycE1lc3NhZ2VzOiBbXSxcbiAgICAgICAgICAgIGJyb2FkY2FzdE1lc3NhZ2VzOiBbeyBmcm9tOiAwLCBwYXlsb2FkOiB7IG1lc3NhZ2U6IHVzZXJNc2cyLm1lc3NhZ2UsIHNpZ25hdHVyZTogdXNlck1zZzIuc2lnbmF0dXJlIH0gfV0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBbdXNlckdwZ1B1YktleV0sXG4gICAgICAgICAgW11cbiAgICAgICAgKTtcbiAgICAgICAgYml0Z29QYWlyLmhhbmRsZUluY29taW5nTWVzc2FnZXMoe1xuICAgICAgICAgIHAycE1lc3NhZ2VzOiBbXSxcbiAgICAgICAgICBicm9hZGNhc3RNZXNzYWdlczogW3sgcGF5bG9hZDogQnVmZmVyLmZyb20odXNlck1zZzIubWVzc2FnZSwgJ2Jhc2U2NCcpLCBmcm9tOiAwIH1dLFxuICAgICAgICB9KTtcbiAgICAgICAgYXNzZXJ0Lm9rKHN0YWdlZEJpdGdvTXNnMiwgJ3N0YWdlZCBCaXRHbyBtc2cyIG1pc3NpbmcnKTtcbiAgICAgICAgcmV0dXJuIHsgc2Vzc2lvbklkLCBiaXRnb01zZzI6IHsgZnJvbTogMiwgLi4uc3RhZ2VkQml0Z29Nc2cyIH0gfTtcbiAgICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gbm9ja0Rlcml2ZVJvdW5kMyhiaXRnb1BhaXI6IERrbHNEcnYuRGVyaXZlLCB0aW1lcyA9IDEpIHtcbiAgICByZXR1cm4gbm9jayhiZ1VybClcbiAgICAgIC5wb3N0KFxuICAgICAgICAnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLFxuICAgICAgICAoYm9keSkgPT4gYm9keS5yb3VuZCA9PT0gJ01QQ3YyRGVyaXZlLVIzJyAmJiBib2R5LnNhZmVJZCA9PT0gU0FGRV9JRCAmJiBib2R5LnBheWxvYWQ/LnNlc3Npb25JZCA9PT0gJ3Rlc3RpZCdcbiAgICAgIClcbiAgICAgIC50aW1lcyh0aW1lcylcbiAgICAgIC5yZXBseSgyMDAsIGFzeW5jICh1cmksIHJlcXVlc3RCb2R5OiB7IHBheWxvYWQ6IE1QQ3YyRGVyaXZlUm91bmQzUmVxdWVzdCB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2Vzc2lvbklkIH0gPSByZXF1ZXN0Qm9keS5wYXlsb2FkO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHNlc3Npb25JZCxcbiAgICAgICAgICBjb21tb25LZXljaGFpbjogRGtsc1R5cGVzLmdldENvbW1vbktleWNoYWluKGJpdGdvUGFpci5nZXRLZXlTaGFyZSgpKSBhcyBOb25FbXB0eVN0cmluZyxcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vY2tzIHRoZSBoYXJkZW5lZCBjaGlsZCBrZXkgcmVnaXN0cmF0aW9ucy5cbiAgICovXG4gIGFzeW5jIGZ1bmN0aW9uIG5vY2tBZGRDaGlsZEtleShjb2luOiBzdHJpbmcsIHRpbWVzID0gMywgaW5kZXggPSBERVJJVkFUSU9OX0lOREVYKSB7XG4gICAgcmV0dXJuIG5vY2soJ2h0dHBzOi8vYml0Z28uZmFrZXVybCcpXG4gICAgICAucG9zdChcbiAgICAgICAgYC9hcGkvdjIvJHtjb2lufS9rZXlgLFxuICAgICAgICAoYm9keTogQWRkS2V5Y2hhaW5PcHRpb25zICYgeyBkZXJpdmVkRnJvbVBhcmVudFdpdGhQYXRoPzogc3RyaW5nIH0pID0+XG4gICAgICAgICAgYm9keS5rZXlUeXBlID09PSAndHNzJyAmJlxuICAgICAgICAgIGJvZHkuaXNNUEN2MiA9PT0gdHJ1ZSAmJlxuICAgICAgICAgIGJvZHkuc2FmZUlkID09PSBTQUZFX0lEICYmXG4gICAgICAgICAgISFib2R5LnBhcmVudCAmJlxuICAgICAgICAgIGJvZHkuZGVyaXZlZEZyb21QYXJlbnRXaXRoUGF0aCA9PT0gYG0vJHtpbmRleH0nYFxuICAgICAgKVxuICAgICAgLnRpbWVzKHRpbWVzKVxuICAgICAgLnJlcGx5KDIwMCwgKHVyaSwgcmVxdWVzdEJvZHk6IEFkZEtleWNoYWluT3B0aW9ucykgPT4gKHtcbiAgICAgICAgaWQ6IHJlcXVlc3RCb2R5LnNvdXJjZSxcbiAgICAgICAgc291cmNlOiByZXF1ZXN0Qm9keS5zb3VyY2UsXG4gICAgICAgIHR5cGU6IHJlcXVlc3RCb2R5LmtleVR5cGUsXG4gICAgICAgIGNvbW1vbktleWNoYWluOiByZXF1ZXN0Qm9keS5jb21tb25LZXljaGFpbixcbiAgICAgICAgZW5jcnlwdGVkUHJ2OiByZXF1ZXN0Qm9keS5lbmNyeXB0ZWRQcnYsXG4gICAgICB9KSk7XG4gIH1cbn0pO1xuIl19