UNPKG

bitgo

Version:
458 lines • 67.2 kB
"use strict"; // // Tests for a Pending Approval // // Copyright 2015, BitGo, Inc. All Rights Reserved. // Object.defineProperty(exports, "__esModule", { value: true }); const _ = require("lodash"); const assert_1 = require("assert"); require("should"); const utxolib = require("@bitgo/utxo-lib"); const BitGoJS = require('../../src/index'); const TestBitGo = require('../lib/test_bitgo'); const TestUtil = require('./testutil'); const Q = require('q'); describe('PendingApproval', function () { let bitgo; let bitgoSharedKeyUser; let bitgoThirdUser; let sharedWallet; /** * There is a 0-limit policy on the shared wallet * Create a pending approval by attempting to send coins */ const createTransactionPendingApproval = function () { return sharedWallet .sendCoins({ address: TestBitGo.TEST_WALLET2_ADDRESS, amount: 0.0001 * 1e8, walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP(), message: 'never gonna', }) .then(function (result) { result.should.have.property('pendingApproval'); return bitgo.pendingApprovals().get({ id: result.pendingApproval }); }); }; /** * There is a 0-limit policy on the shared wallet * Create a pending approval by attempting to send to many */ const createTransactionPendingApprovalToMultipleRecipients = function () { return sharedWallet .sendMany({ recipients: [ { address: TestBitGo.TEST_WALLET3_ADDRESS, amount: 0.0002 * 1e8, }, { address: TestBitGo.TEST_WALLET2_ADDRESS, amount: 0.0001 * 1e8, }, { address: TestBitGo.TEST_SHARED_WALLET_CHANGE_ADDRESS, amount: 0.0005 * 1e8, }, ], walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP(), message: 'never gonna', }) .then(function (result) { result.should.have.property('pendingApproval'); return bitgo.pendingApprovals().get({ id: result.pendingApproval }); }); }; /** * Create a pending approval by attempting to add a user to the wallet */ const createPolicyPendingApproval = function () { // it's ok to set up any tx limit since the daily limit is 0 return sharedWallet .updatePolicyRule({ action: { type: 'getApproval', }, condition: { amount: 1e8 + Math.round(Math.random() * 1e8), }, id: 'com.bitgo.limit.tx', type: 'transactionLimit', }) .then(function (result) { result.should.have.property('pendingApproval'); return bitgo.pendingApprovals().get({ id: result.pendingApproval.id }); }); }; before(function () { bitgo = new TestBitGo(); bitgo.initializeTestVars(); bitgoSharedKeyUser = new TestBitGo(); bitgoSharedKeyUser.initializeTestVars(); bitgoThirdUser = new TestBitGo(); bitgoThirdUser.initializeTestVars(); return bitgo .authenticateTestUser(bitgo.testUserOTP()) .then(function () { return bitgoSharedKeyUser.authenticate({ username: TestBitGo.TEST_SHARED_KEY_USER, password: TestBitGo.TEST_SHARED_KEY_PASSWORD, otp: bitgo.testUserOTP(), }); }) .then(function () { return bitgo.unlock({ otp: bitgo.testUserOTP() }); }) .then(function () { return bitgoSharedKeyUser.unlock({ otp: bitgo.testUserOTP() }); }) .then(function () { return bitgo.wallets().get({ id: TestBitGo.TEST_SHARED_WALLET_ADDRESS }); }) .then(function (result) { sharedWallet = result; }); }); describe('Create and Get', function () { let pendingApproval; before(function () { return createTransactionPendingApproval().then(function (result) { pendingApproval = result; }); }); after(function () { return pendingApproval.reject(); }); it('arguments', function () { assert_1.strict.throws(function () { bitgo.pendingApprovals().get({}, 'invalid'); }); assert_1.strict.throws(function () { bitgo.pendingApprovals().get('invalid'); }); assert_1.strict.throws(function () { bitgo.pendingApprovals().get({ id: 54321 }, 'invalid'); }); }); it('get property methods', function () { pendingApproval.id().should.eql(pendingApproval.pendingApproval.id); pendingApproval.ownerType().should.eql('wallet'); pendingApproval.walletId().should.eql(sharedWallet.id()); assert_1.strict.equal(pendingApproval.enterpriseId(), undefined); pendingApproval.state().should.eql('pending'); pendingApproval.creator().should.eql(TestBitGo.TEST_USERID); pendingApproval.type().should.eql('transactionRequest'); pendingApproval.info().transactionRequest.message.should.eql('never gonna'); pendingApproval.info().transactionRequest.destinationAddress.should.eql(TestBitGo.TEST_WALLET2_ADDRESS); }); it('get', function () { pendingApproval.get({}).then(function (result) { pendingApproval = result; pendingApproval.id().should.eql(pendingApproval.pendingApproval.id); pendingApproval.ownerType().should.eql('wallet'); pendingApproval.walletId().should.eql(sharedWallet.id()); assert_1.strict.equal(pendingApproval.enterpriseId(), undefined); pendingApproval.state().should.eql('pending'); pendingApproval.creator().should.eql(TestBitGo.TEST_USERID); pendingApproval.type().should.eql('transactionRequest'); pendingApproval.info().transactionRequest.destinationAddress.should.eql(TestBitGo.TEST_WALLET2_ADDRESS); }); }); }); describe('Approve', function () { let pendingApproval; before(function () { return createTransactionPendingApproval().then(function (result) { pendingApproval = result; }); }); after(function () { return pendingApproval.reject(); }); it('arguments', function () { assert_1.strict.throws(function () { pendingApproval.approve({}, 'invalid'); }); assert_1.strict.throws(function () { pendingApproval.approve('invalid'); }); }); it('error when self approving', function () { return createPolicyPendingApproval() .then(function (pendingApproval) { return pendingApproval.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() }); }) .catch(function (err) { err.message.should.containEql('cannot approve by self'); return pendingApproval.reject(); }); }); it('can approve when it does not require tx signing', function () { return createPolicyPendingApproval().then(function (pendingApproval) { return bitgoSharedKeyUser .pendingApprovals() .get({ id: pendingApproval.id() }) .then(function (result) { return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); result.info.policyRuleRequest.update.condition.amount.should.eql(pendingApproval.info().policyRuleRequest.update.condition.amount); }); }); }); it('can approve when tx does not require reconstruction', function () { return createTransactionPendingApproval().then(function (pendingApproval) { return bitgoSharedKeyUser .pendingApprovals() .get({ id: pendingApproval.id() }) .then(function (result) { return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); }); }); }); it('error when it does require tx signing but wrong passphrase', function () { return createTransactionPendingApproval() .then(function (pendingApproval) { return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() }); }) .then(function (result) { return result.approve({ walletPassphrase: 'abcdef', otp: bitgo.testUserOTP() }); }) .catch(function (err) { err.message.should.containEql('Unable to decrypt user keychain'); return pendingApproval.reject(); }); }); it('can approve when it does require tx signing', function () { return createTransactionPendingApproval() .then(function (pendingApproval) { return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() }); }) .then(function (result) { return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); }); }); it('cannot approve when transaction needs reconstructing', function () { let approvals = []; return Q.all([createTransactionPendingApproval(), createTransactionPendingApproval()]) .spread(function (approval1, approval2) { approvals = [approval1, approval2]; return bitgoSharedKeyUser.pendingApprovals().get({ id: approval1.id() }); }) .then(function (result) { return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); const approval2 = approvals[1]; return bitgoSharedKeyUser.pendingApprovals().get({ id: approval2.id() }); }) .then(function (result) { return result.approve({ otp: bitgo.testUserOTP() }); }) .then(function () { throw new Error('approval success'); }) .catch(function (error) { error.message.should.equal('unspents expired, wallet passphrase or xprv required to recreate transaction'); }); }); it('can approve when it does require tx signing (multiple recipients)', function () { return createTransactionPendingApprovalToMultipleRecipients() .then(function (pendingApproval) { return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() }); }) .then(function (result) { return result.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); // Parse the completed tx hex and make sure it was built with proper outputs const completedTxHex = result.info.transactionRequest.validTransaction; const transaction = utxolib.bitgo.createTransactionFromHex(completedTxHex, utxolib.networks.bitcoin); if (!transaction || !transaction.outs) { throw new Error('transaction had no outputs or failed to parse successfully'); } const outputAddresses = _.map(transaction.outs, function (out) { return utxolib.address.fromOutputScript(out.script, BitGoJS.getNetworkObj()); }); // Output addresses should contain the 2 destinations, but not the change address outputAddresses.should.containEql(TestBitGo.TEST_WALLET3_ADDRESS); outputAddresses.should.containEql(TestBitGo.TEST_WALLET2_ADDRESS); outputAddresses.should.not.containEql(TestBitGo.TEST_SHARED_WALLET_CHANGE_ADDRESS); }); }); it('can manually pass in reconstructed tx', function () { let pendingApproval; return createTransactionPendingApprovalToMultipleRecipients() .then(function (pendingApproval) { return bitgoSharedKeyUser.pendingApprovals().get({ id: pendingApproval.id() }); }) .then(function (result) { pendingApproval = result; return pendingApproval.constructApprovalTx({ walletPassphrase: TestBitGo.TEST_PASSWORD, otp: bitgo.testUserOTP(), }); }) .then(function (result) { return pendingApproval.approve({ walletPassphrase: TestBitGo.TEST_PASSWORD, tx: result.tx, otp: bitgo.testUserOTP(), }); }) .then(function (result) { result.state.should.eql('approved'); // Parse the completed tx hex and make sure it was built with proper outputs const completedTxHex = result.info.transactionRequest.validTransaction; const transaction = utxolib.bitgo.createTransactionFromHex(completedTxHex, utxolib.networks.bitcoin); if (!transaction || !transaction.outs) { throw new Error('transaction had no outputs or failed to parse successfully'); } const outputAddresses = _.map(transaction.outs, function (out) { return utxolib.address.fromOutputScript(out.script, BitGoJS.getNetworkObj()); }); // Output addresses should contain the 2 destinations, but not the change address outputAddresses.should.containEql(TestBitGo.TEST_WALLET3_ADDRESS); outputAddresses.should.containEql(TestBitGo.TEST_WALLET2_ADDRESS); outputAddresses.should.not.containEql(TestBitGo.TEST_SHARED_WALLET_CHANGE_ADDRESS); }); }); }); describe('Reject', function () { let pendingApproval; before(function () { return Q.delay(500) .then(function () { return createTransactionPendingApproval(); }) .then(function (result) { pendingApproval = result; }); }); it('arguments', function () { assert_1.strict.throws(function () { pendingApproval.reject({}, 'invalid'); }); assert_1.strict.throws(function () { pendingApproval.reject('invalid'); }); }); it('can cancel', function () { return pendingApproval.reject().then(function (result) { result.state.should.eql('rejected'); }); }); it('can reject', function () { return bitgoSharedKeyUser .pendingApprovals() .get({ id: pendingApproval.id() }) .then(function (result) { return result.reject(); }) .then(function (result) { result.state.should.eql('rejected'); }); }); }); describe('Create, Get, Approve and Reject with Multiple Approvers', function () { // setup third user let multipleApproversWallet; let pendingApproval; before(function () { return bitgoThirdUser .authenticate({ username: TestBitGo.TEST_THIRD_USER, password: TestBitGo.TEST_THIRD_PASSWORD, otp: bitgo.testUserOTP(), }) .then(function () { return bitgoThirdUser.unlock({ otp: bitgoThirdUser.testUserOTP() }); }) .then(function () { return bitgoThirdUser.wallets().get({ id: TestBitGo.TEST_WALLETMULTAPPROVERS_ADDRESS }); }) .then(function (result) { multipleApproversWallet = result; if (multipleApproversWallet.approvalsRequired() === 2) { // we don't need to bother setting the number of approvals required return; } return multipleApproversWallet .updateApprovalsRequired({ approvalsRequired: 2 }) .then(function (result) { return bitgoSharedKeyUser.pendingApprovals().get({ id: result.id }); }) .then(function (result) { pendingApproval = result; pendingApproval.approvalsRequired().should.equal(1); return result.approve({ otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); // update wallet variable with new approvalsRequired return bitgoThirdUser.wallets().get({ id: TestBitGo.TEST_WALLETMULTAPPROVERS_ADDRESS }); }) .then(function (result) { multipleApproversWallet = result; }); }); }); after(function () { pendingApproval.reject(); }); it('should fail with too low approvalsRequired', function () { assert_1.strict.throws(function () { multipleApproversWallet.updateApprovalsRequired({ approvalsRequired: 0 }); }, 'invalid approvalsRequired'); }); it('should fail with too high approvalsRequired', function () { const promise = multipleApproversWallet.updateApprovalsRequired({ approvalsRequired: 3 }); return TestUtil.throws(promise, 'approvalsRequired must be less than the number of admins on the wallet'); }); it('should be a no-op with same approvalsRequired', function () { return multipleApproversWallet.updateApprovalsRequired({ approvalsRequired: 2 }).then(function (wallet) { wallet.should.equal(multipleApproversWallet.wallet); }); }); it('should set approvals required to 1 after 2 approvals', function () { return multipleApproversWallet .updateApprovalsRequired({ approvalsRequired: 1 }) .then(function (result) { return bitgoSharedKeyUser.pendingApprovals().get({ id: result.id }); }) .then(function (result) { pendingApproval = result; pendingApproval.approvalsRequired().should.equal(2); return result.approve({ otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('pending'); return bitgo.pendingApprovals().get({ id: result.id }); }) .then(function (result) { return result.approve({ otp: bitgo.testUserOTP() }); }) .then(function (result) { result.state.should.eql('approved'); return bitgoThirdUser.wallets().get({ id: TestBitGo.TEST_WALLETMULTAPPROVERS_ADDRESS }); }) .then(function (wallet) { multipleApproversWallet = wallet; multipleApproversWallet.approvalsRequired().should.equal(1); }); }); }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVuZGluZ2FwcHJvdmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC9pbnRlZ3JhdGlvbi9wZW5kaW5nYXBwcm92YWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLEVBQUU7QUFDRiwrQkFBK0I7QUFDL0IsRUFBRTtBQUNGLG9EQUFvRDtBQUNwRCxFQUFFOztBQUVGLDRCQUE0QjtBQUM1QixtQ0FBMEM7QUFDMUMsa0JBQWdCO0FBQ2hCLDJDQUEyQztBQUUzQyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUMzQyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQUMvQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7QUFFdkMsTUFBTSxDQUFDLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBRXZCLFFBQVEsQ0FBQyxpQkFBaUIsRUFBRTtJQUMxQixJQUFJLEtBQUssQ0FBQztJQUNWLElBQUksa0JBQWtCLENBQUM7SUFDdkIsSUFBSSxjQUFjLENBQUM7SUFDbkIsSUFBSSxZQUFZLENBQUM7SUFFakI7OztPQUdHO0lBQ0gsTUFBTSxnQ0FBZ0MsR0FBRztRQUN2QyxPQUFPLFlBQVk7YUFDaEIsU0FBUyxDQUFDO1lBQ1QsT0FBTyxFQUFFLFNBQVMsQ0FBQyxvQkFBb0I7WUFDdkMsTUFBTSxFQUFFLE1BQU0sR0FBRyxHQUFHO1lBQ3BCLGdCQUFnQixFQUFFLFNBQVMsQ0FBQyxhQUFhO1lBQ3pDLEdBQUcsRUFBRSxLQUFLLENBQUMsV0FBVyxFQUFFO1lBQ3hCLE9BQU8sRUFBRSxhQUFhO1NBQ3ZCLENBQUM7YUFDRCxJQUFJLENBQUMsVUFBVSxNQUFNO1lBQ3BCLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQy9DLE9BQU8sS0FBSyxDQUFDLGdCQUFnQixFQUFF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cmlnaHQgMjAxNSwgQml0R28sIEluYy4gIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vL1xuXG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBzdHJpY3QgYXMgYXNzZXJ0IH0gZnJvbSAnYXNzZXJ0JztcbmltcG9ydCAnc2hvdWxkJztcbmltcG9ydCAqIGFzIHV0eG9saWIgZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcblxuY29uc3QgQml0R29KUyA9IHJlcXVpcmUoJy4uLy4uL3NyYy9pbmRleCcpO1xuY29uc3QgVGVzdEJpdEdvID0gcmVxdWlyZSgnLi4vbGliL3Rlc3RfYml0Z28nKTtcbmNvbnN0IFRlc3RVdGlsID0gcmVxdWlyZSgnLi90ZXN0dXRpbCcpO1xuXG5jb25zdCBRID0gcmVxdWlyZSgncScpO1xuXG5kZXNjcmliZSgnUGVuZGluZ0FwcHJvdmFsJywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z287XG4gIGxldCBiaXRnb1NoYXJlZEtleVVzZXI7XG4gIGxldCBiaXRnb1RoaXJkVXNlcjtcbiAgbGV0IHNoYXJlZFdhbGxldDtcblxuICAvKipcbiAgICogVGhlcmUgaXMgYSAwLWxpbWl0IHBvbGljeSBvbiB0aGUgc2hhcmVkIHdhbGxldFxuICAgKiBDcmVhdGUgYSBwZW5kaW5nIGFwcHJvdmFsIGJ5IGF0dGVtcHRpbmcgdG8gc2VuZCBjb2luc1xuICAgKi9cbiAgY29uc3QgY3JlYXRlVHJhbnNhY3Rpb25QZW5kaW5nQXBwcm92YWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHNoYXJlZFdhbGxldFxuICAgICAgLnNlbmRDb2lucyh7XG4gICAgICAgIGFkZHJlc3M6IFRlc3RCaXRHby5URVNUX1dBTExFVDJfQUREUkVTUyxcbiAgICAgICAgYW1vdW50OiAwLjAwMDEgKiAxZTgsXG4gICAgICAgIHdhbGxldFBhc3NwaHJhc2U6IFRlc3RCaXRHby5URVNUX1BBU1NXT1JELFxuICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgIG1lc3NhZ2U6ICduZXZlciBnb25uYScsXG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICByZXN1bHQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3BlbmRpbmdBcHByb3ZhbCcpO1xuICAgICAgICByZXR1cm4gYml0Z28ucGVuZGluZ0FwcHJvdmFscygpLmdldCh7IGlkOiByZXN1bHQucGVuZGluZ0FwcHJvdmFsIH0pO1xuICAgICAgfSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIFRoZXJlIGlzIGEgMC1saW1pdCBwb2xpY3kgb24gdGhlIHNoYXJlZCB3YWxsZXRcbiAgICogQ3JlYXRlIGEgcGVuZGluZyBhcHByb3ZhbCBieSBhdHRlbXB0aW5nIHRvIHNlbmQgdG8gbWFueVxuICAgKi9cbiAgY29uc3QgY3JlYXRlVHJhbnNhY3Rpb25QZW5kaW5nQXBwcm92YWxUb011bHRpcGxlUmVjaXBpZW50cyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gc2hhcmVkV2FsbGV0XG4gICAgICAuc2VuZE1hbnkoe1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogVGVzdEJpdEdvLlRFU1RfV0FMTEVUM19BRERSRVNTLFxuICAgICAgICAgICAgYW1vdW50OiAwLjAwMDIgKiAxZTgsXG4gICAgICAgICAgfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBhZGRyZXNzOiBUZXN0Qml0R28uVEVTVF9XQUxMRVQyX0FERFJFU1MsXG4gICAgICAgICAgICBhbW91bnQ6IDAuMDAwMSAqIDFlOCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFkZHJlc3M6IFRlc3RCaXRHby5URVNUX1NIQVJFRF9XQUxMRVRfQ0hBTkdFX0FERFJFU1MsXG4gICAgICAgICAgICBhbW91bnQ6IDAuMDAwNSAqIDFlOCxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9QQVNTV09SRCxcbiAgICAgICAgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLFxuICAgICAgICBtZXNzYWdlOiAnbmV2ZXIgZ29ubmEnLFxuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgcmVzdWx0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdwZW5kaW5nQXBwcm92YWwnKTtcbiAgICAgICAgcmV0dXJuIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogcmVzdWx0LnBlbmRpbmdBcHByb3ZhbCB9KTtcbiAgICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBwZW5kaW5nIGFwcHJvdmFsIGJ5IGF0dGVtcHRpbmcgdG8gYWRkIGEgdXNlciB0byB0aGUgd2FsbGV0XG4gICAqL1xuICBjb25zdCBjcmVhdGVQb2xpY3lQZW5kaW5nQXBwcm92YWwgPSBmdW5jdGlvbiAoKSB7XG4gICAgLy8gaXQncyBvayB0byBzZXQgdXAgYW55IHR4IGxpbWl0IHNpbmNlIHRoZSBkYWlseSBsaW1pdCBpcyAwXG4gICAgcmV0dXJuIHNoYXJlZFdhbGxldFxuICAgICAgLnVwZGF0ZVBvbGljeVJ1bGUoe1xuICAgICAgICBhY3Rpb246IHtcbiAgICAgICAgICB0eXBlOiAnZ2V0QXBwcm92YWwnLFxuICAgICAgICB9LFxuICAgICAgICBjb25kaXRpb246IHtcbiAgICAgICAgICBhbW91bnQ6IDFlOCArIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIDFlOCksXG4gICAgICAgIH0sXG4gICAgICAgIGlkOiAnY29tLmJpdGdvLmxpbWl0LnR4JyxcbiAgICAgICAgdHlwZTogJ3RyYW5zYWN0aW9uTGltaXQnLFxuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgcmVzdWx0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdwZW5kaW5nQXBwcm92YWwnKTtcbiAgICAgICAgcmV0dXJuIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogcmVzdWx0LnBlbmRpbmdBcHByb3ZhbC5pZCB9KTtcbiAgICAgIH0pO1xuICB9O1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBuZXcgVGVzdEJpdEdvKCk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYml0Z29TaGFyZWRLZXlVc2VyID0gbmV3IFRlc3RCaXRHbygpO1xuICAgIGJpdGdvU2hhcmVkS2V5VXNlci5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBiaXRnb1RoaXJkVXNlciA9IG5ldyBUZXN0Qml0R28oKTtcbiAgICBiaXRnb1RoaXJkVXNlci5pbml0aWFsaXplVGVzdFZhcnMoKTtcblxuICAgIHJldHVybiBiaXRnb1xuICAgICAgLmF1dGhlbnRpY2F0ZVRlc3RVc2VyKGJpdGdvLnRlc3RVc2VyT1RQKCkpXG4gICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiaXRnb1NoYXJlZEtleVVzZXIuYXV0aGVudGljYXRlKHtcbiAgICAgICAgICB1c2VybmFtZTogVGVzdEJpdEdvLlRFU1RfU0hBUkVEX0tFWV9VU0VSLFxuICAgICAgICAgIHBhc3N3b3JkOiBUZXN0Qml0R28uVEVTVF9TSEFSRURfS0VZX1BBU1NXT1JELFxuICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z28udW5sb2NrKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpIH0pO1xuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvU2hhcmVkS2V5VXNlci51bmxvY2soeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCkgfSk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z28ud2FsbGV0cygpLmdldCh7IGlkOiBUZXN0Qml0R28uVEVTVF9TSEFSRURfV0FMTEVUX0FERFJFU1MgfSk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICBzaGFyZWRXYWxsZXQgPSByZXN1bHQ7XG4gICAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0NyZWF0ZSBhbmQgR2V0JywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBwZW5kaW5nQXBwcm92YWw7XG5cbiAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGNyZWF0ZVRyYW5zYWN0aW9uUGVuZGluZ0FwcHJvdmFsKCkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgIHBlbmRpbmdBcHByb3ZhbCA9IHJlc3VsdDtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHBlbmRpbmdBcHByb3ZhbC5yZWplY3QoKTtcbiAgICB9KTtcblxuICAgIGl0KCdhcmd1bWVudHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYml0Z28ucGVuZGluZ0FwcHJvdmFscygpLmdldCh7fSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnBlbmRpbmdBcHByb3ZhbHMoKS5nZXQoeyBpZDogNTQzMjEgfSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2dldCBwcm9wZXJ0eSBtZXRob2RzJywgZnVuY3Rpb24gKCkge1xuICAgICAgcGVuZGluZ0FwcHJvdmFsLmlkKCkuc2hvdWxkLmVxbChwZW5kaW5nQXBwcm92YWwucGVuZGluZ0FwcHJvdmFsLmlkKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5vd25lclR5cGUoKS5zaG91bGQuZXFsKCd3YWxsZXQnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC53YWxsZXRJZCgpLnNob3VsZC5lcWwoc2hhcmVkV2FsbGV0LmlkKCkpO1xuICAgICAgYXNzZXJ0LmVxdWFsKHBlbmRpbmdBcHByb3ZhbC5lbnRlcnByaXNlSWQoKSwgdW5kZWZpbmVkKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5zdGF0ZSgpLnNob3VsZC5lcWwoJ3BlbmRpbmcnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5jcmVhdG9yKCkuc2hvdWxkLmVxbChUZXN0Qml0R28uVEVTVF9VU0VSSUQpO1xuICAgICAgcGVuZGluZ0FwcHJvdmFsLnR5cGUoKS5zaG91bGQuZXFsKCd0cmFuc2FjdGlvblJlcXVlc3QnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5pbmZvKCkudHJhbnNhY3Rpb25SZXF1ZXN0Lm1lc3NhZ2Uuc2hvdWxkLmVxbCgnbmV2ZXIgZ29ubmEnKTtcbiAgICAgIHBlbmRpbmdBcHByb3ZhbC5pbmZvKCkudHJhbnNhY3Rpb25SZXF1ZXN0LmRlc3RpbmF0aW9uQWRkcmVzcy5zaG91bGQuZXFsKFRlc3RCaXRHby5URVNUX1dBTExFVDJfQUREUkVTUyk7XG4gICAgfSk7XG5cbiAgICBpdCgnZ2V0JywgZnVuY3Rpb24gKCkge1xuICAgICAgcGVuZGluZ0FwcHJvdmFsLmdldCh7fSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgIHBlbmRpbmdBcHByb3ZhbCA9IHJlc3VsdDtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLmlkKCkuc2hvdWxkLmVxbChwZW5kaW5nQXBwcm92YWwucGVuZGluZ0FwcHJvdmFsLmlkKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLm93bmVyVHlwZSgpLnNob3VsZC5lcWwoJ3dhbGxldCcpO1xuICAgICAgICBwZW5kaW5nQXBwcm92YWwud2FsbGV0SWQoKS5zaG91bGQuZXFsKHNoYXJlZFdhbGxldC5pZCgpKTtcbiAgICAgICAgYXNzZXJ0LmVxdWFsKHBlbmRpbmdBcHByb3ZhbC5lbnRlcnByaXNlSWQoKSwgdW5kZWZpbmVkKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLnN0YXRlKCkuc2hvdWxkLmVxbCgncGVuZGluZycpO1xuICAgICAgICBwZW5kaW5nQXBwcm92YWwuY3JlYXRvcigpLnNob3VsZC5lcWwoVGVzdEJpdEdvLlRFU1RfVVNFUklEKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLnR5cGUoKS5zaG91bGQuZXFsKCd0cmFuc2FjdGlvblJlcXVlc3QnKTtcbiAgICAgICAgcGVuZGluZ0FwcHJvdmFsLmluZm8oKS50cmFuc2FjdGlvblJlcXVlc3QuZGV