UNPKG

bitgo

Version:
325 lines 60.3 kB
"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', commonPublicKeychain: 'a'.repeat(128), 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', commonPublicKeychain: 'a'.repeat(128), 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 commonPublicKeychain from BitGo does not match the locally computed keychain', 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', commonPublicKeychain: 'fakefakeee'.repeat(16), // mutated — will not match user/backup computed keychain 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 keychain/); }); 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, eddsaMpcv2PublicKey: 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, commonPublicKeychain: bitgoSession.getCommonKeychain(), 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlS2V5Y2hhaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2ludGVybmFsL3Rzc1V0aWxzL2VkZHNhTVBDdjIvY3JlYXRlS2V5Y2hhaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLDZCQUE4QjtBQUM5QixtQ0FBbUM7QUFHbkMsOENBQXdEO0FBQ3hELDhDQUFpSDtBQUNqSCxvREFBcUU7QUFDckUsK0NBQWlFO0FBRWpFLE1BQU0sZ0JBQWdCLEdBQUcscUJBQVUsQ0FBQyxnQkFBZ0IsQ0FBQztBQUVyRCxRQUFRLENBQUMsd0JBQXdCLEVBQUUsS0FBSztJQUN0QyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDdkIsTUFBTSxRQUFRLEdBQUcsa0NBQWtDLENBQUM7SUFDcEQsTUFBTSxZQUFZLEdBQUcsa0NBQWtDLENBQUM7SUFFeEQsSUFBSSxLQUFhLENBQUM7SUFDbEIsSUFBSSxRQUFvQyxDQUFDO0lBQ3pDLElBQUksTUFBYyxDQUFDO0lBQ25CLElBQUksS0FBeUIsQ0FBQztJQUM5QixJQUFJLFFBQWtCLENBQUM7SUFFdkIsSUFBSSxlQUFzRixDQUFDO0lBQzNGLElBQUksY0FBa0MsQ0FBQztJQUN2QyxJQUFJLFNBQTJFLENBQUM7SUFFaEYsVUFBVSxDQUFDLEtBQUs7UUFDZCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDaEIsTUFBTSx3Q0FBd0MsQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQ3hGLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUM3RixDQUFDLENBQUMsQ0FBQztJQUVI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LENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3hCLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUMxQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN2QyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNyQyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsWUFBWSxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUU1RixNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzFCLE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztZQUM5QyxNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUN2QyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUU5RixNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQ3pCLE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztZQUM1QyxNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUV4QyxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3pFLE1BQU0sQ0FBQyxLQUFLLENBQUMs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QUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUM3RSxPQUFPLEdBQUcsQ0FBQztRQUNiLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztBQUNILENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgbm9jayA9IHJlcXVpcmUoJ25vY2snKTtcbmltcG9ydCAqIGFzIG9wZW5wZ3AgZnJvbSAnb3BlbnBncCc7XG5cbmltcG9ydCB7IEVkZHNhTVBDdjJLZXlHZW5Sb3VuZDFSZXF1ZXN0LCBFZGRzYU1QQ3YyS2V5R2VuUm91bmQyUmVxdWVzdCB9IGZyb20gJ0BiaXRnby9wdWJsaWMtdHlwZXMnO1xuaW1wb3J0IHsgVGVzdGFibGVCRywgVGVzdEJpdEdvIH0gZnJvbSAnQGJpdGdvL3Nkay10ZXN0JztcbmltcG9ydCB7IEFkZEtleWNoYWluT3B0aW9ucywgQmFzZUNvaW4sIGNvbW1vbiwgRUNEU0FVdGlscywgRUREU0FVdGlscywgS2V5Y2hhaW4sIFdhbGxldCB9IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBFZGRzYU1QU0RrZywgTVBTQ29tbXMsIE1QU1R5cGVzIH0gZnJvbSAnQGJpdGdvL3Nkay1saWItbXBjJztcbmltcG9ydCB7IEJpdEdvLCBCaXRnb0dQR1B1YmxpY0tleSB9IGZyb20gJy4uLy4uLy4uLy4uLy4uLy4uL3NyYyc7XG5cbmNvbnN0IE1QQ3YyUGFydGllc0VudW0gPSBFQ0RTQVV0aWxzLk1QQ3YyUGFydGllc0VudW07XG5cbmRlc2NyaWJlKCdUU1MgRWREU0EgTVBDdjIgVXRpbHM6JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICBjb25zdCBjb2luTmFtZSA9ICdzb2wnO1xuICBjb25zdCB3YWxsZXRJZCA9ICc1YjM0MjUyZjFiZjM0OTkzMGUzNDAyMGEwMDAwMDAwMCc7XG4gIGNvbnN0IGVudGVycHJpc2VJZCA9ICc2NDQ5MTUzYTZmNmJjMjAwMDZkNjY3NzFjZGJlMTVkMyc7XG5cbiAgbGV0IGJnVXJsOiBzdHJpbmc7XG4gIGxldCB0c3NVdGlsczogRUREU0FVdGlscy5FZGRzYU1QQ3YyVXRpbHM7XG4gIGxldCB3YWxsZXQ6IFdhbGxldDtcbiAgbGV0IGJpdGdvOiBUZXN0YWJsZUJHICYgQml0R287XG4gIGxldCBiYXNlQ29pbjogQmFzZUNvaW47XG5cbiAgbGV0IGJpdGdvR3BnS2V5UGFpcjogb3BlbnBncC5TZXJpYWxpemVkS2V5UGFpcjxzdHJpbmc+ICYgeyByZXZvY2F0aW9uQ2VydGlmaWNhdGU6IHN0cmluZyB9O1xuICBsZXQgYml0Z29QcnZLZXlPYmo6IG9wZW5wZ3AuUHJpdmF0ZUtleTtcbiAgbGV0IGNvbnN0YW50czogeyBtcGM6IHsgYml0Z29QdWJsaWNLZXk6IHN0cmluZzsgYml0Z29NUEN2MlB1YmxpY0tleTogc3RyaW5nIH0gfTtcblxuICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBub2NrLmNsZWFuQWxsKCk7XG4gICAgYXdhaXQgbm9ja0dldEJpdGdvUHVibGljS2V5QmFzZWRPbkZlYXR1cmVGbGFncyhjb2luTmFtZSwgZW50ZXJwcmlzZUlkLCBiaXRnb0dwZ0tleVBhaXIpO1xuICAgIG5vY2soYmdVcmwpLmdldCgnL2FwaS92MS9jbGllbnQvY29uc3RhbnRzJykudGltZXMoMTApLnJlcGx5KDIwMCwgeyB0dGw6IDM2MDAsIGNvbnN0YW50cyB9KTtcbiAgfSk7XG5cbiAgYmVmb3JlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBvcGVucGdwLmNvbmZpZy5yZWplY3RDdXJ2ZXMgPSBuZXcgU2V0KCk7XG5cbiAgICBiaXRnb0dwZ0tleVBhaXIgPSBhd2FpdCBvcGVucGdwLmdlbmVyYXRlS2V5KHtcbiAgICAgIHVzZXJJRHM6IFt7IG5hbWU6ICdiaXRnbycsIGVtYWlsOiAnYml0Z29AdGVzdC5jb20nIH1dLFxuICAgICAgY3VydmU6ICdlZDI1NTE5JyxcbiAgICAgIGZvcm1hdDogJ2FybW9yZWQnLFxuICAgIH0pO1xuXG4gICAgYml0Z29QcnZLZXlPYmogPSBhd2FpdCBvcGVucGdwLnJlYWRQcml2YXRlS2V5KHsgYXJtb3JlZEtleTogYml0Z29HcGdLZXlQYWlyLnByaXZhdGVLZXkgfSk7XG5cbiAgICBjb25zdGFudHMgPSB7XG4gICAgICBtcGM6IHtcbiAgICAgICAgYml0Z29QdWJsaWNLZXk6IGJpdGdvR3BnS2V5UGFpci5wdWJsaWNLZXksXG4gICAgICAgIGJpdGdvTVBDdjJQdWJsaWNLZXk6IGJpdGdvR3BnS2V5UGFpci5wdWJsaWNLZXksXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHbywgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBiYXNlQ29pbiA9IGJpdGdvLmNvaW4oY29pbk5hbWUpO1xuICAgIGJnVXJsID0gY29tbW9uLkVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0udXJpO1xuXG4gICAgY29uc3Qgd2FsbGV0RGF0YSA9IHtcbiAgICAgIGlkOiB3YWxsZXRJZCxcbiAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCxcbiAgICAgIGNvaW46IGNvaW5OYW1lLFxuICAgICAgY29pblNwZWNpZmljOiB7fSxcbiAgICAgIG11bHRpc2lnVHlwZTogJ3RzcycsXG4gICAgfTtcbiAgICB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0RGF0YSk7XG4gICAgdHNzVXRpbHMgPSBuZXcgRUREU0FVdGlscy5FZGRzYU1QQ3YyVXRpbHMoYml0Z28sIGJhc2VDb2luLCB3YWxsZXQpO1xuICB9KTtcblxuICBhZnRlcihmdW5jdGlvbiAoKSB7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICB9KTtcblxuICBkZXNjcmliZSgnVFNTIGtleSBjaGFpbnMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBUU1MgTVBTIGtleXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnb1Nlc3Npb24gPSBuZXcgRWRkc2FNUFNEa2cuREtHKDMsIDIsIDIpO1xuICAgICAgY29uc3QgYml0Z29TdGF0ZTogeyBtc2cyPzogTVBTVHlwZXMuRGVzZXJpYWxpemVkTWVzc2FnZSB9ID0ge307XG4gICAgICBjb25zdCByb3VuZDFOb2NrID0gYXdhaXQgbm9ja01QU0tleUdlblJvdW5kMShiaXRnb1Nlc3Npb24sIGJpdGdvU3RhdGUsIDEpO1xuICAgICAgY29uc3Qgcm91bmQyTm9jayA9IGF3YWl0IG5vY2tNUFNLZXlHZW5Sb3VuZDIoYml0Z29TZXNzaW9uLCBiaXRnb1N0YXRlLCAxKTtcbiAgICAgIGNvbnN0IGFkZEtleU5vY2sgPSBhd2FpdCBub2NrQWRkS2V5Q2hhaW4oY29pbk5hbWUsIDMpO1xuXG4gICAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICAgIHBhc3NwaHJhc2U6ICd0ZXN0JyxcbiAgICAgICAgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkLFxuICAgICAgICBvcmlnaW5hbFBhc3Njb2RlRW5jcnlwdGlvbkNvZGU6ICcxMjM0NTYnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgeyB1c2VyS2V5Y2hhaW4sIGJhY2t1cEtleWNoYWluLCBiaXRnb0tleWNoYWluIH0gPSBhd2FpdCB0c3NVdGlscy5jcmVhdGVLZXljaGFpbnMocGFyYW1zKTtcblxuICAgICAgYXNzZXJ0Lm9rKHJvdW5kMU5vY2suaXNEb25lKCkpO1xuICAgICAgYXNzZXJ0Lm9rKHJvdW5kMk5vY2suaXNEb25lKCkpO1xuICAgICAgYXNzZXJ0Lm9rKGFkZEtleU5vY2suaXNEb25lKCkpO1xuXG4gICAgICBhc3NlcnQub2sodXNlcktleWNoYWluKTtcbiAgICAgIGFzc2VydC5lcXVhbCh1c2VyS2V5Y2hhaW4uc291cmNlLCAndXNlcicpO1xuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgICBhc3NlcnQub2sodXNlcktleWNoYWluLmVuY3J5cHRlZFBydik7XG4gICAgICBhc3NlcnQub2soYml0Z28uZGVjcnlwdCh7IGlucHV0OiB1c2VyS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2LCBwYXNzd29yZDogcGFyYW1zLnBhc3NwaHJhc2UgfSkpO1xuXG4gICAgICBhc3NlcnQub2soYmFja3VwS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKGJhY2t1cEtleWNoYWluLnNvdXJjZSwgJ2JhY2t1cCcpO1xuICAgICAgYXNzZXJ0Lm9rKGJhY2t1cEtleWNoYWluLmNvbW1vbktleWNoYWluKTtcbiAgICAgIGFzc2VydC5vayhiYWNrdXBLZXljaGFpbi5lbmNyeXB0ZWRQcnYpO1xuICAgICAgYXNzZXJ0Lm9rKGJpdGdvLmRlY3J5cHQoeyBpbnB1dDogYmFja3VwS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2LCBwYXNzd29yZDogcGFyYW1zLnBhc3NwaHJhc2UgfSkpO1xuXG4gICAgICBhc3NlcnQub2soYml0Z29LZXljaGFpbik7XG4gICAgICBhc3NlcnQuZXF1YWwoYml0Z29LZXljaGFpbi5zb3VyY2UsICdiaXRnbycpO1xuICAgICAgYXNzZXJ0Lm9rKGJpdGdvS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuXG4gICAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLmNvbW1vbktleWNoYWluLCBiYWNrdXBLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLmNvbW1vbktleWNoYWluLCBiaXRnb0tleWNoYWluLmNvbW1vbktleWNoYWluKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgY3JlYXRlIFRTUyBrZXkgY2hhaW5zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmFrZUNvbW1vbktleWNoYWluID0gJ2EnLnJlcGVhdCg2NCk7XG5cbiAgICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgICAgbm9ja0tleWNoYWluKHtcbiAgICAgICAgICBjb2luOiBjb2luTmFtZSxcbiAgICAgICAgICBrZXlDaGFpbjogeyBpZDogJzEnLCBwdWI6ICcxJywgdHlwZTogJ3RzcycsIHNvdXJjZTogJ3VzZXInLCByZWR1Y2VkRW5jcnlwdGVkUHJ2OiAnJyB9LFxuICAgICAgICAgIHNvdXJjZTogJ3VzZXInLFxuICAgICAgICB9KSxcbiAgICAgICAgbm9ja0tleWNoYWluKHtcbiAgICAgICAgICBjb2luOiBjb2luTmFtZSxcbiAgICAgICAgICBrZXlDaGFpbjogeyBpZDogJzInLCBwdWI6ICcyJywgdHlwZTogJ3RzcycsIHNvdXJjZTogJ2JhY2t1cCcsIHJlZHVjZWRFbmNyeXB0ZWRQcnY6ICcnIH0sXG4gICAgICAgICAgc291cmNlOiAnYmFja3VwJyxcbiAgICAgICAgfSksXG4gICAgICAgIG5vY2tLZXljaGFpbih7XG4gICAgICAgICAgY29pbjogY29pbk5hbWUsXG4gICAgICAgICAga2V5Q2hhaW46IHsgaWQ6ICczJywgcHViOiAnMycsIHR5cGU6ICd0c3MnLCBzb3VyY2U6ICdiaXRnbycsIHJlZHVjZWRFbmNyeXB0ZWRQcnY6ICcnIH0sXG4gICAgICAgICAgc291cmNlOiAnYml0Z28nLFxuICAgICAgICB9KSxcbiAgICAgIF07XG4gICAgICBjb25zdCBbbm9ja2VkVXNlcktleWNoYWluLCBub2NrZWRCYWNrdXBLZXljaGFpbiwgbm9ja2VkQml0R29LZXljaGFpbl0gPSBhd2FpdCBQcm9taXNlLmFsbChub2NrUHJvbWlzZXMpO1xuXG4gICAgICBjb25zdCBbdXNlcktleWNoYWluLCBiYWNrdXBLZXljaGFpbiwgYml0Z29LZXljaGFpbl0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgIHRzc1V0aWxzLmNyZWF0ZVBhcnRpY2lwYW50S2V5Y2hhaW4oXG4gICAgICAgICAgTVBDdjJQYXJ0aWVzRW51bS5VU0VSLFxuICAgICAgICAgIGZha2VDb21tb25LZXljaGFpbixcbiAgICAgICAgICBCdWZmZXIuZnJvbSgndXNlclByaXZhdGUnKSxcbiAgICAgICAgICBCdWZmZXIuZnJvbSgndXNlclJlZHVjZWQnKSxcbiAgICAgICAgICAncGFzc3BocmFzZSdcbiAgICAgICAgKSxcbiAgICAgICAgdHNzVXRpbHMuY3JlYXRlUGFydGljaXBhbnRLZXljaGFpbihcbiAgICAgICAgICBNUEN2MlBhcnRpZXNFbnVtLkJBQ0tVUCxcbiAgICAgICAgICBmYWtlQ29tbW9uS2V5Y2hhaW4sXG4gICAgICAgICAgQnVmZmVyLmZyb20oJ2JhY2t1cFByaXZhdGUnKSxcbiAgICAgICAgICBCdWZmZXIuZnJvbSgnYmFja3VwUmVkdWNlZCcpLFxuICAgICAgICAgICdwYXNzcGhyYXNlJ1xuICAgICAgICApLFxuICAgICAgICB0c3NVdGlscy5jcmVhdGVQYXJ0aWNpcGFudEtleWNoYWluKE1QQ3YyUGFydGllc0VudW0uQklUR08sIGZha2VDb21tb25LZXljaGFpbiksXG4gICAgICBdKTtcblxuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbik7XG4gICAgICBhc3NlcnQuZXF1YWwoYml0Z29LZXljaGFpbi5zb3VyY2UsICdiaXRnbycpO1xuXG4gICAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLmlkLCBub2NrZWRVc2VyS2V5Y2hhaW4uaWQpO1xuICAgICAgYXNzZXJ0LmVxdWFsKGJhY2t1cEtleWNoYWluLmlkLCBub2NrZWRCYWNrdXBLZXljaGFpbi5pZCk7XG4gICAgICBhc3NlcnQuZXF1YWwoYml0Z29LZXljaGFpbi5pZCwgbm9ja2VkQml0R29LZXljaGFpbi5pZCk7XG5cbiAgICAgICh7IC4uLnVzZXJLZXljaGFpbiwgcmVkdWNlZEVuY3J5cHRlZFBydjogJycgfSkuc2hvdWxkLmRlZXBFcXVhbChub2NrZWRVc2VyS2V5Y2hhaW4pO1xuICAgICAgKHsgLi4uYmFja3VwS2V5Y2hhaW4sIHJlZHVjZWRFbmNyeXB0ZWRQcnY6ICcnIH0pLnNob3VsZC5kZWVwRXF1YWwobm9ja2VkQmFja3VwS2V5Y2hhaW4pO1xuICAgICAgKHsgLi4uYml0Z29LZXljaGFpbiwgcmVkdWNlZEVuY3J5cHRlZFBydjogJycgfSkuc2hvdWxkLmRlZXBFcXVhbChub2NrZWRCaXRHb0tleWNoYWluKTtcblxuICAgICAgLy8gcmVkdWNlZEVuY3J5cHRlZFBydiBtdXN0IHJvdW5kLXRyaXA6IGRlY3J5cHRpbmcgd2l0aCB0aGUgcGFzc3BocmFzZSBzaG91bGQgcmVjb3ZlclxuICAgICAgLy8gdGhlIGJyb3dzZXItc2FmZSBidG9hIGVuY29kaW5nIG9mIHRoZSBvcmlnaW5hbCByZWR1Y2VkIHByaXZhdGUgbWF0ZXJpYWwuXG4gICAgICBjb25zdCBlbmNvZGVSZWR1Y2VkID0gKGJ1ZjogQnVmZmVyKSA9PiBidG9hKFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgQXJyYXkuZnJvbShuZXcgVWludDhBcnJheShidWYpKSkpO1xuXG4gICAgICBhc3NlcnQub2sodXNlcktleWNoYWluLnJlZHVjZWRFbmNyeXB0ZWRQcnYpO1xuICAgICAgYXNzZXJ0LmVxdWFsKFxuICAgICAgICBiaXRnby5kZWNyeXB0KHsgaW5wdXQ6IHVzZXJLZXljaGFpbi5yZWR1Y2VkRW5jcnlwdGVkUHJ2LCBwYXNzd29yZDogJ3Bhc3NwaHJhc2UnIH0pLFxuICAgICAgICBlbmNvZGVSZWR1Y2VkKEJ1ZmZlci5mcm9tKCd1c2VyUmVkdWNlZCcpKVxuICAgICAgKTtcbiAgICAgIGFzc2VydC5vayhiYWNrdXBLZXljaGFpbi5yZWR1Y2VkRW5jcnlwdGVkUHJ2KTtcbiAgICAgIGFzc2VydC5lcXVhbChcbiAgICAgICAgYml0Z28uZGVjcnlwdCh7IGlucHV0OiBiYWNrdXBLZXljaGFpbi5yZWR1Y2VkRW5jcnlwdGVkUHJ2LCBwYXNzd29yZDogJ3Bhc3NwaHJhc2UnIH0pLFxuICAgICAgICBlbmNvZGVSZWR1Y2VkKEJ1ZmZlci5mcm9tKCdiYWNrdXBSZWR1Y2VkJykpXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZWplY3Qgd2hlbiBCaXRHbyBQR1Agc2lnbmF0dXJlIG9uIHJvdW5kIDEgcmVzcG9uc2UgaXMgaW52YWxpZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgIC5wb3N0KCcvYXBpL3YyL21wYy9nZW5lcmF0ZWtleScsIChib2R5KSA9PiBib2R5LnJvdW5kID09PSAnTVBDdjItUjEnKVxuICAgICAgICAub25jZSgpXG4gICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICBzZXNzaW9uSWQ6ICdiYWQtc2Vzc2lvbicsXG4gICAgICAgICAgYml0Z29Nc2cxOiB7XG4gICAgICAgICAgICBtZXNzYWdlOiBCdWZmZXIuZnJvbSgnZ2FyYmFnZScpLnRvU3RyaW5nKCdiYXNlNjQnKSxcbiAgICAgICAgICAgIHNpZ25hdHVyZTogJy0tLS0tQkVHSU4gUEdQIFNJR05BVFVSRS0tLS0tXFxuRkFLRVxcbi0tLS0tRU5EIFBHUCBTSUdOQVRVUkUtLS0tLScsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKHRzc1V0aWxzLmNyZWF0ZUtleWNoYWlucyh7IHBhc3NwaHJhc2U6ICd0ZXN0JywgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkIH0pKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IHdoZW4gQml0R28gUEdQIHNpZ25hdHVyZSBvbiByb3VuZCAyIHJlc3BvbnNlIGlzIGludmFsaWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnb1Nlc3Npb24gPSBuZXcgRWRkc2FNUFNEa2cuREtHKDMsIDIsIDIpO1xuICAgICAgY29uc3QgYml0Z29TdGF0ZTogeyBtc2cyPzogTVBTVHlwZXMuRGVzZXJpYWxpemVkTWVzc2FnZSB9ID0ge307XG4gICAgICBhd2FpdCBub2NrTVBTS2V5R2VuUm91bmQxKGJpdGdvU2Vzc2lvbiwgYml0Z29TdGF0ZSwgMSk7XG5cbiAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgIC5wb3N0KCcvYXBpL3YyL21wYy9nZW5lcmF0ZWtleScsIChib2R5KSA9PiBib2R5LnJvdW5kID09PSAnTVBDdjItUjInKVxuICAgICAgICAub25jZSgpXG4gICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICBzZXNzaW9uSWQ6ICd0ZXN0LXNlc3Npb24taWQnLFxuICAgICAgICAgIGNvbW1vblB1YmxpY0tleWNoYWluOiAnYScucmVwZWF0KDEyOCksXG4gICAgICAgICAgYml0Z29Nc2cyOiB7XG4gICAgICAgICAgICBtZXNzYWdlOiBCdWZmZXIuZnJvbSgnZ2FyYmFnZScpLnRvU3RyaW5nKCdiYXNlNjQnKSxcbiAgICAgICAgICAgIHNpZ25hdHVyZTogJy0tLS0tQkVHSU4gUEdQIFNJR05BVFVSRS0tLS0tXFxuRkFLRVxcbi0tLS0tRU5EIFBHUCBTSUdOQVRVUkUtLS0tLScsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IGFzc2VydC5yZWplY3RzKHRzc1V0aWxzLmNyZWF0ZUtleWNoYWlucyh7IHBhc3NwaHJhc2U6ICd0ZXN0JywgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkIH0pKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmVqZWN0IHdoZW4gc2Vzc2lvbiBJRHMgZnJvbSByb3VuZCAxIGFuZCByb3VuZCAyIGRvIG5vdCBtYXRjaCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvU2Vzc2lvbiA9IG5ldyBFZGRzYU1QU0RrZy5ES0coMywgMiwgMik7XG4gICAgICBjb25zdCBiaXRnb1N0YXRlOiB7IG1zZzI/OiBNUFNUeXBlcy5EZXNlcmlhbGl6ZWRNZXNzYWdlIH0gPSB7fTtcbiAgICAgIGF3YWl0IG5vY2tNUFNLZXlHZW5Sb3VuZDEoYml0Z29TZXNzaW9uLCBiaXRnb1N0YXRlLCAxKTtcblxuICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgLnBvc3QoJy9hcGkvdjIvbXBjL2dlbmVyYXRla2V5JywgKGJvZHkpID0+IGJvZHkucm91bmQgPT09ICdNUEN2Mi1SMicpXG4gICAgICAgIC5vbmNlKClcbiAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgIHNlc3Npb25JZDogJ2RpZmZlcmVudC1zZXNzaW9uLWlkJyxcbiAgICAgICAgICBjb21tb25QdWJsaWNLZXljaGFpbjogJ2EnLnJlcGVhdCgxMjgpLFxuICAgICAgICAgIGJpdGdvTXNnMjogeyBtZXNzYWdlOiAnJywgc2lnbmF0dXJlOiAnJyB9LFxuICAgICAgICB9KTtcblxuICAgICAgYXdhaXQgYXNzZXJ0LnJlamVjdHMoXG4gICAgICAgIHRzc1V0aWxzLmNyZWF0ZUtleWNoYWlucyh7IHBhc3NwaHJhc2U6ICd0ZXN0JywgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkIH0pLFxuICAgICAgICAvUm91bmQgMSBhbmQgcm91bmQgMiBzZXNzaW9uIElEcyBkbyBub3QgbWF0Y2gvXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZWplY3Qgd2hlbiBjb21tb25QdWJsaWNLZXljaGFpbiBmcm9tIEJpdEdvIGRvZXMgbm90IG1hdGNoIHRoZSBsb2NhbGx5IGNvbXB1dGVkIGtleWNoYWluJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z29TZXNzaW9uID0gbmV3IEVkZHNhTVBTRGtnLkRLRygzLCAyLCAyKTtcbiAgICAgIGNvbnN0IGJpdGdvU3RhdGU6IHsgbXNnMj86IE1QU1R5cGVzLkRlc2VyaWFsaXplZE1lc3NhZ2UgfSA9IHt9O1xuICAgICAgYXdhaXQgbm9ja01QU0tleUdlblJvdW5kMShiaXRnb1Nlc3Npb24sIGJpdGdvU3RhdGUsIDEpO1xuXG4gICAgICBub2NrKGJnVXJsKVxuICAgICAgICAucG9zdCgnL2FwaS92Mi9tcGMvZ2VuZXJhdGVrZXknLCAoYm9keSkgPT4gYm9keS5yb3VuZCA9PT0gJ01QQ3YyLVIyJylcbiAgICAgICAgLm9uY2UoKVxuICAgICAgICAucmVwbHkoMjAwLCBhc3luYyAoX3VyaSwgeyBwYXlsb2FkIH06IHsgcGF5bG9hZDogRWRkc2FNUEN2MktleUdlblJvdW5kMlJlcXVlc3QgfSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgdXNlck1zZzIsIGJhY2t1cE