PHP WebShell

Текущая директория: /opt/BitGoJS/modules/express/dist/test/unit/clientRoutes

Просмотр файла: signPayload.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const sinon = require("sinon");
require("should-http");
require("should-sinon");
require("should");
const fs = require("fs");
const bitgo_1 = require("bitgo");
require("../../lib/asserts");
const clientRoutes_1 = require("../../../src/clientRoutes");
describe('Sign an arbitrary payload with trading account key', function () {
    const coin = 'ofc';
    const payload = {
        this: {
            is: {
                a: 'payload',
            },
        },
    };
    const signature = 'signedPayload123';
    const walletId = 'myWalletId';
    const walletStub = sinon.createStubInstance(bitgo_1.Wallet, {
        id: walletId,
        coin: sinon.stub().returns(coin),
        toTradingAccount: sinon.stub().returns({
            signPayload: sinon.stub().returns(signature),
        }),
    });
    const walletsStub = sinon.createStubInstance(bitgo_1.Wallets, {
        get: sinon.stub().resolves(walletStub),
    });
    const coinStub = sinon.createStubInstance(bitgo_1.BaseCoin, { wallets: sinon.stub().returns(walletsStub) });
    const bitGoStub = sinon.createStubInstance(bitgo_1.BitGo, { coin: sinon.stub().returns(coinStub) });
    before(() => {
        process.env['WALLET_myWalletId_PASSPHRASE'] = 'mypass';
    });
    it('should return a signed payload', async function () {
        // TODO(GO-1015): unskip test
        return;
        // eslint-disable-next-line no-unreachable
        const expectedResponse = {
            payload: JSON.stringify(payload),
            signature,
        };
        const req = {
            bitgo: bitGoStub,
            body: {
                payload,
                walletId,
            },
            query: {},
        };
        await (0, clientRoutes_1.handleV2OFCSignPayload)(req).should.be.resolvedWith(expectedResponse);
    });
});
describe('With the handler to sign an arbitrary payload in external signing mode', () => {
    let bitgo;
    const walletId = '61f039aad587c2000745c687373e0fa9';
    const walletPassword = 'wDX058%c4plL1@pP';
    const secret = 'xprv9s21ZrQH143K3EuPWCBuqnWxydaQV6et9htQige4EswvcHKEzNmkVmwTwKoadyHzJYppuADB7Us7AbaNLToNvoFoSxuWqndQRYtnNy5DUY2';
    const validPrv = '{"61f039aad587c2000745c687373e0fa9":"{\\"iv\\":\\"+1u1Y9cvsYuRMeyH2slnXQ==\\",\\"v\\":1,\\"iter\\":10000,\\"ks\\":256,\\"ts\\":64,\\"mode\\":\\"ccm\\",\\"adata\\":\\"\\",\\"cipher\\":\\"aes\\",\\"salt\\":\\"54kOXTqJ9mc=\\",\\"ct\\":\\"JF5wQ82wa1dYyFxFlbHCvK4a+A6MTHdhOqc5uXsz2icWhkY2Lin/3Ab8ZwvwDaR1JYKmC/g1gXIGwVZEOl1M/bRHY420h7sDtmTS6Ebse5NWbF0ItfUJlk6HVATGa+C6mkbaVxJ4kQW/ehnT3riqzU069ATPz8E=\\"}"}';
    const payload = {
        this: {
            is: {
                a: 'payload',
            },
        },
    };
    before(() => {
        bitgo = new bitgo_1.BitGo({ env: 'test' });
    });
    it('should return a payload signed with trading account key read from the local file system', async () => {
        const stubbedSignature = Buffer.from('mysign');
        const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv);
        const envStub = sinon
            .stub(process, 'env')
            .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword });
        const signMessageStub = sinon.stub(bitgo_1.Coin.Ofc.prototype, 'signMessage').resolves(stubbedSignature);
        const stubbedSigHex = stubbedSignature.toString('hex');
        const expectedResponse = {
            payload: JSON.stringify(payload),
            signature: stubbedSigHex,
        };
        const req = {
            bitgo,
            body: {
                walletId,
                payload,
            },
            config: {
                signerFileSystemPath: 'signerFileSystemPath',
            },
        };
        await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.resolvedWith(expectedResponse);
        readFileStub.should.be.calledOnceWith('signerFileSystemPath');
        signMessageStub.should.be.calledOnceWith(sinon.match({
            prv: secret,
        }));
        readFileStub.restore();
        envStub.restore();
        signMessageStub.restore();
    });
    it('should use wallet passphrase from request body', async () => {
        const stubbedSignature = Buffer.from('mysign');
        const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv);
        const signMessageStub = sinon.stub(bitgo_1.Coin.Ofc.prototype, 'signMessage').resolves(stubbedSignature);
        const stubbedSigHex = stubbedSignature.toString('hex');
        const expectedResponse = {
            payload: JSON.stringify(payload),
            signature: stubbedSigHex,
        };
        const req = {
            bitgo,
            body: {
                walletId,
                payload,
                walletPassphrase: walletPassword,
            },
            config: {
                signerFileSystemPath: 'signerFileSystemPath',
            },
        };
        await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.resolvedWith(expectedResponse);
        readFileStub.should.be.calledOnceWith('signerFileSystemPath');
        signMessageStub.should.be.calledOnceWith(sinon.match({
            prv: secret,
        }));
        readFileStub.restore();
        signMessageStub.restore();
    });
    it('should prioritize request body passphrase over environment variable', async () => {
        const stubbedSignature = Buffer.from('mysign');
        const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv);
        const envStub = sinon
            .stub(process, 'env')
            .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword });
        const signMessageStub = sinon.stub(bitgo_1.Coin.Ofc.prototype, 'signMessage').resolves(stubbedSignature);
        const stubbedSigHex = stubbedSignature.toString('hex');
        const expectedResponse = {
            payload: JSON.stringify(payload),
            signature: stubbedSigHex,
        };
        const req = {
            bitgo,
            body: {
                walletId,
                payload,
                walletPassphrase: walletPassword,
            },
            config: {
                signerFileSystemPath: 'signerFileSystemPath',
            },
        };
        await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.resolvedWith(expectedResponse);
        readFileStub.should.be.calledOnceWith('signerFileSystemPath');
        signMessageStub.should.be.calledOnceWith(sinon.match({
            prv: secret,
        }));
        readFileStub.restore();
        envStub.restore();
        signMessageStub.restore();
    });
    describe('With invalid setup', () => {
        const invalidPrv = '{"61f039aad587c2000745c687373e0fa9":"invalid"}';
        it('should throw an error with missing wallet passphrase in env', async () => {
            const req = {
                bitgo,
                body: {
                    walletId,
                    payload,
                },
            };
            await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.rejectedWith('Could not find wallet passphrase WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE in environment');
        });
        it('should throw an error with undefined signerFileSystemPath in env', async () => {
            const envStub = sinon
                .stub(process, 'env')
                .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword });
            const req = {
                bitgo,
                body: {
                    walletId,
                    payload,
                },
                config: {
                    signerFileSystemPath: undefined,
                },
            };
            await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.rejectedWith('Missing required configuration: signerFileSystemPath');
            envStub.restore();
        });
        it('should throw error when trying to decrypt with invalid private key', async () => {
            const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(invalidPrv);
            const envStub = sinon
                .stub(process, 'env')
                .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword });
            const req = {
                bitgo,
                body: {
                    walletId,
                    payload,
                },
                config: {
                    signerFileSystemPath: 'signerFileSystemPath',
                },
            };
            await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.rejectedWith("Error when trying to decrypt private key: INVALID: json decode: this isn't json!");
            readFileStub.restore();
            envStub.restore();
        });
        it('should throw error when trying to decrypt with invalid wallet passphrase key', async () => {
            const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv);
            const envStub = sinon
                .stub(process, 'env')
                .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: 'invalidPassphrase' });
            const req = {
                bitgo,
                body: {
                    walletId,
                    payload,
                },
                config: {
                    signerFileSystemPath: 'signerFileSystemPath',
                },
            };
            await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.rejectedWith("Error when trying to decrypt private key: CORRUPT: password error - ccm: tag doesn't match");
            readFileStub.restore();
            envStub.restore();
        });
        it('should throw error when trying to decrypt with invalid wallet passphrase in body', async () => {
            const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv);
            const req = {
                bitgo,
                body: {
                    walletId,
                    payload,
                    walletPassphrase: 'invalidPassphrase',
                },
                config: {
                    signerFileSystemPath: 'signerFileSystemPath',
                },
            };
            await (0, clientRoutes_1.handleV2OFCSignPayloadInExtSigningMode)(req).should.be.rejectedWith("Error when trying to decrypt private key: CORRUPT: password error - ccm: tag doesn't match");
            readFileStub.restore();
        });
    });
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnblBheWxvYWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90ZXN0L3VuaXQvY2xpZW50Um91dGVzL3NpZ25QYXlsb2FkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsK0JBQStCO0FBQy9CLHVCQUFxQjtBQUNyQix3QkFBc0I7QUFDdEIsa0JBQWdCO0FBQ2hCLHlCQUF5QjtBQUV6QixpQ0FBK0Q7QUFFL0QsNkJBQTJCO0FBQzNCLDREQUEyRztBQUUzRyxRQUFRLENBQUMsb0RBQW9ELEVBQUU7SUFDN0QsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDO0lBQ25CLE1BQU0sT0FBTyxHQUFHO1FBQ2QsSUFBSSxFQUFFO1lBQ0osRUFBRSxFQUFFO2dCQUNGLENBQUMsRUFBRSxTQUFTO2FBQ2I7U0FDRjtLQUNGLENBQUM7SUFDRixNQUFNLFNBQVMsR0FBRyxrQkFBa0IsQ0FBQztJQUNyQyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUM7SUFFOUIsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDLGNBQWEsRUFBRTtRQUN6RCxFQUFFLEVBQUUsUUFBUTtRQUNaLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztRQUNoQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsT0FBTyxDQUFDO1lBQ3JDLFdBQVcsRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztTQUM3QyxDQUFDO0tBQ0gsQ0FBQyxDQUFDO0lBRUgsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDLGVBQWMsRUFBRTtRQUMzRCxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7S0FDdkMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixD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QUFRLENBQUMsQ0FBQztZQUU1RSxNQUFNLEdBQUcsR0FBRztnQkFDVixLQUFLO2dCQUNMLElBQUksRUFBRTtvQkFDSixRQUFRO29CQUNSLE9BQU87b0JBQ1AsZ0JBQWdCLEVBQUUsbUJBQW1CO2lCQUN0QztnQkFDRCxNQUFNLEVBQUU7b0JBQ04sb0JBQW9CLEVBQUUsc0JBQXNCO2lCQUM3QzthQUNvQixDQUFDO1lBRXhCLE1BQU0sSUFBQSxxREFBc0MsRUFBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FDdEUsNEZBQTRGLENBQzdGLENBQUM7WUFFRixZQUFZLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDekIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgc2lub24gZnJvbSAnc2lub24nO1xuaW1wb3J0ICdzaG91bGQtaHR0cCc7XG5pbXBvcnQgJ3Nob3VsZC1zaW5vbic7XG5pbXBvcnQgJ3Nob3VsZCc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgeyBSZXF1ZXN0IH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyBCaXRHbywgQ29pbiwgQmFzZUNvaW4sIFdhbGxldCwgV2FsbGV0cyB9IGZyb20gJ2JpdGdvJztcblxuaW1wb3J0ICcuLi8uLi9saWIvYXNzZXJ0cyc7XG5pbXBvcnQgeyBoYW5kbGVWMk9GQ1NpZ25QYXlsb2FkLCBoYW5kbGVWMk9GQ1NpZ25QYXlsb2FkSW5FeHRTaWduaW5nTW9kZSB9IGZyb20gJy4uLy4uLy4uL3NyYy9jbGllbnRSb3V0ZXMnO1xuXG5kZXNjcmliZSgnU2lnbiBhbiBhcmJpdHJhcnkgcGF5bG9hZCB3aXRoIHRyYWRpbmcgYWNjb3VudCBrZXknLCBmdW5jdGlvbiAoKSB7XG4gIGNvbnN0IGNvaW4gPSAnb2ZjJztcbiAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICB0aGlzOiB7XG4gICAgICBpczoge1xuICAgICAgICBhOiAncGF5bG9hZCcsXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG4gIGNvbnN0IHNpZ25hdHVyZSA9ICdzaWduZWRQYXlsb2FkMTIzJztcbiAgY29uc3Qgd2FsbGV0SWQgPSAnbXlXYWxsZXRJZCc7XG5cbiAgY29uc3Qgd2FsbGV0U3R1YiA9IHNpbm9uLmNyZWF0ZVN0dWJJbnN0YW5jZShXYWxsZXQgYXMgYW55LCB7XG4gICAgaWQ6IHdhbGxldElkLFxuICAgIGNvaW46IHNpbm9uLnN0dWIoKS5yZXR1cm5zKGNvaW4pLFxuICAgIHRvVHJhZGluZ0FjY291bnQ6IHNpbm9uLnN0dWIoKS5yZXR1cm5zKHtcbiAgICAgIHNpZ25QYXlsb2FkOiBzaW5vbi5zdHViKCkucmV0dXJucyhzaWduYXR1cmUpLFxuICAgIH0pLFxuICB9KTtcblxuICBjb25zdCB3YWxsZXRzU3R1YiA9IHNpbm9uLmNyZWF0ZVN0dWJJbnN0YW5jZShXYWxsZXRzIGFzIGFueSwge1xuICAgIGdldDogc2lub24uc3R1YigpLnJlc29sdmVzKHdhbGxldFN0dWIpLFxuICB9KTtcblxuICBjb25zdCBjb2luU3R1YiA9IHNpbm9uLmNyZWF0ZVN0dWJJbnN0YW5jZShCYXNlQ29pbiBhcyBhbnksIHsgd2FsbGV0czogc2lub24uc3R1YigpLnJldHVybnMod2FsbGV0c1N0dWIpIH0pO1xuXG4gIGNvbnN0IGJpdEdvU3R1YiA9IHNpbm9uLmNyZWF0ZVN0dWJJbnN0YW5jZShCaXRHbyBhcyBhbnksIHsgY29pbjogc2lub24uc3R1YigpLnJldHVybnMoY29pblN0dWIpIH0pO1xuXG4gIGJlZm9yZSgoKSA9PiB7XG4gICAgcHJvY2Vzcy5lbnZbJ1dBTExFVF9teVdhbGxldElkX1BBU1NQSFJBU0UnXSA9ICdteXBhc3MnO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiBhIHNpZ25lZCBwYXlsb2FkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIC8vIFRPRE8oR08tMTAxNSk6IHVuc2tpcCB0ZXN0XG4gICAgcmV0dXJuO1xuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVucmVhY2hhYmxlXG4gICAgY29uc3QgZXhwZWN0ZWRSZXNwb25zZSA9IHtcbiAgICAgIHBheWxvYWQ6IEpTT04uc3RyaW5naWZ5KHBheWxvYWQpLFxuICAgICAgc2lnbmF0dXJlLFxuICAgIH07XG4gICAgY29uc3QgcmVxID0ge1xuICAgICAgYml0Z286IGJpdEdvU3R1YixcbiAgICAgIGJvZHk6IHtcbiAgICAgICAgcGF5bG9hZCxcbiAgICAgICAgd2FsbGV0SWQsXG4gICAgICB9LFxuICAgICAgcXVlcnk6IHt9LFxuICAgIH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0O1xuICAgIGF3YWl0IGhhbmRsZVYyT0ZDU2lnblBheWxvYWQocmVxKS5zaG91bGQuYmUucmVzb2x2ZWRXaXRoKGV4cGVjdGVkUmVzcG9uc2UpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZSgnV2l0aCB0aGUgaGFuZGxlciB0byBzaWduIGFuIGFyYml0cmFyeSBwYXlsb2FkIGluIGV4dGVybmFsIHNpZ25pbmcgbW9kZScsICgpID0+IHtcbiAgbGV0IGJpdGdvOiBCaXRHbztcblxuICBjb25zdCB3YWxsZXRJZCA9ICc2MWYwMzlhYWQ1ODdjMjAwMDc0NWM2ODczNzNlMGZhOSc7XG4gIGNvbnN0IHdhbGxldFBhc3N3b3JkID0gJ3dEWDA1OCVjNHBsTDFAcFAnO1xuICBjb25zdCBzZWNyZXQgPVxuICAgICd4cHJ2OXMyMVpyUUgxNDNLM0V1UFdDQnVxbld4eWRhUVY2ZXQ5aHRRaWdlNEVzd3ZjSEtFek5ta1Ztd1R3S29hZHlIekpZcHB1QURCN1VzN0FiYU5MVG9Odm9Gb1N4dVdxbmRRUll0bk55NURVWTInO1xuICBjb25zdCB2YWxpZFBydiA9XG4gICAgJ3tcIjYxZjAzOWFhZDU4N2MyMDAwNzQ1YzY4NzM3M2UwZmE5XCI6XCJ7XFxcXFwiaXZcXFxcXCI6XFxcXFwiKzF1MVk5Y3ZzWXVSTWV5SDJzbG5YUT09XFxcXFwiLFxcXFxcInZcXFxcXCI6MSxcXFxcXCJpdGVyXFxcXFwiOjEwMDAwLFxcXFxcImtzXFxcXFwiOjI1NixcXFxcXCJ0c1xcXFxcIjo2NCxcXFxcXCJtb2RlXFxcXFwiOlxcXFxcImNjbVxcXFxcIixcXFxcXCJhZGF0YVxcXFxcIjpcXFxcXCJcXFxcXCIsXFxcXFwiY2lwaGVyXFxcXFwiOlxcXFxcImFlc1xcXFxcIixcXFxcXCJzYWx0XFxcXFwiOlxcXFxcIjU0a09YVHFKOW1jPVxcXFxcIixcXFxcXCJjdFxcXFxcIjpcXFxcXCJKRjV3UTgyd2ExZFl5RnhGbGJIQ3ZLNGErQTZNVEhkaE9xYzV1WHN6MmljV2hrWTJMaW4vM0FiOFp3dndEYVIxSllLbUMvZzFnWElHd1ZaRU9sMU0vYlJIWTQyMGg3c0R0bVRTNkVic2U1TldiRjBJdGZVSmxrNkhWQVRHYStDNm1rYmFWeEo0a1FXL2VoblQzcmlxelUwNjlBVFB6OEU9XFxcXFwifVwifSc7XG5cbiAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICB0aGlzOiB7XG4gICAgICBpczoge1xuICAgICAgICBhOiAncGF5bG9hZCcsXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG5cbiAgYmVmb3JlKCgpID0+IHtcbiAgICBiaXRnbyA9IG5ldyBCaXRHbyh7IGVudjogJ3Rlc3QnIH0pO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiBhIHBheWxvYWQgc2lnbmVkIHdpdGggdHJhZGluZyBhY2NvdW50IGtleSByZWFkIGZyb20gdGhlIGxvY2FsIGZpbGUgc3lzdGVtJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHN0dWJiZWRTaWduYXR1cmUgPSBCdWZmZXIuZnJvbSgnbXlzaWduJyk7XG4gICAgY29uc3QgcmVhZEZpbGVTdHViID0gc2lub24uc3R1Yihmcy5wcm9taXNlcywgJ3JlYWRGaWxlJykucmVzb2x2ZXModmFsaWRQcnYpO1xuICAgIGNvbnN0IGVudlN0dWIgPSBzaW5vblxuICAgICAgLnN0dWIocHJvY2VzcywgJ2VudicpXG4gICAgICAudmFsdWUoeyBXQUxMRVRfNjFmMDM5YWFkNTg3YzIwMDA3NDVjNjg3MzczZTBmYTlfUEFTU1BIUkFTRTogd2FsbGV0UGFzc3dvcmQgfSk7XG5cbiAgICBjb25zdCBzaWduTWVzc2FnZVN0dWIgPSBzaW5vbi5zdHViKENvaW4uT2ZjLnByb3RvdHlwZSwgJ3NpZ25NZXNzYWdlJykucmVzb2x2ZXMoc3R1YmJlZFNpZ25hdHVyZSk7XG5cbiAgICBjb25zdCBzdHViYmVkU2lnSGV4ID0gc3R1YmJlZFNpZ25hdHVyZS50b1N0cmluZygnaGV4Jyk7XG5cbiAgICBjb25zdCBleHBlY3RlZFJlc3BvbnNlID0ge1xuICAgICAgcGF5bG9hZDogSlNPTi5zdHJpbmdpZnkocGF5bG9hZCksXG4gICAgICBzaWduYXR1cmU6IHN0dWJiZWRTaWdIZXgsXG4gICAgfTtcblxuICAgIGNvbnN0IHJlcSA9IHtcbiAgICAgIGJpdGdvLFxuICAgICAgYm9keToge1xuICAgICAgICB3YWxsZXRJZCxcbiAgICAgICAgcGF5bG9hZCxcbiAgICAgIH0sXG4gICAgICBjb25maWc6IHtcbiAgICAgICAgc2lnbmVyRmlsZVN5c3RlbVBhdGg6ICdzaWduZXJGaWxlU3lzdGVtUGF0aCcsXG4gICAgICB9LFxuICAgIH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0O1xuXG4gICAgYXdhaXQgaGFuZGxlVjJPRkNTaWduUGF5bG9hZEluRXh0U2lnbmluZ01vZGUocmVxKS5zaG91bGQuYmUucmVzb2x2ZWRXaXRoKGV4cGVjdGVkUmVzcG9uc2UpO1xuICAgIHJlYWRGaWxlU3R1Yi5zaG91bGQuYmUuY2FsbGVkT25jZVdpdGgoJ3NpZ25lckZpbGVTeXN0ZW1QYXRoJyk7XG4gICAgc2lnbk1lc3NhZ2VTdHViLnNob3VsZC5iZS5jYWxsZWRPbmNlV2l0aChcbiAgICAgIHNpbm9uLm1hdGNoKHtcbiAgICAgICAgcHJ2OiBzZWNyZXQsXG4gICAgICB9KVxuICAgICk7XG4gICAgcmVhZEZpbGVTdHViLnJlc3RvcmUoKTtcbiAgICBlbnZTdHViLnJlc3RvcmUoKTtcbiAgICBzaWduTWVzc2FnZVN0dWIucmVzdG9yZSgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHVzZSB3YWxsZXQgcGFzc3BocmFzZSBmcm9tIHJlcXVlc3QgYm9keScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBzdHViYmVkU2lnbmF0dXJlID0gQnVmZmVyLmZyb20oJ215c2lnbicpO1xuICAgIGNvbnN0IHJlYWRGaWxlU3R1YiA9IHNpbm9uLnN0dWIoZnMucHJvbWlzZXMsICdyZWFkRmlsZScpLnJlc29sdmVzKHZhbGlkUHJ2KTtcblxuICAgIGNvbnN0IHNpZ25NZXNzYWdlU3R1YiA9IHNpbm9uLnN0dWIoQ29pbi5PZmMucHJvdG90eXBlLCAnc2lnbk1lc3NhZ2UnKS5yZXNvbHZlcyhzdHViYmVkU2lnbmF0dXJlKTtcblxuICAgIGNvbnN0IHN0dWJiZWRTaWdIZXggPSBzdHViYmVkU2lnbmF0dXJlLnRvU3RyaW5nKCdoZXgnKTtcblxuICAgIGNvbnN0IGV4cGVjdGVkUmVzcG9uc2UgPSB7XG4gICAgICBwYXlsb2FkOiBKU09OLnN0cmluZ2lmeShwYXlsb2FkKSxcbiAgICAgIHNpZ25hdHVyZTogc3R1YmJlZFNpZ0hleCxcbiAgICB9O1xuXG4gICAgY29uc3QgcmVxID0ge1xuICAgICAgYml0Z28sXG4gICAgICBib2R5OiB7XG4gICAgICAgIHdhbGxldElkLFxuICAgICAgICBwYXlsb2FkLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiB3YWxsZXRQYXNzd29yZCxcbiAgICAgIH0sXG4gICAgICBjb25maWc6IHtcbiAgICAgICAgc2lnbmVyRmlsZVN5c3RlbVBhdGg6ICdzaWduZXJGaWxlU3lzdGVtUGF0aCcsXG4gICAgICB9LFxuICAgIH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0O1xuXG4gICAgYXdhaXQgaGFuZGxlVjJPRkNTaWduUGF5bG9hZEluRXh0U2lnbmluZ01vZGUocmVxKS5zaG91bGQuYmUucmVzb2x2ZWRXaXRoKGV4cGVjdGVkUmVzcG9uc2UpO1xuICAgIHJlYWRGaWxlU3R1Yi5zaG91bGQuYmUuY2FsbGVkT25jZVdpdGgoJ3NpZ25lckZpbGVTeXN0ZW1QYXRoJyk7XG4gICAgc2lnbk1lc3NhZ2VTdHViLnNob3VsZC5iZS5jYWxsZWRPbmNlV2l0aChcbiAgICAgIHNpbm9uLm1hdGNoKHtcbiAgICAgICAgcHJ2OiBzZWNyZXQsXG4gICAgICB9KVxuICAgICk7XG4gICAgcmVhZEZpbGVTdHViLnJlc3RvcmUoKTtcbiAgICBzaWduTWVzc2FnZVN0dWIucmVzdG9yZSgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHByaW9yaXRpemUgcmVxdWVzdCBib2R5IHBhc3NwaHJhc2Ugb3ZlciBlbnZpcm9ubWVudCB2YXJpYWJsZScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBzdHViYmVkU2lnbmF0dXJlID0gQnVmZmVyLmZyb20oJ215c2lnbicpO1xuICAgIGNvbnN0IHJlYWRGaWxlU3R1YiA9IHNpbm9uLnN0dWIoZnMucHJvbWlzZXMsICdyZWFkRmlsZScpLnJlc29sdmVzKHZhbGlkUHJ2KTtcbiAgICBjb25zdCBlbnZTdHViID0gc2lub25cbiAgICAgIC5zdHViKHByb2Nlc3MsICdlbnYnKVxuICAgICAgLnZhbHVlKHsgV0FMTEVUXzYxZjAzOWFhZDU4N2MyMDAwNzQ1YzY4NzM3M2UwZmE5X1BBU1NQSFJBU0U6IHdhbGxldFBhc3N3b3JkIH0pO1xuXG4gICAgY29uc3Qgc2lnbk1lc3NhZ2VTdHViID0gc2lub24uc3R1YihDb2luLk9mYy5wcm90b3R5cGUsICdzaWduTWVzc2FnZScpLnJlc29sdmVzKHN0dWJiZWRTaWduYXR1cmUpO1xuXG4gICAgY29uc3Qgc3R1YmJlZFNpZ0hleCA9IHN0dWJiZWRTaWduYXR1cmUudG9TdHJpbmcoJ2hleCcpO1xuXG4gICAgY29uc3QgZXhwZWN0ZWRSZXNwb25zZSA9IHtcbiAgICAgIHBheWxvYWQ6IEpTT04uc3RyaW5naWZ5KHBheWxvYWQpLFxuICAgICAgc2lnbmF0dXJlOiBzdHViYmVkU2lnSGV4LFxuICAgIH07XG4gICAgY29uc3QgcmVxID0ge1xuICAgICAgYml0Z28sXG4gICAgICBib2R5OiB7XG4gICAgICAgIHdhbGxldElkLFxuICAgICAgICBwYXlsb2FkLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiB3YWxsZXRQYXNzd29yZCxcbiAgICAgIH0sXG4gICAgICBjb25maWc6IHtcbiAgICAgICAgc2lnbmVyRmlsZVN5c3RlbVBhdGg6ICdzaWduZXJGaWxlU3lzdGVtUGF0aCcsXG4gICAgICB9LFxuICAgIH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0O1xuXG4gICAgYXdhaXQgaGFuZGxlVjJPRkNTaWduUGF5bG9hZEluRXh0U2lnbmluZ01vZGUocmVxKS5zaG91bGQuYmUucmVzb2x2ZWRXaXRoKGV4cGVjdGVkUmVzcG9uc2UpO1xuICAgIHJlYWRGaWxlU3R1Yi5zaG91bGQuYmUuY2FsbGVkT25jZVdpdGgoJ3NpZ25lckZpbGVTeXN0ZW1QYXRoJyk7XG4gICAgc2lnbk1lc3NhZ2VTdHViLnNob3VsZC5iZS5jYWxsZWRPbmNlV2l0aChcbiAgICAgIHNpbm9uLm1hdGNoKHtcbiAgICAgICAgcHJ2OiBzZWNyZXQsXG4gICAgICB9KVxuICAgICk7XG4gICAgcmVhZEZpbGVTdHViLnJlc3RvcmUoKTtcbiAgICBlbnZTdHViLnJlc3RvcmUoKTtcbiAgICBzaWduTWVzc2FnZVN0dWIucmVzdG9yZSgpO1xuICB9KTtcblxuICBkZXNjcmliZSgnV2l0aCBpbnZhbGlkIHNldHVwJywgKCkgPT4ge1xuICAgIGNvbnN0IGludmFsaWRQcnYgPSAne1wiNjFmMDM5YWFkNTg3YzIwMDA3NDVjNjg3MzczZTBmYTlcIjpcImludmFsaWRcIn0nO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBhbiBlcnJvciB3aXRoIG1pc3Npbmcgd2FsbGV0IHBhc3NwaHJhc2UgaW4gZW52JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVxID0ge1xuICAgICAgICBiaXRnbyxcbiAgICAgICAgYm9keToge1xuICAgICAgICAgIHdhbGxldElkLFxuICAgICAgICAgIHBheWxvYWQsXG4gICAgICAgIH0sXG4gICAgICB9IGFzIHVua25vd24gYXMgUmVxdWVzdDtcblxuICAgICAgYXdhaXQgaGFuZGxlVjJPRkNTaWduUGF5bG9hZEluRXh0U2lnbmluZ01vZGUocmVxKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKFxuICAgICAgICAnQ291bGQgbm90IGZpbmQgd2FsbGV0IHBhc3NwaHJhc2UgV0FMTEVUXzYxZjAzOWFhZDU4N2MyMDAwNzQ1YzY4NzM3M2UwZmE5X1BBU1NQSFJBU0UgaW4gZW52aXJvbm1lbnQnXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBhbiBlcnJvciB3aXRoIHVuZGVmaW5lZCBzaWduZXJGaWxlU3lzdGVtUGF0aCBpbiBlbnYnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBlbnZTdHViID0gc2lub25cbiAgICAgICAgLnN0dWIocHJvY2VzcywgJ2VudicpXG4gICAgICAgIC52YWx1ZSh7IFdBTExFVF82MWYwMzlhYWQ1ODdjMjAwMDc0NWM2ODczNzNlMGZhOV9QQVNTUEhSQVNFOiB3YWxsZXRQYXNzd29yZCB9KTtcblxuICAgICAgY29uc3QgcmVxID0ge1xuICAgICAgICBiaXRnbyxcbiAgICAgICAgYm9keToge1xuICAgICAgICAgIHdhbGxldElkLFxuICAgICAgICAgIHBheWxvYWQsXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgIHNpZ25lckZpbGVTeXN0ZW1QYXRoOiB1bmRlZmluZWQsXG4gICAgICAgIH0sXG4gICAgICB9IGFzIHVua25vd24gYXMgUmVxdWVzdDtcblxuICAgICAgYXdhaXQgaGFuZGxlVjJPRkNTaWduUGF5bG9hZEluRXh0U2lnbmluZ01vZGUocmVxKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKFxuICAgICAgICAnTWlzc2luZyByZXF1aXJlZCBjb25maWd1cmF0aW9uOiBzaWduZXJGaWxlU3lzdGVtUGF0aCdcbiAgICAgICk7XG4gICAgICBlbnZTdHViLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3Igd2hlbiB0cnlpbmcgdG8gZGVjcnlwdCB3aXRoIGludmFsaWQgcHJpdmF0ZSBrZXknLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZWFkRmlsZVN0dWIgPSBzaW5vbi5zdHViKGZzLnByb21pc2VzLCAncmVhZEZpbGUnKS5yZXNvbHZlcyhpbnZhbGlkUHJ2KTtcbiAgICAgIGNvbnN0IGVudlN0dWIgPSBzaW5vblxuICAgICAgICAuc3R1Yihwcm9jZXNzLCAnZW52JylcbiAgICAgICAgLnZhbHVlKHsgV0FMTEVUXzYxZjAzOWFhZDU4N2MyMDAwNzQ1YzY4NzM3M2UwZmE5X1BBU1NQSFJBU0U6IHdhbGxldFBhc3N3b3JkIH0pO1xuXG4gICAgICBjb25zdCByZXEgPSB7XG4gICAgICAgIGJpdGdvLFxuICAgICAgICBib2R5OiB7XG4gICAgICAgICAgd2FsbGV0SWQsXG4gICAgICAgICAgcGF5bG9hZCxcbiAgICAgICAgfSxcbiAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgc2lnbmVyRmlsZVN5c3RlbVBhdGg6ICdzaWduZXJGaWxlU3lzdGVtUGF0aCcsXG4gICAgICAgIH0sXG4gICAgICB9IGFzIHVua25vd24gYXMgUmVxdWVzdDtcblxuICAgICAgYXdhaXQgaGFuZGxlVjJPRkNTaWduUGF5bG9hZEluRXh0U2lnbmluZ01vZGUocmVxKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKFxuICAgICAgICBcIkVycm9yIHdoZW4gdHJ5aW5nIHRvIGRlY3J5cHQgcHJpdmF0ZSBrZXk6IElOVkFMSUQ6IGpzb24gZGVjb2RlOiB0aGlzIGlzbid0IGpzb24hXCJcbiAgICAgICk7XG5cbiAgICAgIHJlYWRGaWxlU3R1Yi5yZXN0b3JlKCk7XG4gICAgICBlbnZTdHViLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3Igd2hlbiB0cnlpbmcgdG8gZGVjcnlwdCB3aXRoIGludmFsaWQgd2FsbGV0IHBhc3NwaHJhc2Uga2V5JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVhZEZpbGVTdHViID0gc2lub24uc3R1Yihmcy5wcm9taXNlcywgJ3JlYWRGaWxlJykucmVzb2x2ZXModmFsaWRQcnYpO1xuICAgICAgY29uc3QgZW52U3R1YiA9IHNpbm9uXG4gICAgICAgIC5zdHViKHByb2Nlc3MsICdlbnYnKVxuICAgICAgICAudmFsdWUoeyBXQUxMRVRfNjFmMDM5YWFkNTg3YzIwMDA3NDVjNjg3MzczZTBmYTlfUEFTU1BIUkFTRTogJ2ludmFsaWRQYXNzcGhyYXNlJyB9KTtcblxuICAgICAgY29uc3QgcmVxID0ge1xuICAgICAgICBiaXRnbyxcbiAgICAgICAgYm9keToge1xuICAgICAgICAgIHdhbGxldElkLFxuICAgICAgICAgIHBheWxvYWQsXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgIHNpZ25lckZpbGVTeXN0ZW1QYXRoOiAnc2lnbmVyRmlsZVN5c3RlbVBhdGgnLFxuICAgICAgICB9LFxuICAgICAgfSBhcyB1bmtub3duIGFzIFJlcXVlc3Q7XG5cbiAgICAgIGF3YWl0IGhhbmRsZVYyT0ZDU2lnblBheWxvYWRJbkV4dFNpZ25pbmdNb2RlKHJlcSkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aChcbiAgICAgICAgXCJFcnJvciB3aGVuIHRyeWluZyB0byBkZWNyeXB0IHByaXZhdGUga2V5OiBDT1JSVVBUOiBwYXNzd29yZCBlcnJvciAtIGNjbTogdGFnIGRvZXNuJ3QgbWF0Y2hcIlxuICAgICAgKTtcblxuICAgICAgcmVhZEZpbGVTdHViLnJlc3RvcmUoKTtcbiAgICAgIGVudlN0dWIucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciB3aGVuIHRyeWluZyB0byBkZWNyeXB0IHdpdGggaW52YWxpZCB3YWxsZXQgcGFzc3BocmFzZSBpbiBib2R5JywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVhZEZpbGVTdHViID0gc2lub24uc3R1Yihmcy5wcm9taXNlcywgJ3JlYWRGaWxlJykucmVzb2x2ZXModmFsaWRQcnYpO1xuXG4gICAgICBjb25zdCByZXEgPSB7XG4gICAgICAgIGJpdGdvLFxuICAgICAgICBib2R5OiB7XG4gICAgICAgICAgd2FsbGV0SWQsXG4gICAgICAgICAgcGF5bG9hZCxcbiAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiAnaW52YWxpZFBhc3NwaHJhc2UnLFxuICAgICAgICB9LFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICBzaWduZXJGaWxlU3lzdGVtUGF0aDogJ3NpZ25lckZpbGVTeXN0ZW1QYXRoJyxcbiAgICAgICAgfSxcbiAgICAgIH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0O1xuXG4gICAgICBhd2FpdCBoYW5kbGVWMk9GQ1NpZ25QYXlsb2FkSW5FeHRTaWduaW5nTW9kZShyZXEpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgIFwiRXJyb3Igd2hlbiB0cnlpbmcgdG8gZGVjcnlwdCBwcml2YXRlIGtleTogQ09SUlVQVDogcGFzc3dvcmQgZXJyb3IgLSBjY206IHRhZyBkb2Vzbid0IG1hdGNoXCJcbiAgICAgICk7XG5cbiAgICAgIHJlYWRGaWxlU3R1Yi5yZXN0b3JlKCk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=

Выполнить команду


Для локальной разработки. Не используйте в интернете!