bitgo
Version:
BitGo JavaScript SDK
324 lines • 60.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
const nock = require("nock");
const openpgp = require("openpgp");
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 MPCv2PartiesEnum = sdk_core_1.ECDSAUtils.MPCv2PartiesEnum;
describe('TSS EdDSA MPCv2 Utils:', async function () {
const coinName = 'sol';
const walletId = '5b34252f1bf349930e34020a00000000';
const enterpriseId = '6449153a6f6bc20006d66771cdbe15d3';
let bgUrl;
let tssUtils;
let wallet;
let bitgo;
let baseCoin;
let bitgoGpgKeyPair;
let bitgoPrvKeyObj;
let constants;
beforeEach(async function () {
nock.cleanAll();
await nockGetBitgoPublicKeyBasedOnFeatureFlags(coinName, enterpriseId, bitgoGpgKeyPair);
nock(bgUrl).get('/api/v1/client/constants').times(10).reply(200, { ttl: 3600, constants });
});
before(async function () {
openpgp.config.rejectCurves = new Set();
bitgoGpgKeyPair = await openpgp.generateKey({
userIDs: [{ name: 'bitgo', email: 'bitgo@test.com' }],
curve: 'ed25519',
format: 'armored',
});
bitgoPrvKeyObj = await openpgp.readPrivateKey({ armoredKey: bitgoGpgKeyPair.privateKey });
constants = {
mpc: {
bitgoPublicKey: bitgoGpgKeyPair.publicKey,
bitgoMPCv2PublicKey: bitgoGpgKeyPair.publicKey,
},
};
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
baseCoin = bitgo.coin(coinName);
bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
const walletData = {
id: walletId,
enterprise: enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
};
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, walletData);
tssUtils = new sdk_core_1.EDDSAUtils.EddsaMPCv2Utils(bitgo, baseCoin, wallet);
});
after(function () {
nock.cleanAll();
});
describe('TSS key chains', async function () {
it('should generate TSS MPS keys', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
const round1Nock = await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
const round2Nock = await nockMPSKeyGenRound2(bitgoSession, bitgoState, 1);
const addKeyNock = await nockAddKeyChain(coinName, 3);
const params = {
passphrase: 'test',
enterprise: enterpriseId,
originalPasscodeEncryptionCode: '123456',
};
const { userKeychain, backupKeychain, bitgoKeychain } = await tssUtils.createKeychains(params);
assert.ok(round1Nock.isDone());
assert.ok(round2Nock.isDone());
assert.ok(addKeyNock.isDone());
assert.ok(userKeychain);
assert.equal(userKeychain.source, 'user');
assert.ok(userKeychain.commonKeychain);
assert.ok(userKeychain.encryptedPrv);
assert.ok(bitgo.decrypt({ input: userKeychain.encryptedPrv, password: params.passphrase }));
assert.ok(backupKeychain);
assert.equal(backupKeychain.source, 'backup');
assert.ok(backupKeychain.commonKeychain);
assert.ok(backupKeychain.encryptedPrv);
assert.ok(bitgo.decrypt({ input: backupKeychain.encryptedPrv, password: params.passphrase }));
assert.ok(bitgoKeychain);
assert.equal(bitgoKeychain.source, 'bitgo');
assert.ok(bitgoKeychain.commonKeychain);
assert.equal(userKeychain.commonKeychain, backupKeychain.commonKeychain);
assert.equal(userKeychain.commonKeychain, bitgoKeychain.commonKeychain);
});
it('should create TSS key chains', async function () {
const fakeCommonKeychain = 'a'.repeat(64);
const nockPromises = [
nockKeychain({
coin: coinName,
keyChain: { id: '1', pub: '1', type: 'tss', source: 'user', reducedEncryptedPrv: '' },
source: 'user',
}),
nockKeychain({
coin: coinName,
keyChain: { id: '2', pub: '2', type: 'tss', source: 'backup', reducedEncryptedPrv: '' },
source: 'backup',
}),
nockKeychain({
coin: coinName,
keyChain: { id: '3', pub: '3', type: 'tss', source: 'bitgo', reducedEncryptedPrv: '' },
source: 'bitgo',
}),
];
const [nockedUserKeychain, nockedBackupKeychain, nockedBitGoKeychain] = await Promise.all(nockPromises);
const [userKeychain, backupKeychain, bitgoKeychain] = await Promise.all([
tssUtils.createParticipantKeychain(MPCv2PartiesEnum.USER, fakeCommonKeychain, Buffer.from('userPrivate'), Buffer.from('userReduced'), 'passphrase'),
tssUtils.createParticipantKeychain(MPCv2PartiesEnum.BACKUP, fakeCommonKeychain, Buffer.from('backupPrivate'), Buffer.from('backupReduced'), 'passphrase'),
tssUtils.createParticipantKeychain(MPCv2PartiesEnum.BITGO, fakeCommonKeychain),
]);
assert.ok(userKeychain);
assert.equal(bitgoKeychain.source, 'bitgo');
assert.equal(userKeychain.id, nockedUserKeychain.id);
assert.equal(backupKeychain.id, nockedBackupKeychain.id);
assert.equal(bitgoKeychain.id, nockedBitGoKeychain.id);
({ ...userKeychain, reducedEncryptedPrv: '' }).should.deepEqual(nockedUserKeychain);
({ ...backupKeychain, reducedEncryptedPrv: '' }).should.deepEqual(nockedBackupKeychain);
({ ...bitgoKeychain, reducedEncryptedPrv: '' }).should.deepEqual(nockedBitGoKeychain);
// reducedEncryptedPrv must round-trip: decrypting with the passphrase should recover
// the browser-safe btoa encoding of the original reduced private material.
const encodeReduced = (buf) => btoa(String.fromCharCode.apply(null, Array.from(new Uint8Array(buf))));
assert.ok(userKeychain.reducedEncryptedPrv);
assert.equal(bitgo.decrypt({ input: userKeychain.reducedEncryptedPrv, password: 'passphrase' }), encodeReduced(Buffer.from('userReduced')));
assert.ok(backupKeychain.reducedEncryptedPrv);
assert.equal(bitgo.decrypt({ input: backupKeychain.reducedEncryptedPrv, password: 'passphrase' }), encodeReduced(Buffer.from('backupReduced')));
});
it('should reject when BitGo PGP signature on round 1 response is invalid', async function () {
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R1')
.once()
.reply(200, {
sessionId: 'bad-session',
bitgoMsg1: {
message: Buffer.from('garbage').toString('base64'),
signature: '-----BEGIN PGP SIGNATURE-----\nFAKE\n-----END PGP SIGNATURE-----',
},
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }));
});
it('should reject when BitGo PGP signature on round 2 response is invalid', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.once()
.reply(200, {
sessionId: 'test-session-id',
commonPublicKey: 'a'.repeat(64),
bitgoMsg2: {
message: Buffer.from('garbage').toString('base64'),
signature: '-----BEGIN PGP SIGNATURE-----\nFAKE\n-----END PGP SIGNATURE-----',
},
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }));
});
it('should reject when session IDs from round 1 and round 2 do not match', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.once()
.reply(200, {
sessionId: 'different-session-id',
commonPublicKey: 'a'.repeat(64),
bitgoMsg2: { message: '', signature: '' },
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }), /Round 1 and round 2 session IDs do not match/);
});
it('should reject when commonPublicKey from BitGo does not match the locally computed key', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.once()
.reply(200, async (_uri, { payload }) => {
const { userMsg2, backupMsg2 } = payload;
assert.ok(bitgoState.msg2, 'BitGo round-2 message missing — round-1 nock must run first');
const userDeserMsg2 = {
from: 0,
payload: new Uint8Array(Buffer.from(userMsg2.message, 'base64')),
};
const backupDeserMsg2 = {
from: 1,
payload: new Uint8Array(Buffer.from(backupMsg2.message, 'base64')),
};
bitgoSession.handleIncomingMessages([userDeserMsg2, backupDeserMsg2, bitgoState.msg2]);
return {
sessionId: 'test-session-id',
commonPublicKey: 'fakefakeee'.repeat(8), // mutated — will not match user/backup computed key
bitgoMsg2: await sdk_lib_mpc_1.MPSComms.detachSignMpsMessage(Buffer.from(bitgoState.msg2.payload), bitgoPrvKeyObj),
};
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }), /does not match BitGo common public key/);
});
it('should reject when BitGo GPG public key does not match known keys in prod/test envs', async function () {
// Use a staging env so envRequiresBitgoPubGpgKeyConfig returns true
const stagingBitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'staging' });
stagingBitgo.initializeTestVars();
const stagingBaseCoin = stagingBitgo.coin(coinName);
const stagingBgUrl = sdk_core_1.common.Environments[stagingBitgo.getEnv()].uri;
const stagingWallet = new sdk_core_1.Wallet(stagingBitgo, stagingBaseCoin, {
id: walletId,
enterprise: enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
});
const stagingTssUtils = new sdk_core_1.EDDSAUtils.EddsaMPCv2Utils(stagingBitgo, stagingBaseCoin, stagingWallet);
// Return a key that is NOT in the hardcoded BitGo MPC v2 key list
nock(stagingBgUrl).get(`/api/v2/${coinName}/tss/pubkey`).query({ enterpriseId }).reply(200, {
name: 'irrelevant',
publicKey: bitgoGpgKeyPair.publicKey,
mpcv2PublicKey: bitgoGpgKeyPair.publicKey,
enterpriseId,
});
nock(stagingBgUrl).get('/api/v1/client/constants').reply(200, { ttl: 3600, constants });
await assert.rejects(stagingTssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }), /Invalid BitGo GPG public key/);
});
});
// ---------------------------------------------------------------------------
// Nock helpers
// ---------------------------------------------------------------------------
async function nockGetBitgoPublicKeyBasedOnFeatureFlags(coin, enterprise, bitgoKeyPair) {
const response = {
name: 'irrelevant',
publicKey: bitgoKeyPair.publicKey,
mpcv2PublicKey: bitgoKeyPair.publicKey,
eddsaMpcv2PublicKey: bitgoKeyPair.publicKey,
enterpriseId: enterprise,
};
nock(bgUrl).get(`/api/v2/${coin}/tss/pubkey`).query({ enterpriseId: enterprise }).reply(200, response);
return response;
}
async function nockMPSKeyGenRound1(bitgoSession, bitgoState, times = 1) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R1')
.times(times)
.reply(200, async (_uri, { payload }) => {
const { userGpgPublicKey, backupGpgPublicKey, userMsg1, backupMsg1 } = payload;
openpgp.config.rejectCurves = new Set();
const userPubKeyObj = await openpgp.readKey({ armoredKey: userGpgPublicKey });
const backupPubKeyObj = await openpgp.readKey({ armoredKey: backupGpgPublicKey });
const userPk = await sdk_lib_mpc_1.MPSComms.extractEd25519PublicKey(userPubKeyObj);
const backupPk = await sdk_lib_mpc_1.MPSComms.extractEd25519PublicKey(backupPubKeyObj);
const [, bitgoSk] = await sdk_lib_mpc_1.MPSComms.extractEd25519KeyPair(bitgoPrvKeyObj);
bitgoSession.initDkg(bitgoSk, [userPk, backupPk]);
const bitgoRawMsg1 = bitgoSession.getFirstMessage();
await sdk_lib_mpc_1.MPSComms.verifyMpsMessage(userMsg1, userPubKeyObj);
await sdk_lib_mpc_1.MPSComms.verifyMpsMessage(backupMsg1, backupPubKeyObj);
// Process all 3 round-1 messages (including BitGo's own) to advance state and produce bitgoMsg2
const userDeserMsg1 = {
from: 0,
payload: new Uint8Array(Buffer.from(userMsg1.message, 'base64')),
};
const backupDeserMsg1 = {
from: 1,
payload: new Uint8Array(Buffer.from(backupMsg1.message, 'base64')),
};
const [bitgoRawMsg2] = bitgoSession.handleIncomingMessages([userDeserMsg1, backupDeserMsg1, bitgoRawMsg1]);
bitgoState.msg2 = bitgoRawMsg2;
return {
sessionId: 'test-session-id',
bitgoMsg1: await sdk_lib_mpc_1.MPSComms.detachSignMpsMessage(Buffer.from(bitgoRawMsg1.payload), bitgoPrvKeyObj),
};
});
}
async function nockMPSKeyGenRound2(bitgoSession, bitgoState, times = 1) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.times(times)
.reply(200, async (_uri, { payload }) => {
const { sessionId, userMsg2, backupMsg2 } = payload;
openpgp.config.rejectCurves = new Set();
assert.ok(bitgoState.msg2, 'BitGo round-2 message missing — round-1 nock must run first');
const userDeserMsg2 = {
from: 0,
payload: new Uint8Array(Buffer.from(userMsg2.message, 'base64')),
};
const backupDeserMsg2 = {
from: 1,
payload: new Uint8Array(Buffer.from(backupMsg2.message, 'base64')),
};
// Complete DKG with all 3 round-2 messages (user, backup, and BitGo's own msg2)
bitgoSession.handleIncomingMessages([userDeserMsg2, backupDeserMsg2, bitgoState.msg2]);
return {
sessionId,
commonPublicKey: bitgoSession.getSharePublicKey().toString('hex'),
bitgoMsg2: await sdk_lib_mpc_1.MPSComms.detachSignMpsMessage(Buffer.from(bitgoState.msg2.payload), bitgoPrvKeyObj),
};
});
}
async function nockKeychain(params, times = 1) {
nock(bgUrl)
.post(`/api/v2/${params.coin}/key`, (body) => body.keyType === 'tss' && body.source === params.source)
.times(times)
.reply(200, params.keyChain);
return params.keyChain;
}
async function nockAddKeyChain(coin, times = 1) {
return nock(bgUrl)
.post(`/api/v2/${coin}/key`, (body) => body.keyType === 'tss' && body.isMPCv2)
.times(times)
.reply(200, async (_uri, requestBody) => {
const key = {
id: requestBody.source,
source: requestBody.source,
type: requestBody.keyType,
commonKeychain: requestBody.commonKeychain,
encryptedPrv: requestBody.encryptedPrv,
};
nock(bgUrl).get(`/api/v2/${coin}/key/${requestBody.source}`).reply(200, key);
return key;
});
}
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlS2V5Y2hhaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2ludGVybmFsL3Rzc1V0aWxzL2VkZHNhTVBDdjIvY3JlYXRlS2V5Y2hhaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLDZCQUE4QjtBQUM5QixtQ0FBbUM7QUFHbkMsOENBQXdEO0FBQ3hELDhDQUFpSDtBQUNqSCxvREFBcUU7QUFDckUsK0NBQWlFO0FBRWpFLE1BQU0sZ0JBQWdCLEdBQUcscUJBQVUsQ0FBQyxnQkFBZ0IsQ0FBQztBQUVyRCxRQUFRLENBQUMsd0JBQXdCLEVBQUUsS0FBSztJQUN0QyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDdkIsTUFBTSxRQUFRLEdBQUcsa0NBQWtDLENBQUM7SUFDcEQsTUFBTSxZQUFZLEdBQUcsa0NBQWtDLENBQUM7SUFFeEQsSUFBSSxLQUFhLENBQUM7SUFDbEIsSUFBSSxRQUFvQyxDQUFDO0lBQ3pDLElBQUksTUFBYyxDQUFDO0lBQ25CLElBQUksS0FBeUIsQ0FBQztJQUM5QixJQUFJLFFBQWtCLENBQUM7SUFFdkIsSUFBSSxlQUFzRixDQUFDO0lBQzNGLElBQUksY0FBa0MsQ0FBQztJQUN2QyxJQUFJLFNBQTJFLENBQUM7SUFFaEYsVUFBVSxDQUFDLEtBQUs7UUFDZCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDaEIsTUFBTSx3Q0FBd0MsQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQ3hGLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUM3RixDQUFDLENBQUMsQ0FBQztJQUVILE1BQU0sQ0FBQyxLQUFLO1FBQ1YsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUV4QyxlQUFlLEdBQUcsTUFBTSxPQUFPLENBQUMsV0FBVyxDQUFDO1lBQzFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQztZQUNyRCxLQUFLLEVBQUUsU0FBUztZQUNoQixNQUFNLEVBQUUsU0FBUztTQUNsQixDQUFDLENBQUM7UUFFSCxjQUFjLEdBQUcsTUFBTSxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUUsVUFBVSxFQUFFLGVBQWUsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBRTFGLFNBQVMsR0FBRztZQUNWLEdBQUcsRUFBRTtnQkFDSCxjQUFjLEVBQUUsZUFBZSxDQUFDLFNBQVM7Z0JBQ3pDLG1CQUFtQixFQUFFLGVBQWUsQ0FBQyxTQUFTO2FBQy9DO1NBQ0YsQ0FBQztRQUVGLEtBQUssR0FBRyxvQkFBUyxDQUFDLFFBQVEsQ0FBQyxXQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUNuRCxLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMzQixRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoQyxLQUFLLEdBQUcsaUJBQU0sQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDO1FBRWhELE1BQU0sVUFBVSxHQUFHO1lBQ2pCLEVBQUUsRUFBRSxRQUFRO1lBQ1osVUFBVSxFQUFFLFlBQVk7WUFDeEIsSUFBSSxFQUFFLFFBQVE7WUFDZCxZQUFZLEVBQUUsRUFBRTtZQUNoQixZQUFZLEVBQUUsS0FBSztTQUNwQixDQUFDO1FBQ0YsTUFBTSxHQUFHLElBQUksaUJBQU0sQ0FBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2pELFFBQVEsR0FBRyxJQUFJLHFCQUFVLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDckUsQ0FBQyxDQUFDLENBQUM7SUFFSCxLQUFLLENBQUM7UUFDSixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDbEIsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsZ0JBQWdCLEVBQUUsS0FBSztRQUM5QixFQUFFLENBQUMsOEJBQThCLEVBQUUsS0FBSztZQUN0QyxNQUFNLFlBQVksR0FBRyxJQUFJLHlCQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbEQsTUFBTSxVQUFVLEdBQTRDLEVBQUUsQ0FBQztZQUMvRCxNQUFNLFVBQVUsR0FBRyxNQUFNLG1CQUFtQixDQUFDLFlBQVksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDMUUsTUFBTSxVQUFVLEdBQUcsTUFBTSxtQkFBbUIsQ0FBQyxZQUFZLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzFFLE1BQU0sVUFBVSxHQUFHLE1BQU0sZUFBZSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUV0RCxNQUFNLE1BQU0sR0FBRztnQkFDYixVQUFVLEVBQUUsTUFBTTtnQkFDbEIsVUFBVSxFQUFFLFlBQVk7Z0JBQ3hCLDhCQUE4QixFQUFFLFFBQVE7YUFDekMsQ0FBQztZQUVGLE1BQU0sRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLGFBQWEsRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUUvRixNQUFNLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDL0IsTUFBTSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUUvQixNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3hCLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUMxQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN2QyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNyQyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsWUFBWSxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUU1RixNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzFCLE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztZQUM5QyxNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUN2QyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUU5RixNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQ3pCLE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztZQUM1QyxNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUV4QyxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3pFLE1BQU0sQ0FBQyxLQUFLLENBQUMs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RyxDQUFDLENBQUM7WUFDN0UsT0FBTyxHQUFHLENBQUM7UUFDYixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7QUFDSCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0IG5vY2sgPSByZXF1aXJlKCdub2NrJyk7XG5pbXBvcnQgKiBhcyBvcGVucGdwIGZyb20gJ29wZW5wZ3AnO1xuXG5pbXBvcnQgeyBFZGRzYU1QQ3YyS2V5R2VuUm91bmQxUmVxdWVzdCwgRWRkc2FNUEN2MktleUdlblJvdW5kMlJlcXVlc3QgfSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCB7IFRlc3RhYmxlQkcsIFRlc3RCaXRHbyB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBBZGRLZXljaGFpbk9wdGlvbnMsIEJhc2VDb2luLCBjb21tb24sIEVDRFNBVXRpbHMsIEVERFNBVXRpbHMsIEtleWNoYWluLCBXYWxsZXQgfSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgRWRkc2FNUFNEa2csIE1QU0NvbW1zLCBNUFNUeXBlcyB9IGZyb20gJ0BiaXRnby9zZGstbGliLW1wYyc7XG5pbXBvcnQgeyBCaXRHbywgQml0Z29HUEdQdWJsaWNLZXkgfSBmcm9tICcuLi8uLi8uLi8uLi8uLi8uLi9zcmMnO1xuXG5jb25zdCBNUEN2MlBhcnRpZXNFbnVtID0gRUNEU0FVdGlscy5NUEN2MlBhcnRpZXNFbnVtO1xuXG5kZXNjcmliZSgnVFNTIEVkRFNBIE1QQ3YyIFV0aWxzOicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgY29uc3QgY29pbk5hbWUgPSAnc29sJztcbiAgY29uc3Qgd2FsbGV0SWQgPSAnNWIzNDI1MmYxYmYzNDk5MzBlMzQwMjBhMDAwMDAwMDAnO1xuICBjb25zdCBlbnRlcnByaXNlSWQgPSAnNjQ0OTE1M2E2ZjZiYzIwMDA2ZDY2NzcxY2RiZTE1ZDMnO1xuXG4gIGxldCBiZ1VybDogc3RyaW5nO1xuICBsZXQgdHNzVXRpbHM6IEVERFNBVXRpbHMuRWRkc2FNUEN2MlV0aWxzO1xuICBsZXQgd2FsbGV0OiBXYWxsZXQ7XG4gIGxldCBiaXRnbzogVGVzdGFibGVCRyAmIEJpdEdvO1xuICBsZXQgYmFzZUNvaW46IEJhc2VDb2luO1xuXG4gIGxldCBiaXRnb0dwZ0tleVBhaXI6IG9wZW5wZ3AuU2VyaWFsaXplZEtleVBhaXI8c3RyaW5nPiAmIHsgcmV2b2NhdGlvbkNlcnRpZmljYXRlOiBzdHJpbmcgfTtcbiAgbGV0IGJpdGdvUHJ2S2V5T2JqOiBvcGVucGdwLlByaXZhdGVLZXk7XG4gIGxldCBjb25zdGFudHM6IHsgbXBjOiB7IGJpdGdvUHVibGljS2V5OiBzdHJpbmc7IGJpdGdvTVBDdjJQdWJsaWNLZXk6IHN0cmluZyB9IH07XG5cbiAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICAgIGF3YWl0IG5vY2tHZXRCaXRnb1B1YmxpY0tleUJhc2VkT25GZWF0dXJlRmxhZ3MoY29pbk5hbWUsIGVudGVycHJpc2VJZCwgYml0Z29HcGdLZXlQYWlyKTtcbiAgICBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjEvY2xpZW50L2NvbnN0YW50cycpLnRpbWVzKDEwKS5yZXBseSgyMDAsIHsgdHRsOiAzNjAwLCBjb25zdGFudHMgfSk7XG4gIH0pO1xuXG4gIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgb3BlbnBncC5jb25maWcucmVqZWN0Q3VydmVzID0gbmV3IFNldCgpO1xuXG4gICAgYml0Z29HcGdLZXlQYWlyID0gYXdhaXQgb3BlbnBncC5nZW5lcmF0ZUtleSh7XG4gICAgICB1c2VySURzOiBbeyBuYW1lOiAnYml0Z28nLCBlbWFpbDogJ2JpdGdvQHRlc3QuY29tJyB9XSxcbiAgICAgIGN1cnZlOiAnZWQyNTUxOScsXG4gICAgICBmb3JtYXQ6ICdhcm1vcmVkJyxcbiAgICB9KTtcblxuICAgIGJpdGdvUHJ2S2V5T2JqID0gYXdhaXQgb3BlbnBncC5yZWFkUHJpdmF0ZUtleSh7IGFybW9yZWRLZXk6IGJpdGdvR3BnS2V5UGFpci5wcml2YXRlS2V5IH0pO1xuXG4gICAgY29uc3RhbnRzID0ge1xuICAgICAgbXBjOiB7XG4gICAgICAgIGJpdGdvUHVibGljS2V5OiBiaXRnb0dwZ0tleVBhaXIucHVibGljS2V5LFxuICAgICAgICBiaXRnb01QQ3YyUHVibGljS2V5OiBiaXRnb0dwZ0tleVBhaXIucHVibGljS2V5LFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R28sIHsgZW52OiAnbW9jaycgfSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZUNvaW4gPSBiaXRnby5jb2luKGNvaW5OYW1lKTtcbiAgICBiZ1VybCA9IGNvbW1vbi5FbnZpcm9ubWVudHNbYml0Z28uZ2V0RW52KCldLnVyaTtcblxuICAgIGNvbnN0IHdhbGxldERhdGEgPSB7XG4gICAgICBpZDogd2FsbGV0SWQsXG4gICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlSWQsXG4gICAgICBjb2luOiBjb2luTmFtZSxcbiAgICAgIGNvaW5TcGVjaWZpYzoge30sXG4gICAgICBtdWx0aXNpZ1R5cGU6ICd0c3MnLFxuICAgIH07XG4gICAgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZUNvaW4sIHdhbGxldERhdGEpO1xuICAgIHRzc1V0aWxzID0gbmV3IEVERFNBVXRpbHMuRWRkc2FNUEN2MlV0aWxzKGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0KTtcbiAgfSk7XG5cbiAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1RTUyBrZXkgY2hhaW5zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgVFNTIE1QUyBrZXlzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z29TZXNzaW9uID0gbmV3IEVkZHNhTVBTRGtnLkRLRygzLCAyLCAyKTtcbiAgICAgIGNvbnN0IGJpdGdvU3RhdGU6IHsgbXNnMj86IE1QU1R5cGVzLkRlc2VyaWFsaXplZE1lc3NhZ2UgfSA9IHt9O1xuICAgICAgY29uc3Qgcm91bmQxTm9jayA9IGF3YWl0IG5vY2tNUFNLZXlHZW5Sb3VuZDEoYml0Z29TZXNzaW9uLCBiaXRnb1N0YXRlLCAxKTtcbiAgICAgIGNvbnN0IHJvdW5kMk5vY2sgPSBhd2FpdCBub2NrTVBTS2V5R2VuUm91bmQyKGJpdGdvU2Vzc2lvbiwgYml0Z29TdGF0ZSwgMSk7XG4gICAgICBjb25zdCBhZGRLZXlOb2NrID0gYXdhaXQgbm9ja0FkZEtleUNoYWluKGNvaW5OYW1lLCAzKTtcblxuICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICBwYXNzcGhyYXNlOiAndGVzdCcsXG4gICAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCxcbiAgICAgICAgb3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlOiAnMTIzNDU2JyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHsgdXNlcktleWNoYWluLCBiYWNrdXBLZXljaGFpbiwgYml0Z29LZXljaGFpbiB9ID0gYXdhaXQgdHNzVXRpbHMuY3JlYXRlS2V5Y2hhaW5zKHBhcmFtcyk7XG5cbiAgICAgIGFzc2VydC5vayhyb3VuZDFOb2NrLmlzRG9uZSgpKTtcbiAgICAgIGFzc2VydC5vayhyb3VuZDJOb2NrLmlzRG9uZSgpKTtcbiAgICAgIGFzc2VydC5vayhhZGRLZXlOb2NrLmlzRG9uZSgpKTtcblxuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbik7XG4gICAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLnNvdXJjZSwgJ3VzZXInKTtcbiAgICAgIGFzc2VydC5vayh1c2VyS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbi5lbmNyeXB0ZWRQcnYpO1xuICAgICAgYXNzZXJ0Lm9rKGJpdGdvLmRlY3J5cHQoeyBpbnB1dDogdXNlcktleWNoYWluLmVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6IHBhcmFtcy5wYXNzcGhyYXNlIH0pKTtcblxuICAgICAgYXNzZXJ0Lm9rKGJhY2t1cEtleWNoYWluKTtcbiAgICAgIGFzc2VydC5lcXVhbChiYWNrdXBLZXljaGFpbi5zb3VyY2UsICdiYWNrdXAnKTtcbiAgICAgIGFzc2VydC5vayhiYWNrdXBLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgICBhc3NlcnQub2soYmFja3VwS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2KTtcbiAgICAgIGFzc2VydC5vayhiaXRnby5kZWNyeXB0KHsgaW5wdXQ6IGJhY2t1cEtleWNoYWluLmVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6IHBhcmFtcy5wYXNzcGhyYXNlIH0pKTtcblxuICAgICAgYXNzZXJ0Lm9rKGJpdGdvS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uc291cmNlLCAnYml0Z28nKTtcbiAgICAgIGFzc2VydC5vayhiaXRnb0tleWNoYWluLmNvbW1vbktleWNoYWluKTtcblxuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbiwgYmFja3VwS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbiwgYml0Z29LZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGNyZWF0ZSBUU1Mga2V5IGNoYWlucycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGZha2VDb21tb25LZXljaGFpbiA9ICdhJy5yZXBlYXQoNjQpO1xuXG4gICAgICBjb25zdCBub2NrUHJvbWlzZXMgPSBbXG4gICAgICAgIG5vY2tLZXljaGFpbih7XG4gICAgICAgICAgY29pbjogY29pbk5hbWUsXG4gICAgICAgICAga2V5Q2hhaW46IHsgaWQ6ICcxJywgcHViOiAnMScsIHR5cGU6ICd0c3MnLCBzb3VyY2U6ICd1c2VyJywgcmVkdWNlZEVuY3J5cHRlZFBydjogJycgfSxcbiAgICAgICAgICBzb3VyY2U6ICd1c2VyJyxcbiAgICAgICAgfSksXG4gICAgICAgIG5vY2tLZXljaGFpbih7XG4gICAgICAgICAgY29pbjogY29pbk5hbWUsXG4gICAgICAgICAga2V5Q2hhaW46IHsgaWQ6ICcyJywgcHViOiAnMicsIHR5cGU6ICd0c3MnLCBzb3VyY2U6ICdiYWNrdXAnLCByZWR1Y2VkRW5jcnlwdGVkUHJ2OiAnJyB9LFxuICAgICAgICAgIHNvdXJjZTogJ2JhY2t1cCcsXG4gICAgICAgIH0pLFxuICAgICAgICBub2NrS2V5Y2hhaW4oe1xuICAgICAgICAgIGNvaW46IGNvaW5OYW1lLFxuICAgICAgICAgIGtleUNoYWluOiB7IGlkOiAnMycsIHB1YjogJzMnLCB0eXBlOiAndHNzJywgc291cmNlOiAnYml0Z28nLCByZWR1Y2VkRW5jcnlwdGVkUHJ2OiAnJyB9LFxuICAgICAgICAgIHNvdXJjZTogJ2JpdGdvJyxcbiAgICAgICAgfSksXG4gICAgICBdO1xuICAgICAgY29uc3QgW25vY2tlZFVzZXJLZXljaGFpbiwgbm9ja2VkQmFja3VwS2V5Y2hhaW4sIG5vY2tlZEJpdEdvS2V5Y2hhaW5dID0gYXdhaXQgUHJvbWlzZS5hbGwobm9ja1Byb21pc2VzKTtcblxuICAgICAgY29uc3QgW3VzZXJLZXljaGFpbiwgYmFja3VwS2V5Y2hhaW4sIGJpdGdvS2V5Y2hhaW5dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICB0c3NVdGlscy5jcmVhdGVQYXJ0aWNpcGFudEtleWNoYWluKFxuICAgICAgICAgIE1QQ3YyUGFydGllc0VudW0uVVNFUixcbiAgICAgICAgICBmYWtlQ29tbW9uS2V5Y2hhaW4sXG4gICAgICAgICAgQnVmZmVyLmZyb20oJ3VzZXJQcml2YXRlJyksXG4gICAgICAgICAgQnVmZmVyLmZyb20oJ3VzZXJSZWR1Y2VkJyksXG4gICAgICAgICAgJ3Bhc3NwaHJhc2UnXG4gICAgICAgICksXG4gICAgICAgIHRzc1V0aWxzLmNyZWF0ZVBhcnRpY2lwYW50S2V5Y2hhaW4oXG4gICAgICAgICAgTVBDdjJQYXJ0aWVzRW51bS5CQUNLVVAsXG4gICAgICAgICAgZmFrZUNvbW1vbktleWNoYWluLFxuICAgICAgICAgIEJ1ZmZlci5mcm9tKCdiYWNrdXBQcml2YXRlJyksXG4gICAgICAgICAgQnVmZmVyLmZyb20oJ2JhY2t1cFJlZHVjZWQnKSxcbiAgICAgICAgICAncGFzc3BocmFzZSdcbiAgICAgICAgKSxcbiAgICAgICAgdHNzVXRpbHMuY3JlYXRlUGFydGljaXBhbnRLZXljaGFpbihNUEN2MlBhcnRpZXNFbnVtLkJJVEdPLCBmYWtlQ29tbW9uS2V5Y2hhaW4pLFxuICAgICAgXSk7XG5cbiAgICAgIGFzc2VydC5vayh1c2VyS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uc291cmNlLCAnYml0Z28nKTtcblxuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5pZCwgbm9ja2VkVXNlcktleWNoYWluLmlkKTtcbiAgICAgIGFzc2VydC5lcXVhbChiYWNrdXBLZXljaGFpbi5pZCwgbm9ja2VkQmFja3VwS2V5Y2hhaW4uaWQpO1xuICAgICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uaWQsIG5vY2tlZEJpdEdvS2V5Y2hhaW4uaWQpO1xuXG4gICAgICAoeyAuLi51c2VyS2V5Y2hhaW4sIHJlZHVjZWRFbmNyeXB0ZWRQcnY6ICcnIH0pLnNob3VsZC5kZWVwRXF1YWwobm9ja2VkVXNlcktleWNoYWluKTtcbiAgICAgICh7IC4uLmJhY2t1cEtleWNoYWluLCByZWR1Y2VkRW5jcnlwdGVkUHJ2OiAnJyB9KS5zaG91bGQuZGVlcEVxdWFsKG5vY2tlZEJhY2t1cEtleWNoYWluKTtcbiAgICAgICh7IC4uLmJpdGdvS2V5Y2hhaW4sIHJlZHVjZWRFbmNyeXB0ZWRQcnY6ICcnIH0pLnNob3VsZC5kZWVwRXF1YWwobm9ja2VkQml0R29LZXljaGFpbik7XG5cbiAgICAgIC8vIHJlZHVjZWRFbmNyeXB0ZWRQcnYgbXVzdCByb3VuZC10cmlwOiBkZWNyeXB0aW5nIHdpdGggdGhlIHBhc3NwaHJhc2Ugc2hvdWxkIHJlY292ZXJcbiAgICAgIC8vIHRoZSBicm93c2VyLXNhZmUgYnRvYSBlbmNvZGluZyBvZiB0aGUgb3JpZ2luYWwgcmVkdWNlZCBwcml2YXRlIG1hdGVyaWFsLlxuICAgICAgY29uc3QgZW5jb2RlUmVkdWNlZCA9IChidWY6IEJ1ZmZlcikgPT4gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIEFycmF5LmZyb20obmV3IFVpbnQ4QXJyYXkoYnVmKSkpKTtcblxuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbi5yZWR1Y2VkRW5jcnlwdGVkUHJ2KTtcbiAgICAgIGFzc2VydC5lcXVhbChcbiAgICAgICAgYml0Z28uZGVjcnlwdCh7IGlucHV0OiB1c2VyS2V5Y2hhaW4ucmVkdWNlZEVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6ICdwYXNzcGhyYXNlJyB9KSxcbiAgICAgICAgZW5jb2RlUmVkdWNlZChCdWZmZXIuZnJvbSgndXNlclJlZHVjZWQnKSlcbiAgICAgICk7XG4gICAgICBhc3NlcnQub2soYmFja3VwS2V5Y2hhaW4ucmVkdWNlZEVuY3J5cHRlZFBydik7XG4gICAgICBhc3NlcnQuZXF1YWwoXG4gICAgICAgIGJpdGdvLmRlY3J5cHQoeyBpbnB1dDogYmFja3VwS2V5Y2hhaW4ucmVkdWNlZEVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6ICdwYXNzcGhyYXNlJyB9KSxcbiAgICAgICAgZW5jb2RlUmVkdWNlZChCdWZmZXIuZnJvbSgnYmFja3VwUmVkdWNlZCcpKVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IHdoZW4gQml0R28gUEdQIHNpZ25hdHVyZSBvbiByb3VuZCAxIHJlc3BvbnNlIGlzIGludmFsaWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrKGJnVXJsKVxuICAgICAgICAucG9zdCgnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLCAoYm9keSkgPT4gYm9keS5yb3VuZCA9PT0gJ01QQ3YyLVIxJylcbiAgICAgICAgLm9uY2UoKVxuICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgc2Vzc2lvbklkOiAnYmFkLXNlc3Npb24nLFxuICAgICAgICAgIGJpdGdvTXNnMToge1xuICAgICAgICAgICAgbWVzc2FnZTogQnVmZmVyLmZyb20oJ2dhcmJhZ2UnKS50b1N0cmluZygnYmFzZTY0JyksXG4gICAgICAgICAgICBzaWduYXR1cmU6ICctLS0tLUJFR0lOIFBHUCBTSUdOQVRVUkUtLS0tLVxcbkZBS0VcXG4tLS0tLUVORCBQR1AgU0lHTkFUVVJFLS0tLS0nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyh0c3NVdGlscy5jcmVhdGVLZXljaGFpbnMoeyBwYXNzcGhyYXNlOiAndGVzdCcsIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCB9KSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlamVjdCB3aGVuIEJpdEdvIFBHUCBzaWduYXR1cmUgb24gcm91bmQgMiByZXNwb25zZSBpcyBpbnZhbGlkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z29TZXNzaW9uID0gbmV3IEVkZHNhTVBTRGtnLkRLRygzLCAyLCAyKTtcbiAgICAgIGNvbnN0IGJpdGdvU3RhdGU6IHsgbXNnMj86IE1QU1R5cGVzLkRlc2VyaWFsaXplZE1lc3NhZ2UgfSA9IHt9O1xuICAgICAgYXdhaXQgbm9ja01QU0tleUdlblJvdW5kMShiaXRnb1Nlc3Npb24sIGJpdGdvU3RhdGUsIDEpO1xuXG4gICAgICBub2NrKGJnVXJsKVxuICAgICAgICAucG9zdCgnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLCAoYm9keSkgPT4gYm9keS5yb3VuZCA9PT0gJ01QQ3YyLVIyJylcbiAgICAgICAgLm9uY2UoKVxuICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgc2Vzc2lvbklkOiAndGVzdC1zZXNzaW9uLWlkJyxcbiAgICAgICAgICBjb21tb25QdWJsaWNLZXk6ICdhJy5yZXBlYXQoNjQpLFxuICAgICAgICAgIGJpdGdvTXNnMjoge1xuICAgICAgICAgICAgbWVzc2FnZTogQnVmZmVyLmZyb20oJ2dhcmJhZ2UnKS50b1N0cmluZygnYmFzZTY0JyksXG4gICAgICAgICAgICBzaWduYXR1cmU6ICctLS0tLUJFR0lOIFBHUCBTSUdOQVRVUkUtLS0tLVxcbkZBS0VcXG4tLS0tLUVORCBQR1AgU0lHTkFUVVJFLS0tLS0nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBhc3NlcnQucmVqZWN0cyh0c3NVdGlscy5jcmVhdGVLZXljaGFpbnMoeyBwYXNzcGhyYXNlOiAndGVzdCcsIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCB9KSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlamVjdCB3aGVuIHNlc3Npb24gSURzIGZyb20gcm91bmQgMSBhbmQgcm91bmQgMiBkbyBub3QgbWF0Y2gnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnb1Nlc3Npb24gPSBuZXcgRWRkc2FNUFNEa2cuREtHKDMsIDIsIDIpO1xuICAgICAgY29uc3QgYml0Z29TdGF0ZTogeyBtc2cyPzogTVBTVHlwZXMuRGVzZXJpYWxpemVkTWVzc2FnZSB9ID0ge307XG4gICAgICBhd2FpdCBub2NrTVBTS2V5R2VuUm91bmQxKGJpdGdvU2Vzc2lvbiwgYml0Z29TdGF0ZSwgMSk7XG5cbiAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgIC5wb3N0KCcvYXBpL3YyL21wYy9nZW5lcmF0ZWtleScsIChib2R5KSA9PiBib2R5LnJvdW5kID09PSAnTVBDdjItUjInKVxuICAgICAgICAub25jZSgpXG4gICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICBzZXNzaW9uSWQ6ICdkaWZmZXJlbnQtc2Vzc2lvbi1pZCcsXG4gICAgICAgICAgY29tbW9uUHVibGljS2V5OiAnYScucmVwZWF0KDY0KSxcbiAgICAgICAgICBiaXRnb01zZzI6IHsgbWVzc2FnZTogJycsIHNpZ25hdHVyZTogJycgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKFxuICAgICAgICB0c3NVdGlscy5jcmVhdGVLZXljaGFpbnMoeyBwYXNzcGhyYXNlOiAndGVzdCcsIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCB9KSxcbiAgICAgICAgL1JvdW5kIDEgYW5kIHJvdW5kIDIgc2Vzc2lvbiBJRHMgZG8gbm90IG1hdGNoL1xuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IHdoZW4gY29tbW9uUHVibGljS2V5IGZyb20gQml0R28gZG9lcyBub3QgbWF0Y2ggdGhlIGxvY2FsbHkgY29tcHV0ZWQga2V5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z29TZXNzaW9uID0gbmV3IEVkZHNhTVBTRGtnLkRLRygzLCAyLCAyKTtcbiAgICAgIGNvbnN0IGJpdGdvU3RhdGU6IHsgbXNnMj86IE1QU1R5cGVzLkRlc2VyaWFsaXplZE1lc3NhZ2UgfSA9IHt9O1xuICAgICAgYXdhaXQgbm9ja01QU0tleUdlblJvdW5kMShiaXRnb1Nlc3Npb24sIGJpdGdvU3RhdGUsIDEpO1xuXG4gICAgICBub2NrKGJnVXJsKVxuICAgICAgICAucG9zdCgnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLCAoYm9keSkgPT4gYm9keS5yb3VuZCA9PT0gJ01QQ3YyLVIyJylcbiAgICAgICAgLm9uY2UoKVxuICAgICAgICAucmVwbHkoMjAwLCBhc3luYyAoX3VyaSwgeyBwYXlsb2FkIH06IHsgcGF5bG9hZDogRWRkc2FNUEN2MktleUdlblJvdW5kMlJlcXVlc3QgfSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgdXNlck1zZzIsIGJhY2t1cE1zZzIgfSA9IHBheWxvYWQ7XG4gICAgICAgICAgYXNzZXJ0Lm9rKGJpdGdvU3RhdGUubXNnMiwgJ0JpdEdvIHJvdW5kLTIgbWVzc2FnZSBtaXNzaW5nIOKAlCByb3VuZC0xIG5vY2