bitgo
Version:
BitGo JavaScript SDK
458 lines • 67.2 kB
JavaScript
"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