PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/dist/test/integration
Просмотр файла: accesstoken.js
"use strict";
//
// Tests for API Access Tokens
//
// Copyright 2016, BitGo, Inc. All Rights Reserved.
//
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/no-empty-function */
const assert_1 = require("assert");
const should = require("should");
const _ = require("lodash");
const TestBitGo = require('../lib/test_bitgo');
const TestUtil = require('./testutil');
describe('Access Token', function () {
let INITIAL_TOKEN_COUNT; // used as an offset when checking if tokens were properly created or removed
let loginAccessTokenHex; // save token hex for when we remove a token that was just set
let bitgo;
const someScopes = ['openid', 'profile', 'wallet_create', 'wallet_view_all'];
before(function () {
bitgo = new TestBitGo();
bitgo.initializeTestVars();
return bitgo
.authenticateTestUser(bitgo.testUserOTP())
.then(function () {
loginAccessTokenHex = bitgo._token;
const filterFunc = function (tok) {
return tok.label;
};
return TestUtil.deleteTestTokens(bitgo, filterFunc);
})
.then(function () {
return bitgo.listAccessTokens();
})
.then(function (tokens) {
INITIAL_TOKEN_COUNT = tokens.length;
});
});
describe('authentication with access token', function () {
let addedTokenHex;
it('should authenticate with added access token', function () {
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes })
.then(function (res) {
addedTokenHex = res.token;
return bitgo.authenticateWithAccessToken({ accessToken: addedTokenHex });
})
.then(function () {
bitgo._token.should.equal(addedTokenHex);
// set _token back to original login value
return bitgo.authenticateWithAccessToken({ accessToken: loginAccessTokenHex });
})
.then(function () {
bitgo._token.should.equal(loginAccessTokenHex);
return bitgo.removeAccessToken({ label: 'test token' });
});
});
});
describe('Add', function () {
describe('bad args', function () {
it('arguments', function () {
assert_1.strict.throws(function () {
bitgo.addAccessToken({}, 'invalid');
});
assert_1.strict.throws(function () {
bitgo.addAccessToken({}, function () { });
});
assert_1.strict.throws(function () {
bitgo.addAccessToken({
otp: bitgo.testUserOTP(),
scope: ['wallet_view_all', 'openid', 'profile'],
}, 'invalid');
});
});
it('fails to add without scope', function () {
assert_1.strict.throws(function () {
bitgo.addAccessToken({
otp: bitgo.testUserOTP(),
}, function () { });
});
});
it('fails to add with empty scope', function () {
assert_1.strict.throws(function () {
bitgo.addAccessToken({
otp: bitgo.testUserOTP(),
scope: [],
}, function () { });
});
});
it('fails to add with incorrect type of scope', function () {
assert_1.strict.throws(function () {
bitgo.addAccessToken({
otp: bitgo.testUserOTP(),
scope: 'notAnArray',
}, function () { });
});
});
it('fails to add with invalid scope', function () {
const promise = bitgo.addAccessToken({ otp: 'badToken', label: 'test token', scope: ['invalid'] });
return TestUtil.throws(promise, 'invalid scope');
});
it('fails to add with bad otp', function () {
const promise = bitgo.addAccessToken({ otp: 'badToken', label: 'test token', scope: someScopes });
return TestUtil.throws(promise, 'invalid');
});
});
describe('success', function () {
afterEach(function () {
return bitgo.removeAccessToken({ label: 'test token' });
});
it('simple add', function () {
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes })
.then(function (res) {
res.should.have.property('user');
res.should.have.property('scope');
res.should.have.property('created');
res.should.have.property('expires');
res.should.have.property('origin');
res.should.have.property('label');
res.should.have.property('isExtensible');
res.should.have.property('token');
res.should.not.have.property('unlock');
res.should.not.have.property('enterprise');
res.label.should.equal('test token');
res.isExtensible.should.equal(false);
return bitgo.listAccessTokens();
})
.then(function (tokens) {
const numTokens = tokens.length;
numTokens.should.equal(INITIAL_TOKEN_COUNT + 1);
});
});
it('duration', function () {
const DURATION = 3600 * 10; // ten days
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', duration: DURATION, scope: someScopes })
.then(function (res) {
res.label.should.equal('test token');
const created = res.created;
const expires = res.expires;
const createdPlusDuration = new Date(new Date(created).getTime() + DURATION * 1000).getTime();
const expiresTime = new Date(expires).getTime();
const leeway = 10; // because of the miniscule time it takes to execute a function, we give a 10 ms leeway in the time differences
createdPlusDuration.should.be.greaterThan(expiresTime - leeway);
createdPlusDuration.should.be.lessThan(expiresTime + leeway);
});
});
it('ipRestrict', function () {
const IPRESTRICT = ['0.0.0.0', '8.8.8.8'];
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', ipRestrict: IPRESTRICT, scope: someScopes })
.then(function (token) {
token.should.have.property('token');
});
});
it('txValueLimit', function () {
const TXVALUELIMIT = 1e8; // 1 BTC
return bitgo
.addAccessToken({
otp: bitgo.testUserOTP(),
label: 'test token',
txValueLimit: TXVALUELIMIT,
scope: someScopes,
})
.then(function (res) {
res.unlock.txValueLimit.should.equal(1e8);
});
});
// see some examples of Scope Values under https://www.bitgo.com/api/#partner-oauth
it('scopes', function () {
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes })
.then(function (res) {
res.scope.should.have.length(4);
});
});
});
});
describe('List', function () {
it('should list no new access token', function () {
return bitgo.listAccessTokens().then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT);
});
});
it('should add and list single access token', function () {
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes })
.then(function (res) {
res.label.should.equal('test token');
return bitgo.listAccessTokens();
})
.then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT + 1);
const token = _.find(tokens, function (tok) {
return tok.label === 'test token';
});
should.exist(token);
});
});
it('should add another and list multiple access tokens', function () {
let token1;
let token2;
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token 2', scope: someScopes })
.then(function (res) {
res.label.should.equal('test token 2');
return bitgo.listAccessTokens();
})
.then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT + 2);
token1 = _.find(tokens, function (tok) {
return tok.label === 'test token 2';
});
token2 = _.find(tokens, function (tok) {
return tok.label === 'test token';
});
should.exist(token1);
should.exist(token2);
// cleanup access tokens for future tests
return bitgo.removeAccessToken({ id: token1.id });
})
.then(function () {
return bitgo.removeAccessToken({ id: token2.id });
});
});
});
describe('Update', function () {
should.exist(true); // no-op
// access tokens have no update API, they can only be created or removed
});
describe('Remove', function () {
let ambiguousTokenId;
before(function () {
return bitgo.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes });
});
it('arguments', function () {
assert_1.strict.throws(function () {
bitgo.removeAccessToken({}, 'invalid');
});
assert_1.strict.throws(function () {
bitgo.removeAccessToken({}, function () { });
});
assert_1.strict.throws(function () {
bitgo.removeAccessToken({ id: 'non-existent id' }, 'invalid');
});
assert_1.strict.throws(function () {
bitgo.removeAccessToken({ label: 'non-existent label' }, 'invalid');
});
});
it('should fail with ambigous remove', function () {
// begin by adding second token
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes })
.then(function (token) {
ambiguousTokenId = token.id;
const promise = bitgo.removeAccessToken({ label: 'test token' });
return TestUtil.throws(promise, 'ambiguous call: multiple tokens matching this label');
});
});
it('should remove by label', function () {
return bitgo
.listAccessTokens()
.then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT + 2);
// now remove
return bitgo.removeAccessToken({ id: ambiguousTokenId });
})
.then(function () {
return bitgo.listAccessTokens();
})
.then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT + 1);
return bitgo.removeAccessToken({ label: 'test token' });
})
.then(function () {
return bitgo.listAccessTokens();
})
.then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT);
});
});
it('should remove access token by id', function () {
return bitgo
.addAccessToken({ otp: bitgo.testUserOTP(), label: 'test token', scope: someScopes })
.then(function (tok) {
return bitgo.removeAccessToken({ id: tok.id });
})
.then(function () {
return bitgo.listAccessTokens();
})
.then(function (tokens) {
tokens.length.should.equal(INITIAL_TOKEN_COUNT);
});
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjZXNzdG9rZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L2ludGVncmF0aW9uL2FjY2Vzc3Rva2VuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxFQUFFO0FBQ0YsOEJBQThCO0FBQzlCLEVBQUU7QUFDRixvREFBb0Q7QUFDcEQsRUFBRTs7QUFFRix5REFBeUQ7QUFFekQsbUNBQTBDO0FBQzFDLGlDQUFpQztBQUNqQyw0QkFBNEI7QUFFNUIsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7QUFDL0MsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBRXZDLFFBQVEsQ0FBQyxjQUFjLEVBQUU7SUFDdkIsSUFBSSxtQkFBbUIsQ0FBQyxDQUFDLDZFQUE2RTtJQUN0RyxJQUFJLG1CQUFtQixDQUFDLENBQUMsOERBQThEO0lBQ3ZGLElBQUksS0FBSyxDQUFDO0lBQ1YsTUFBTSxVQUFVLEdBQUcsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO0lBRTdFLE1BQU0sQ0FBQztRQUNMLEtBQUssR0FBRyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzNCLE9BQU8sS0FBSzthQUNULG9CQUFvQixDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQzthQUN6QyxJQUFJLENBQUM7WUFDSixtQkFBbUIsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1lBRW5DLE1BQU0sVUFBVSxHQUFHLFVBQVUsR0FBRztnQkFDOUIsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDO1lBQ25CLENBQUMsQ0FBQztZQUNGLE9BQU8sUUFBUSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUM7YUFDRCxJQUFJLENBQUM7WUFDSixPQUFPLEtBQUss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bi8vXG4vLyBDb3B5cmlnaHQgMjAxNiwgQml0R28sIEluYy4gIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vL1xuXG4vKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb24gKi9cblxuaW1wb3J0IHsgc3RyaWN0IGFzIGFzc2VydCB9IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgKiBhcyBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcblxuY29uc3QgVGVzdEJpdEdvID0gcmVxdWlyZSgnLi4vbGliL3Rlc3RfYml0Z28nKTtcbmNvbnN0IFRlc3RVdGlsID0gcmVxdWlyZSgnLi90ZXN0dXRpbCcpO1xuXG5kZXNjcmliZSgnQWNjZXNzIFRva2VuJywgZnVuY3Rpb24gKCkge1xuICBsZXQgSU5JVElBTF9UT0tFTl9DT1VOVDsgLy8gdXNlZCBhcyBhbiBvZmZzZXQgd2hlbiBjaGVja2luZyBpZiB0b2tlbnMgd2VyZSBwcm9wZXJseSBjcmVhdGVkIG9yIHJlbW92ZWRcbiAgbGV0IGxvZ2luQWNjZXNzVG9rZW5IZXg7IC8vIHNhdmUgdG9rZW4gaGV4IGZvciB3aGVuIHdlIHJlbW92ZSBhIHRva2VuIHRoYXQgd2FzIGp1c3Qgc2V0XG4gIGxldCBiaXRnbztcbiAgY29uc3Qgc29tZVNjb3BlcyA9IFsnb3BlbmlkJywgJ3Byb2ZpbGUnLCAnd2FsbGV0X2NyZWF0ZScsICd3YWxsZXRfdmlld19hbGwnXTtcblxuICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgIGJpdGdvID0gbmV3IFRlc3RCaXRHbygpO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIHJldHVybiBiaXRnb1xuICAgICAgLmF1dGhlbnRpY2F0ZVRlc3RVc2VyKGJpdGdvLnRlc3RVc2VyT1RQKCkpXG4gICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxvZ2luQWNjZXNzVG9rZW5IZXggPSBiaXRnby5fdG9rZW47XG5cbiAgICAgICAgY29uc3QgZmlsdGVyRnVuYyA9IGZ1bmN0aW9uICh0b2spIHtcbiAgICAgICAgICByZXR1cm4gdG9rLmxhYmVsO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gVGVzdFV0aWwuZGVsZXRlVGVzdFRva2VucyhiaXRnbywgZmlsdGVyRnVuYyk7XG4gICAgICB9KVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z28ubGlzdEFjY2Vzc1Rva2VucygpO1xuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbnMpIHtcbiAgICAgICAgSU5JVElBTF9UT0tFTl9DT1VOVCA9IHRva2Vucy5sZW5ndGg7XG4gICAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2F1dGhlbnRpY2F0aW9uIHdpdGggYWNjZXNzIHRva2VuJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBhZGRlZFRva2VuSGV4O1xuICAgIGl0KCdzaG91bGQgYXV0aGVudGljYXRlIHdpdGggYWRkZWQgYWNjZXNzIHRva2VuJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgIGFkZGVkVG9rZW5IZXggPSByZXMudG9rZW47XG4gICAgICAgICAgcmV0dXJuIGJpdGdvLmF1dGhlbnRpY2F0ZVdpdGhBY2Nlc3NUb2tlbih7IGFjY2Vzc1Rva2VuOiBhZGRlZFRva2VuSGV4IH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYml0Z28uX3Rva2VuLnNob3VsZC5lcXVhbChhZGRlZFRva2VuSGV4KTtcblxuICAgICAgICAgIC8vIHNldCBfdG9rZW4gYmFjayB0byBvcmlnaW5hbCBsb2dpbiB2YWx1ZVxuICAgICAgICAgIHJldHVybiBiaXRnby5hdXRoZW50aWNhdGVXaXRoQWNjZXNzVG9rZW4oeyBhY2Nlc3NUb2tlbjogbG9naW5BY2Nlc3NUb2tlbkhleCB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGJpdGdvLl90b2tlbi5zaG91bGQuZXF1YWwobG9naW5BY2Nlc3NUb2tlbkhleCk7XG5cbiAgICAgICAgICByZXR1cm4gYml0Z28ucmVtb3ZlQWNjZXNzVG9rZW4oeyBsYWJlbDogJ3Rlc3QgdG9rZW4nIH0pO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0FkZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBkZXNjcmliZSgnYmFkIGFyZ3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnYXJndW1lbnRzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBiaXRnby5hZGRBY2Nlc3NUb2tlbih7fSwgJ2ludmFsaWQnKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGJpdGdvLmFkZEFjY2Vzc1Rva2VuKHt9LCBmdW5jdGlvbiAoKSB7fSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGJpdGdvLmFkZEFjY2Vzc1Rva2VuKFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgICAgICAgIHNjb3BlOiBbJ3dhbGxldF92aWV3X2FsbCcsICdvcGVuaWQnLCAncHJvZmlsZSddLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICdpbnZhbGlkJ1xuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdmYWlscyB0byBhZGQgd2l0aG91dCBzY29wZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYml0Z28uYWRkQWNjZXNzVG9rZW4oXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7fVxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdmYWlscyB0byBhZGQgd2l0aCBlbXB0eSBzY29wZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYml0Z28uYWRkQWNjZXNzVG9rZW4oXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgICAgICAgc2NvcGU6IFtdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHt9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2ZhaWxzIHRvIGFkZCB3aXRoIGluY29ycmVjdCB0eXBlIG9mIHNjb3BlJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBiaXRnby5hZGRBY2Nlc3NUb2tlbihcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLFxuICAgICAgICAgICAgICBzY29wZTogJ25vdEFuQXJyYXknLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHt9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2ZhaWxzIHRvIGFkZCB3aXRoIGludmFsaWQgc2NvcGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHByb21pc2UgPSBiaXRnby5hZGRBY2Nlc3NUb2tlbih7IG90cDogJ2JhZFRva2VuJywgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IFsnaW52YWxpZCddIH0pO1xuICAgICAgICByZXR1cm4gVGVzdFV0aWwudGhyb3dzKHByb21pc2UsICdpbnZhbGlkIHNjb3BlJyk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2ZhaWxzIHRvIGFkZCB3aXRoIGJhZCBvdHAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHByb21pc2UgPSBiaXRnby5hZGRBY2Nlc3NUb2tlbih7IG90cDogJ2JhZFRva2VuJywgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSk7XG4gICAgICAgIHJldHVybiBUZXN0VXRpbC50aHJvd3MocHJvbWlzZSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ3N1Y2Nlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z28ucmVtb3ZlQWNjZXNzVG9rZW4oeyBsYWJlbDogJ3Rlc3QgdG9rZW4nIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaW1wbGUgYWRkJywgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgICAuYWRkQWNjZXNzVG9rZW4oeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksIGxhYmVsOiAndGVzdCB0b2tlbicsIHNjb3BlOiBzb21lU2NvcGVzIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgcmVzLnNob3VsZC5oYXZlLnByb3BlcnR5KCd1c2VyJyk7XG4gICAgICAgICAgICByZXMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3Njb3BlJyk7XG4gICAgICAgICAgICByZXMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2NyZWF0ZWQnKTtcbiAgICAgICAgICAgIHJlcy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnZXhwaXJlcycpO1xuICAgICAgICAgICAgcmVzLnNob3VsZC5oYXZlLnByb3BlcnR5KCdvcmlnaW4nKTtcbiAgICAgICAgICAgIHJlcy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbGFiZWwnKTtcbiAgICAgICAgICAgIHJlcy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaXNFeHRlbnNpYmxlJyk7XG4gICAgICAgICAgICByZXMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3Rva2VuJyk7XG5cbiAgICAgICAgICAgIHJlcy5zaG91bGQubm90LmhhdmUucHJvcGVydHkoJ3VubG9jaycpO1xuICAgICAgICAgICAgcmVzLnNob3VsZC5ub3QuaGF2ZS5wcm9wZXJ0eSgnZW50ZXJwcmlzZScpO1xuXG4gICAgICAgICAgICByZXMubGFiZWwuc2hvdWxkLmVxdWFsKCd0ZXN0IHRva2VuJyk7XG4gICAgICAgICAgICByZXMuaXNFeHRlbnNpYmxlLnNob3VsZC5lcXVhbChmYWxzZSk7XG5cbiAgICAgICAgICAgIHJldHVybiBiaXRnby5saXN0QWNjZXNzVG9rZW5zKCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgICAgICBjb25zdCBudW1Ub2tlbnMgPSB0b2tlbnMubGVuZ3RoO1xuICAgICAgICAgICAgbnVtVG9rZW5zLnNob3VsZC5lcXVhbChJTklUSUFMX1RPS0VOX0NPVU5UICsgMSk7XG4gICAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2R1cmF0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBEVVJBVElPTiA9IDM2MDAgKiAxMDsgLy8gdGVuIGRheXNcbiAgICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgICAgLmFkZEFjY2Vzc1Rva2VuKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLCBsYWJlbDogJ3Rlc3QgdG9rZW4nLCBkdXJhdGlvbjogRFVSQVRJT04sIHNjb3BlOiBzb21lU2NvcGVzIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgcmVzLmxhYmVsLnNob3VsZC5lcXVhbCgndGVzdCB0b2tlbicpO1xuXG4gICAgICAgICAgICBjb25zdCBjcmVhdGVkID0gcmVzLmNyZWF0ZWQ7XG4gICAgICAgICAgICBjb25zdCBleHBpcmVzID0gcmVzLmV4cGlyZXM7XG4gICAgICAgICAgICBjb25zdCBjcmVhdGVkUGx1c0R1cmF0aW9uID0gbmV3IERhdGUobmV3IERhdGUoY3JlYXRlZCkuZ2V0VGltZSgpICsgRFVSQVRJT04gKiAxMDAwKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICBjb25zdCBleHBpcmVzVGltZSA9IG5ldyBEYXRlKGV4cGlyZXMpLmdldFRpbWUoKTtcbiAgICAgICAgICAgIGNvbnN0IGxlZXdheSA9IDEwOyAvLyBiZWNhdXNlIG9mIHRoZSBtaW5pc2N1bGUgdGltZSBpdCB0YWtlcyB0byBleGVjdXRlIGEgZnVuY3Rpb24sIHdlIGdpdmUgYSAxMCBtcyBsZWV3YXkgaW4gdGhlIHRpbWUgZGlmZmVyZW5jZXNcbiAgICAgICAgICAgIGNyZWF0ZWRQbHVzRHVyYXRpb24uc2hvdWxkLmJlLmdyZWF0ZXJUaGFuKGV4cGlyZXNUaW1lIC0gbGVld2F5KTtcbiAgICAgICAgICAgIGNyZWF0ZWRQbHVzRHVyYXRpb24uc2hvdWxkLmJlLmxlc3NUaGFuKGV4cGlyZXNUaW1lICsgbGVld2F5KTtcbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnaXBSZXN0cmljdCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgSVBSRVNUUklDVCA9IFsnMC4wLjAuMCcsICc4LjguOC44J107XG4gICAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgaXBSZXN0cmljdDogSVBSRVNUUklDVCwgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICAgIHRva2VuLnNob3VsZC5oYXZlLnByb3BlcnR5KCd0b2tlbicpO1xuICAgICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCd0eFZhbHVlTGltaXQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IFRYVkFMVUVMSU1JVCA9IDFlODsgLy8gMSBCVENcbiAgICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgICAgLmFkZEFjY2Vzc1Rva2VuKHtcbiAgICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgICAgIGxhYmVsOiAndGVzdCB0b2tlbicsXG4gICAgICAgICAgICB0eFZhbHVlTGltaXQ6IFRYVkFMVUVMSU1JVCxcbiAgICAgICAgICAgIHNjb3BlOiBzb21lU2NvcGVzLFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgcmVzLnVubG9jay50eFZhbHVlTGltaXQuc2hvdWxkLmVxdWFsKDFlOCk7XG4gICAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgLy8gc2VlIHNvbWUgZXhhbXBsZXMgb2YgU2NvcGUgVmFsdWVzIHVuZGVyIGh0dHBzOi8vd3d3LmJpdGdvLmNvbS9hcGkvI3BhcnRuZXItb2F1dGhcbiAgICAgIGl0KCdzY29wZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICByZXMuc2NvcGUuc2hvdWxkLmhhdmUubGVuZ3RoKDQpO1xuICAgICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdMaXN0JywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgbGlzdCBubyBuZXcgYWNjZXNzIHRva2VuJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGJpdGdvLmxpc3RBY2Nlc3NUb2tlbnMoKS50aGVuKGZ1bmN0aW9uICh0b2tlbnMpIHtcbiAgICAgICAgdG9rZW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWRkIGFuZCBsaXN0IHNpbmdsZSBhY2Nlc3MgdG9rZW4nLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgLmFkZEFjY2Vzc1Rva2VuKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLCBsYWJlbDogJ3Rlc3QgdG9rZW4nLCBzY29wZTogc29tZVNjb3BlcyB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgcmVzLmxhYmVsLnNob3VsZC5lcXVhbCgndGVzdCB0b2tlbicpO1xuXG4gICAgICAgICAgcmV0dXJuIGJpdGdvLmxpc3RBY2Nlc3NUb2tlbnMoKTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2Vucykge1xuICAgICAgICAgIHRva2Vucy5sZW5ndGguc2hvdWxkLmVxdWFsKElOSVRJQUxfVE9LRU5fQ09VTlQgKyAxKTtcbiAgICAgICAgICBjb25zdCB0b2tlbiA9IF8uZmluZCh0b2tlbnMsIGZ1bmN0aW9uICh0b2spIHtcbiAgICAgICAgICAgIHJldHVybiB0b2subGFiZWwgPT09ICd0ZXN0IHRva2VuJztcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBzaG91bGQuZXhpc3QodG9rZW4pO1xuICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWRkIGFub3RoZXIgYW5kIGxpc3QgbXVsdGlwbGUgYWNjZXNzIHRva2VucycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCB0b2tlbjE7XG4gICAgICBsZXQgdG9rZW4yO1xuICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuIDInLCBzY29wZTogc29tZVNjb3BlcyB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgcmVzLmxhYmVsLnNob3VsZC5lcXVhbCgndGVzdCB0b2tlbiAyJyk7XG5cbiAgICAgICAgICByZXR1cm4gYml0Z28ubGlzdEFjY2Vzc1Rva2VucygpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgICAgdG9rZW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCArIDIpO1xuXG4gICAgICAgICAgdG9rZW4xID0gXy5maW5kKHRva2VucywgZnVuY3Rpb24gKHRvaykge1xuICAgICAgICAgICAgcmV0dXJuIHRvay5sYWJlbCA9PT0gJ3Rlc3QgdG9rZW4gMic7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdG9rZW4yID0gXy5maW5kKHRva2VucywgZnVuY3Rpb24gKHRvaykge1xuICAgICAgICAgICAgcmV0dXJuIHRvay5sYWJlbCA9PT0gJ3Rlc3QgdG9rZW4nO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgc2hvdWxkLmV4aXN0KHRva2VuMSk7XG4gICAgICAgICAgc2hvdWxkLmV4aXN0KHRva2VuMik7XG5cbiAgICAgICAgICAvLyBjbGVhbnVwIGFjY2VzcyB0b2tlbnMgZm9yIGZ1dHVyZSB0ZXN0c1xuICAgICAgICAgIHJldHVybiBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGlkOiB0b2tlbjEuaWQgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gYml0Z28ucmVtb3ZlQWNjZXNzVG9rZW4oeyBpZDogdG9rZW4yLmlkIH0pO1xuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1VwZGF0ZScsIGZ1bmN0aW9uICgpIHtcbiAgICBzaG91bGQuZXhpc3QodHJ1ZSk7IC8vIG5vLW9wXG4gICAgLy8gYWNjZXNzIHRva2VucyBoYXZlIG5vIHVwZGF0ZSBBUEksIHRoZXkgY2FuIG9ubHkgYmUgY3JlYXRlZCBvciByZW1vdmVkXG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdSZW1vdmUnLCBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IGFtYmlndW91c1Rva2VuSWQ7XG4gICAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBiaXRnby5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnYXJndW1lbnRzJywgZnVuY3Rpb24gKCkge1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHt9LCAnaW52YWxpZCcpO1xuICAgICAgfSk7XG4gICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYml0Z28ucmVtb3ZlQWNjZXNzVG9rZW4oe30sIGZ1bmN0aW9uICgpIHt9KTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgaWQ6ICdub24tZXhpc3RlbnQgaWQnIH0sICdpbnZhbGlkJyk7XG4gICAgICB9KTtcbiAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGxhYmVsOiAnbm9uLWV4aXN0ZW50IGxhYmVsJyB9LCAnaW52YWxpZCcpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2l0aCBhbWJpZ291cyByZW1vdmUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBiZWdpbiBieSBhZGRpbmcgc2Vjb25kIHRva2VuXG4gICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgLmFkZEFjY2Vzc1Rva2VuKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLCBsYWJlbDogJ3Rlc3QgdG9rZW4nLCBzY29wZTogc29tZVNjb3BlcyB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICBhbWJpZ3VvdXNUb2tlbklkID0gdG9rZW4uaWQ7XG4gICAgICAgICAgY29uc3QgcHJvbWlzZSA9IGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgbGFiZWw6ICd0ZXN0IHRva2VuJyB9KTtcbiAgICAgICAgICByZXR1cm4gVGVzdFV0aWwudGhyb3dzKHByb21pc2UsICdhbWJpZ3VvdXMgY2FsbDogbXVsdGlwbGUgdG9rZW5zIG1hdGNoaW5nIHRoaXMgbGFiZWwnKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlbW92ZSBieSBsYWJlbCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAubGlzdEFjY2Vzc1Rva2VucygpXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbnMpIHtcbiAgICAgICAgICB0b2tlbnMubGVuZ3RoLnNob3VsZC5lcXVhbChJTklUSUFMX1RPS0VOX0NPVU5UICsgMik7XG5cbiAgICAgICAgICAvLyBub3cgcmVtb3ZlXG4gICAgICAgICAgcmV0dXJuIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgaWQ6IGFtYmlndW91c1Rva2VuSWQgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gYml0Z28ubGlzdEFjY2Vzc1Rva2VucygpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgICAgdG9rZW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCArIDEpO1xuXG4gICAgICAgICAgcmV0dXJuIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgbGFiZWw6ICd0ZXN0IHRva2VuJyB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBiaXRnby5saXN0QWNjZXNzVG9rZW5zKCk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbnMpIHtcbiAgICAgICAgICB0b2tlbnMubGVuZ3RoLnNob3VsZC5lcXVhbChJTklUSUFMX1RPS0VOX0NPVU5UKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlbW92ZSBhY2Nlc3MgdG9rZW4gYnkgaWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgLmFkZEFjY2Vzc1Rva2VuKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLCBsYWJlbDogJ3Rlc3QgdG9rZW4nLCBzY29wZTogc29tZVNjb3BlcyB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rKSB7XG4gICAgICAgICAgcmV0dXJuIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgaWQ6IHRvay5pZCB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHJldHVybiBiaXRnby5saXN0QWNjZXNzVG9rZW5zKCk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbnMpIHtcbiAgICAgICAgICB0b2tlbnMubGVuZ3RoLnNob3VsZC5lcXVhbChJTklUSUFMX1RPS0VOX0NPVU5UKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=Выполнить команду
Для локальной разработки. Не используйте в интернете!