bitgo
Version:
BitGo JavaScript SDK
358 lines • 68.3 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(await 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(await 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 send webauthnInfo (with enterpriseId) on the user keychain when webauthnInfo is provided', async function () {
const commonKeychain = 'a'.repeat(64);
const capturedBodies = {};
const addKeyNock = nock('https://bitgo.fakeurl')
.post(`/api/v2/${coinName}/key`, (body) => body.keyType === 'tss' && body.isMPCv2)
.times(1)
.reply(200, async (uri, requestBody) => {
capturedBodies[requestBody.source] = requestBody;
return {
id: requestBody.source,
source: requestBody.source,
type: requestBody.keyType,
commonKeychain: requestBody.commonKeychain,
encryptedPrv: requestBody.encryptedPrv,
};
});
const webauthnInfo = { otpDeviceId: 'device-123', prfSalt: 'salt-abc', passphrase: 'prf-derived-passphrase' };
// Direct participant-keychain call avoids the EdDSA DKG ceremony while still exercising the
// user-keychain webauthn assembly that POSTs to /key.
await tssUtils.createParticipantKeychain(MPCv2PartiesEnum.USER, commonKeychain, Buffer.from('userPrivate'), Buffer.from('userReduced'), 'passphrase', undefined, webauthnInfo, undefined, enterpriseId);
assert.ok(addKeyNock.isDone());
// User keychain must carry webauthnInfo (the field the backend POST /key consumes), including
// enterpriseId, and must NOT use the deprecated webauthnDevices array.
const userBody = capturedBodies['user'];
assert.ok(userBody, 'user keychain should have been created');
assert.ok(userBody.webauthnInfo, 'user keychain body should include webauthnInfo');
assert.equal(userBody.webauthnInfo.otpDeviceId, webauthnInfo.otpDeviceId);
assert.equal(userBody.webauthnInfo.prfSalt, webauthnInfo.prfSalt);
assert.equal(userBody.webauthnInfo.enterpriseId, enterpriseId);
assert.ok(userBody.webauthnInfo.encryptedPrv, 'encryptedPrv should be set');
assert.ok(await bitgo.decrypt({ input: userBody.webauthnInfo.encryptedPrv, password: webauthnInfo.passphrase }));
assert.strictEqual(userBody.webauthnDevices, undefined, 'deprecated webauthnDevices should not be sent');
});
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(await bitgo.decrypt({ input: userKeychain.reducedEncryptedPrv, password: 'passphrase' }), encodeReduced(Buffer.from('userReduced')));
assert.ok(backupKeychain.reducedEncryptedPrv);
assert.equal(await 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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LENBQUM7SUFDUCxDQUFDO0FBQ0gsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBhc3NlcnQgZnJvbSAnYXNzZXJ0JztcbmltcG9ydCBub2NrID0gcmVxdWlyZSgnbm9jaycpO1xuaW1wb3J0ICogYXMgb3BlbnBncCBmcm9tICdvcGVucGdwJztcblxuaW1wb3J0IHsgRWRkc2FNUEN2MktleUdlblJvdW5kMVJlcXVlc3QsIEVkZHNhTVBDdjJLZXlHZW5Sb3VuZDJSZXF1ZXN0IH0gZnJvbSAnQGJpdGdvL3B1YmxpYy10eXBlcyc7XG5pbXBvcnQgeyBUZXN0YWJsZUJHLCBUZXN0Qml0R28gfSBmcm9tICdAYml0Z28vc2RrLXRlc3QnO1xuaW1wb3J0IHsgQWRkS2V5Y2hhaW5PcHRpb25zLCBCYXNlQ29pbiwgY29tbW9uLCBFQ0RTQVV0aWxzLCBFRERTQVV0aWxzLCBLZXljaGFpbiwgV2FsbGV0IH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IEVkZHNhTVBTRGtnLCBNUFNDb21tcywgTVBTVHlwZXMgfSBmcm9tICdAYml0Z28vc2RrLWxpYi1tcGMnO1xuaW1wb3J0IHsgQml0R28sIEJpdGdvR1BHUHVibGljS2V5IH0gZnJvbSAnLi4vLi4vLi4vLi4vLi4vLi4vc3JjJztcblxuY29uc3QgTVBDdjJQYXJ0aWVzRW51bSA9IEVDRFNBVXRpbHMuTVBDdjJQYXJ0aWVzRW51bTtcblxuZGVzY3JpYmUoJ1RTUyBFZERTQSBNUEN2MiBVdGlsczonLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gIGNvbnN0IGNvaW5OYW1lID0gJ3NvbCc7XG4gIGNvbnN0IHdhbGxldElkID0gJzViMzQyNTJmMWJmMzQ5OTMwZTM0MDIwYTAwMDAwMDAwJztcbiAgY29uc3QgZW50ZXJwcmlzZUlkID0gJzY0NDkxNTNhNmY2YmMyMDAwNmQ2Njc3MWNkYmUxNWQzJztcblxuICBsZXQgYmdVcmw6IHN0cmluZztcbiAgbGV0IHRzc1V0aWxzOiBFRERTQVV0aWxzLkVkZHNhTVBDdjJVdGlscztcbiAgbGV0IHdhbGxldDogV2FsbGV0O1xuICBsZXQgYml0Z286IFRlc3RhYmxlQkcgJiBCaXRHbztcbiAgbGV0IGJhc2VDb2luOiBCYXNlQ29pbjtcblxuICBsZXQgYml0Z29HcGdLZXlQYWlyOiBvcGVucGdwLlNlcmlhbGl6ZWRLZXlQYWlyPHN0cmluZz4gJiB7IHJldm9jYXRpb25DZXJ0aWZpY2F0ZTogc3RyaW5nIH07XG4gIGxldCBiaXRnb1BydktleU9iajogb3BlbnBncC5Qcml2YXRlS2V5O1xuICBsZXQgY29uc3RhbnRzOiB7IG1wYzogeyBiaXRnb1B1YmxpY0tleTogc3RyaW5nOyBiaXRnb01QQ3YyUHVibGljS2V5OiBzdHJpbmcgfSB9O1xuXG4gIGJlZm9yZUVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgICBhd2FpdCBub2NrR2V0Qml0Z29QdWJsaWNLZXlCYXNlZE9uRmVhdHVyZUZsYWdzKGNvaW5OYW1lLCBlbnRlcnByaXNlSWQsIGJpdGdvR3BnS2V5UGFpcik7XG4gICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YxL2NsaWVudC9jb25zdGFudHMnKS50aW1lcygxMCkucmVwbHkoMjAwLCB7IHR0bDogMzYwMCwgY29uc3RhbnRzIH0pO1xuICB9KTtcblxuICBiZWZvcmUoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIG9wZW5wZ3AuY29uZmlnLnJlamVjdEN1cnZlcyA9IG5ldyBTZXQoKTtcblxuICAgIGJpdGdvR3BnS2V5UGFpciA9IGF3YWl0IG9wZW5wZ3AuZ2VuZXJhdGVLZXkoe1xuICAgICAgdXNlcklEczogW3sgbmFtZTogJ2JpdGdvJywgZW1haWw6ICdiaXRnb0B0ZXN0LmNvbScgfV0sXG4gICAgICBjdXJ2ZTogJ2VkMjU1MTknLFxuICAgICAgZm9ybWF0OiAnYXJtb3JlZCcsXG4gICAgfSk7XG5cbiAgICBiaXRnb1BydktleU9iaiA9IGF3YWl0IG9wZW5wZ3AucmVhZFByaXZhdGVLZXkoeyBhcm1vcmVkS2V5OiBiaXRnb0dwZ0tleVBhaXIucHJpdmF0ZUtleSB9KTtcblxuICAgIGNvbnN0YW50cyA9IHtcbiAgICAgIG1wYzoge1xuICAgICAgICBiaXRnb1B1YmxpY0tleTogYml0Z29HcGdLZXlQYWlyLnB1YmxpY0tleSxcbiAgICAgICAgYml0Z29NUEN2MlB1YmxpY0tleTogYml0Z29HcGdLZXlQYWlyLnB1YmxpY0tleSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvLCB7IGVudjogJ21vY2snIH0pO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGJhc2VDb2luID0gYml0Z28uY29pbihjb2luTmFtZSk7XG4gICAgYmdVcmwgPSBjb21tb24uRW52aXJvbm1lbnRzW2JpdGdvLmdldEVudigpXS51cmk7XG5cbiAgICBjb25zdCB3YWxsZXREYXRhID0ge1xuICAgICAgaWQ6IHdhbGxldElkLFxuICAgICAgZW50ZXJwcmlzZTogZW50ZXJwcmlzZUlkLFxuICAgICAgY29pbjogY29pbk5hbWUsXG4gICAgICBjb2luU3BlY2lmaWM6IHt9LFxuICAgICAgbXVsdGlzaWdUeXBlOiAndHNzJyxcbiAgICB9O1xuICAgIHdhbGxldCA9IG5ldyBXYWxsZXQoYml0Z28sIGJhc2VDb2luLCB3YWxsZXREYXRhKTtcbiAgICB0c3NVdGlscyA9IG5ldyBFRERTQVV0aWxzLkVkZHNhTVBDdjJVdGlscyhiaXRnbywgYmFzZUNvaW4sIHdhbGxldCk7XG4gIH0pO1xuXG4gIGFmdGVyKGZ1bmN0aW9uICgpIHtcbiAgICBub2NrLmNsZWFuQWxsKCk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdUU1Mga2V5IGNoYWlucycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIGdlbmVyYXRlIFRTUyBNUFMga2V5cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvU2Vzc2lvbiA9IG5ldyBFZGRzYU1QU0RrZy5ES0coMywgMiwgMik7XG4gICAgICBjb25zdCBiaXRnb1N0YXRlOiB7IG1zZzI/OiBNUFNUeXBlcy5EZXNlcmlhbGl6ZWRNZXNzYWdlIH0gPSB7fTtcbiAgICAgIGNvbnN0IHJvdW5kMU5vY2sgPSBhd2FpdCBub2NrTVBTS2V5R2VuUm91bmQxKGJpdGdvU2Vzc2lvbiwgYml0Z29TdGF0ZSwgMSk7XG4gICAgICBjb25zdCByb3VuZDJOb2NrID0gYXdhaXQgbm9ja01QU0tleUdlblJvdW5kMihiaXRnb1Nlc3Npb24sIGJpdGdvU3RhdGUsIDEpO1xuICAgICAgY29uc3QgYWRkS2V5Tm9jayA9IGF3YWl0IG5vY2tBZGRLZXlDaGFpbihjb2luTmFtZSwgMyk7XG5cbiAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgcGFzc3BocmFzZTogJ3Rlc3QnLFxuICAgICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlSWQsXG4gICAgICAgIG9yaWdpbmFsUGFzc2NvZGVFbmNyeXB0aW9uQ29kZTogJzEyMzQ1NicsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCB7IHVzZXJLZXljaGFpbiwgYmFja3VwS2V5Y2hhaW4sIGJpdGdvS2V5Y2hhaW4gfSA9IGF3YWl0IHRzc1V0aWxzLmNyZWF0ZUtleWNoYWlucyhwYXJhbXMpO1xuXG4gICAgICBhc3NlcnQub2socm91bmQxTm9jay5pc0RvbmUoKSk7XG4gICAgICBhc3NlcnQub2socm91bmQyTm9jay5pc0RvbmUoKSk7XG4gICAgICBhc3NlcnQub2soYWRkS2V5Tm9jay5pc0RvbmUoKSk7XG5cbiAgICAgIGFzc2VydC5vayh1c2VyS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5zb3VyY2UsICd1c2VyJyk7XG4gICAgICBhc3NlcnQub2sodXNlcktleWNoYWluLmNvbW1vbktleWNoYWluKTtcbiAgICAgIGFzc2VydC5vayh1c2VyS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2KTtcbiAgICAgIGFzc2VydC5vayhhd2FpdCBiaXRnby5kZWNyeXB0KHsgaW5wdXQ6IHVzZXJLZXljaGFpbi5lbmNyeXB0ZWRQcnYsIHBhc3N3b3JkOiBwYXJhbXMucGFzc3BocmFzZSB9KSk7XG5cbiAgICAgIGFzc2VydC5vayhiYWNrdXBLZXljaGFpbik7XG4gICAgICBhc3NlcnQuZXF1YWwoYmFja3VwS2V5Y2hhaW4uc291cmNlLCAnYmFja3VwJyk7XG4gICAgICBhc3NlcnQub2soYmFja3VwS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0Lm9rKGJhY2t1cEtleWNoYWluLmVuY3J5cHRlZFBydik7XG4gICAgICBhc3NlcnQub2soYXdhaXQgYml0Z28uZGVjcnlwdCh7IGlucHV0OiBiYWNrdXBLZXljaGFpbi5lbmNyeXB0ZWRQcnYsIHBhc3N3b3JkOiBwYXJhbXMucGFzc3BocmFzZSB9KSk7XG5cbiAgICAgIGFzc2VydC5vayhiaXRnb0tleWNoYWluKTtcbiAgICAgIGFzc2VydC5lcXVhbChiaXRnb0tleWNoYWluLnNvdXJjZSwgJ2JpdGdvJyk7XG4gICAgICBhc3NlcnQub2soYml0Z29LZXljaGFpbi5jb21tb25LZXljaGFpbik7XG5cbiAgICAgIGFzc2VydC5lcXVhbCh1c2VyS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4sIGJhY2t1cEtleWNoYWluLmNvbW1vbktleWNoYWluKTtcbiAgICAgIGFzc2VydC5lcXVhbCh1c2VyS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4sIGJpdGdvS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBzZW5kIHdlYmF1dGhuSW5mbyAod2l0aCBlbnRlcnByaXNlSWQpIG9uIHRoZSB1c2VyIGtleWNoYWluIHdoZW4gd2ViYXV0aG5JbmZvIGlzIHByb3ZpZGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgY29tbW9uS2V5Y2hhaW4gPSAnYScucmVwZWF0KDY0KTtcbiAgICAgIGNvbnN0IGNhcHR1cmVkQm9kaWVzOiBSZWNvcmQ8c3RyaW5nLCBBZGRLZXljaGFpbk9wdGlvbnM+ID0ge307XG4gICAgICBjb25zdCBhZGRLZXlOb2NrID0gbm9jaygnaHR0cHM6Ly9iaXRnby5mYWtldXJsJylcbiAgICAgICAgLnBvc3QoYC9hcGkvdjIvJHtjb2luTmFtZX0va2V5YCwgKGJvZHkpID0+IGJvZHkua2V5VHlwZSA9PT0gJ3RzcycgJiYgYm9keS5pc01QQ3YyKVxuICAgICAgICAudGltZXMoMSlcbiAgICAgICAgLnJlcGx5KDIwMCwgYXN5bmMgKHVyaSwgcmVxdWVzdEJvZHk6IEFkZEtleWNoYWluT3B0aW9ucykgPT4ge1xuICAgICAgICAgIGNhcHR1cmVkQm9kaWVzW3JlcXVlc3RCb2R5LnNvdXJjZSBhcyBzdHJpbmddID0gcmVxdWVzdEJvZHk7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGlkOiByZXF1ZXN0Qm9keS5zb3VyY2UsXG4gICAgICAgICAgICBzb3VyY2U6IHJlcXVlc3RCb2R5LnNvdXJjZSxcbiAgICAgICAgICAgIHR5cGU6IHJlcXVlc3RCb2R5LmtleVR5cGUsXG4gICAgICAgICAgICBjb21tb25LZXljaGFpbjogcmVxdWVzdEJvZHkuY29tbW9uS2V5Y2hhaW4sXG4gICAgICAgICAgICBlbmNyeXB0ZWRQcnY6IHJlcXVlc3RCb2R5LmVuY3J5cHRlZFBydixcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcblxuICAgICAgY29uc3Qgd2ViYXV0aG5JbmZvID0geyBvdHBEZXZpY2VJZDogJ2RldmljZS0xMjMnLCBwcmZTYWx0OiAnc2FsdC1hYmMnLCBwYXNzcGhyYXNlOiAncHJmLWRlcml2ZWQtcGFzc3BocmFzZScgfTtcbiAgICAgIC8vIERpcmVjdCBwYXJ0aWNpcGFudC1rZXljaGFpbiBjYWxsIGF2b2lkcyB0aGUgRWREU0EgREtHIGNlcmVtb255IHdoaWxlIHN0aWxsIGV4ZXJjaXNpbmcgdGhlXG4gICAgICAvLyB1c2VyLWtleWNoYWluIHdlYmF1dGhuIGFzc2VtYmx5IHRoYXQgUE9TVHMgdG8gL2tleS5cbiAgICAgIGF3YWl0IHRzc1V0aWxzLmNyZWF0ZVBhcnRpY2lwYW50S2V5Y2hhaW4oXG4gICAgICAgIE1QQ3YyUGFydGllc0VudW0uVVNFUixcbiAgICAgICAgY29tbW9uS2V5Y2hhaW4sXG4gICAgICAgIEJ1ZmZlci5mcm9tKCd1c2VyUHJpdmF0ZScpLFxuICAgICAgICBCdWZmZXIuZnJvbSgndXNlclJlZHVjZWQnKSxcbiAgICAgICAgJ3Bhc3NwaHJhc2UnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIHdlYmF1dGhuSW5mbyxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICBlbnRlcnByaXNlSWRcbiAgICAgICk7XG4gICAgICBhc3NlcnQub2soYWRkS2V5Tm9jay5pc0RvbmUoKSk7XG5cbiAgICAgIC8vIFVzZXIga2V5Y2hhaW4gbXVzdCBjYXJyeSB3ZWJhdXRobkluZm8gKHRoZSBmaWVsZCB0aGUgYmFja2VuZCBQT1NUIC9rZXkgY29uc3VtZXMpLCBpbmNsdWRpbmdcbiAgICAgIC8vIGVudGVycHJpc2VJZCwgYW5kIG11c3QgTk9UIHVzZSB0aGUgZGVwcmVjYXRlZCB3ZWJhdXRobkRldmljZXMgYXJyYXkuXG4gICAgICBjb25zdCB1c2VyQm9keSA9IGNhcHR1cmVkQm9kaWVzWyd1c2VyJ107XG4gICAgICBhc3NlcnQub2sodXNlckJvZHksICd1c2VyIGtleWNoYWluIHNob3VsZCBoYXZlIGJlZW4gY3JlYXRlZCcpO1xuICAgICAgYXNzZXJ0Lm9rKHVzZXJCb2R5LndlYmF1dGhuSW5mbywgJ3VzZXIga2V5Y2hhaW4gYm9keSBzaG91bGQgaW5jbHVkZSB3ZWJhdXRobkluZm8nKTtcbiAgICAgIGFzc2VydC5lcXVhbCh1c2VyQm9keS53ZWJhdXRobkluZm8ub3RwRGV2aWNlSWQsIHdlYmF1dGhuSW5mby5vdHBEZXZpY2VJZCk7XG4gICAgICBhc3NlcnQuZXF1YWwodXNlckJvZHkud2ViYXV0aG5JbmZvLnByZlNhbHQsIHdlYmF1dGhuSW5mby5wcmZTYWx0KTtcbiAgICAgIGFzc2VydC5lcXVhbCh1c2VyQm9keS53ZWJhdXRobkluZm8uZW50ZXJwcml