PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/dist/test/v2/unit/internal
Просмотр файла: opengpgUtils.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const openpgp = require("openpgp");
const should = require("should");
const crypto = require("crypto");
const assert = require("assert");
const sdk_core_1 = require("@bitgo/sdk-core");
const utxo_lib_1 = require("@bitgo/utxo-lib");
const sinon = require("sinon");
const sodium = require('libsodium-wrappers-sumo');
describe('OpenGPG Utils Tests', function () {
let senderKey;
let recipientKey;
let otherKey;
before(async function () {
openpgp.config.rejectCurves = new Set();
senderKey = await openpgp.generateKey({
userIDs: [
{
name: 'sender',
email: 'sender@username.com',
},
],
curve: 'secp256k1',
});
recipientKey = await openpgp.generateKey({
userIDs: [
{
name: 'recipient',
email: 'recipient@username.com',
},
],
curve: 'secp256k1',
});
otherKey = await openpgp.generateKey({
userIDs: [
{
name: 'other',
email: 'other@username.com',
},
],
curve: 'secp256k1',
});
});
describe('createShareProof', function () {
it('should create an Ed share proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await decodedProof.verifyPrimaryUser([decodedPubKey]))[0].valid;
isValid.should.be.true();
const proofSubkeys = decodedProof.getSubkeys()[1];
const decodedUValueProof = Buffer.from(proofSubkeys.keyPacket.publicParams.Q.slice(1)).toString('hex');
const rawUValueProof = Buffer.from(sodium.crypto_scalarmult_ed25519_base_noclamp(Buffer.from(uValue, 'hex'))).toString('hex');
decodedUValueProof.should.equal(rawUValueProof);
});
it('should create an Ec share proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'ecdsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await decodedProof.verifyPrimaryUser([decodedPubKey]))[0].valid;
isValid.should.be.true();
const proofSubkeys = decodedProof.getSubkeys()[1];
const decodedUValueProof = proofSubkeys.keyPacket.publicParams.Q;
const rawUValueProof = utxo_lib_1.ecc.pointFromScalar(Buffer.from(uValue, 'hex'), false);
equal(decodedUValueProof, rawUValueProof).should.be.true();
});
});
describe('verifyPrimaryUserWrapper', function () {
it('should verify primary user with a date check', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await sdk_core_1.openpgpUtils.verifyPrimaryUserWrapper(decodedProof, decodedPubKey, true))[0].valid;
should.exist(isValid);
if (isValid !== null) {
isValid.should.be.true();
}
});
it('should verify primary user without a date check', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
// verify proof
const decodedProof = await openpgp.readKey({ armoredKey: proof }).should.be.fulfilled();
const decodedPubKey = await openpgp.readKey({ armoredKey: senderKey.publicKey }).should.be.fulfilled();
const isValid = (await sdk_core_1.openpgpUtils.verifyPrimaryUserWrapper(decodedProof, decodedPubKey, false))[0].valid;
should.exist(isValid);
if (isValid !== null) {
isValid.should.be.true();
}
});
});
describe('verifyShareProof EdDSA', function () {
it('should be able to verify a valid proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
const isValid = await sdk_core_1.openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'eddsa');
isValid.should.be.true();
});
it('should be able to detect sender is an attacker', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(otherKey.privateKey, uValue, 'eddsa');
const isValid = await sdk_core_1.openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'eddsa');
isValid.should.be.false();
});
it('should be able to detect u value is corrupted', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'eddsa');
const uValueCorrupted = crypto.randomBytes(32).toString('hex');
const isValid = await sdk_core_1.openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValueCorrupted, 'eddsa');
isValid.should.be.false();
});
});
describe('verifyShareProof ECDSA', function () {
it('should be able to verify a valid proof', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'ecdsa');
const isValid = await sdk_core_1.openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'ecdsa');
isValid.should.be.true();
});
it('should be able to detect sender is an attacker', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(otherKey.privateKey, uValue, 'ecdsa');
const isValid = await sdk_core_1.openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValue, 'ecdsa');
isValid.should.be.false();
});
it('should be able to detect u value is corrupted', async function () {
const uValue = crypto.randomBytes(32).toString('hex');
const proof = await sdk_core_1.openpgpUtils.createShareProof(senderKey.privateKey, uValue, 'ecdsa');
const uValueCorrupted = crypto.randomBytes(32).toString('hex');
const isValid = await sdk_core_1.openpgpUtils.verifyShareProof(senderKey.publicKey, proof, uValueCorrupted, 'ecdsa');
isValid.should.be.false();
});
});
describe('verifySharedDataProof and createSharedDataProof test', function () {
it('should be able to detect if proof value is corrupted or not', async function () {
const sharedData1 = crypto.randomBytes(32).toString('hex');
const sharedData2 = crypto.randomBytes(32).toString('hex');
const dataToProofArray = [
{ name: 's1', value: sharedData1 },
{ name: 's2', value: sharedData2 },
];
const proof = await sdk_core_1.openpgpUtils.createSharedDataProof(senderKey.privateKey, otherKey.publicKey, dataToProofArray);
let isValid = await sdk_core_1.openpgpUtils.verifySharedDataProof(senderKey.publicKey, proof, dataToProofArray);
isValid.should.be.true();
// tamper with the data
dataToProofArray[0].value = 'tampered data';
isValid = await sdk_core_1.openpgpUtils.verifySharedDataProof(senderKey.publicKey, proof, dataToProofArray);
isValid.should.be.false();
});
it('should be able verify data proof if created in the future', async function () {
const sharedData1 = crypto.randomBytes(32).toString('hex');
const sharedData2 = crypto.randomBytes(32).toString('hex');
const dataToProofArray = [
{ name: 's1', value: sharedData1 },
{ name: 's2', value: sharedData2 },
];
const proof = await sdk_core_1.openpgpUtils.createSharedDataProof(senderKey.privateKey, otherKey.publicKey, dataToProofArray);
const clock = sinon.useFakeTimers(new Date('2001-02-14T12:00:00Z').getTime());
const isValid = await sdk_core_1.openpgpUtils.verifySharedDataProof(senderKey.publicKey, proof, dataToProofArray);
isValid.should.be.true();
clock.restore();
});
});
describe('encrypt and decrypt with signing', function () {
it('should successfully encrypt, sign, and decrypt', async function () {
const text = 'original message';
const signedMessage = await sdk_core_1.openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
const decryptedMessage = await sdk_core_1.openpgpUtils.readSignedMessage(signedMessage, senderKey.publicKey, recipientKey.privateKey);
decryptedMessage.should.equal(text);
});
it('should fail on verification with wrong public key', async function () {
const text = 'original message';
const signedMessage = await sdk_core_1.openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
await sdk_core_1.openpgpUtils
.readSignedMessage(signedMessage, otherKey.publicKey, recipientKey.privateKey)
.should.be.rejected();
});
it('should fail on decryption with wrong private key', async function () {
const text = 'original message';
const signedMessage = await sdk_core_1.openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
await sdk_core_1.openpgpUtils
.readSignedMessage(signedMessage, senderKey.publicKey, otherKey.privateKey)
.should.be.rejectedWith('Error decrypting message: Session key decryption failed.');
});
it('should encrypt, sign, and decrypt without previously clearing rejectedCurves', async function () {
openpgp.config.rejectCurves = new Set([openpgp.enums.curve.secp256k1]);
const text = 'original message';
const signedMessage = await sdk_core_1.openpgpUtils.encryptAndSignText(text, recipientKey.publicKey, senderKey.privateKey);
const decryptedMessage = await sdk_core_1.openpgpUtils.readSignedMessage(signedMessage, senderKey.publicKey, recipientKey.privateKey);
decryptedMessage.should.equal(text);
openpgp.config.rejectCurves = new Set();
});
});
describe('signatures and verification', function () {
it('should verify signature', async function () {
const text = 'some payload';
const signature = await sdk_core_1.openpgpUtils.signText(text, senderKey.privateKey);
const isValidSignature = await sdk_core_1.openpgpUtils.verifySignature(text, signature, senderKey.publicKey);
isValidSignature.should.be.true();
});
it('should fail verification if public key is incorrect', async function () {
const text = 'some payload';
const signature = await sdk_core_1.openpgpUtils.signText(text, senderKey.privateKey);
const isValidSignature = await sdk_core_1.openpgpUtils.verifySignature(text, signature, recipientKey.publicKey);
isValidSignature.should.be.false();
});
it('should fail verification if message is incorrect', async function () {
const text = 'some payload';
const signature = await sdk_core_1.openpgpUtils.signText(text, senderKey.privateKey);
const isValidSignature = await sdk_core_1.openpgpUtils.verifySignature('something else', signature, senderKey.publicKey);
isValidSignature.should.be.false();
});
});
describe('GPG key generation', function () {
it('should generate a a GPG key for secp256k1 with random name and email', async function () {
const gpgKey = await sdk_core_1.openpgpUtils.generateGPGKeyPair('secp256k1');
should.exist(gpgKey);
should.exist(gpgKey.privateKey);
should.exist(gpgKey.publicKey);
});
it('should generate a a GPG key for with random name and email', async function () {
const gpgKey = await sdk_core_1.openpgpUtils.generateGPGKeyPair('ed25519');
should.exist(gpgKey);
should.exist(gpgKey.privateKey);
should.exist(gpgKey.publicKey);
});
it('should generate a a GPG key with provided name and email', async function () {
const userName = 'John Doe';
const userEmail = 'john.doe@example.com';
const gpgKey = await sdk_core_1.openpgpUtils.generateGPGKeyPair('secp256k1', userName, userEmail);
should.exist(gpgKey);
should.exist(gpgKey.privateKey);
should.exist(gpgKey.publicKey);
const parsedKey = await openpgp.readKey({ armoredKey: gpgKey.publicKey });
should.exist(parsedKey);
assert(parsedKey);
const primaryUser = await parsedKey.getPrimaryUser();
primaryUser.user.userID?.name?.should.equal(userName);
primaryUser.user.userID?.email?.should.equal(userEmail);
});
it('should fail to generate a a GPG key for unknown curve', async function () {
await sdk_core_1.openpgpUtils
.generateGPGKeyPair('unknownCurve')
.should.be.rejectedWith('Error generating keypair: Unknown curve');
});
});
function equal(buf1, buf2) {
if (buf1.byteLength != buf2.byteLength)
return false;
const dv1 = new Int8Array(buf1);
const dv2 = new Int8Array(buf2);
for (let i = 0; i != buf1.byteLength; i++) {
if (dv1[i] != dv2[i])
return false;
}
return true;
}
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmdwZ1V0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2ludGVybmFsL29wZW5ncGdVdGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUFtQztBQUNuQyxpQ0FBaUM7QUFDakMsaUNBQWlDO0FBQ2pDLGlDQUFpQztBQUVqQyw4Q0FBK0M7QUFDL0MsOENBQW1EO0FBQ25ELCtCQUErQjtBQUUvQixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FBQztBQUVsRCxRQUFRLENBQUMscUJBQXFCLEVBQUU7SUFDOUIsSUFBSSxTQUFvRCxDQUFDO0lBQ3pELElBQUksWUFBdUQsQ0FBQztJQUM1RCxJQUFJLFFBQW1ELENBQUM7SUFFeEQsTUFBTSxDQUFDLEtBQUs7UUFDVixPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLFNBQVMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxXQUFXLENBQUM7WUFDcEMsT0FBTyxFQUFFO2dCQUNQO29CQUNFLElBQUksRUFBRSxRQUFRO29CQUNkLEtBQUssRUFBRSxxQkFBcUI7aUJBQzdCO2FBQ0Y7WUFDRCxLQUFLLEVBQUUsV0FBVztTQUNuQixDQUFDLENBQUM7UUFDSCxZQUFZLEdBQUcsTUFBTSxPQUFPLENBQUMsV0FBVyxDQUFDO1lBQ3ZDLE9BQU8sRUFBRTtnQkFDUDtvQkFDRSxJQUFJLEVBQUUsV0FBVztvQkFDakIsS0FBSyxFQUFFLHdCQUF3QjtpQkFDaEM7YUFDRjtZQUNELEtBQUssRUFBRSxXQUFXO1NBQ25CLENBQUMsQ0FBQztRQUNILFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxXQUFXLENBQUM7WUFDbkMsT0FBTyxFQUFFO2dCQUNQO29CQUNFLElBQUksRUFBRSxPQUFPO29CQUNiLEtBQUssRUFBRSxvQkFBb0I7aUJBQzVCO2FBQ0Y7WUFDRCxLQUFLLEVBQUUsV0FB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QUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsU0FBUyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUk7UUFDdkIsSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxVQUFVO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDckQsTUFBTSxHQUFHLEdBQUcsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUMxQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3JDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDSCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIG9wZW5wZ3AgZnJvbSAnb3BlbnBncCc7XG5pbXBvcnQgKiBhcyBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5cbmltcG9ydCB7IG9wZW5wZ3BVdGlscyB9IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBlY2MgYXMgc2VjcDI1NmsxIH0gZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcbmltcG9ydCAqIGFzIHNpbm9uIGZyb20gJ3Npbm9uJztcblxuY29uc3Qgc29kaXVtID0gcmVxdWlyZSgnbGlic29kaXVtLXdyYXBwZXJzLXN1bW8nKTtcblxuZGVzY3JpYmUoJ09wZW5HUEcgVXRpbHMgVGVzdHMnLCBmdW5jdGlvbiAoKSB7XG4gIGxldCBzZW5kZXJLZXk6IHsgcHVibGljS2V5OiBzdHJpbmc7IHByaXZhdGVLZXk6IHN0cmluZyB9O1xuICBsZXQgcmVjaXBpZW50S2V5OiB7IHB1YmxpY0tleTogc3RyaW5nOyBwcml2YXRlS2V5OiBzdHJpbmcgfTtcbiAgbGV0IG90aGVyS2V5OiB7IHB1YmxpY0tleTogc3RyaW5nOyBwcml2YXRlS2V5OiBzdHJpbmcgfTtcblxuICBiZWZvcmUoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIG9wZW5wZ3AuY29uZmlnLnJlamVjdEN1cnZlcyA9IG5ldyBTZXQoKTtcbiAgICBzZW5kZXJLZXkgPSBhd2FpdCBvcGVucGdwLmdlbmVyYXRlS2V5KHtcbiAgICAgIHVzZXJJRHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6ICdzZW5kZXInLFxuICAgICAgICAgIGVtYWlsOiAnc2VuZGVyQHVzZXJuYW1lLmNvbScsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgY3VydmU6ICdzZWNwMjU2azEnLFxuICAgIH0pO1xuICAgIHJlY2lwaWVudEtleSA9IGF3YWl0IG9wZW5wZ3AuZ2VuZXJhdGVLZXkoe1xuICAgICAgdXNlcklEczogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ3JlY2lwaWVudCcsXG4gICAgICAgICAgZW1haWw6ICdyZWNpcGllbnRAdXNlcm5hbWUuY29tJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBjdXJ2ZTogJ3NlY3AyNTZrMScsXG4gICAgfSk7XG4gICAgb3RoZXJLZXkgPSBhd2FpdCBvcGVucGdwLmdlbmVyYXRlS2V5KHtcbiAgICAgIHVzZXJJRHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6ICdvdGhlcicsXG4gICAgICAgICAgZW1haWw6ICdvdGhlckB1c2VybmFtZS5jb20nLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIGN1cnZlOiAnc2VjcDI1NmsxJyxcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2NyZWF0ZVNoYXJlUHJvb2YnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBjcmVhdGUgYW4gRWQgc2hhcmUgcHJvb2YnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB1VmFsdWUgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHByb29mID0gYXdhaXQgb3BlbnBncFV0aWxzLmNyZWF0ZVNoYXJlUHJvb2Yoc2VuZGVyS2V5LnByaXZhdGVLZXksIHVWYWx1ZSwgJ2VkZHNhJyk7XG5cbiAgICAgIC8vIHZlcmlmeSBwcm9vZlxuICAgICAgY29uc3QgZGVjb2RlZFByb29mID0gYXdhaXQgb3BlbnBncC5yZWFkS2V5KHsgYXJtb3JlZEtleTogcHJvb2YgfSkuc2hvdWxkLmJlLmZ1bGZpbGxlZCgpO1xuICAgICAgY29uc3QgZGVjb2RlZFB1YktleSA9IGF3YWl0IG9wZW5wZ3AucmVhZEtleSh7IGFybW9yZWRLZXk6IHNlbmRlcktleS5wdWJsaWNLZXkgfSkuc2hvdWxkLmJlLmZ1bGZpbGxlZCgpO1xuICAgICAgY29uc3QgaXNWYWxpZCA9IChhd2FpdCBkZWNvZGVkUHJvb2YudmVyaWZ5UHJpbWFyeVVzZXIoW2RlY29kZWRQdWJLZXldKSlbMF0udmFsaWQ7XG4gICAgICBpc1ZhbGlkLnNob3VsZC5iZS50cnVlKCk7XG5cbiAgICAgIGNvbnN0IHByb29mU3Via2V5cyA9IGRlY29kZWRQcm9vZi5nZXRTdWJrZXlzKClbMV07XG5cbiAgICAgIGNvbnN0IGRlY29kZWRVVmFsdWVQcm9vZiA9IEJ1ZmZlci5mcm9tKHByb29mU3Via2V5cy5rZXlQYWNrZXQucHVibGljUGFyYW1zLlEuc2xpY2UoMSkpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHJhd1VWYWx1ZVByb29mID0gQnVmZmVyLmZyb20oXG4gICAgICAgIHNvZGl1bS5jcnlwdG9fc2NhbGFybXVsdF9lZDI1NTE5X2Jhc2Vfbm9jbGFtcChCdWZmZXIuZnJvbSh1VmFsdWUsICdoZXgnKSlcbiAgICAgICkudG9TdHJpbmcoJ2hleCcpO1xuXG4gICAgICBkZWNvZGVkVVZhbHVlUHJvb2Yuc2hvdWxkLmVxdWFsKHJhd1VWYWx1ZVByb29mKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgY3JlYXRlIGFuIEVjIHNoYXJlIHByb29mJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdVZhbHVlID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnaGV4Jyk7XG4gICAgICBjb25zdCBwcm9vZiA9IGF3YWl0IG9wZW5wZ3BVdGlscy5jcmVhdGVTaGFyZVByb29mKHNlbmRlcktleS5wcml2YXRlS2V5LCB1VmFsdWUsICdlY2RzYScpO1xuXG4gICAgICAvLyB2ZXJpZnkgcHJvb2ZcbiAgICAgIGNvbnN0IGRlY29kZWRQcm9vZiA9IGF3YWl0IG9wZW5wZ3AucmVhZEtleSh7IGFybW9yZWRLZXk6IHByb29mIH0pLnNob3VsZC5iZS5mdWxmaWxsZWQoKTtcbiAgICAgIGNvbnN0IGRlY29kZWRQdWJLZXkgPSBhd2FpdCBvcGVucGdwLnJlYWRLZXkoeyBhcm1vcmVkS2V5OiBzZW5kZXJLZXkucHVibGljS2V5IH0pLnNob3VsZC5iZS5mdWxmaWxsZWQoKTtcbiAgICAgIGNvbnN0IGlzVmFsaWQgPSAoYXdhaXQgZGVjb2RlZFByb29mLnZlcmlmeVByaW1hcnlVc2VyKFtkZWNvZGVkUHViS2V5XSkpWzBdLnZhbGlkO1xuICAgICAgaXNWYWxpZC5zaG91bGQuYmUudHJ1ZSgpO1xuXG4gICAgICBjb25zdCBwcm9vZlN1YmtleXMgPSBkZWNvZGVkUHJvb2YuZ2V0U3Via2V5cygpWzFdO1xuXG4gICAgICBjb25zdCBkZWNvZGVkVVZhbHVlUHJvb2YgPSBwcm9vZlN1YmtleXMua2V5UGFja2V0LnB1YmxpY1BhcmFtcy5RO1xuICAgICAgY29uc3QgcmF3VVZhbHVlUHJvb2YgPSBzZWNwMjU2azEucG9pbnRGcm9tU2NhbGFyKEJ1ZmZlci5mcm9tKHVWYWx1ZSwgJ2hleCcpLCBmYWxzZSk7XG4gICAgICBlcXVhbChkZWNvZGVkVVZhbHVlUHJvb2YsIHJhd1VWYWx1ZVByb29mKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgndmVyaWZ5UHJpbWFyeVVzZXJXcmFwcGVyJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHByaW1hcnkgdXNlciB3aXRoIGEgZGF0ZSBjaGVjaycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHVWYWx1ZSA9IGNyeXB0by5yYW5kb21CeXRlcygzMikudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgY29uc3QgcHJvb2YgPSBhd2FpdCBvcGVucGdwVXRpbHMuY3JlYXRlU2hhcmVQcm9vZihzZW5kZXJLZXkucHJpdmF0ZUtleSwgdVZhbHVlLCAnZWRkc2EnKTtcblxuICAgICAgLy8gdmVyaWZ5IHByb29mXG4gICAgICBjb25zdCBkZWNvZGVkUHJvb2YgPSBhd2FpdCBvcGVucGdwLnJlYWRLZXkoeyBhcm1vcmVkS2V5OiBwcm9vZiB9KS5zaG91bGQuYmUuZnVsZmlsbGVkKCk7XG4gICAgICBjb25zdCBkZWNvZGVkUHViS2V5ID0gYXdhaXQgb3BlbnBncC5yZWFkS2V5KHsgYXJtb3JlZEtleTogc2VuZGVyS2V5LnB1YmxpY0tleSB9KS5zaG91bGQuYmUuZnVsZmlsbGVkKCk7XG4gICAgICBjb25zdCBpc1ZhbGlkID0gKGF3YWl0IG9wZW5wZ3BVdGlscy52ZXJpZnlQcmltYXJ5VXNlcldyYXBwZXIoZGVjb2RlZFByb29mLCBkZWNvZGVkUHViS2V5LCB0cnVlKSlbMF0udmFsaWQ7XG4gICAgICBzaG91bGQuZXhpc3QoaXNWYWxpZCk7XG4gICAgICBpZiAoaXNWYWxpZCAhPT0gbnVsbCkge1xuICAgICAgICBpc1ZhbGlkLnNob3VsZC5iZS50cnVlKCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZlcmlmeSBwcmltYXJ5IHVzZXIgd2l0aG91dCBhIGRhdGUgY2hlY2snLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB1VmFsdWUgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHByb29mID0gYXdhaXQgb3BlbnBncFV0aWxzLmNyZWF0ZVNoYXJlUHJvb2Yoc2VuZGVyS2V5LnByaXZhdGVLZXksIHVWYWx1ZSwgJ2VkZHNhJyk7XG5cbiAgICAgIC8vIHZlcmlmeSBwcm9vZlxuICAgICAgY29uc3QgZGVjb2RlZFByb29mID0gYXdhaXQgb3BlbnBncC5yZWFkS2V5KHsgYXJtb3JlZEtleTogcHJvb2YgfSkuc2hvdWxkLmJlLmZ1bGZpbGxlZCgpO1xuICAgICAgY29uc3QgZGVjb2RlZFB1YktleSA9IGF3YWl0IG9wZW5wZ3AucmVhZEtleSh7IGFybW9yZWRLZXk6IHNlbmRlcktleS5wdWJsaWNLZXkgfSkuc2hvdWxkLmJlLmZ1bGZpbGxlZCgpO1xuICAgICAgY29uc3QgaXNWYWxpZCA9IChhd2FpdCBvcGVucGdwVXRpbHMudmVyaWZ5UHJpbWFyeVVzZXJXcmFwcGVyKGRlY29kZWRQcm9vZiwgZGVjb2RlZFB1YktleSwgZmFsc2UpKVswXS52YWxpZDtcbiAgICAgIHNob3VsZC5leGlzdChpc1ZhbGlkKTtcbiAgICAgIGlmIChpc1ZhbGlkICE9PSBudWxsKSB7XG4gICAgICAgIGlzVmFsaWQuc2hvdWxkLmJlLnRydWUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3ZlcmlmeVNoYXJlUHJvb2YgRWREU0EnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBiZSBhYmxlIHRvIHZlcmlmeSBhIHZhbGlkIHByb29mJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdVZhbHVlID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnaGV4Jyk7XG4gICAgICBjb25zdCBwcm9vZiA9IGF3YWl0IG9wZW5wZ3BVdGlscy5jcmVhdGVTaGFyZVByb29mKHNlbmRlcktleS5wcml2YXRlS2V5LCB1VmFsdWUsICdlZGRzYScpO1xuICAgICAgY29uc3QgaXNWYWxpZCA9IGF3YWl0IG9wZW5wZ3BVdGlscy52ZXJpZnlTaGFyZVByb29mKHNlbmRlcktleS5wdWJsaWNLZXksIHByb29mLCB1VmFsdWUsICdlZGRzYScpO1xuICAgICAgaXNWYWxpZC5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBiZSBhYmxlIHRvIGRldGVjdCBzZW5kZXIgaXMgYW4gYXR0YWNrZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB1VmFsdWUgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHByb29mID0gYXdhaXQgb3BlbnBncFV0aWxzLmNyZWF0ZVNoYXJlUHJvb2Yob3RoZXJLZXkucHJpdmF0ZUtleSwgdVZhbHVlLCAnZWRkc2EnKTtcbiAgICAgIGNvbnN0IGlzVmFsaWQgPSBhd2FpdCBvcGVucGdwVXRpbHMudmVyaWZ5U2hhcmVQcm9vZihzZW5kZXJLZXkucHVibGljS2V5LCBwcm9vZiwgdVZhbHVlLCAnZWRkc2EnKTtcbiAgICAgIGlzVmFsaWQuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGJlIGFibGUgdG8gZGV0ZWN0IHUgdmFsdWUgaXMgY29ycnVwdGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdVZhbHVlID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnaGV4Jyk7XG4gICAgICBjb25zdCBwcm9vZiA9IGF3YWl0IG9wZW5wZ3BVdGlscy5jcmVhdGVTaGFyZVByb29mKHNlbmRlcktleS5wcml2YXRlS2V5LCB1VmFsdWUsICdlZGRzYScpO1xuICAgICAgY29uc3QgdVZhbHVlQ29ycnVwdGVkID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnaGV4Jyk7XG4gICAgICBjb25zdCBpc1ZhbGlkID0gYXdhaXQgb3BlbnBncFV0aWxzLnZlcmlmeVNoYXJlUHJvb2Yoc2VuZGVyS2V5LnB1YmxpY0tleSwgcHJvb2YsIHVWYWx1ZUNvcnJ1cHRlZCwgJ2VkZHNhJyk7XG4gICAgICBpc1ZhbGlkLnNob3VsZC5iZS5mYWxzZSgpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgndmVyaWZ5U2hhcmVQcm9vZiBFQ0RTQScsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIGJlIGFibGUgdG8gdmVyaWZ5IGEgdmFsaWQgcHJvb2YnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB1VmFsdWUgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHByb29mID0gYXdhaXQgb3BlbnBncFV0aWxzLmNyZWF0ZVNoYXJlUHJvb2Yoc2VuZGVyS2V5LnByaXZhdGVLZXksIHVWYWx1ZSwgJ2VjZHNhJyk7XG4gICAgICBjb25zdCBpc1ZhbGlkID0gYXdhaXQgb3BlbnBncFV0aWxzLnZlcmlmeVNoYXJlUHJvb2Yoc2VuZGVyS2V5LnB1YmxpY0tleSwgcHJvb2YsIHVWYWx1ZSwgJ2VjZHNhJyk7XG4gICAgICBpc1ZhbGlkLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGJlIGFibGUgdG8gZGV0ZWN0IHNlbmRlciBpcyBhbiBhdHRhY2tlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHVWYWx1ZSA9IGNyeXB0by5yYW5kb21CeXRlcygzMikudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgY29uc3QgcHJvb2YgPSBhd2FpdCBvcGVucGdwVXRpbHMuY3JlYXRlU2hhcmVQcm9vZihvdGhlcktleS5wcml2YXRlS2V5LCB1VmFsdWUsICdlY2RzYScpO1xuICAgICAgY29uc3QgaXNWYWxpZCA9IGF3YWl0IG9wZW5wZ3BVdGlscy52ZXJpZnlTaGFyZVByb29mKHNlbmRlcktleS5wdWJsaWNLZXksIHByb29mLCB1VmFsdWUsICdlY2RzYScpO1xuICAgICAgaXNWYWxpZC5zaG91bGQuYmUuZmFsc2UoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYmUgYWJsZSB0byBkZXRlY3QgdSB2YWx1ZSBpcyBjb3JydXB0ZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB1VmFsdWUgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHByb29mID0gYXdhaXQgb3BlbnBncFV0aWxzLmNyZWF0ZVNoYXJlUHJvb2Yoc2VuZGVyS2V5LnByaXZhdGVLZXksIHVWYWx1ZSwgJ2VjZHNhJyk7XG4gICAgICBjb25zdCB1VmFsdWVDb3JydXB0ZWQgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IGlzVmFsaWQgPSBhd2FpdCBvcGVucGdwVXRpbHMudmVyaWZ5U2hhcmVQcm9vZihzZW5kZXJLZXkucHVibGljS2V5LCBwcm9vZiwgdVZhbHVlQ29ycnVwdGVkLCAnZWNkc2EnKTtcbiAgICAgIGlzVmFsaWQuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd2ZXJpZnlTaGFyZWREYXRhUHJvb2YgYW5kIGNyZWF0ZVNoYXJlZERhdGFQcm9vZiB0ZXN0JywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgYmUgYWJsZSB0byBkZXRlY3QgaWYgcHJvb2YgdmFsdWUgaXMgY29ycnVwdGVkIG9yIG5vdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHNoYXJlZERhdGExID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnaGV4Jyk7XG4gICAgICBjb25zdCBzaGFyZWREYXRhMiA9IGNyeXB0by5yYW5kb21CeXRlcygzMikudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgY29uc3QgZGF0YVRvUHJvb2ZBcnJheSA9IFtcbiAgICAgICAgeyBuYW1lOiAnczEnLCB2YWx1ZTogc2hhcmVkRGF0YTEgfSxcbiAgICAgICAgeyBuYW1lOiAnczInLCB2YWx1ZTogc2hhcmVkRGF0YTIgfSxcbiAgICAgIF07XG4gICAgICBjb25zdCBwcm9vZiA9IGF3YWl0IG9wZW5wZ3BVdGlscy5jcmVhdGVTaGFyZWREYXRhUHJvb2YoXG4gICAgICAgIHNlbmRlcktleS5wcml2YXRlS2V5LFxuICAgICAgICBvdGhlcktleS5wdWJsaWNLZXksXG4gICAgICAgIGRhdGFUb1Byb29mQXJyYXlcbiAgICAgICk7XG4gICAgICBsZXQgaXNWYWxpZCA9IGF3YWl0IG9wZW5wZ3BVdGlscy52ZXJpZnlTaGFyZWREYXRhUHJvb2Yoc2VuZGVyS2V5LnB1YmxpY0tleSwgcHJvb2YsIGRhdGFUb1Byb29mQXJyYXkpO1xuICAgICAgaXNWYWxpZC5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgLy8gdGFtcGVyIHdpdGggdGhlIGRhdGFcbiAgICAgIGRhdGFUb1Byb29mQXJyYXlbMF0udmFsdWUgPSAndGFtcGVyZWQgZGF0YSc7XG4gICAgICBpc1ZhbGlkID0gYXdhaXQgb3BlbnBncFV0aWxzLnZlcmlmeVNoYXJlZERhdGFQcm9vZihzZW5kZXJLZXkucHVibGljS2V5LCBwcm9vZiwgZGF0YVRvUHJvb2ZBcnJheSk7XG4gICAgICBpc1ZhbGlkLnNob3VsZC5iZS5mYWxzZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBiZSBhYmxlIHZlcmlmeSBkYXRhIHByb29mIGlmIGNyZWF0ZWQgaW4gdGhlIGZ1dHVyZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHNoYXJlZERhdGExID0gY3J5cHRvLnJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnaGV4Jyk7XG4gICAgICBjb25zdCBzaGFyZWREYXRhMiA9IGNyeXB0by5yYW5kb21CeXRlcygzMikudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgY29uc3QgZGF0YVRvUHJvb2ZBcnJheSA9IFtcbiAgICAgICAgeyBuYW1lOiAnczEnLCB2YWx1ZTogc2hhcmVkRGF0YTEgfSxcbiAgICAgICAgeyBuYW1lOiAnczInLCB2YWx1ZTogc2hhcmVkRGF0YTIgfSxcbiAgICAgIF07XG4gICAgICBjb25zdCBwcm9vZiA9IGF3YWl0IG9wZW5wZ3BVdGlscy5jcmVhdGVTaGFyZWREYXRhUHJvb2YoXG4gICAgICAgIHNlbmRlcktleS5wcml2YXRlS2V5LFxuICAgICAgICBvdGhlcktleS5wdWJsaWNLZXksXG4gICAgICAgIGRhdGFUb1Byb29mQXJyYXlcbiAgICAgICk7XG4gICAgICBjb25zdCBjbG9jayA9IHNpbm9uLnVzZUZha2VUaW1lcnMobmV3IERhdGUoJzIwMDEtMDItMTRUMTI6MDA6MDBaJykuZ2V0VGltZSgpKTtcbiAgICAgIGNvbnN0IGlzVmFsaWQgPSBhd2FpdCBvcGVucGdwVXRpbHMudmVyaWZ5U2hhcmVkRGF0YVByb29mKHNlbmRlcktleS5wdWJsaWNLZXksIHByb29mLCBkYXRhVG9Qcm9vZkFycmF5KTtcbiAgICAgIGlzVmFsaWQuc2hvdWxkLmJlLnRydWUoKTtcbiAgICAgIGNsb2NrLnJlc3RvcmUoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2VuY3J5cHQgYW5kIGRlY3J5cHQgd2l0aCBzaWduaW5nJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgc3VjY2Vzc2Z1bGx5IGVuY3J5cHQsIHNpZ24sIGFuZCBkZWNyeXB0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdGV4dCA9ICdvcmlnaW5hbCBtZXNzYWdlJztcblxuICAgICAgY29uc3Qgc2lnbmVkTWVzc2FnZSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5lbmNyeXB0QW5kU2lnblRleHQodGV4dCwgcmVjaXBpZW50S2V5LnB1YmxpY0tleSwgc2VuZGVyS2V5LnByaXZhdGVLZXkpO1xuICAgICAgY29uc3QgZGVjcnlwdGVkTWVzc2FnZSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5yZWFkU2lnbmVkTWVzc2FnZShcbiAgICAgICAgc2lnbmVkTWVzc2FnZSxcbiAgICAgICAgc2VuZGVyS2V5LnB1YmxpY0tleSxcbiAgICAgICAgcmVjaXBpZW50S2V5LnByaXZhdGVLZXlcbiAgICAgICk7XG5cbiAgICAgIGRlY3J5cHRlZE1lc3NhZ2Uuc2hvdWxkLmVxdWFsKHRleHQpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIG9uIHZlcmlmaWNhdGlvbiB3aXRoIHdyb25nIHB1YmxpYyBrZXknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0ZXh0ID0gJ29yaWdpbmFsIG1lc3NhZ2UnO1xuXG4gICAgICBjb25zdCBzaWduZWRNZXNzYWdlID0gYXdhaXQgb3BlbnBncFV0aWxzLmVuY3J5cHRBbmRTaWduVGV4dCh0ZXh0LCByZWNpcGllbnRLZXkucHVibGljS2V5LCBzZW5kZXJLZXkucHJpdmF0ZUtleSk7XG4gICAgICBhd2FpdCBvcGVucGdwVXRpbHNcbiAgICAgICAgLnJlYWRTaWduZWRNZXNzYWdlKHNpZ25lZE1lc3NhZ2UsIG90aGVyS2V5LnB1YmxpY0tleSwgcmVjaXBpZW50S2V5LnByaXZhdGVLZXkpXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCBvbiBkZWNyeXB0aW9uIHdpdGggd3JvbmcgcHJpdmF0ZSBrZXknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0ZXh0ID0gJ29yaWdpbmFsIG1lc3NhZ2UnO1xuXG4gICAgICBjb25zdCBzaWduZWRNZXNzYWdlID0gYXdhaXQgb3BlbnBncFV0aWxzLmVuY3J5cHRBbmRTaWduVGV4dCh0ZXh0LCByZWNpcGllbnRLZXkucHVibGljS2V5LCBzZW5kZXJLZXkucHJpdmF0ZUtleSk7XG4gICAgICBhd2FpdCBvcGVucGdwVXRpbHNcbiAgICAgICAgLnJlYWRTaWduZWRNZXNzYWdlKHNpZ25lZE1lc3NhZ2UsIHNlbmRlcktleS5wdWJsaWNLZXksIG90aGVyS2V5LnByaXZhdGVLZXkpXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdFcnJvciBkZWNyeXB0aW5nIG1lc3NhZ2U6IFNlc3Npb24ga2V5IGRlY3J5cHRpb24gZmFpbGVkLicpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBlbmNyeXB0LCBzaWduLCBhbmQgZGVjcnlwdCB3aXRob3V0IHByZXZpb3VzbHkgY2xlYXJpbmcgcmVqZWN0ZWRDdXJ2ZXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBvcGVucGdwLmNvbmZpZy5yZWplY3RDdXJ2ZXMgPSBuZXcgU2V0KFtvcGVucGdwLmVudW1zLmN1cnZlLnNlY3AyNTZrMV0pO1xuXG4gICAgICBjb25zdCB0ZXh0ID0gJ29yaWdpbmFsIG1lc3NhZ2UnO1xuICAgICAgY29uc3Qgc2lnbmVkTWVzc2FnZSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5lbmNyeXB0QW5kU2lnblRleHQodGV4dCwgcmVjaXBpZW50S2V5LnB1YmxpY0tleSwgc2VuZGVyS2V5LnByaXZhdGVLZXkpO1xuICAgICAgY29uc3QgZGVjcnlwdGVkTWVzc2FnZSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5yZWFkU2lnbmVkTWVzc2FnZShcbiAgICAgICAgc2lnbmVkTWVzc2FnZSxcbiAgICAgICAgc2VuZGVyS2V5LnB1YmxpY0tleSxcbiAgICAgICAgcmVjaXBpZW50S2V5LnByaXZhdGVLZXlcbiAgICAgICk7XG4gICAgICBkZWNyeXB0ZWRNZXNzYWdlLnNob3VsZC5lcXVhbCh0ZXh0KTtcblxuICAgICAgb3BlbnBncC5jb25maWcucmVqZWN0Q3VydmVzID0gbmV3IFNldCgpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnc2lnbmF0dXJlcyBhbmQgdmVyaWZpY2F0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHNpZ25hdHVyZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHRleHQgPSAnc29tZSBwYXlsb2FkJztcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5zaWduVGV4dCh0ZXh0LCBzZW5kZXJLZXkucHJpdmF0ZUtleSk7XG4gICAgICBjb25zdCBpc1ZhbGlkU2lnbmF0dXJlID0gYXdhaXQgb3BlbnBncFV0aWxzLnZlcmlmeVNpZ25hdHVyZSh0ZXh0LCBzaWduYXR1cmUsIHNlbmRlcktleS5wdWJsaWNLZXkpO1xuXG4gICAgICBpc1ZhbGlkU2lnbmF0dXJlLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdmVyaWZpY2F0aW9uIGlmIHB1YmxpYyBrZXkgaXMgaW5jb3JyZWN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdGV4dCA9ICdzb21lIHBheWxvYWQnO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gYXdhaXQgb3BlbnBncFV0aWxzLnNpZ25UZXh0KHRleHQsIHNlbmRlcktleS5wcml2YXRlS2V5KTtcbiAgICAgIGNvbnN0IGlzVmFsaWRTaWduYXR1cmUgPSBhd2FpdCBvcGVucGdwVXRpbHMudmVyaWZ5U2lnbmF0dXJlKHRleHQsIHNpZ25hdHVyZSwgcmVjaXBpZW50S2V5LnB1YmxpY0tleSk7XG5cbiAgICAgIGlzVmFsaWRTaWduYXR1cmUuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdmVyaWZpY2F0aW9uIGlmIG1lc3NhZ2UgaXMgaW5jb3JyZWN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdGV4dCA9ICdzb21lIHBheWxvYWQnO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gYXdhaXQgb3BlbnBncFV0aWxzLnNpZ25UZXh0KHRleHQsIHNlbmRlcktleS5wcml2YXRlS2V5KTtcbiAgICAgIGNvbnN0IGlzVmFsaWRTaWduYXR1cmUgPSBhd2FpdCBvcGVucGdwVXRpbHMudmVyaWZ5U2lnbmF0dXJlKCdzb21ldGhpbmcgZWxzZScsIHNpZ25hdHVyZSwgc2VuZGVyS2V5LnB1YmxpY0tleSk7XG5cbiAgICAgIGlzVmFsaWRTaWduYXR1cmUuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdHUEcga2V5IGdlbmVyYXRpb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBhIGEgR1BHIGtleSBmb3Igc2VjcDI1NmsxIHdpdGggcmFuZG9tIG5hbWUgYW5kIGVtYWlsJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZ3BnS2V5ID0gYXdhaXQgb3BlbnBncFV0aWxzLmdlbmVyYXRlR1BHS2V5UGFpcignc2VjcDI1NmsxJyk7XG5cbiAgICAgIHNob3VsZC5leGlzdChncGdLZXkpO1xuICAgICAgc2hvdWxkLmV4aXN0KGdwZ0tleS5wcml2YXRlS2V5KTtcbiAgICAgIHNob3VsZC5leGlzdChncGdLZXkucHVibGljS2V5KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgYSBhIEdQRyBrZXkgZm9yICB3aXRoIHJhbmRvbSBuYW1lIGFuZCBlbWFpbCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGdwZ0tleSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5nZW5lcmF0ZUdQR0tleVBhaXIoJ2VkMjU1MTknKTtcblxuICAgICAgc2hvdWxkLmV4aXN0KGdwZ0tleSk7XG4gICAgICBzaG91bGQuZXhpc3QoZ3BnS2V5LnByaXZhdGVLZXkpO1xuICAgICAgc2hvdWxkLmV4aXN0KGdwZ0tleS5wdWJsaWNLZXkpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBhIGEgR1BHIGtleSB3aXRoIHByb3ZpZGVkIG5hbWUgYW5kIGVtYWlsJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdXNlck5hbWUgPSAnSm9obiBEb2UnO1xuICAgICAgY29uc3QgdXNlckVtYWlsID0gJ2pvaG4uZG9lQGV4YW1wbGUuY29tJztcbiAgICAgIGNvbnN0IGdwZ0tleSA9IGF3YWl0IG9wZW5wZ3BVdGlscy5nZW5lcmF0ZUdQR0tleVBhaXIoJ3NlY3AyNTZrMScsIHVzZXJOYW1lLCB1c2VyRW1haWwpO1xuXG4gICAgICBzaG91bGQuZXhpc3QoZ3BnS2V5KTtcbiAgICAgIHNob3VsZC5leGlzdChncGdLZXkucHJpdmF0ZUtleSk7XG4gICAgICBzaG91bGQuZXhpc3QoZ3BnS2V5LnB1YmxpY0tleSk7XG5cbiAgICAgIGNvbnN0IHBhcnNlZEtleSA9IGF3YWl0IG9wZW5wZ3AucmVhZEtleSh7IGFybW9yZWRLZXk6IGdwZ0tleS5wdWJsaWNLZXkgfSk7XG4gICAgICBzaG91bGQuZXhpc3QocGFyc2VkS2V5KTtcblxuICAgICAgYXNzZXJ0KHBhcnNlZEtleSk7XG4gICAgICBjb25zdCBwcmltYXJ5VXNlciA9IGF3YWl0IHBhcnNlZEtleS5nZXRQcmltYXJ5VXNlcigpO1xuICAgICAgcHJpbWFyeVVzZXIudXNlci51c2VySUQ/Lm5hbWU/LnNob3VsZC5lcXVhbCh1c2VyTmFtZSk7XG4gICAgICBwcmltYXJ5VXNlci51c2VyLnVzZXJJRD8uZW1haWw/LnNob3VsZC5lcXVhbCh1c2VyRW1haWwpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHRvIGdlbmVyYXRlIGEgYSBHUEcga2V5IGZvciB1bmtub3duIGN1cnZlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgb3BlbnBncFV0aWxzXG4gICAgICAgIC5nZW5lcmF0ZUdQR0tleVBhaXIoJ3Vua25vd25DdXJ2ZScgYXMgb3BlbnBncC5FbGxpcHRpY0N1cnZlTmFtZSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ0Vycm9yIGdlbmVyYXRpbmcga2V5cGFpcjogVW5rbm93biBjdXJ2ZScpO1xuICAgIH0pO1xuICB9KTtcblxuICBmdW5jdGlvbiBlcXVhbChidWYxLCBidWYyKSB7XG4gICAgaWYgKGJ1ZjEuYnl0ZUxlbmd0aCAhPSBidWYyLmJ5dGVMZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICBjb25zdCBkdjEgPSBuZXcgSW50OEFycmF5KGJ1ZjEpO1xuICAgIGNvbnN0IGR2MiA9IG5ldyBJbnQ4QXJyYXkoYnVmMik7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgIT0gYnVmMS5ieXRlTGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChkdjFbaV0gIT0gZHYyW2ldKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG59KTtcbiJdfQ==Выполнить команду
Для локальной разработки. Не используйте в интернете!