PHP WebShell
Текущая директория: /opt/BitGoJS/modules/express/dist/src
Просмотр файла: expressApp.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = exports.prepareIpc = exports.app = exports.setupRoutes = exports.createBaseUri = exports.createServer = exports.startup = void 0;
/**
* @prettier
*/
const express = require("express");
const path = require("path");
const _ = require("lodash");
const debugLib = require("debug");
const https = require("https");
const http = require("http");
const morgan = require("morgan");
const fs = require("fs");
const timeout = require("connect-timeout");
const config_1 = require("./config");
const debug = debugLib('bitgo:express');
const constants_1 = require("constants");
const errors_1 = require("./errors");
const bitgo_1 = require("bitgo");
const clientRoutes = require("./clientRoutes");
/**
* Set up the logging middleware provided by morgan
*
* @param app
* @param config
*/
function setupLogging(app, config) {
// Set up morgan for logging, with optional logging into a file
let middleware;
if (config.logFile) {
// create a write stream (in append mode)
const accessLogPath = path.resolve(config.logFile);
const accessLogStream = fs.createWriteStream(accessLogPath, { flags: 'a' });
/* eslint-disable-next-line no-console */
console.log('Log location: ' + accessLogPath);
// setup the logger
middleware = morgan('combined', { stream: accessLogStream });
}
else {
middleware = morgan('combined');
}
app.use(middleware);
morgan.token('remote-user', function (req) {
return req.isProxy ? 'proxy' : 'local_express';
});
}
/**
* If we're running in a custom env, set the appropriate environment URI and network properties
*
* @param config
*/
function configureEnvironment(config) {
const { customRootUri, customBitcoinNetwork } = config;
if (customRootUri) {
bitgo_1.Environments['custom'].uri = customRootUri;
}
if (customBitcoinNetwork) {
bitgo_1.Environments['custom'].network = customBitcoinNetwork;
}
}
/**
* Create an HTTP server configured for accepting HTTPS connections
*
* @param config application configuration
* @param app
* @return {Server}
*/
async function createHttpsServer(app, config) {
const { keyPath, crtPath, sslKey, sslCert } = config;
let key;
let cert;
if (sslKey && sslCert) {
key = sslKey;
cert = sslCert;
}
else if (keyPath && crtPath) {
const privateKeyPromise = fs.promises.readFile(keyPath, 'utf8');
const certificatePromise = fs.promises.readFile(crtPath, 'utf8');
[key, cert] = await Promise.all([privateKeyPromise, certificatePromise]);
}
else {
throw new Error('Failed to get ssl key and certificate');
}
return https.createServer({ secureOptions: constants_1.SSL_OP_NO_TLSv1, key, cert }, app);
}
/**
* Create an HTTP server configured for accepting plain old HTTP connections
*
* @param app
* @return {Server}
*/
function createHttpServer(app) {
return http.createServer(app);
}
/**
* Create a startup function which will be run upon server initialization
*
* @param config
* @param baseUri
* @return {Function}
*/
function startup(config, baseUri) {
return function () {
const { env, ipc, customRootUri, customBitcoinNetwork, signerMode, lightningSignerFileSystemPath } = config;
/* eslint-disable no-console */
console.log('BitGo-Express running');
console.log(`Environment: ${env}`);
if (ipc) {
console.log(`IPC path: ${ipc}`);
}
else {
console.log(`Base URI: ${baseUri}`);
}
if (customRootUri) {
console.log(`Custom root URI: ${customRootUri}`);
}
if (customBitcoinNetwork) {
console.log(`Custom bitcoin network: ${customBitcoinNetwork}`);
}
if (signerMode) {
console.log(`External signer mode: ${signerMode}`);
}
if (lightningSignerFileSystemPath) {
console.log(`Lightning signer file system path: ${lightningSignerFileSystemPath}`);
}
/* eslint-enable no-console */
};
}
exports.startup = startup;
/**
* helper function to determine whether we should run the server over TLS or not
*/
function isTLS(config) {
const { keyPath, crtPath, sslKey, sslCert } = config;
return Boolean((keyPath && crtPath) || (sslKey && sslCert));
}
/**
* Create either a HTTP or HTTPS server
*/
async function createServer(config, app) {
const server = isTLS(config) ? await createHttpsServer(app, config) : createHttpServer(app);
// Set keepAliveTimeout and headersTimeout if specified in config
if (config.keepAliveTimeout !== undefined) {
server.keepAliveTimeout = config.keepAliveTimeout;
}
if (config.headersTimeout !== undefined) {
server.headersTimeout = config.headersTimeout;
}
return server;
}
exports.createServer = createServer;
/**
* Create the base URI where the BitGoExpress server will be available once started
* @return {string}
*/
function createBaseUri(config) {
const { bind, port } = config;
const tls = isTLS(config);
const isStandardPort = (port === 80 && !tls) || (port === 443 && tls);
return `http${tls ? 's' : ''}://${bind}${!isStandardPort ? ':' + port : ''}`;
}
exports.createBaseUri = createBaseUri;
/**
* Check the that the json file exists
* @param path
*/
function checkJsonFilePath(path) {
try {
const jsonFile = fs.readFileSync(path, { encoding: 'utf8' });
JSON.parse(jsonFile);
}
catch (e) {
throw new Error(`Failed to parse ${path} - ${e.message}`);
}
}
/**
* Check environment and other preconditions to ensure bitgo-express can start safely
* @param config
*/
function checkPreconditions(config) {
const { env, disableEnvCheck, bind, ipc, disableSSL, keyPath, crtPath, sslKey, sslCert, customRootUri, customBitcoinNetwork, externalSignerUrl, signerMode, signerFileSystemPath, lightningSignerFileSystemPath, } = config;
// warn or throw if the NODE_ENV is not production when BITGO_ENV is production - this can leak system info from express
if (env === 'prod' && process.env.NODE_ENV !== 'production') {
if (!disableEnvCheck) {
throw new errors_1.NodeEnvironmentError('NODE_ENV should be set to production when running against prod environment. Use --disableenvcheck if you really want to run in a non-production node configuration.');
}
else {
console.warn(`warning: unsafe NODE_ENV '${process.env.NODE_ENV}'. NODE_ENV must be set to 'production' when running against BitGo production environment.`);
}
}
const needsTLS = !ipc && env === 'prod' && bind !== 'localhost' && !disableSSL;
// make sure keyPath and crtPath are set when running over TLS
if (needsTLS && !(keyPath && crtPath) && !(sslKey && sslCert)) {
throw new errors_1.TlsConfigurationError('Must enable TLS when running against prod and listening on external interfaces!');
}
if (Boolean(keyPath) !== Boolean(crtPath) || Boolean(sslKey) !== Boolean(sslCert)) {
throw new errors_1.TlsConfigurationError('Must provide both keypath and crtpath when running in TLS mode!');
}
if ((customRootUri || customBitcoinNetwork) && env !== 'custom') {
console.warn(`customRootUri or customBitcoinNetwork is set, but env is '${env}'. Setting env to 'custom'.`);
config.env = 'custom';
}
if (externalSignerUrl !== undefined && (signerMode !== undefined || signerFileSystemPath !== undefined)) {
throw new errors_1.ExternalSignerConfigError('signerMode or signerFileSystemPath is set, but externalSignerUrl is also set.');
}
if ((signerMode !== undefined || signerFileSystemPath !== undefined) && !(signerMode && signerFileSystemPath)) {
throw new errors_1.ExternalSignerConfigError('signerMode and signerFileSystemPath must both be set in order to run in external signing mode.');
}
if (signerMode !== undefined && lightningSignerFileSystemPath !== undefined) {
throw new errors_1.LightningSignerConfigError('signerMode and lightningSignerFileSystemPath cannot be set at the same time.');
}
if (signerFileSystemPath !== undefined) {
checkJsonFilePath(signerFileSystemPath);
}
if (lightningSignerFileSystemPath !== undefined) {
checkJsonFilePath(lightningSignerFileSystemPath);
}
}
function setupRoutes(app, config) {
if (config.signerMode) {
clientRoutes.setupSigningRoutes(app, config);
}
else {
if (config.lightningSignerFileSystemPath) {
clientRoutes.setupLightningSignerNodeRoutes(app, config);
}
clientRoutes.setupAPIRoutes(app, config);
}
}
exports.setupRoutes = setupRoutes;
function app(cfg) {
debug('app is initializing');
const app = express();
setupLogging(app, cfg);
debug('logging setup');
const { debugNamespace } = cfg;
// enable specified debug namespaces
if (_.isArray(debugNamespace)) {
for (const ns of debugNamespace) {
if (ns && !debugLib.enabled(ns)) {
debugLib.enable(ns);
}
}
}
checkPreconditions(cfg);
debug('preconditions satisfied');
// Be more robust about accepting URLs with double slashes
app.use(function replaceUrlSlashes(req, res, next) {
req.url = req.url.replace(/\/\//g, '/');
next();
});
app.use(timeout(cfg.timeout));
// Decorate the client routes
setupRoutes(app, cfg);
configureEnvironment(cfg);
return app;
}
exports.app = app;
/**
* Prepare to listen on an IPC (unix domain) socket instead of a normal TCP port.
* @param ipcSocketFilePath path to file where IPC socket should be created
*/
async function prepareIpc(ipcSocketFilePath) {
if (process.platform === 'win32') {
throw new errors_1.IpcError(`IPC option is not supported on platform ${process.platform}`);
}
try {
const stat = fs.statSync(ipcSocketFilePath);
if (!stat.isSocket()) {
throw new errors_1.IpcError('IPC socket is not actually a socket');
}
// ipc socket does exist and is indeed a socket. However, the socket cannot already exist prior
// to being bound since it will be created by express internally when binding. If there's a stale
// socket from the last run, clean it up before attempting to bind to it again. Arguably, it would
// be better to do this before exiting, but that gets a bit more complicated when all exit paths
// need to clean up the socket file correctly.
fs.unlinkSync(ipcSocketFilePath);
}
catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
}
exports.prepareIpc = prepareIpc;
async function init() {
const cfg = (0, config_1.config)();
const expressApp = app(cfg);
const server = await createServer(cfg, expressApp);
const { port, bind, ipc } = cfg;
const baseUri = createBaseUri(cfg);
if (ipc) {
await prepareIpc(ipc);
server.listen(ipc, startup(cfg, baseUri));
}
else {
server.listen(port, bind, startup(cfg, baseUri));
}
}
exports.init = init;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwcmVzc0FwcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9leHByZXNzQXBwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBOztHQUVHO0FBQ0gsbUNBQW1DO0FBQ25DLDZCQUE2QjtBQUM3Qiw0QkFBNEI7QUFDNUIsa0NBQWtDO0FBQ2xDLCtCQUErQjtBQUMvQiw2QkFBNkI7QUFDN0IsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUV6QiwyQ0FBMkM7QUFFM0MscUNBQTBDO0FBRTFDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUV4Qyx5Q0FBNEM7QUFDNUMscUNBTWtCO0FBRWxCLGlDQUFxQztBQUNyQywrQ0FBK0M7QUFFL0M7Ozs7O0dBS0c7QUFDSCxTQUFTLFlBQVksQ0FBQyxHQUF3QixFQUFFLE1BQWM7SUFDNUQsK0RBQStEO0lBQy9ELElBQUksVUFBVSxDQUFDO0lBQ2YsSUFBSSxNQUFNLENBQUMsT0FBTyxFQUFFO1FBQ2xCLHlDQUF5QztRQUN6QyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNuRCxNQUFNLGVBQWUsR0FBRyxFQUFFLENBQUMsaUJBQWlCLENBQUMsYUFBYSxFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDNUUseUNBQXlDO1FBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLENBQUM7UUFDOUMsbUJBQW1CO1FBQ25CLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxDQUFDLENBQUM7S0FDOUQ7U0FBTTtRQUNMLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7S0FDakM7SUFFRCxHQUFHLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3BCLE1BQU0sQ0FBQyxL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cmV0dGllclxuICovXG5pbXBvcnQgKiBhcyBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCAqIGFzIGRlYnVnTGliIGZyb20gJ2RlYnVnJztcbmltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgKiBhcyBtb3JnYW4gZnJvbSAnbW9yZ2FuJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCB0eXBlIHsgUmVxdWVzdCBhcyBTdGF0aWNSZXF1ZXN0IH0gZnJvbSAnZXhwcmVzcy1zZXJ2ZS1zdGF0aWMtY29yZSc7XG5pbXBvcnQgKiBhcyB0aW1lb3V0IGZyb20gJ2Nvbm5lY3QtdGltZW91dCc7XG5cbmltcG9ydCB7IENvbmZpZywgY29uZmlnIH0gZnJvbSAnLi9jb25maWcnO1xuXG5jb25zdCBkZWJ1ZyA9IGRlYnVnTGliKCdiaXRnbzpleHByZXNzJyk7XG5cbmltcG9ydCB7IFNTTF9PUF9OT19UTFN2MSB9IGZyb20gJ2NvbnN0YW50cyc7XG5pbXBvcnQge1xuICBJcGNFcnJvcixcbiAgTm9kZUVudmlyb25tZW50RXJyb3IsXG4gIFRsc0NvbmZpZ3VyYXRpb25FcnJvcixcbiAgRXh0ZXJuYWxTaWduZXJDb25maWdFcnJvcixcbiAgTGlnaHRuaW5nU2lnbmVyQ29uZmlnRXJyb3IsXG59IGZyb20gJy4vZXJyb3JzJztcblxuaW1wb3J0IHsgRW52aXJvbm1lbnRzIH0gZnJvbSAnYml0Z28nO1xuaW1wb3J0ICogYXMgY2xpZW50Um91dGVzIGZyb20gJy4vY2xpZW50Um91dGVzJztcblxuLyoqXG4gKiBTZXQgdXAgdGhlIGxvZ2dpbmcgbWlkZGxld2FyZSBwcm92aWRlZCBieSBtb3JnYW5cbiAqXG4gKiBAcGFyYW0gYXBwXG4gKiBAcGFyYW0gY29uZmlnXG4gKi9cbmZ1bmN0aW9uIHNldHVwTG9nZ2luZyhhcHA6IGV4cHJlc3MuQXBwbGljYXRpb24sIGNvbmZpZzogQ29uZmlnKTogdm9pZCB7XG4gIC8vIFNldCB1cCBtb3JnYW4gZm9yIGxvZ2dpbmcsIHdpdGggb3B0aW9uYWwgbG9nZ2luZyBpbnRvIGEgZmlsZVxuICBsZXQgbWlkZGxld2FyZTtcbiAgaWYgKGNvbmZpZy5sb2dGaWxlKSB7XG4gICAgLy8gY3JlYXRlIGEgd3JpdGUgc3RyZWFtIChpbiBhcHBlbmQgbW9kZSlcbiAgICBjb25zdCBhY2Nlc3NMb2dQYXRoID0gcGF0aC5yZXNvbHZlKGNvbmZpZy5sb2dGaWxlKTtcbiAgICBjb25zdCBhY2Nlc3NMb2dTdHJlYW0gPSBmcy5jcmVhdGVXcml0ZVN0cmVhbShhY2Nlc3NMb2dQYXRoLCB7IGZsYWdzOiAnYScgfSk7XG4gICAgLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGUgKi9cbiAgICBjb25zb2xlLmxvZygnTG9nIGxvY2F0aW9uOiAnICsgYWNjZXNzTG9nUGF0aCk7XG4gICAgLy8gc2V0dXAgdGhlIGxvZ2dlclxuICAgIG1pZGRsZXdhcmUgPSBtb3JnYW4oJ2NvbWJpbmVkJywgeyBzdHJlYW06IGFjY2Vzc0xvZ1N0cmVhbSB9KTtcbiAgfSBlbHNlIHtcbiAgICBtaWRkbGV3YXJlID0gbW9yZ2FuKCdjb21iaW5lZCcpO1xuICB9XG5cbiAgYXBwLnVzZShtaWRkbGV3YXJlKTtcbiAgbW9yZ2FuLnRva2VuKCdyZW1vdGUtdXNlcicsIGZ1bmN0aW9uIChyZXE6IFN0YXRpY1JlcXVlc3QpIHtcbiAgICByZXR1cm4gcmVxLmlzUHJveHkgPyAncHJveHknIDogJ2xvY2FsX2V4cHJlc3MnO1xuICB9KTtcbn1cblxuLyoqXG4gKiBJZiB3ZSdyZSBydW5uaW5nIGluIGEgY3VzdG9tIGVudiwgc2V0IHRoZSBhcHByb3ByaWF0ZSBlbnZpcm9ubWVudCBVUkkgYW5kIG5ldHdvcmsgcHJvcGVydGllc1xuICpcbiAqIEBwYXJhbSBjb25maWdcbiAqL1xuZnVuY3Rpb24gY29uZmlndXJlRW52aXJvbm1lbnQoY29uZmlnOiBDb25maWcpOiB2b2lkIHtcbiAgY29uc3QgeyBjdXN0b21Sb290VXJpLCBjdXN0b21CaXRjb2luTmV0d29yayB9ID0gY29uZmlnO1xuICBpZiAoY3VzdG9tUm9vdFVyaSkge1xuICAgIEVudmlyb25tZW50c1snY3VzdG9tJ10udXJpID0gY3VzdG9tUm9vdFVyaTtcbiAgfVxuXG4gIGlmIChjdXN0b21CaXRjb2luTmV0d29yaykge1xuICAgIEVudmlyb25tZW50c1snY3VzdG9tJ10ubmV0d29yayA9IGN1c3RvbUJpdGNvaW5OZXR3b3JrO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlIGFuIEhUVFAgc2VydmVyIGNvbmZpZ3VyZWQgZm9yIGFjY2VwdGluZyBIVFRQUyBjb25uZWN0aW9uc1xuICpcbiAqIEBwYXJhbSBjb25maWcgYXBwbGljYXRpb24gY29uZmlndXJhdGlvblxuICogQHBhcmFtIGFwcFxuICogQHJldHVybiB7U2VydmVyfVxuICovXG5hc3luYyBmdW5jdGlvbiBjcmVhdGVIdHRwc1NlcnZlcihhcHA6IGV4cHJlc3MuQXBwbGljYXRpb24sIGNvbmZpZzogQ29uZmlnKTogUHJvbWlzZTxodHRwcy5TZXJ2ZXI+IHtcbiAgY29uc3QgeyBrZXlQYXRoLCBjcnRQYXRoLCBzc2xLZXksIHNzbENlcnQgfSA9IGNvbmZpZztcbiAgbGV0IGtleTogc3RyaW5nO1xuICBsZXQgY2VydDogc3RyaW5nO1xuICBpZiAoc3NsS2V5ICYmIHNzbENlcnQpIHtcbiAgICBrZXkgPSBzc2xLZXk7XG4gICAgY2VydCA9IHNzbENlcnQ7XG4gIH0gZWxzZSBpZiAoa2V5UGF0aCAmJiBjcnRQYXRoKSB7XG4gICAgY29uc3QgcHJpdmF0ZUtleVByb21pc2UgPSBmcy5wcm9taXNlcy5yZWFkRmlsZShrZXlQYXRoLCAndXRmOCcpO1xuICAgIGNvbnN0IGNlcnRpZmljYXRlUHJvbWlzZSA9IGZzLnByb21pc2VzLnJlYWRGaWxlKGNydFBhdGgsICd1dGY4Jyk7XG5cbiAgICBba2V5LCBjZXJ0XSA9IGF3YWl0IFByb21pc2UuYWxsKFtwcml2YXRlS2V5UHJvbWlzZSwgY2VydGlmaWNhdGVQcm9taXNlXSk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZ2V0IHNzbCBrZXkgYW5kIGNlcnRpZmljYXRlJyk7XG4gIH1cblxuICByZXR1cm4gaHR0cHMuY3JlYXRlU2VydmVyKHsgc2VjdXJlT3B0aW9uczogU1NMX09QX05PX1RMU3YxLCBrZXksIGNlcnQgfSwgYXBwKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYW4gSFRUUCBzZXJ2ZXIgY29uZmlndXJlZCBmb3IgYWNjZXB0aW5nIHBsYWluIG9sZCBIVFRQIGNvbm5lY3Rpb25zXG4gKlxuICogQHBhcmFtIGFwcFxuICogQHJldHVybiB7U2VydmVyfVxuICovXG5mdW5jdGlvbiBjcmVhdGVIdHRwU2VydmVyKGFwcDogZXhwcmVzcy5BcHBsaWNhdGlvbik6IGh0dHAuU2VydmVyIHtcbiAgcmV0dXJuIGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgc3RhcnR1cCBmdW5jdGlvbiB3aGljaCB3aWxsIGJlIHJ1biB1cG9uIHNlcnZlciBpbml0aWFsaXphdGlvblxuICpcbiAqIEBwYXJhbSBjb25maWdcbiAqIEBwYXJhbSBiYXNlVXJpXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0YXJ0dXAoY29uZmlnOiBDb25maWcsIGJhc2VVcmk6IHN0cmluZyk6ICgpID0+IHZvaWQge1xuICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHsgZW52LCBpcGMsIGN1c3RvbVJvb3RVcmksIGN1c3RvbUJpdGNvaW5OZXR3b3JrLCBzaWduZXJNb2RlLCBsaWdodG5pbmdTaWduZXJGaWxlU3lzdGVtUGF0aCB9ID0gY29uZmlnO1xuICAgIC8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cbiAgICBjb25zb2xlLmxvZygnQml0R28tRXhwcmVzcyBydW5uaW5nJyk7XG4gICAgY29uc29sZS5sb2coYEVudmlyb25tZW50OiAke2Vudn1gKTtcbiAgICBpZiAoaXBjKSB7XG4gICAgICBjb25zb2xlLmxvZyhgSVBDIHBhdGg6ICR7aXBjfWApO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmxvZyhgQmFzZSBVUkk6ICR7YmFzZVVyaX1gKTtcbiAgICB9XG4gICAgaWYgKGN1c3RvbVJvb3RVcmkpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBDdXN0b20gcm9vdCBVUkk6ICR7Y3VzdG9tUm9vdFVyaX1gKTtcbiAgICB9XG4gICAgaWYgKGN1c3RvbUJpdGNvaW5OZXR3b3JrKSB7XG4gICAgICBjb25zb2xlLmxvZyhgQ3VzdG9tIGJpdGNvaW4gbmV0d29yazogJHtjdXN0b21CaXRjb2luTmV0d29ya31gKTtcbiAgICB9XG4gICAgaWYgKHNpZ25lck1vZGUpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBFeHRlcm5hbCBzaWduZXIgbW9kZTogJHtzaWduZXJNb2RlfWApO1xuICAgIH1cbiAgICBpZiAobGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGgpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBMaWdodG5pbmcgc2lnbmVyIGZpbGUgc3lzdGVtIHBhdGg6ICR7bGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGh9YCk7XG4gICAgfVxuICAgIC8qIGVzbGludC1lbmFibGUgbm8tY29uc29sZSAqL1xuICB9O1xufVxuXG4vKipcbiAqIGhlbHBlciBmdW5jdGlvbiB0byBkZXRlcm1pbmUgd2hldGhlciB3ZSBzaG91bGQgcnVuIHRoZSBzZXJ2ZXIgb3ZlciBUTFMgb3Igbm90XG4gKi9cbmZ1bmN0aW9uIGlzVExTKGNvbmZpZzogQ29uZmlnKTogY29uZmlnIGlzIENvbmZpZyAmIHsga2V5UGF0aDogc3RyaW5nOyBjcnRQYXRoOiBzdHJpbmcgfSB7XG4gIGNvbnN0IHsga2V5UGF0aCwgY3J0UGF0aCwgc3NsS2V5LCBzc2xDZXJ0IH0gPSBjb25maWc7XG4gIHJldHVybiBCb29sZWFuKChrZXlQYXRoICYmIGNydFBhdGgpIHx8IChzc2xLZXkgJiYgc3NsQ2VydCkpO1xufVxuXG4vKipcbiAqIENyZWF0ZSBlaXRoZXIgYSBIVFRQIG9yIEhUVFBTIHNlcnZlclxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlU2VydmVyKGNvbmZpZzogQ29uZmlnLCBhcHA6IGV4cHJlc3MuQXBwbGljYXRpb24pOiBQcm9taXNlPGh0dHBzLlNlcnZlciB8IGh0dHAuU2VydmVyPiB7XG4gIGNvbnN0IHNlcnZlciA9IGlzVExTKGNvbmZpZykgPyBhd2FpdCBjcmVhdGVIdHRwc1NlcnZlcihhcHAsIGNvbmZpZykgOiBjcmVhdGVIdHRwU2VydmVyKGFwcCk7XG5cbiAgLy8gU2V0IGtlZXBBbGl2ZVRpbWVvdXQgYW5kIGhlYWRlcnNUaW1lb3V0IGlmIHNwZWNpZmllZCBpbiBjb25maWdcbiAgaWYgKGNvbmZpZy5rZWVwQWxpdmVUaW1lb3V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICBzZXJ2ZXIua2VlcEFsaXZlVGltZW91dCA9IGNvbmZpZy5rZWVwQWxpdmVUaW1lb3V0O1xuICB9XG4gIGlmIChjb25maWcuaGVhZGVyc1RpbWVvdXQgIT09IHVuZGVmaW5lZCkge1xuICAgIHNlcnZlci5oZWFkZXJzVGltZW91dCA9IGNvbmZpZy5oZWFkZXJzVGltZW91dDtcbiAgfVxuICByZXR1cm4gc2VydmVyO1xufVxuXG4vKipcbiAqIENyZWF0ZSB0aGUgYmFzZSBVUkkgd2hlcmUgdGhlIEJpdEdvRXhwcmVzcyBzZXJ2ZXIgd2lsbCBiZSBhdmFpbGFibGUgb25jZSBzdGFydGVkXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVCYXNlVXJpKGNvbmZpZzogQ29uZmlnKTogc3RyaW5nIHtcbiAgY29uc3QgeyBiaW5kLCBwb3J0IH0gPSBjb25maWc7XG4gIGNvbnN0IHRscyA9IGlzVExTKGNvbmZpZyk7XG4gIGNvbnN0IGlzU3RhbmRhcmRQb3J0ID0gKHBvcnQgPT09IDgwICYmICF0bHMpIHx8IChwb3J0ID09PSA0NDMgJiYgdGxzKTtcbiAgcmV0dXJuIGBodHRwJHt0bHMgPyAncycgOiAnJ306Ly8ke2JpbmR9JHshaXNTdGFuZGFyZFBvcnQgPyAnOicgKyBwb3J0IDogJyd9YDtcbn1cblxuLyoqXG4gKiBDaGVjayB0aGUgdGhhdCB0aGUganNvbiBmaWxlIGV4aXN0c1xuICogQHBhcmFtIHBhdGhcbiAqL1xuZnVuY3Rpb24gY2hlY2tKc29uRmlsZVBhdGgocGF0aDogc3RyaW5nKSB7XG4gIHRyeSB7XG4gICAgY29uc3QganNvbkZpbGUgPSBmcy5yZWFkRmlsZVN5bmMocGF0aCwgeyBlbmNvZGluZzogJ3V0ZjgnIH0pO1xuICAgIEpTT04ucGFyc2UoanNvbkZpbGUpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gcGFyc2UgJHtwYXRofSAtICR7ZS5tZXNzYWdlfWApO1xuICB9XG59XG5cbi8qKlxuICogQ2hlY2sgZW52aXJvbm1lbnQgYW5kIG90aGVyIHByZWNvbmRpdGlvbnMgdG8gZW5zdXJlIGJpdGdvLWV4cHJlc3MgY2FuIHN0YXJ0IHNhZmVseVxuICogQHBhcmFtIGNvbmZpZ1xuICovXG5mdW5jdGlvbiBjaGVja1ByZWNvbmRpdGlvbnMoY29uZmlnOiBDb25maWcpIHtcbiAgY29uc3Qge1xuICAgIGVudixcbiAgICBkaXNhYmxlRW52Q2hlY2ssXG4gICAgYmluZCxcbiAgICBpcGMsXG4gICAgZGlzYWJsZVNTTCxcbiAgICBrZXlQYXRoLFxuICAgIGNydFBhdGgsXG4gICAgc3NsS2V5LFxuICAgIHNzbENlcnQsXG4gICAgY3VzdG9tUm9vdFVyaSxcbiAgICBjdXN0b21CaXRjb2luTmV0d29yayxcbiAgICBleHRlcm5hbFNpZ25lclVybCxcbiAgICBzaWduZXJNb2RlLFxuICAgIHNpZ25lckZpbGVTeXN0ZW1QYXRoLFxuICAgIGxpZ2h0bmluZ1NpZ25lckZpbGVTeXN0ZW1QYXRoLFxuICB9ID0gY29uZmlnO1xuXG4gIC8vIHdhcm4gb3IgdGhyb3cgaWYgdGhlIE5PREVfRU5WIGlzIG5vdCBwcm9kdWN0aW9uIHdoZW4gQklUR09fRU5WIGlzIHByb2R1Y3Rpb24gLSB0aGlzIGNhbiBsZWFrIHN5c3RlbSBpbmZvIGZyb20gZXhwcmVzc1xuICBpZiAoZW52ID09PSAncHJvZCcgJiYgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICAgIGlmICghZGlzYWJsZUVudkNoZWNrKSB7XG4gICAgICB0aHJvdyBuZXcgTm9kZUVudmlyb25tZW50RXJyb3IoXG4gICAgICAgICdOT0RFX0VOViBzaG91bGQgYmUgc2V0IHRvIHByb2R1Y3Rpb24gd2hlbiBydW5uaW5nIGFnYWluc3QgcHJvZCBlbnZpcm9ubWVudC4gVXNlIC0tZGlzYWJsZWVudmNoZWNrIGlmIHlvdSByZWFsbHkgd2FudCB0byBydW4gaW4gYSBub24tcHJvZHVjdGlvbiBub2RlIGNvbmZpZ3VyYXRpb24uJ1xuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgd2FybmluZzogdW5zYWZlIE5PREVfRU5WICcke3Byb2Nlc3MuZW52Lk5PREVfRU5WfScuIE5PREVfRU5WIG11c3QgYmUgc2V0IHRvICdwcm9kdWN0aW9uJyB3aGVuIHJ1bm5pbmcgYWdhaW5zdCBCaXRHbyBwcm9kdWN0aW9uIGVudmlyb25tZW50LmBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbmVlZHNUTFMgPSAhaXBjICYmIGVudiA9PT0gJ3Byb2QnICYmIGJpbmQgIT09ICdsb2NhbGhvc3QnICYmICFkaXNhYmxlU1NMO1xuXG4gIC8vIG1ha2Ugc3VyZSBrZXlQYXRoIGFuZCBjcnRQYXRoIGFyZSBzZXQgd2hlbiBydW5uaW5nIG92ZXIgVExTXG4gIGlmIChuZWVkc1RMUyAmJiAhKGtleVBhdGggJiYgY3J0UGF0aCkgJiYgIShzc2xLZXkgJiYgc3NsQ2VydCkpIHtcbiAgICB0aHJvdyBuZXcgVGxzQ29uZmlndXJhdGlvbkVycm9yKCdNdXN0IGVuYWJsZSBUTFMgd2hlbiBydW5uaW5nIGFnYWluc3QgcHJvZCBhbmQgbGlzdGVuaW5nIG9uIGV4dGVybmFsIGludGVyZmFjZXMhJyk7XG4gIH1cblxuICBpZiAoQm9vbGVhbihrZXlQYXRoKSAhPT0gQm9vbGVhbihjcnRQYXRoKSB8fCBCb29sZWFuKHNzbEtleSkgIT09IEJvb2xlYW4oc3NsQ2VydCkpIHtcbiAgICB0aHJvdyBuZXcgVGxzQ29uZmlndXJhdGlvbkVycm9yKCdNdXN0IHByb3ZpZGUgYm90aCBrZXlwYXRoIGFuZCBjcnRwYXRoIHdoZW4gcnVubmluZyBpbiBUTFMgbW9kZSEnKTtcbiAgfVxuXG4gIGlmICgoY3VzdG9tUm9vdFVyaSB8fCBjdXN0b21CaXRjb2luTmV0d29yaykgJiYgZW52ICE9PSAnY3VzdG9tJykge1xuICAgIGNvbnNvbGUud2FybihgY3VzdG9tUm9vdFVyaSBvciBjdXN0b21CaXRjb2luTmV0d29yayBpcyBzZXQsIGJ1dCBlbnYgaXMgJyR7ZW52fScuIFNldHRpbmcgZW52IHRvICdjdXN0b20nLmApO1xuICAgIGNvbmZpZy5lbnYgPSAnY3VzdG9tJztcbiAgfVxuXG4gIGlmIChleHRlcm5hbFNpZ25lclVybCAhPT0gdW5kZWZpbmVkICYmIChzaWduZXJNb2RlICE9PSB1bmRlZmluZWQgfHwgc2lnbmVyRmlsZVN5c3RlbVBhdGggIT09IHVuZGVmaW5lZCkpIHtcbiAgICB0aHJvdyBuZXcgRXh0ZXJuYWxTaWduZXJDb25maWdFcnJvcihcbiAgICAgICdzaWduZXJNb2RlIG9yIHNpZ25lckZpbGVTeXN0ZW1QYXRoIGlzIHNldCwgYnV0IGV4dGVybmFsU2lnbmVyVXJsIGlzIGFsc28gc2V0LidcbiAgICApO1xuICB9XG5cbiAgaWYgKChzaWduZXJNb2RlICE9PSB1bmRlZmluZWQgfHwgc2lnbmVyRmlsZVN5c3RlbVBhdGggIT09IHVuZGVmaW5lZCkgJiYgIShzaWduZXJNb2RlICYmIHNpZ25lckZpbGVTeXN0ZW1QYXRoKSkge1xuICAgIHRocm93IG5ldyBFeHRlcm5hbFNpZ25lckNvbmZpZ0Vycm9yKFxuICAgICAgJ3NpZ25lck1vZGUgYW5kIHNpZ25lckZpbGVTeXN0ZW1QYXRoIG11c3QgYm90aCBiZSBzZXQgaW4gb3JkZXIgdG8gcnVuIGluIGV4dGVybmFsIHNpZ25pbmcgbW9kZS4nXG4gICAgKTtcbiAgfVxuXG4gIGlmIChzaWduZXJNb2RlICE9PSB1bmRlZmluZWQgJiYgbGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGggIT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBMaWdodG5pbmdTaWduZXJDb25maWdFcnJvcihcbiAgICAgICdzaWduZXJNb2RlIGFuZCBsaWdodG5pbmdTaWduZXJGaWxlU3lzdGVtUGF0aCBjYW5ub3QgYmUgc2V0IGF0IHRoZSBzYW1lIHRpbWUuJ1xuICAgICk7XG4gIH1cblxuICBpZiAoc2lnbmVyRmlsZVN5c3RlbVBhdGggIT09IHVuZGVmaW5lZCkge1xuICAgIGNoZWNrSnNvbkZpbGVQYXRoKHNpZ25lckZpbGVTeXN0ZW1QYXRoKTtcbiAgfVxuXG4gIGlmIChsaWdodG5pbmdTaWduZXJGaWxlU3lzdGVtUGF0aCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY2hlY2tKc29uRmlsZVBhdGgobGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGgpO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cFJvdXRlcyhhcHA6IGV4cHJlc3MuQXBwbGljYXRpb24sIGNvbmZpZzogQ29uZmlnKTogdm9pZCB7XG4gIGlmIChjb25maWcuc2lnbmVyTW9kZSkge1xuICAgIGNsaWVudFJvdXRlcy5zZXR1cFNpZ25pbmdSb3V0ZXMoYXBwLCBjb25maWcpO1xuICB9IGVsc2Uge1xuICAgIGlmIChjb25maWcubGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGgpIHtcbiAgICAgIGNsaWVudFJvdXRlcy5zZXR1cExpZ2h0bmluZ1NpZ25lck5vZGVSb3V0ZXMoYXBwLCBjb25maWcpO1xuICAgIH1cbiAgICBjbGllbnRSb3V0ZXMuc2V0dXBBUElSb3V0ZXMoYXBwLCBjb25maWcpO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHAoY2ZnOiBDb25maWcpOiBleHByZXNzLkFwcGxpY2F0aW9uIHtcbiAgZGVidWcoJ2FwcCBpcyBpbml0aWFsaXppbmcnKTtcblxuICBjb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbiAgc2V0dXBMb2dnaW5nKGFwcCwgY2ZnKTtcbiAgZGVidWcoJ2xvZ2dpbmcgc2V0dXAnKTtcblxuICBjb25zdCB7IGRlYnVnTmFtZXNwYWNlIH0gPSBjZmc7XG5cbiAgLy8gZW5hYmxlIHNwZWNpZmllZCBkZWJ1ZyBuYW1lc3BhY2VzXG4gIGlmIChfLmlzQXJyYXkoZGVidWdOYW1lc3BhY2UpKSB7XG4gICAgZm9yIChjb25zdCBucyBvZiBkZWJ1Z05hbWVzcGFjZSkge1xuICAgICAgaWYgKG5zICYmICFkZWJ1Z0xpYi5lbmFibGVkKG5zKSkge1xuICAgICAgICBkZWJ1Z0xpYi5lbmFibGUobnMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNoZWNrUHJlY29uZGl0aW9ucyhjZmcpO1xuICBkZWJ1ZygncHJlY29uZGl0aW9ucyBzYXRpc2ZpZWQnKTtcblxuICAvLyBCZSBtb3JlIHJvYnVzdCBhYm91dCBhY2NlcHRpbmcgVVJMcyB3aXRoIGRvdWJsZSBzbGFzaGVzXG4gIGFwcC51c2UoZnVuY3Rpb24gcmVwbGFjZVVybFNsYXNoZXMocmVxLCByZXMsIG5leHQpIHtcbiAgICByZXEudXJsID0gcmVxLnVybC5yZXBsYWNlKC9cXC9cXC8vZywgJy8nKTtcbiAgICBuZXh0KCk7XG4gIH0pO1xuXG4gIGFwcC51c2UodGltZW91dChjZmcudGltZW91dCkpO1xuXG4gIC8vIERlY29yYXRlIHRoZSBjbGllbnQgcm91dGVzXG4gIHNldHVwUm91dGVzKGFwcCwgY2ZnKTtcblxuICBjb25maWd1cmVFbnZpcm9ubWVudChjZmcpO1xuXG4gIHJldHVybiBhcHA7XG59XG5cbi8qKlxuICogUHJlcGFyZSB0byBsaXN0ZW4gb24gYW4gSVBDICh1bml4IGRvbWFpbikgc29ja2V0IGluc3RlYWQgb2YgYSBub3JtYWwgVENQIHBvcnQuXG4gKiBAcGFyYW0gaXBjU29ja2V0RmlsZVBhdGggcGF0aCB0byBmaWxlIHdoZXJlIElQQyBzb2NrZXQgc2hvdWxkIGJlIGNyZWF0ZWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHByZXBhcmVJcGMoaXBjU29ja2V0RmlsZVBhdGg6IHN0cmluZykge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgIHRocm93IG5ldyBJcGNFcnJvcihgSVBDIG9wdGlvbiBpcyBub3Qgc3VwcG9ydGVkIG9uIHBsYXRmb3JtICR7cHJvY2Vzcy5wbGF0Zm9ybX1gKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgY29uc3Qgc3RhdCA9IGZzLnN0YXRTeW5jKGlwY1NvY2tldEZpbGVQYXRoKTtcbiAgICBpZiAoIXN0YXQuaXNTb2NrZXQoKSkge1xuICAgICAgdGhyb3cgbmV3IElwY0Vycm9yKCdJUEMgc29ja2V0IGlzIG5vdCBhY3R1YWxseSBhIHNvY2tldCcpO1xuICAgIH1cbiAgICAvLyBpcGMgc29ja2V0IGRvZXMgZXhpc3QgYW5kIGlzIGluZGVlZCBhIHNvY2tldC4gSG93ZXZlciwgdGhlIHNvY2tldCBjYW5ub3QgYWxyZWFkeSBleGlzdCBwcmlvclxuICAgIC8vIHRvIGJlaW5nIGJvdW5kIHNpbmNlIGl0IHdpbGwgYmUgY3JlYXRlZCBieSBleHByZXNzIGludGVybmFsbHkgd2hlbiBiaW5kaW5nLiBJZiB0aGVyZSdzIGEgc3RhbGVcbiAgICAvLyBzb2NrZXQgZnJvbSB0aGUgbGFzdCBydW4sIGNsZWFuIGl0IHVwIGJlZm9yZSBhdHRlbXB0aW5nIHRvIGJpbmQgdG8gaXQgYWdhaW4uIEFyZ3VhYmx5LCBpdCB3b3VsZFxuICAgIC8vIGJlIGJldHRlciB0byBkbyB0aGlzIGJlZm9yZSBleGl0aW5nLCBidXQgdGhhdCBnZXRzIGEgYml0IG1vcmUgY29tcGxpY2F0ZWQgd2hlbiBhbGwgZXhpdCBwYXRoc1xuICAgIC8vIG5lZWQgdG8gY2xlYW4gdXAgdGhlIHNvY2tldCBmaWxlIGNvcnJlY3RseS5cbiAgICBmcy51bmxpbmtTeW5jKGlwY1NvY2tldEZpbGVQYXRoKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGlmIChlLmNvZGUgIT09ICdFTk9FTlQnKSB7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY2ZnID0gY29uZmlnKCk7XG4gIGNvbnN0IGV4cHJlc3NBcHAgPSBhcHAoY2ZnKTtcblxuICBjb25zdCBzZXJ2ZXIgPSBhd2FpdCBjcmVhdGVTZXJ2ZXIoY2ZnLCBleHByZXNzQXBwKTtcblxuICBjb25zdCB7IHBvcnQsIGJpbmQsIGlwYyB9ID0gY2ZnO1xuICBjb25zdCBiYXNlVXJpID0gY3JlYXRlQmFzZVVyaShjZmcpO1xuXG4gIGlmIChpcGMpIHtcbiAgICBhd2FpdCBwcmVwYXJlSXBjKGlwYyk7XG4gICAgc2VydmVyLmxpc3RlbihpcGMsIHN0YXJ0dXAoY2ZnLCBiYXNlVXJpKSk7XG4gIH0gZWxzZSB7XG4gICAgc2VydmVyLmxpc3Rlbihwb3J0LCBiaW5kLCBzdGFydHVwKGNmZywgYmFzZVVyaSkpO1xuICB9XG59XG4iXX0=Выполнить команду
Для локальной разработки. Не используйте в интернете!