PHP WebShell
Текущая директория: /opt/BitGoJS/modules/express/dist/test/integration
Просмотр файла: externalSigner.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @prettier
*/
require("should");
require("should-http");
const sinon = require("sinon");
const request = require("supertest");
const expressApp_1 = require("../../src/expressApp");
const nock = require("nock");
const bitgo_1 = require("bitgo");
describe('Custom signing function', () => {
let agent;
const externalSignerUrl = 'https://external-signer.invalid';
before(() => {
const args = {
debug: true,
env: 'test',
externalSignerUrl,
timeout: 60000,
};
const app = (0, expressApp_1.app)(args);
agent = request.agent(app);
if (!nock.isActive()) {
nock.activate();
}
nock.disableNetConnect();
nock.enableNetConnect('127.0.0.1');
});
after(() => {
if (nock.isActive()) {
nock.restore();
}
});
it('should make a request to external signer when sending', async function () {
const bgUrl = bitgo_1.Environments.test.uri;
// setup nock to external signer
const signernock = nock(externalSignerUrl)
.post('/api/v2/btc/sign')
.reply(200, { externalSigner: 'external signer response' });
// setup nock to wallet platform GET /wallet/fakeid
const wpWalletnock = nock(bgUrl)
.get('/api/v2/btc/wallet/fakeid')
.reply(200, { id: 'fakeid', keys: ['abc', 'def', 'ghi'], coinSpecific: {} });
const wpKeychainNocks = [
nock(bgUrl).get('/api/v2/btc/key/abc').reply(200, { pub: 'xpubabc' }),
nock(bgUrl).get('/api/v2/btc/key/def').reply(200, { pub: 'xpubdef' }),
nock(bgUrl).get('/api/v2/btc/key/ghi').reply(200, { pub: 'xpubghi' }),
];
const wpLatestBlockNock = nock(bgUrl).get('/api/v2/btc/public/block/latest').reply(200);
const wpBuildnock = nock(bgUrl)
.post('/api/v2/btc/wallet/fakeid/tx/build')
.reply(200, { wpBuild: 'WP build response' });
const wpSendnock = nock(bgUrl).post('/api/v2/btc/wallet/fakeid/tx/send').reply(200, { wpSend: 'WP send response' });
const postProcessPrebuildStub = sinon.stub(bitgo_1.Coin.Btc.prototype, 'postProcessPrebuild').resolvesArg(0);
const verifyTransactionStub = sinon.stub(bitgo_1.Coin.Btc.prototype, 'verifyTransaction').resolves(true);
// make request to express application to initiate send
const result = await agent
.post('/api/v2/btc/wallet/fakeid/sendcoins')
.type('json')
.send({ address: 'abc', amount: 123 });
// check to make sure request to external signer was successful
result.ok.should.be.true();
// make sure wallet platform request contained response from external signer
result.body.should.have.property('wpSend', 'WP send response');
signernock.done();
wpKeychainNocks.forEach((s) => s.done());
wpLatestBlockNock.done();
wpWalletnock.done();
wpBuildnock.done();
wpSendnock.done();
postProcessPrebuildStub.restore();
verifyTransactionStub.restore();
});
it('should retry requests to external signer on an "ECONNREFUSED" error', async function () {
const bgUrl = bitgo_1.Environments.test.uri;
// setup persistent nock to external signer
const signernock = nock(externalSignerUrl)
.post('/api/v2/btc/sign')
.times(3)
.replyWithError({ code: 'ECONNREFUSED' });
// setup nock to wallet platform GET /wallet/fakeid
const wpWalletnock = nock(bgUrl)
.get('/api/v2/btc/wallet/fakeid')
.reply(200, { id: 'fakeid', keys: ['abc', 'def', 'ghi'], coinSpecific: {} });
const wpKeychainNocks = [
nock(bgUrl).get('/api/v2/btc/key/abc').reply(200, { pub: 'xpubabc' }),
nock(bgUrl).get('/api/v2/btc/key/def').reply(200, { pub: 'xpubdef' }),
nock(bgUrl).get('/api/v2/btc/key/ghi').reply(200, { pub: 'xpubghi' }),
];
const wpLatestBlockNock = nock(bgUrl).get('/api/v2/btc/public/block/latest').reply(200);
const wpBuildnock = nock(bgUrl)
.post('/api/v2/btc/wallet/fakeid/tx/build')
.reply(200, { wpBuild: 'WP build response' });
const postProcessPrebuildStub = sinon.stub(bitgo_1.Coin.Btc.prototype, 'postProcessPrebuild').resolvesArg(0);
const verifyTransactionStub = sinon.stub(bitgo_1.Coin.Btc.prototype, 'verifyTransaction').resolves(true);
const clock = sinon.useFakeTimers();
// make request to express application to initiate send
const resultPromise = agent
.post('/api/v2/btc/wallet/fakeid/sendcoins')
.type('json')
.send({ address: 'abc', amount: 123 });
// every 10 "fake" ms, push the clock forward another 10 "fake" ms
const interval = clock.setInterval(async () => {
await clock.tickAsync(10);
}, 10);
// start running the setInterval loop above to push the clock forward
clock.next();
const result = await resultPromise;
result.ok.should.be.false();
result.should.have.property('text');
result.text.should.match(/giving up after reaching max retry limit of/);
signernock.done();
wpKeychainNocks.forEach((s) => s.done());
wpLatestBlockNock.done();
wpWalletnock.done();
wpBuildnock.done();
clock.clearInterval(interval);
clock.restore();
postProcessPrebuildStub.restore();
verifyTransactionStub.restore();
});
it('should not retry requests to external signer for an error other than "ECONNREFUSED"', async function () {
const bgUrl = bitgo_1.Environments.test.uri;
// setup nocks to external signer
const signernock = nock(externalSignerUrl).post('/api/v2/btc/sign').replyWithError({ code: 'not ECONNREFUSED' });
// setup nock to wallet platform GET /wallet/fakeid
const wpWalletnock = nock(bgUrl)
.get('/api/v2/btc/wallet/fakeid')
.reply(200, { id: 'fakeid', keys: ['abc', 'def', 'ghi'], coinSpecific: {} });
const wpKeychainNocks = [
nock(bgUrl).get('/api/v2/btc/key/abc').reply(200, { pub: 'xpubabc' }),
nock(bgUrl).get('/api/v2/btc/key/def').reply(200, { pub: 'xpubdef' }),
nock(bgUrl).get('/api/v2/btc/key/ghi').reply(200, { pub: 'xpubghi' }),
];
const wpLatestBlockNock = nock(bgUrl).get('/api/v2/btc/public/block/latest').reply(200);
const wpBuildnock = nock(bgUrl)
.post('/api/v2/btc/wallet/fakeid/tx/build')
.reply(200, { wpBuild: 'WP build response' });
const postProcessPrebuildStub = sinon.stub(bitgo_1.Coin.Btc.prototype, 'postProcessPrebuild').resolvesArg(0);
const verifyTransactionStub = sinon.stub(bitgo_1.Coin.Btc.prototype, 'verifyTransaction').resolves(true);
// check to make sure request to external signer is not attempted a second time
nock.emitter.on('no match', (req) => {
if (req.path === '/api/v2/btc/sign') {
throw new Error(`Unexpected retry request was sent to ${req.path}`);
}
});
// make request to express application to initiate send
const result = await agent
.post('/api/v2/btc/wallet/fakeid/sendcoins')
.type('json')
.send({ address: 'abc', amount: 123 });
result.ok.should.be.false();
signernock.done();
wpKeychainNocks.forEach((s) => s.done());
wpLatestBlockNock.done();
wpWalletnock.done();
wpBuildnock.done();
postProcessPrebuildStub.restore();
verifyTransactionStub.restore();
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXh0ZXJuYWxTaWduZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L2ludGVncmF0aW9uL2V4dGVybmFsU2lnbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUE7O0dBRUc7QUFDSCxrQkFBZ0I7QUFDaEIsdUJBQXFCO0FBQ3JCLCtCQUErQjtBQUUvQixxQ0FBcUM7QUFDckMscURBQXlEO0FBQ3pELDZCQUE2QjtBQUM3QixpQ0FBMkM7QUFFM0MsUUFBUSxDQUFDLHlCQUF5QixFQUFFLEdBQUcsRUFBRTtJQUN2QyxJQUFJLEtBQTZCLENBQUM7SUFDbEMsTUFBTSxpQkFBaUIsR0FBRyxpQ0FBaUMsQ0FBQztJQUM1RCxNQUFNLENBQUMsR0FBRyxFQUFFO1FBQ1YsTUFBTSxJQUFJLEdBQVE7WUFDaEIsS0FBSyxFQUFFLElBQUk7WUFDWCxHQUFHLEVBQUUsTUFBTTtZQUNYLGlCQUFpQjtZQUNqQixPQUFPLEVBQUUsS0FBSztTQUNmLENBQUM7UUFFRixNQUFNLEdBQUcsR0FBRyxJQUFBLGdCQUFVLEVBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0IsS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFM0IsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUNwQixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7U0FDakI7UUFDRCxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN6QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDckMsQ0FBQyxDQUFDLENBQUM7SUFFSCxLQUFLLENBQUMsR0FBRyxFQUFFO1FBQ1QsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUU7WUFDbkIsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1NBQ2hCO0lBQ0gsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsdURBQXVELEVBQUUsS0FBSztRQUMvRCxNQUFN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IEBwcmV0dGllclxuICovXG5pbXBvcnQgJ3Nob3VsZCc7XG5pbXBvcnQgJ3Nob3VsZC1odHRwJztcbmltcG9ydCAqIGFzIHNpbm9uIGZyb20gJ3Npbm9uJztcblxuaW1wb3J0ICogYXMgcmVxdWVzdCBmcm9tICdzdXBlcnRlc3QnO1xuaW1wb3J0IHsgYXBwIGFzIGV4cHJlc3NBcHAgfSBmcm9tICcuLi8uLi9zcmMvZXhwcmVzc0FwcCc7XG5pbXBvcnQgKiBhcyBub2NrIGZyb20gJ25vY2snO1xuaW1wb3J0IHsgQ29pbiwgRW52aXJvbm1lbnRzIH0gZnJvbSAnYml0Z28nO1xuXG5kZXNjcmliZSgnQ3VzdG9tIHNpZ25pbmcgZnVuY3Rpb24nLCAoKSA9PiB7XG4gIGxldCBhZ2VudDogcmVxdWVzdC5TdXBlckFnZW50VGVzdDtcbiAgY29uc3QgZXh0ZXJuYWxTaWduZXJVcmwgPSAnaHR0cHM6Ly9leHRlcm5hbC1zaWduZXIuaW52YWxpZCc7XG4gIGJlZm9yZSgoKSA9PiB7XG4gICAgY29uc3QgYXJnczogYW55ID0ge1xuICAgICAgZGVidWc6IHRydWUsXG4gICAgICBlbnY6ICd0ZXN0JyxcbiAgICAgIGV4dGVybmFsU2lnbmVyVXJsLFxuICAgICAgdGltZW91dDogNjAwMDAsXG4gICAgfTtcblxuICAgIGNvbnN0IGFwcCA9IGV4cHJlc3NBcHAoYXJncyk7XG4gICAgYWdlbnQgPSByZXF1ZXN0LmFnZW50KGFwcCk7XG5cbiAgICBpZiAoIW5vY2suaXNBY3RpdmUoKSkge1xuICAgICAgbm9jay5hY3RpdmF0ZSgpO1xuICAgIH1cbiAgICBub2NrLmRpc2FibGVOZXRDb25uZWN0KCk7XG4gICAgbm9jay5lbmFibGVOZXRDb25uZWN0KCcxMjcuMC4wLjEnKTtcbiAgfSk7XG5cbiAgYWZ0ZXIoKCkgPT4ge1xuICAgIGlmIChub2NrLmlzQWN0aXZlKCkpIHtcbiAgICAgIG5vY2sucmVzdG9yZSgpO1xuICAgIH1cbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBtYWtlIGEgcmVxdWVzdCB0byBleHRlcm5hbCBzaWduZXIgd2hlbiBzZW5kaW5nJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IGJnVXJsID0gRW52aXJvbm1lbnRzLnRlc3QudXJpO1xuICAgIC8vIHNldHVwIG5vY2sgdG8gZXh0ZXJuYWwgc2lnbmVyXG4gICAgY29uc3Qgc2lnbmVybm9jayA9IG5vY2soZXh0ZXJuYWxTaWduZXJVcmwpXG4gICAgICAucG9zdCgnL2FwaS92Mi9idGMvc2lnbicpXG4gICAgICAucmVwbHkoMjAwLCB7IGV4dGVybmFsU2lnbmVyOiAnZXh0ZXJuYWwgc2lnbmVyIHJlc3BvbnNlJyB9KTtcblxuICAgIC8vIHNldHVwIG5vY2sgdG8gd2FsbGV0IHBsYXRmb3JtIEdFVCAvd2FsbGV0L2Zha2VpZFxuICAgIGNvbnN0IHdwV2FsbGV0bm9jayA9IG5vY2soYmdVcmwpXG4gICAgICAuZ2V0KCcvYXBpL3YyL2J0Yy93YWxsZXQvZmFrZWlkJylcbiAgICAgIC5yZXBseSgyMDAsIHsgaWQ6ICdmYWtlaWQnLCBrZXlzOiBbJ2FiYycsICdkZWYnLCAnZ2hpJ10sIGNvaW5TcGVjaWZpYzoge30gfSk7XG4gICAgY29uc3Qgd3BLZXljaGFpbk5vY2tzID0gW1xuICAgICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9rZXkvYWJjJykucmVwbHkoMjAwLCB7IHB1YjogJ3hwdWJhYmMnIH0pLFxuICAgICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9rZXkvZGVmJykucmVwbHkoMjAwLCB7IHB1YjogJ3hwdWJkZWYnIH0pLFxuICAgICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9rZXkvZ2hpJykucmVwbHkoMjAwLCB7IHB1YjogJ3hwdWJnaGknIH0pLFxuICAgIF07XG4gICAgY29uc3Qgd3BMYXRlc3RCbG9ja05vY2sgPSBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjIvYnRjL3B1YmxpYy9ibG9jay9sYXRlc3QnKS5yZXBseSgyMDApO1xuXG4gICAgY29uc3Qgd3BCdWlsZG5vY2sgPSBub2NrKGJnVXJsKVxuICAgICAgLnBvc3QoJy9hcGkvdjIvYnRjL3dhbGxldC9mYWtlaWQvdHgvYnVpbGQnKVxuICAgICAgLnJlcGx5KDIwMCwgeyB3cEJ1aWxkOiAnV1AgYnVpbGQgcmVzcG9uc2UnIH0pO1xuICAgIGNvbnN0IHdwU2VuZG5vY2sgPSBub2NrKGJnVXJsKS5wb3N0KCcvYXBpL3YyL2J0Yy93YWxsZXQvZmFrZWlkL3R4L3NlbmQnKS5yZXBseSgyMDAsIHsgd3BTZW5kOiAnV1Agc2VuZCByZXNwb25zZScgfSk7XG5cbiAgICBjb25zdCBwb3N0UHJvY2Vzc1ByZWJ1aWxkU3R1YiA9IHNpbm9uLnN0dWIoQ29pbi5CdGMucHJvdG90eXBlLCAncG9zdFByb2Nlc3NQcmVidWlsZCcpLnJlc29sdmVzQXJnKDApO1xuICAgIGNvbnN0IHZlcmlmeVRyYW5zYWN0aW9uU3R1YiA9IHNpbm9uLnN0dWIoQ29pbi5CdGMucHJvdG90eXBlLCAndmVyaWZ5VHJhbnNhY3Rpb24nKS5yZXNvbHZlcyh0cnVlKTtcblxuICAgIC8vIG1ha2UgcmVxdWVzdCB0byBleHByZXNzIGFwcGxpY2F0aW9uIHRvIGluaXRpYXRlIHNlbmRcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBhZ2VudFxuICAgICAgLnBvc3QoJy9hcGkvdjIvYnRjL3dhbGxldC9mYWtlaWQvc2VuZGNvaW5zJylcbiAgICAgIC50eXBlKCdqc29uJylcbiAgICAgIC5zZW5kKHsgYWRkcmVzczogJ2FiYycsIGFtb3VudDogMTIzIH0pO1xuXG4gICAgLy8gY2hlY2sgdG8gbWFrZSBzdXJlIHJlcXVlc3QgdG8gZXh0ZXJuYWwgc2lnbmVyIHdhcyBzdWNjZXNzZnVsXG4gICAgcmVzdWx0Lm9rLnNob3VsZC5iZS50cnVlKCk7XG5cbiAgICAvLyBtYWtlIHN1cmUgd2FsbGV0IHBsYXRmb3JtIHJlcXVlc3QgY29udGFpbmVkIHJlc3BvbnNlIGZyb20gZXh0ZXJuYWwgc2lnbmVyXG4gICAgcmVzdWx0LmJvZHkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3dwU2VuZCcsICdXUCBzZW5kIHJlc3BvbnNlJyk7XG5cbiAgICBzaWduZXJub2NrLmRvbmUoKTtcbiAgICB3cEtleWNoYWluTm9ja3MuZm9yRWFjaCgocykgPT4gcy5kb25lKCkpO1xuICAgIHdwTGF0ZXN0QmxvY2tOb2NrLmRvbmUoKTtcbiAgICB3cFdhbGxldG5vY2suZG9uZSgpO1xuICAgIHdwQnVpbGRub2NrLmRvbmUoKTtcbiAgICB3cFNlbmRub2NrLmRvbmUoKTtcblxuICAgIHBvc3RQcm9jZXNzUHJlYnVpbGRTdHViLnJlc3RvcmUoKTtcbiAgICB2ZXJpZnlUcmFuc2FjdGlvblN0dWIucmVzdG9yZSgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHJ5IHJlcXVlc3RzIHRvIGV4dGVybmFsIHNpZ25lciBvbiBhbiBcIkVDT05OUkVGVVNFRFwiIGVycm9yJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IGJnVXJsID0gRW52aXJvbm1lbnRzLnRlc3QudXJpO1xuICAgIC8vIHNldHVwIHBlcnNpc3RlbnQgbm9jayB0byBleHRlcm5hbCBzaWduZXJcbiAgICBjb25zdCBzaWduZXJub2NrID0gbm9jayhleHRlcm5hbFNpZ25lclVybClcbiAgICAgIC5wb3N0KCcvYXBpL3YyL2J0Yy9zaWduJylcbiAgICAgIC50aW1lcygzKVxuICAgICAgLnJlcGx5V2l0aEVycm9yKHsgY29kZTogJ0VDT05OUkVGVVNFRCcgfSk7XG5cbiAgICAvLyBzZXR1cCBub2NrIHRvIHdhbGxldCBwbGF0Zm9ybSBHRVQgL3dhbGxldC9mYWtlaWRcbiAgICBjb25zdCB3cFdhbGxldG5vY2sgPSBub2NrKGJnVXJsKVxuICAgICAgLmdldCgnL2FwaS92Mi9idGMvd2FsbGV0L2Zha2VpZCcpXG4gICAgICAucmVwbHkoMjAwLCB7IGlkOiAnZmFrZWlkJywga2V5czogWydhYmMnLCAnZGVmJywgJ2doaSddLCBjb2luU3BlY2lmaWM6IHt9IH0pO1xuICAgIGNvbnN0IHdwS2V5Y2hhaW5Ob2NrcyA9IFtcbiAgICAgIG5vY2soYmdVcmwpLmdldCgnL2FwaS92Mi9idGMva2V5L2FiYycpLnJlcGx5KDIwMCwgeyBwdWI6ICd4cHViYWJjJyB9KSxcbiAgICAgIG5vY2soYmdVcmwpLmdldCgnL2FwaS92Mi9idGMva2V5L2RlZicpLnJlcGx5KDIwMCwgeyBwdWI6ICd4cHViZGVmJyB9KSxcbiAgICAgIG5vY2soYmdVcmwpLmdldCgnL2FwaS92Mi9idGMva2V5L2doaScpLnJlcGx5KDIwMCwgeyBwdWI6ICd4cHViZ2hpJyB9KSxcbiAgICBdO1xuICAgIGNvbnN0IHdwTGF0ZXN0QmxvY2tOb2NrID0gbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9wdWJsaWMvYmxvY2svbGF0ZXN0JykucmVwbHkoMjAwKTtcblxuICAgIGNvbnN0IHdwQnVpbGRub2NrID0gbm9jayhiZ1VybClcbiAgICAgIC5wb3N0KCcvYXBpL3YyL2J0Yy93YWxsZXQvZmFrZWlkL3R4L2J1aWxkJylcbiAgICAgIC5yZXBseSgyMDAsIHsgd3BCdWlsZDogJ1dQIGJ1aWxkIHJlc3BvbnNlJyB9KTtcblxuICAgIGNvbnN0IHBvc3RQcm9jZXNzUHJlYnVpbGRTdHViID0gc2lub24uc3R1YihDb2luLkJ0Yy5wcm90b3R5cGUsICdwb3N0UHJvY2Vzc1ByZWJ1aWxkJykucmVzb2x2ZXNBcmcoMCk7XG4gICAgY29uc3QgdmVyaWZ5VHJhbnNhY3Rpb25TdHViID0gc2lub24uc3R1YihDb2luLkJ0Yy5wcm90b3R5cGUsICd2ZXJpZnlUcmFuc2FjdGlvbicpLnJlc29sdmVzKHRydWUpO1xuXG4gICAgY29uc3QgY2xvY2sgPSBzaW5vbi51c2VGYWtlVGltZXJzKCk7XG5cbiAgICAvLyBtYWtlIHJlcXVlc3QgdG8gZXhwcmVzcyBhcHBsaWNhdGlvbiB0byBpbml0aWF0ZSBzZW5kXG4gICAgY29uc3QgcmVzdWx0UHJvbWlzZSA9IGFnZW50XG4gICAgICAucG9zdCgnL2FwaS92Mi9idGMvd2FsbGV0L2Zha2VpZC9zZW5kY29pbnMnKVxuICAgICAgLnR5cGUoJ2pzb24nKVxuICAgICAgLnNlbmQoeyBhZGRyZXNzOiAnYWJjJywgYW1vdW50OiAxMjMgfSk7XG5cbiAgICAvLyBldmVyeSAxMCBcImZha2VcIiBtcywgcHVzaCB0aGUgY2xvY2sgZm9yd2FyZCBhbm90aGVyIDEwIFwiZmFrZVwiIG1zXG4gICAgY29uc3QgaW50ZXJ2YWwgPSBjbG9jay5zZXRJbnRlcnZhbChhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBjbG9jay50aWNrQXN5bmMoMTApO1xuICAgIH0sIDEwKTtcblxuICAgIC8vIHN0YXJ0IHJ1bm5pbmcgdGhlIHNldEludGVydmFsIGxvb3AgYWJvdmUgdG8gcHVzaCB0aGUgY2xvY2sgZm9yd2FyZFxuICAgIGNsb2NrLm5leHQoKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJlc3VsdFByb21pc2U7XG5cbiAgICByZXN1bHQub2suc2hvdWxkLmJlLmZhbHNlKCk7XG5cbiAgICByZXN1bHQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3RleHQnKTtcbiAgICByZXN1bHQudGV4dC5zaG91bGQubWF0Y2goL2dpdmluZyB1cCBhZnRlciByZWFjaGluZyBtYXggcmV0cnkgbGltaXQgb2YvKTtcblxuICAgIHNpZ25lcm5vY2suZG9uZSgpO1xuICAgIHdwS2V5Y2hhaW5Ob2Nrcy5mb3JFYWNoKChzKSA9PiBzLmRvbmUoKSk7XG4gICAgd3BMYXRlc3RCbG9ja05vY2suZG9uZSgpO1xuICAgIHdwV2FsbGV0bm9jay5kb25lKCk7XG4gICAgd3BCdWlsZG5vY2suZG9uZSgpO1xuXG4gICAgY2xvY2suY2xlYXJJbnRlcnZhbChpbnRlcnZhbCBhcyBhbnkpO1xuICAgIGNsb2NrLnJlc3RvcmUoKTtcbiAgICBwb3N0UHJvY2Vzc1ByZWJ1aWxkU3R1Yi5yZXN0b3JlKCk7XG4gICAgdmVyaWZ5VHJhbnNhY3Rpb25TdHViLnJlc3RvcmUoKTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBub3QgcmV0cnkgcmVxdWVzdHMgdG8gZXh0ZXJuYWwgc2lnbmVyIGZvciBhbiBlcnJvciBvdGhlciB0aGFuIFwiRUNPTk5SRUZVU0VEXCInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3QgYmdVcmwgPSBFbnZpcm9ubWVudHMudGVzdC51cmk7XG4gICAgLy8gc2V0dXAgbm9ja3MgdG8gZXh0ZXJuYWwgc2lnbmVyXG4gICAgY29uc3Qgc2lnbmVybm9jayA9IG5vY2soZXh0ZXJuYWxTaWduZXJVcmwpLnBvc3QoJy9hcGkvdjIvYnRjL3NpZ24nKS5yZXBseVdpdGhFcnJvcih7IGNvZGU6ICdub3QgRUNPTk5SRUZVU0VEJyB9KTtcblxuICAgIC8vIHNldHVwIG5vY2sgdG8gd2FsbGV0IHBsYXRmb3JtIEdFVCAvd2FsbGV0L2Zha2VpZFxuICAgIGNvbnN0IHdwV2FsbGV0bm9jayA9IG5vY2soYmdVcmwpXG4gICAgICAuZ2V0KCcvYXBpL3YyL2J0Yy93YWxsZXQvZmFrZWlkJylcbiAgICAgIC5yZXBseSgyMDAsIHsgaWQ6ICdmYWtlaWQnLCBrZXlzOiBbJ2FiYycsICdkZWYnLCAnZ2hpJ10sIGNvaW5TcGVjaWZpYzoge30gfSk7XG4gICAgY29uc3Qgd3BLZXljaGFpbk5vY2tzID0gW1xuICAgICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9rZXkvYWJjJykucmVwbHkoMjAwLCB7IHB1YjogJ3hwdWJhYmMnIH0pLFxuICAgICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9rZXkvZGVmJykucmVwbHkoMjAwLCB7IHB1YjogJ3hwdWJkZWYnIH0pLFxuICAgICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YyL2J0Yy9rZXkvZ2hpJykucmVwbHkoMjAwLCB7IHB1YjogJ3hwdWJnaGknIH0pLFxuICAgIF07XG4gICAgY29uc3Qgd3BMYXRlc3RCbG9ja05vY2sgPSBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjIvYnRjL3B1YmxpYy9ibG9jay9sYXRlc3QnKS5yZXBseSgyMDApO1xuXG4gICAgY29uc3Qgd3BCdWlsZG5vY2sgPSBub2NrKGJnVXJsKVxuICAgICAgLnBvc3QoJy9hcGkvdjIvYnRjL3dhbGxldC9mYWtlaWQvdHgvYnVpbGQnKVxuICAgICAgLnJlcGx5KDIwMCwgeyB3cEJ1aWxkOiAnV1AgYnVpbGQgcmVzcG9uc2UnIH0pO1xuXG4gICAgY29uc3QgcG9zdFByb2Nlc3NQcmVidWlsZFN0dWIgPSBzaW5vbi5zdHViKENvaW4uQnRjLnByb3RvdHlwZSwgJ3Bvc3RQcm9jZXNzUHJlYnVpbGQnKS5yZXNvbHZlc0FyZygwKTtcbiAgICBjb25zdCB2ZXJpZnlUcmFuc2FjdGlvblN0dWIgPSBzaW5vbi5zdHViKENvaW4uQnRjLnByb3RvdHlwZSwgJ3ZlcmlmeVRyYW5zYWN0aW9uJykucmVzb2x2ZXModHJ1ZSk7XG5cbiAgICAvLyBjaGVjayB0byBtYWtlIHN1cmUgcmVxdWVzdCB0byBleHRlcm5hbCBzaWduZXIgaXMgbm90IGF0dGVtcHRlZCBhIHNlY29uZCB0aW1lXG4gICAgbm9jay5lbWl0dGVyLm9uKCdubyBtYXRjaCcsIChyZXEpID0+IHtcbiAgICAgIGlmIChyZXEucGF0aCA9PT0gJy9hcGkvdjIvYnRjL3NpZ24nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5leHBlY3RlZCByZXRyeSByZXF1ZXN0IHdhcyBzZW50IHRvICR7cmVxLnBhdGh9YCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBtYWtlIHJlcXVlc3QgdG8gZXhwcmVzcyBhcHBsaWNhdGlvbiB0byBpbml0aWF0ZSBzZW5kXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYWdlbnRcbiAgICAgIC5wb3N0KCcvYXBpL3YyL2J0Yy93YWxsZXQvZmFrZWlkL3NlbmRjb2lucycpXG4gICAgICAudHlwZSgnanNvbicpXG4gICAgICAuc2VuZCh7IGFkZHJlc3M6ICdhYmMnLCBhbW91bnQ6IDEyMyB9KTtcblxuICAgIHJlc3VsdC5vay5zaG91bGQuYmUuZmFsc2UoKTtcblxuICAgIHNpZ25lcm5vY2suZG9uZSgpO1xuICAgIHdwS2V5Y2hhaW5Ob2Nrcy5mb3JFYWNoKChzKSA9PiBzLmRvbmUoKSk7XG4gICAgd3BMYXRlc3RCbG9ja05vY2suZG9uZSgpO1xuICAgIHdwV2FsbGV0bm9jay5kb25lKCk7XG4gICAgd3BCdWlsZG5vY2suZG9uZSgpO1xuXG4gICAgcG9zdFByb2Nlc3NQcmVidWlsZFN0dWIucmVzdG9yZSgpO1xuICAgIHZlcmlmeVRyYW5zYWN0aW9uU3R1Yi5yZXN0b3JlKCk7XG4gIH0pO1xufSk7XG4iXX0=Выполнить команду
Для локальной разработки. Не используйте в интернете!