UNPKG

bitgo

Version:
297 lines • 43.2 kB
"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjZXNzdG9rZW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L2ludGVncmF0aW9uL2FjY2Vzc3Rva2VuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxFQUFFO0FBQ0YsOEJBQThCO0FBQzlCLEVBQUU7QUFDRixvREFBb0Q7QUFDcEQsRUFBRTs7QUFFRix5REFBeUQ7QUFFekQsbUNBQTBDO0FBQzFDLGlDQUFrQztBQUNsQyw0QkFBNEI7QUFFNUIsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7QUFDL0MsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBRXZDLFFBQVEsQ0FBQyxjQUFjLEVBQUU7SUFDdkIsSUFBSSxtQkFBbUIsQ0FBQyxDQUFDLDZFQUE2RTtJQUN0RyxJQUFJLG1CQUFtQixDQUFDLENBQUMsOERBQThEO0lBQ3ZGLElBQUksS0FBSyxDQUFDO0lBQ1YsTUFBTSxVQUFVLEdBQUcsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO0lBRTdFLE1BQU0sQ0FBQztRQUNMLEtBQUssR0FBRyxJQUFJLFNBQVMsRUFBRSxDQUFDO1FBQ3hCLEtBQUssQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzNCLE9BQU8sS0FBSzthQUNULG9CQUFvQixDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQzthQUN6QyxJQUFJLENBQUM7WUFDSixtQkFBbUIsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1lBRW5DLE1BQU0sVUFBVSxHQUFHLFVBQVUsR0FBRztnQkFDOUIsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDO1lBQ25CLENBQUMsQ0FBQztZQUNGLE9BQU8sUUFBUSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUM7YUFDRCxJQUFJLENBQUM7WUFDSixPQUFPLEtBQUss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bi8vXG4vLyBDb3B5cmlnaHQgMjAxNiwgQml0R28sIEluYy4gIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vL1xuXG4vKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb24gKi9cblxuaW1wb3J0IHsgc3RyaWN0IGFzIGFzc2VydCB9IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgc2hvdWxkID0gcmVxdWlyZSgnc2hvdWxkJyk7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5cbmNvbnN0IFRlc3RCaXRHbyA9IHJlcXVpcmUoJy4uL2xpYi90ZXN0X2JpdGdvJyk7XG5jb25zdCBUZXN0VXRpbCA9IHJlcXVpcmUoJy4vdGVzdHV0aWwnKTtcblxuZGVzY3JpYmUoJ0FjY2VzcyBUb2tlbicsIGZ1bmN0aW9uICgpIHtcbiAgbGV0IElOSVRJQUxfVE9LRU5fQ09VTlQ7IC8vIHVzZWQgYXMgYW4gb2Zmc2V0IHdoZW4gY2hlY2tpbmcgaWYgdG9rZW5zIHdlcmUgcHJvcGVybHkgY3JlYXRlZCBvciByZW1vdmVkXG4gIGxldCBsb2dpbkFjY2Vzc1Rva2VuSGV4OyAvLyBzYXZlIHRva2VuIGhleCBmb3Igd2hlbiB3ZSByZW1vdmUgYSB0b2tlbiB0aGF0IHdhcyBqdXN0IHNldFxuICBsZXQgYml0Z287XG4gIGNvbnN0IHNvbWVTY29wZXMgPSBbJ29wZW5pZCcsICdwcm9maWxlJywgJ3dhbGxldF9jcmVhdGUnLCAnd2FsbGV0X3ZpZXdfYWxsJ107XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IG5ldyBUZXN0Qml0R28oKTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICByZXR1cm4gYml0Z29cbiAgICAgIC5hdXRoZW50aWNhdGVUZXN0VXNlcihiaXRnby50ZXN0VXNlck9UUCgpKVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICBsb2dpbkFjY2Vzc1Rva2VuSGV4ID0gYml0Z28uX3Rva2VuO1xuXG4gICAgICAgIGNvbnN0IGZpbHRlckZ1bmMgPSBmdW5jdGlvbiAodG9rKSB7XG4gICAgICAgICAgcmV0dXJuIHRvay5sYWJlbDtcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIFRlc3RVdGlsLmRlbGV0ZVRlc3RUb2tlbnMoYml0Z28sIGZpbHRlckZ1bmMpO1xuICAgICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvLmxpc3RBY2Nlc3NUb2tlbnMoKTtcbiAgICAgIH0pXG4gICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgIElOSVRJQUxfVE9LRU5fQ09VTlQgPSB0b2tlbnMubGVuZ3RoO1xuICAgICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdhdXRoZW50aWNhdGlvbiB3aXRoIGFjY2VzcyB0b2tlbicsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgYWRkZWRUb2tlbkhleDtcbiAgICBpdCgnc2hvdWxkIGF1dGhlbnRpY2F0ZSB3aXRoIGFkZGVkIGFjY2VzcyB0b2tlbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAuYWRkQWNjZXNzVG9rZW4oeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksIGxhYmVsOiAndGVzdCB0b2tlbicsIHNjb3BlOiBzb21lU2NvcGVzIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICBhZGRlZFRva2VuSGV4ID0gcmVzLnRva2VuO1xuICAgICAgICAgIHJldHVybiBiaXRnby5hdXRoZW50aWNhdGVXaXRoQWNjZXNzVG9rZW4oeyBhY2Nlc3NUb2tlbjogYWRkZWRUb2tlbkhleCB9KTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGJpdGdvLl90b2tlbi5zaG91bGQuZXF1YWwoYWRkZWRUb2tlbkhleCk7XG5cbiAgICAgICAgICAvLyBzZXQgX3Rva2VuIGJhY2sgdG8gb3JpZ2luYWwgbG9naW4gdmFsdWVcbiAgICAgICAgICByZXR1cm4gYml0Z28uYXV0aGVudGljYXRlV2l0aEFjY2Vzc1Rva2VuKHsgYWNjZXNzVG9rZW46IGxvZ2luQWNjZXNzVG9rZW5IZXggfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBiaXRnby5fdG9rZW4uc2hvdWxkLmVxdWFsKGxvZ2luQWNjZXNzVG9rZW5IZXgpO1xuXG4gICAgICAgICAgcmV0dXJuIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgbGFiZWw6ICd0ZXN0IHRva2VuJyB9KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdBZGQnLCBmdW5jdGlvbiAoKSB7XG4gICAgZGVzY3JpYmUoJ2JhZCBhcmdzJywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ2FyZ3VtZW50cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYml0Z28uYWRkQWNjZXNzVG9rZW4oe30sICdpbnZhbGlkJyk7XG4gICAgICAgIH0pO1xuICAgICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBiaXRnby5hZGRBY2Nlc3NUb2tlbih7fSwgZnVuY3Rpb24gKCkge30pO1xuICAgICAgICB9KTtcblxuICAgICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBiaXRnby5hZGRBY2Nlc3NUb2tlbihcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLFxuICAgICAgICAgICAgICBzY29wZTogWyd3YWxsZXRfdmlld19hbGwnLCAnb3BlbmlkJywgJ3Byb2ZpbGUnXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAnaW52YWxpZCdcbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnZmFpbHMgdG8gYWRkIHdpdGhvdXQgc2NvcGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGJpdGdvLmFkZEFjY2Vzc1Rva2VuKFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge31cbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnZmFpbHMgdG8gYWRkIHdpdGggZW1wdHkgc2NvcGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGJpdGdvLmFkZEFjY2Vzc1Rva2VuKFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgICAgICAgIHNjb3BlOiBbXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7fVxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdmYWlscyB0byBhZGQgd2l0aCBpbmNvcnJlY3QgdHlwZSBvZiBzY29wZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYml0Z28uYWRkQWNjZXNzVG9rZW4oXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG90cDogYml0Z28udGVzdFVzZXJPVFAoKSxcbiAgICAgICAgICAgICAgc2NvcGU6ICdub3RBbkFycmF5JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7fVxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdmYWlscyB0byBhZGQgd2l0aCBpbnZhbGlkIHNjb3BlJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBwcm9taXNlID0gYml0Z28uYWRkQWNjZXNzVG9rZW4oeyBvdHA6ICdiYWRUb2tlbicsIGxhYmVsOiAndGVzdCB0b2tlbicsIHNjb3BlOiBbJ2ludmFsaWQnXSB9KTtcbiAgICAgICAgcmV0dXJuIFRlc3RVdGlsLnRocm93cyhwcm9taXNlLCAnaW52YWxpZCBzY29wZScpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdmYWlscyB0byBhZGQgd2l0aCBiYWQgb3RwJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBwcm9taXNlID0gYml0Z28uYWRkQWNjZXNzVG9rZW4oeyBvdHA6ICdiYWRUb2tlbicsIGxhYmVsOiAndGVzdCB0b2tlbicsIHNjb3BlOiBzb21lU2NvcGVzIH0pO1xuICAgICAgICByZXR1cm4gVGVzdFV0aWwudGhyb3dzKHByb21pc2UsICdpbnZhbGlkJyk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdzdWNjZXNzJywgZnVuY3Rpb24gKCkge1xuICAgICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgbGFiZWw6ICd0ZXN0IHRva2VuJyB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2ltcGxlIGFkZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgICAgLmFkZEFjY2Vzc1Rva2VuKHsgb3RwOiBiaXRnby50ZXN0VXNlck9UUCgpLCBsYWJlbDogJ3Rlc3QgdG9rZW4nLCBzY29wZTogc29tZVNjb3BlcyB9KVxuICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgIHJlcy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndXNlcicpO1xuICAgICAgICAgICAgcmVzLnNob3VsZC5oYXZlLnByb3BlcnR5KCdzY29wZScpO1xuICAgICAgICAgICAgcmVzLnNob3VsZC5oYXZlLnByb3BlcnR5KCdjcmVhdGVkJyk7XG4gICAgICAgICAgICByZXMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2V4cGlyZXMnKTtcbiAgICAgICAgICAgIHJlcy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnb3JpZ2luJyk7XG4gICAgICAgICAgICByZXMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2xhYmVsJyk7XG4gICAgICAgICAgICByZXMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2lzRXh0ZW5zaWJsZScpO1xuICAgICAgICAgICAgcmVzLnNob3VsZC5oYXZlLnByb3BlcnR5KCd0b2tlbicpO1xuXG4gICAgICAgICAgICByZXMuc2hvdWxkLm5vdC5oYXZlLnByb3BlcnR5KCd1bmxvY2snKTtcbiAgICAgICAgICAgIHJlcy5zaG91bGQubm90LmhhdmUucHJvcGVydHkoJ2VudGVycHJpc2UnKTtcblxuICAgICAgICAgICAgcmVzLmxhYmVsLnNob3VsZC5lcXVhbCgndGVzdCB0b2tlbicpO1xuICAgICAgICAgICAgcmVzLmlzRXh0ZW5zaWJsZS5zaG91bGQuZXF1YWwoZmFsc2UpO1xuXG4gICAgICAgICAgICByZXR1cm4gYml0Z28ubGlzdEFjY2Vzc1Rva2VucygpO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2Vucykge1xuICAgICAgICAgICAgY29uc3QgbnVtVG9rZW5zID0gdG9rZW5zLmxlbmd0aDtcbiAgICAgICAgICAgIG51bVRva2Vucy5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCArIDEpO1xuICAgICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdkdXJhdGlvbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgRFVSQVRJT04gPSAzNjAwICogMTA7IC8vIHRlbiBkYXlzXG4gICAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgZHVyYXRpb246IERVUkFUSU9OLCBzY29wZTogc29tZVNjb3BlcyB9KVxuICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgIHJlcy5sYWJlbC5zaG91bGQuZXF1YWwoJ3Rlc3QgdG9rZW4nKTtcblxuICAgICAgICAgICAgY29uc3QgY3JlYXRlZCA9IHJlcy5jcmVhdGVkO1xuICAgICAgICAgICAgY29uc3QgZXhwaXJlcyA9IHJlcy5leHBpcmVzO1xuICAgICAgICAgICAgY29uc3QgY3JlYXRlZFBsdXNEdXJhdGlvbiA9IG5ldyBEYXRlKG5ldyBEYXRlKGNyZWF0ZWQpLmdldFRpbWUoKSArIERVUkFUSU9OICogMTAwMCkuZ2V0VGltZSgpO1xuICAgICAgICAgICAgY29uc3QgZXhwaXJlc1RpbWUgPSBuZXcgRGF0ZShleHBpcmVzKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICBjb25zdCBsZWV3YXkgPSAxMDsgLy8gYmVjYXVzZSBvZiB0aGUgbWluaXNjdWxlIHRpbWUgaXQgdGFrZXMgdG8gZXhlY3V0ZSBhIGZ1bmN0aW9uLCB3ZSBnaXZlIGEgMTAgbXMgbGVld2F5IGluIHRoZSB0aW1lIGRpZmZlcmVuY2VzXG4gICAgICAgICAgICBjcmVhdGVkUGx1c0R1cmF0aW9uLnNob3VsZC5iZS5ncmVhdGVyVGhhbihleHBpcmVzVGltZSAtIGxlZXdheSk7XG4gICAgICAgICAgICBjcmVhdGVkUGx1c0R1cmF0aW9uLnNob3VsZC5iZS5sZXNzVGhhbihleHBpcmVzVGltZSArIGxlZXdheSk7XG4gICAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2lwUmVzdHJpY3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IElQUkVTVFJJQ1QgPSBbJzAuMC4wLjAnLCAnOC44LjguOCddO1xuICAgICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgICAuYWRkQWNjZXNzVG9rZW4oeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksIGxhYmVsOiAndGVzdCB0b2tlbicsIGlwUmVzdHJpY3Q6IElQUkVTVFJJQ1QsIHNjb3BlOiBzb21lU2NvcGVzIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAgICB0b2tlbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndG9rZW4nKTtcbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgndHhWYWx1ZUxpbWl0JywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBUWFZBTFVFTElNSVQgPSAxZTg7IC8vIDEgQlRDXG4gICAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7XG4gICAgICAgICAgICBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksXG4gICAgICAgICAgICBsYWJlbDogJ3Rlc3QgdG9rZW4nLFxuICAgICAgICAgICAgdHhWYWx1ZUxpbWl0OiBUWFZBTFVFTElNSVQsXG4gICAgICAgICAgICBzY29wZTogc29tZVNjb3BlcyxcbiAgICAgICAgICB9KVxuICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgIHJlcy51bmxvY2sudHhWYWx1ZUxpbWl0LnNob3VsZC5lcXVhbCgxZTgpO1xuICAgICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIHNlZSBzb21lIGV4YW1wbGVzIG9mIFNjb3BlIFZhbHVlcyB1bmRlciBodHRwczovL3d3dy5iaXRnby5jb20vYXBpLyNwYXJ0bmVyLW9hdXRoXG4gICAgICBpdCgnc2NvcGVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgICAuYWRkQWNjZXNzVG9rZW4oeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksIGxhYmVsOiAndGVzdCB0b2tlbicsIHNjb3BlOiBzb21lU2NvcGVzIH0pXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgcmVzLnNjb3BlLnNob3VsZC5oYXZlLmxlbmd0aCg0KTtcbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnTGlzdCcsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIGxpc3Qgbm8gbmV3IGFjY2VzcyB0b2tlbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBiaXRnby5saXN0QWNjZXNzVG9rZW5zKCkudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgIHRva2Vucy5sZW5ndGguc2hvdWxkLmVxdWFsKElOSVRJQUxfVE9LRU5fQ09VTlQpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFkZCBhbmQgbGlzdCBzaW5nbGUgYWNjZXNzIHRva2VuJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgIHJlcy5sYWJlbC5zaG91bGQuZXF1YWwoJ3Rlc3QgdG9rZW4nKTtcblxuICAgICAgICAgIHJldHVybiBiaXRnby5saXN0QWNjZXNzVG9rZW5zKCk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbnMpIHtcbiAgICAgICAgICB0b2tlbnMubGVuZ3RoLnNob3VsZC5lcXVhbChJTklUSUFMX1RPS0VOX0NPVU5UICsgMSk7XG4gICAgICAgICAgY29uc3QgdG9rZW4gPSBfLmZpbmQodG9rZW5zLCBmdW5jdGlvbiAodG9rKSB7XG4gICAgICAgICAgICByZXR1cm4gdG9rLmxhYmVsID09PSAndGVzdCB0b2tlbic7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgc2hvdWxkLmV4aXN0KHRva2VuKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFkZCBhbm90aGVyIGFuZCBsaXN0IG11bHRpcGxlIGFjY2VzcyB0b2tlbnMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgdG9rZW4xO1xuICAgICAgbGV0IHRva2VuMjtcbiAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAuYWRkQWNjZXNzVG9rZW4oeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksIGxhYmVsOiAndGVzdCB0b2tlbiAyJywgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgIHJlcy5sYWJlbC5zaG91bGQuZXF1YWwoJ3Rlc3QgdG9rZW4gMicpO1xuXG4gICAgICAgICAgcmV0dXJuIGJpdGdvLmxpc3RBY2Nlc3NUb2tlbnMoKTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2Vucykge1xuICAgICAgICAgIHRva2Vucy5sZW5ndGguc2hvdWxkLmVxdWFsKElOSVRJQUxfVE9LRU5fQ09VTlQgKyAyKTtcblxuICAgICAgICAgIHRva2VuMSA9IF8uZmluZCh0b2tlbnMsIGZ1bmN0aW9uICh0b2spIHtcbiAgICAgICAgICAgIHJldHVybiB0b2subGFiZWwgPT09ICd0ZXN0IHRva2VuIDInO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRva2VuMiA9IF8uZmluZCh0b2tlbnMsIGZ1bmN0aW9uICh0b2spIHtcbiAgICAgICAgICAgIHJldHVybiB0b2subGFiZWwgPT09ICd0ZXN0IHRva2VuJztcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIHNob3VsZC5leGlzdCh0b2tlbjEpO1xuICAgICAgICAgIHNob3VsZC5leGlzdCh0b2tlbjIpO1xuXG4gICAgICAgICAgLy8gY2xlYW51cCBhY2Nlc3MgdG9rZW5zIGZvciBmdXR1cmUgdGVzdHNcbiAgICAgICAgICByZXR1cm4gYml0Z28ucmVtb3ZlQWNjZXNzVG9rZW4oeyBpZDogdG9rZW4xLmlkIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHsgaWQ6IHRva2VuMi5pZCB9KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdVcGRhdGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgc2hvdWxkLmV4aXN0KHRydWUpOyAvLyBuby1vcFxuICAgIC8vIGFjY2VzcyB0b2tlbnMgaGF2ZSBubyB1cGRhdGUgQVBJLCB0aGV5IGNhbiBvbmx5IGJlIGNyZWF0ZWQgb3IgcmVtb3ZlZFxuICB9KTtcblxuICBkZXNjcmliZSgnUmVtb3ZlJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBhbWJpZ3VvdXNUb2tlbklkO1xuICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gYml0Z28uYWRkQWNjZXNzVG9rZW4oeyBvdHA6IGJpdGdvLnRlc3RVc2VyT1RQKCksIGxhYmVsOiAndGVzdCB0b2tlbicsIHNjb3BlOiBzb21lU2NvcGVzIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2FyZ3VtZW50cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7fSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgICAgYXNzZXJ0LnRocm93cyhmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJpdGdvLnJlbW92ZUFjY2Vzc1Rva2VuKHt9LCBmdW5jdGlvbiAoKSB7fSk7XG4gICAgICB9KTtcbiAgICAgIGFzc2VydC50aHJvd3MoZnVuY3Rpb24gKCkge1xuICAgICAgICBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGlkOiAnbm9uLWV4aXN0ZW50IGlkJyB9LCAnaW52YWxpZCcpO1xuICAgICAgfSk7XG4gICAgICBhc3NlcnQudGhyb3dzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYml0Z28ucmVtb3ZlQWNjZXNzVG9rZW4oeyBsYWJlbDogJ25vbi1leGlzdGVudCBsYWJlbCcgfSwgJ2ludmFsaWQnKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHdpdGggYW1iaWdvdXMgcmVtb3ZlJywgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gYmVnaW4gYnkgYWRkaW5nIHNlY29uZCB0b2tlblxuICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAgYW1iaWd1b3VzVG9rZW5JZCA9IHRva2VuLmlkO1xuICAgICAgICAgIGNvbnN0IHByb21pc2UgPSBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGxhYmVsOiAndGVzdCB0b2tlbicgfSk7XG4gICAgICAgICAgcmV0dXJuIFRlc3RVdGlsLnRocm93cyhwcm9taXNlLCAnYW1iaWd1b3VzIGNhbGw6IG11bHRpcGxlIHRva2VucyBtYXRjaGluZyB0aGlzIGxhYmVsJyk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZW1vdmUgYnkgbGFiZWwnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgLmxpc3RBY2Nlc3NUb2tlbnMoKVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgICAgdG9rZW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCArIDIpO1xuXG4gICAgICAgICAgLy8gbm93IHJlbW92ZVxuICAgICAgICAgIHJldHVybiBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGlkOiBhbWJpZ3VvdXNUb2tlbklkIH0pO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIGJpdGdvLmxpc3RBY2Nlc3NUb2tlbnMoKTtcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2Vucykge1xuICAgICAgICAgIHRva2Vucy5sZW5ndGguc2hvdWxkLmVxdWFsKElOSVRJQUxfVE9LRU5fQ09VTlQgKyAxKTtcblxuICAgICAgICAgIHJldHVybiBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGxhYmVsOiAndGVzdCB0b2tlbicgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gYml0Z28ubGlzdEFjY2Vzc1Rva2VucygpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgICAgdG9rZW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZW1vdmUgYWNjZXNzIHRva2VuIGJ5IGlkJywgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgIC5hZGRBY2Nlc3NUb2tlbih7IG90cDogYml0Z28udGVzdFVzZXJPVFAoKSwgbGFiZWw6ICd0ZXN0IHRva2VuJywgc2NvcGU6IHNvbWVTY29wZXMgfSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRvaykge1xuICAgICAgICAgIHJldHVybiBiaXRnby5yZW1vdmVBY2Nlc3NUb2tlbih7IGlkOiB0b2suaWQgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gYml0Z28ubGlzdEFjY2Vzc1Rva2VucygpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW5zKSB7XG4gICAgICAgICAgdG9rZW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoSU5JVElBTF9UT0tFTl9DT1VOVCk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19