UNPKG

verdaccio

Version:

A lightweight private npm proxy registry

747 lines (591 loc) 76.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _zlib = _interopRequireDefault(require("zlib")); var _stream = _interopRequireDefault(require("stream")); var _url = _interopRequireDefault(require("url")); var _JSONStream = _interopRequireDefault(require("JSONStream")); var _lodash = _interopRequireDefault(require("lodash")); var _request = _interopRequireDefault(require("request")); var _streams = require("@verdaccio/streams"); var _utils = require("./utils"); var _constants = require("./constants"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const LoggerApi = require('./logger'); const encode = function (thing) { return encodeURIComponent(thing).replace(/^%40/, '@'); }; const jsonContentType = _constants.HEADERS.JSON; const contentTypeAccept = `${jsonContentType};`; /** * Just a helper (`config[key] || default` doesn't work because of zeroes) */ const setConfig = (config, key, def) => { return _lodash.default.isNil(config[key]) === false ? config[key] : def; }; /** * Implements Storage interface * (same for storage.js, local-storage.js, up-storage.js) */ class ProxyStorage { // FIXME: upname is assigned to each instance // @ts-ignore // FIXME: proxy can be boolean or object, something smells here // @ts-ignore // @ts-ignore /** * Constructor * @param {*} config * @param {*} mainConfig */ constructor(config, mainConfig) { _defineProperty(this, "config", void 0); _defineProperty(this, "failed_requests", void 0); _defineProperty(this, "userAgent", void 0); _defineProperty(this, "ca", void 0); _defineProperty(this, "logger", void 0); _defineProperty(this, "server_id", void 0); _defineProperty(this, "url", void 0); _defineProperty(this, "maxage", void 0); _defineProperty(this, "timeout", void 0); _defineProperty(this, "max_fails", void 0); _defineProperty(this, "fail_timeout", void 0); _defineProperty(this, "agent_options", void 0); _defineProperty(this, "upname", void 0); _defineProperty(this, "proxy", void 0); _defineProperty(this, "last_request_time", void 0); _defineProperty(this, "strict_ssl", void 0); this.config = config; this.failed_requests = 0; this.userAgent = mainConfig.user_agent; this.ca = config.ca; this.logger = LoggerApi.logger.child({ sub: 'out' }); this.server_id = mainConfig.server_id; this.url = _url.default.parse(this.config.url); // $FlowFixMe this._setupProxy(this.url.hostname, config, mainConfig, this.url.protocol === 'https:'); this.config.url = this.config.url.replace(/\/$/, ''); if (this.config.timeout && Number(this.config.timeout) >= 1000) { this.logger.warn(['Too big timeout value: ' + this.config.timeout, 'We changed time format to nginx-like one', '(see http://nginx.org/en/docs/syntax.html)', 'so please update your config accordingly'].join('\n')); } // a bunch of different configurable timers this.maxage = (0, _utils.parseInterval)(setConfig(this.config, 'maxage', '2m')); this.timeout = (0, _utils.parseInterval)(setConfig(this.config, 'timeout', '30s')); this.max_fails = Number(setConfig(this.config, 'max_fails', 2)); this.fail_timeout = (0, _utils.parseInterval)(setConfig(this.config, 'fail_timeout', '5m')); this.strict_ssl = Boolean(setConfig(this.config, 'strict_ssl', true)); this.agent_options = setConfig(this.config, 'agent_options', { keepAlive: true, maxSockets: 40, maxFreeSockets: 10 }); } /** * Fetch an asset. * @param {*} options * @param {*} cb * @return {Request} */ request(options, cb) { let json; if (this._statusCheck() === false) { const streamRead = new _stream.default.Readable(); process.nextTick(function () { if (cb) { cb(_utils.ErrorCode.getInternalError(_constants.API_ERROR.UPLINK_OFFLINE)); } streamRead.emit('error', _utils.ErrorCode.getInternalError(_constants.API_ERROR.UPLINK_OFFLINE)); }); // $FlowFixMe streamRead._read = function () {}; // preventing 'Uncaught, unspecified "error" event' streamRead.on('error', function () {}); return streamRead; } const self = this; const headers = this._setHeaders(options); this._addProxyHeaders(options.req, headers); this._overrideWithUpLinkConfLocaligHeaders(headers); const method = options.method || 'GET'; const uri = options.uri_full || this.config.url + options.uri; self.logger.info({ method: method, headers: headers, uri: uri }, "making request: '@{method} @{uri}'"); if ((0, _utils.isObject)(options.json)) { json = JSON.stringify(options.json); headers['Content-Type'] = headers['Content-Type'] || _constants.HEADERS.JSON; } const requestCallback = cb ? function (err, res, body) { let error; const responseLength = err ? 0 : body.length; // $FlowFixMe processBody(); logActivity(); // $FlowFixMe cb(err, res, body); /** * Perform a decode. */ function processBody() { if (err) { error = err.message; return; } if (options.json && res.statusCode < 300) { try { // $FlowFixMe body = JSON.parse(body.toString(_constants.CHARACTER_ENCODING.UTF8)); } catch (_err) { body = {}; err = _err; error = err.message; } } if (!err && (0, _utils.isObject)(body)) { if (_lodash.default.isString(body.error)) { error = body.error; } } } /** * Perform a log. */ function logActivity() { let message = "@{!status}, req: '@{request.method} @{request.url}'"; message += error ? ', error: @{!error}' : ', bytes: @{bytes.in}/@{bytes.out}'; self.logger.warn({ err: err || undefined, // if error is null/false change this to undefined so it wont log request: { method: method, url: uri }, level: 35, // http status: res != null ? res.statusCode : 'ERR', error: error, bytes: { in: json ? json.length : 0, out: responseLength || 0 } }, message); } } : undefined; let requestOptions = { url: uri, method: method, headers: headers, body: json, proxy: this.proxy, encoding: null, gzip: true, timeout: this.timeout, strictSSL: this.strict_ssl, agentOptions: this.agent_options }; if (this.ca) { requestOptions = Object.assign({}, requestOptions, { ca: this.ca }); } const req = (0, _request.default)(requestOptions, requestCallback); let statusCalled = false; req.on('response', function (res) { // FIXME: _verdaccio_aborted seems not used // @ts-ignore if (!req._verdaccio_aborted && !statusCalled) { statusCalled = true; self._statusCheck(true); } if (_lodash.default.isNil(requestCallback) === false) { (function do_log() { const message = "@{!status}, req: '@{request.method} @{request.url}' (streaming)"; self.logger.warn({ request: { method: method, url: uri }, level: 35, // http status: _lodash.default.isNull(res) === false ? res.statusCode : 'ERR' }, message); })(); } }); req.on('error', function (_err) { // FIXME: _verdaccio_aborted seems not used // @ts-ignore if (!req._verdaccio_aborted && !statusCalled) { statusCalled = true; self._statusCheck(false); } }); // @ts-ignore return req; } /** * Set default headers. * @param {Object} options * @return {Object} * @private */ _setHeaders(options) { const headers = options.headers || {}; const accept = _constants.HEADERS.ACCEPT; const acceptEncoding = _constants.HEADERS.ACCEPT_ENCODING; const userAgent = _constants.HEADERS.USER_AGENT; headers[accept] = headers[accept] || contentTypeAccept; headers[acceptEncoding] = headers[acceptEncoding] || 'gzip'; // registry.npmjs.org will only return search result if user-agent include string 'npm' headers[userAgent] = headers[userAgent] || `npm (${this.userAgent})`; return this._setAuth(headers); } /** * Validate configuration auth and assign Header authorization * @param {Object} headers * @return {Object} * @private */ _setAuth(headers) { const { auth } = this.config; if (_lodash.default.isNil(auth) || headers[_constants.HEADERS.AUTHORIZATION]) { return headers; } // $FlowFixMe if (_lodash.default.isObject(auth) === false && _lodash.default.isObject(auth.token) === false) { this._throwErrorAuth('Auth invalid'); } // get NPM_TOKEN http://blog.npmjs.org/post/118393368555/deploying-with-npm-private-modules // or get other variable export in env // https://github.com/verdaccio/verdaccio/releases/tag/v2.5.0 let token; const tokenConf = auth; if (_lodash.default.isNil(tokenConf.token) === false && _lodash.default.isString(tokenConf.token)) { token = tokenConf.token; } else if (_lodash.default.isNil(tokenConf.token_env) === false) { if (_lodash.default.isString(tokenConf.token_env)) { token = process.env[tokenConf.token_env]; } else if (_lodash.default.isBoolean(tokenConf.token_env) && tokenConf.token_env) { token = process.env.NPM_TOKEN; } else { this.logger.error(_constants.ERROR_CODE.token_required); this._throwErrorAuth(_constants.ERROR_CODE.token_required); } } else { token = process.env.NPM_TOKEN; } if (_lodash.default.isNil(token)) { this._throwErrorAuth(_constants.ERROR_CODE.token_required); } // define type Auth allow basic and bearer const type = tokenConf.type || _constants.TOKEN_BASIC; this._setHeaderAuthorization(headers, type, token); return headers; } /** * @param {string} message * @throws {Error} * @private */ _throwErrorAuth(message) { this.logger.error(message); throw new Error(message); } /** * Assign Header authorization with type authentication * @param {Object} headers * @param {string} type * @param {string} token * @private */ _setHeaderAuthorization(headers, type, token) { const _type = type.toLowerCase(); if (_type !== _constants.TOKEN_BEARER.toLowerCase() && _type !== _constants.TOKEN_BASIC.toLowerCase()) { this._throwErrorAuth(`Auth type '${_type}' not allowed`); } type = _lodash.default.upperFirst(type); headers[_constants.HEADERS.AUTHORIZATION] = (0, _utils.buildToken)(type, token); } /** * It will add or override specified headers from config file. * * Eg: * * uplinks: npmjs: url: https://registry.npmjs.org/ headers: Accept: "application/vnd.npm.install-v2+json; q=1.0" verdaccio-staging: url: https://mycompany.com/npm headers: Accept: "application/json" authorization: "Basic YourBase64EncodedCredentials==" * @param {Object} headers * @private */ _overrideWithUpLinkConfLocaligHeaders(headers) { if (!this.config.headers) { return headers; } // add/override headers specified in the config /* eslint guard-for-in: 0 */ for (const key in this.config.headers) { headers[key] = this.config.headers[key]; } } /** * Determine whether can fetch from the provided URL * @param {*} url * @return {Boolean} */ isUplinkValid(url) { // $FlowFixMe const urlParsed = _url.default.parse(url); const isHTTPS = urlDomainParsed => urlDomainParsed.protocol === 'https:' && (urlParsed.port === null || urlParsed.port === '443'); const getHost = urlDomainParsed => isHTTPS(urlDomainParsed) ? urlDomainParsed.hostname : urlDomainParsed.host; const isMatchProtocol = urlParsed.protocol === this.url.protocol; const isMatchHost = getHost(urlParsed) === getHost(this.url); // @ts-ignore const isMatchPath = urlParsed.path.indexOf(this.url.path) === 0; return isMatchProtocol && isMatchHost && isMatchPath; } /** * Get a remote package metadata * @param {*} name package name * @param {*} options request options, eg: eTag. * @param {*} callback */ getRemoteMetadata(name, options, callback) { const headers = {}; if (_lodash.default.isNil(options.etag) === false) { headers['If-None-Match'] = options.etag; headers[_constants.HEADERS.ACCEPT] = contentTypeAccept; } this.request({ uri: `/${encode(name)}`, json: true, headers: headers, req: options.req }, (err, res, body) => { if (err) { return callback(err); } if (res.statusCode === _constants.HTTP_STATUS.NOT_FOUND) { return callback(_utils.ErrorCode.getNotFound(_constants.API_ERROR.NOT_PACKAGE_UPLINK)); } if (!(res.statusCode >= _constants.HTTP_STATUS.OK && res.statusCode < _constants.HTTP_STATUS.MULTIPLE_CHOICES)) { const error = _utils.ErrorCode.getInternalError(`${_constants.API_ERROR.BAD_STATUS_CODE}: ${res.statusCode}`); // $FlowFixMe error.remoteStatus = res.statusCode; return callback(error); } callback(null, body, res.headers.etag); }); } /** * Fetch a tarball from the uplink. * @param {String} url * @return {Stream} */ fetchTarball(url) { const stream = new _streams.ReadTarball({}); let current_length = 0; let expected_length; stream.abort = () => {}; const readStream = this.request({ uri_full: url, encoding: null, headers: { Accept: contentTypeAccept } }); readStream.on('response', function (res) { if (res.statusCode === _constants.HTTP_STATUS.NOT_FOUND) { return stream.emit('error', _utils.ErrorCode.getNotFound(_constants.API_ERROR.NOT_FILE_UPLINK)); } if (!(res.statusCode >= _constants.HTTP_STATUS.OK && res.statusCode < _constants.HTTP_STATUS.MULTIPLE_CHOICES)) { return stream.emit('error', _utils.ErrorCode.getInternalError(`bad uplink status code: ${res.statusCode}`)); } if (res.headers[_constants.HEADER_TYPE.CONTENT_LENGTH]) { expected_length = res.headers[_constants.HEADER_TYPE.CONTENT_LENGTH]; stream.emit(_constants.HEADER_TYPE.CONTENT_LENGTH, res.headers[_constants.HEADER_TYPE.CONTENT_LENGTH]); } readStream.pipe(stream); }); readStream.on('error', function (err) { stream.emit('error', err); }); readStream.on('data', function (data) { current_length += data.length; }); readStream.on('end', function (data) { if (data) { current_length += data.length; } if (expected_length && current_length != expected_length) { stream.emit('error', _utils.ErrorCode.getInternalError(_constants.API_ERROR.CONTENT_MISMATCH)); } }); return stream; } /** * Perform a stream search. * @param {*} options request options * @return {Stream} */ search(options) { const transformStream = new _stream.default.PassThrough({ objectMode: true }); const requestStream = this.request({ uri: options.req.url, req: options.req, headers: { referer: options.req.headers.referer } }); const parsePackage = pkg => { if ((0, _utils.isObject)(pkg)) { transformStream.emit('data', pkg); } }; requestStream.on('response', res => { if (!String(res.statusCode).match(/^2\d\d$/)) { return transformStream.emit('error', _utils.ErrorCode.getInternalError(`bad status code ${res.statusCode} from uplink`)); } // See https://github.com/request/request#requestoptions-callback // Request library will not decode gzip stream. let jsonStream; if (res.headers[_constants.HEADER_TYPE.CONTENT_ENCODING] === _constants.HEADERS.GZIP) { jsonStream = res.pipe(_zlib.default.createUnzip()); } else { jsonStream = res; } jsonStream.pipe(_JSONStream.default.parse('*')).on('data', parsePackage); jsonStream.on('end', () => { transformStream.emit('end'); }); }); requestStream.on('error', err => { transformStream.emit('error', err); }); transformStream.abort = () => { // FIXME: this is clearly a potential issue // there is no abort method on Stream.Readable // @ts-ignore requestStream.abort(); transformStream.emit('end'); }; return transformStream; } /** * Add proxy headers. * FIXME: object mutations, it should return an new object * @param {*} req the http request * @param {*} headers the request headers */ _addProxyHeaders(req, headers) { if (req) { // Only submit X-Forwarded-For field if we don't have a proxy selected // in the config file. // // Otherwise misconfigured proxy could return 407: // https://github.com/rlidwka/sinopia/issues/254 // // FIXME: proxy logic is odd, something is wrong here. // @ts-ignore if (!this.proxy) { headers['X-Forwarded-For'] = (req.headers['x-forwarded-for'] ? req.headers['x-forwarded-for'] + ', ' : '') + req.connection.remoteAddress; } } // always attach Via header to avoid loops, even if we're not proxying headers['Via'] = req && req.headers['via'] ? req.headers['via'] + ', ' : ''; headers['Via'] += '1.1 ' + this.server_id + ' (Verdaccio)'; } /** * Check whether the remote host is available. * @param {*} alive * @return {Boolean} */ _statusCheck(alive) { if (arguments.length === 0) { return this._ifRequestFailure() === false; } if (alive) { if (this.failed_requests >= this.max_fails) { this.logger.warn({ host: this.url.host }, 'host @{host} is back online'); } this.failed_requests = 0; } else { this.failed_requests++; if (this.failed_requests === this.max_fails) { this.logger.warn({ host: this.url.host }, 'host @{host} is now offline'); } } this.last_request_time = Date.now(); } /** * If the request failure. * @return {boolean} * @private */ _ifRequestFailure() { return this.failed_requests >= this.max_fails && Math.abs(Date.now() - this.last_request_time) < this.fail_timeout; } /** * Set up a proxy. * @param {*} hostname * @param {*} config * @param {*} mainconfig * @param {*} isHTTPS */ _setupProxy(hostname, config, mainconfig, isHTTPS) { let noProxyList; const proxy_key = isHTTPS ? 'https_proxy' : 'http_proxy'; // get http_proxy and no_proxy configs if (proxy_key in config) { this.proxy = config[proxy_key]; } else if (proxy_key in mainconfig) { this.proxy = mainconfig[proxy_key]; } if ('no_proxy' in config) { // $FlowFixMe noProxyList = config.no_proxy; } else if ('no_proxy' in mainconfig) { noProxyList = mainconfig.no_proxy; } // use wget-like algorithm to determine if proxy shouldn't be used if (hostname[0] !== '.') { hostname = '.' + hostname; } if (_lodash.default.isString(noProxyList) && noProxyList.length) { // $FlowFixMe noProxyList = noProxyList.split(','); } if (_lodash.default.isArray(noProxyList)) { for (let i = 0; i < noProxyList.length; i++) { let noProxyItem = noProxyList[i]; if (noProxyItem[0] !== '.') { noProxyItem = '.' + noProxyItem; } if (hostname.lastIndexOf(noProxyItem) === hostname.length - noProxyItem.length) { if (this.proxy) { this.logger.debug({ url: this.url.href, rule: noProxyItem }, 'not using proxy for @{url}, excluded by @{rule} rule'); // @ts-ignore this.proxy = false; } break; } } } // if it's non-string (i.e. "false"), don't use it if (_lodash.default.isString(this.proxy) === false) { delete this.proxy; } else { this.logger.debug({ url: this.url.href, proxy: this.proxy }, 'using proxy @{proxy} for @{url}'); } } } var _default = ProxyStorage; exports.default = _default; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdXAtc3RvcmFnZS50cyJdLCJuYW1lcyI6WyJMb2dnZXJBcGkiLCJyZXF1aXJlIiwiZW5jb2RlIiwidGhpbmciLCJlbmNvZGVVUklDb21wb25lbnQiLCJyZXBsYWNlIiwianNvbkNvbnRlbnRUeXBlIiwiSEVBREVSUyIsIkpTT04iLCJjb250ZW50VHlwZUFjY2VwdCIsInNldENvbmZpZyIsImNvbmZpZyIsImtleSIsImRlZiIsIl8iLCJpc05pbCIsIlByb3h5U3RvcmFnZSIsImNvbnN0cnVjdG9yIiwibWFpbkNvbmZpZyIsImZhaWxlZF9yZXF1ZXN0cyIsInVzZXJBZ2VudCIsInVzZXJfYWdlbnQiLCJjYSIsImxvZ2dlciIsImNoaWxkIiwic3ViIiwic2VydmVyX2lkIiwidXJsIiwiVVJMIiwicGFyc2UiLCJfc2V0dXBQcm94eSIsImhvc3RuYW1lIiwicHJvdG9jb2wiLCJ0aW1lb3V0IiwiTnVtYmVyIiwid2FybiIsImpvaW4iLCJtYXhhZ2UiLCJtYXhfZmFpbHMiLCJmYWlsX3RpbWVvdXQiLCJzdHJpY3Rfc3NsIiwiQm9vbGVhbiIsImFnZW50X29wdGlvbnMiLCJrZWVwQWxpdmUiLCJtYXhTb2NrZXRzIiwibWF4RnJlZVNvY2tldHMiLCJyZXF1ZXN0Iiwib3B0aW9ucyIsImNiIiwianNvbiIsIl9zdGF0dXNDaGVjayIsInN0cmVhbVJlYWQiLCJTdHJlYW0iLCJSZWFkYWJsZSIsInByb2Nlc3MiLCJuZXh0VGljayIsIkVycm9yQ29kZSIsImdldEludGVybmFsRXJyb3IiLCJBUElfRVJST1IiLCJVUExJTktfT0ZGTElORSIsImVtaXQiLCJfcmVhZCIsIm9uIiwic2VsZiIsImhlYWRlcnMiLCJfc2V0SGVhZGVycyIsIl9hZGRQcm94eUhlYWRlcnMiLCJyZXEiLCJfb3ZlcnJpZGVXaXRoVXBMaW5rQ29uZkxvY2FsaWdIZWFkZXJzIiwibWV0aG9kIiwidXJpIiwidXJpX2Z1bGwiLCJpbmZvIiwic3RyaW5naWZ5IiwicmVxdWVzdENhbGxiYWNrIiwiZXJyIiwicmVzIiwiYm9keSIsImVycm9yIiwicmVzcG9uc2VMZW5ndGgiLCJsZW5ndGgiLCJwcm9jZXNzQm9keSIsImxvZ0FjdGl2aXR5IiwibWVzc2FnZSIsInN0YXR1c0NvZGUiLCJ0b1N0cmluZyIsIkNIQVJBQ1RFUl9FTkNPRElORyIsIlVURjgiLCJfZXJyIiwiaXNTdHJpbmciLCJ1bmRlZmluZWQiLCJsZXZlbCIsInN0YXR1cyIsImJ5dGVzIiwiaW4iLCJvdXQiLCJyZXF1ZXN0T3B0aW9ucyIsInByb3h5IiwiZW5jb2RpbmciLCJnemlwIiwic3RyaWN0U1NMIiwiYWdlbnRPcHRpb25zIiwiT2JqZWN0IiwiYXNzaWduIiwic3RhdHVzQ2FsbGVkIiwiX3ZlcmRhY2Npb19hYm9ydGVkIiwiZG9fbG9nIiwiaXNOdWxsIiwiYWNjZXB0IiwiQUNDRVBUIiwiYWNjZXB0RW5jb2RpbmciLCJBQ0NFUFRfRU5DT0RJTkciLCJVU0VSX0FHRU5UIiwiX3NldEF1dGgiLCJhdXRoIiwiQVVUSE9SSVpBVElPTiIsImlzT2JqZWN0IiwidG9rZW4iLCJfdGhyb3dFcnJvckF1dGgiLCJ0b2tlbkNvbmYiLCJ0b2tlbl9lbnYiLCJlbnYiLCJpc0Jvb2xlYW4iLCJOUE1fVE9LRU4iLCJFUlJPUl9DT0RFIiwidG9rZW5fcmVxdWlyZWQiLCJ0eXBlIiwiVE9LRU5fQkFTSUMiLCJfc2V0SGVhZGVyQXV0aG9yaXphdGlvbiIsIkVycm9yIiwiX3R5cGUiLCJ0b0xvd2VyQ2FzZSIsIlRPS0VOX0JFQVJFUiIsInVwcGVyRmlyc3QiLCJpc1VwbGlua1ZhbGlkIiwidXJsUGFyc2VkIiwiaXNIVFRQUyIsInVybERvbWFpblBhcnNlZCIsInBvcnQiLCJnZXRIb3N0IiwiaG9zdCIsImlzTWF0Y2hQcm90b2NvbCIsImlzTWF0Y2hIb3N0IiwiaXNNYXRjaFBhdGgiLCJwYXRoIiwiaW5kZXhPZiIsImdldFJlbW90ZU1ldGFkYXRhIiwibmFtZSIsImNhbGxiYWNrIiwiZXRhZyIsIkhUVFBfU1RBVFVTIiwiTk9UX0ZPVU5EIiwiZ2V0Tm90Rm91bmQiLCJOT1RfUEFDS0FHRV9VUExJTksiLCJPSyIsIk1VTFRJUExFX0NIT0lDRVMiLCJCQURfU1RBVFVTX0NPREUiLCJyZW1vdGVTdGF0dXMiLCJmZXRjaFRhcmJhbGwiLCJzdHJlYW0iLCJSZWFkVGFyYmFsbCIsImN1cnJlbnRfbGVuZ3RoIiwiZXhwZWN0ZWRfbGVuZ3RoIiwiYWJvcnQiLCJyZWFkU3RyZWFtIiwiQWNjZXB0IiwiTk9UX0ZJTEVfVVBMSU5LIiwiSEVBREVSX1RZUEUiLCJDT05URU5UX0xFTkdUSCIsInBpcGUiLCJkYXRhIiwiQ09OVEVOVF9NSVNNQVRDSCIsInNlYXJjaCIsInRyYW5zZm9ybVN0cmVhbSIsIlBhc3NUaHJvdWdoIiwib2JqZWN0TW9kZSIsInJlcXVlc3RTdHJlYW0iLCJyZWZlcmVyIiwicGFyc2VQYWNrYWdlIiwicGtnIiwiU3RyaW5nIiwibWF0Y2giLCJqc29uU3RyZWFtIiwiQ09OVEVOVF9FTkNPRElORyIsIkdaSVAiLCJ6bGliIiwiY3JlYXRlVW56aXAiLCJKU09OU3RyZWFtIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJhbGl2ZSIsImFyZ3VtZW50cyIsIl9pZlJlcXVlc3RGYWlsdXJlIiwibGFzdF9yZXF1ZXN0X3RpbWUiLCJEYXRlIiwibm93IiwiTWF0aCIsImFicyIsIm1haW5jb25maWciLCJub1Byb3h5TGlzdCIsInByb3h5X2tleSIsIm5vX3Byb3h5Iiwic3BsaXQiLCJpc0FycmF5IiwiaSIsIm5vUHJveHlJdGVtIiwibGFzdEluZGV4T2YiLCJkZWJ1ZyIsImhyZWYiLCJydWxlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBR0E7O0FBQ0E7Ozs7OztBQVVBLE1BQU1BLFNBQVMsR0FBR0MsT0FBTyxDQUFDLFVBQUQsQ0FBekI7O0FBRUEsTUFBTUMsTUFBTSxHQUFHLFVBQVVDLEtBQVYsRUFBeUI7QUFDdEMsU0FBT0Msa0JBQWtCLENBQUNELEtBQUQsQ0FBbEIsQ0FB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QyxHQUFHTCxXQUFXLENBQUN2SCxNQUFoQyxFQUF3QzRILENBQUMsRUFBekMsRUFBNkM7QUFDM0MsWUFBSUMsV0FBVyxHQUFHTixXQUFXLENBQUNLLENBQUQsQ0FBN0I7O0FBQ0EsWUFBSUMsV0FBVyxDQUFDLENBQUQsQ0FBWCxLQUFtQixHQUF2QixFQUE0QjtBQUMxQkEsVUFBQUEsV0FBVyxHQUFHLE1BQU1BLFdBQXBCO0FBQ0Q7O0FBQ0QsWUFBSTlLLFFBQVEsQ0FBQytLLFdBQVQsQ0FBcUJELFdBQXJCLE1BQXNDOUssUUFBUSxDQUFDaUQsTUFBVCxHQUFrQjZILFdBQVcsQ0FBQzdILE1BQXhFLEVBQWdGO0FBQzlFLGNBQUksS0FBS2lCLEtBQVQsRUFBZ0I7QUFDZCxpQkFBSzFFLE1BQUwsQ0FBWXdMLEtBQVosQ0FDRTtBQUFFcEwsY0FBQUEsR0FBRyxFQUFFLEtBQUtBLEdBQUwsQ0FBU3FMLElBQWhCO0FBQXNCQyxjQUFBQSxJQUFJLEVBQUVKO0FBQTVCLGFBREYsRUFFRSxzREFGRixFQURjLENBS2Q7O0FBQ0EsaUJBQUs1RyxLQUFMLEdBQWEsS0FBYjtBQUNEOztBQUNEO0FBQ0Q7QUFDRjtBQUNGLEtBN0NLLENBK0NOOzs7QUFDQSxRQUFJbkYsZ0JBQUUyRSxRQUFGLENBQVcsS0FBS1EsS0FBaEIsTUFBMkIsS0FBL0IsRUFBc0M7QUFDcEMsYUFBTyxLQUFLQSxLQUFaO0FBQ0QsS0FGRCxNQUVPO0FBQ0wsV0FBSzFFLE1BQUwsQ0FBWXdMLEtBQVosQ0FDRTtBQUFFcEwsUUFBQUEsR0FBRyxFQUFFLEtBQUtBLEdBQUwsQ0FBU3FMLElBQWhCO0FBQXNCL0csUUFBQUEsS0FBSyxFQUFFLEtBQUtBO0FBQWxDLE9BREYsRUFFRSxpQ0FGRjtBQUlEO0FBQ0Y7O0FBdHFCa0M7O2VBeXFCdEJqRixZIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHpsaWIgZnJvbSAnemxpYic7XG5pbXBvcnQgU3RyZWFtLCB7IFJlYWRhYmxlIH0gZnJvbSAnc3RyZWFtJztcbmltcG9ydCBVUkwsIHsgVXJsV2l0aFN0cmluZ1F1ZXJ5IH0gZnJvbSAndXJsJztcbmltcG9ydCBKU09OU3RyZWFtIGZyb20gJ0pTT05TdHJlYW0nO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCByZXF1ZXN0IGZyb20gJ3JlcXVlc3QnO1xuaW1wb3J0IHsgUmVhZFRhcmJhbGwgfSBmcm9tICdAdmVyZGFjY2lvL3N0cmVhbXMnO1xuaW1wb3J0IHsgQ29uZmlnLCBDYWxsYmFjaywgSGVhZGVycywgTG9nZ2VyLCBQYWNrYWdlIH0gZnJvbSAnQHZlcmRhY2Npby90eXBlcyc7XG5pbXBvcnQgeyBJUHJveHksIFVwTGlua0NvbmZMb2NhbCB9IGZyb20gJy4uLy4uL3R5cGVzJztcbmltcG9ydCB7IHBhcnNlSW50ZXJ2YWwsIGlzT2JqZWN0LCBFcnJvckNvZGUsIGJ1aWxkVG9rZW4gfSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCB7XG4gIEVSUk9SX0NPREUsXG4gIFRPS0VOX0JBU0lDLFxuICBUT0tFTl9CRUFSRVIsXG4gIEhFQURFUlMsXG4gIEhUVFBfU1RBVFVTLFxuICBBUElfRVJST1IsXG4gIEhFQURFUl9UWVBFLFxuICBDSEFSQUNURVJfRU5DT0RJTkdcbn0gZnJvbSAnLi9jb25zdGFudHMnO1xuY29uc3QgTG9nZ2VyQXBpID0gcmVxdWlyZSgnLi9sb2dnZXInKTtcblxuY29uc3QgZW5jb2RlID0gZnVuY3Rpb24gKHRoaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudCh0aGluZykucmVwbGFjZSgvXiU0MC8sICdAJyk7XG59O1xuXG5jb25zdCBqc29uQ29udGVudFR5cGUgPSBIRUFERVJTLkpTT047XG5jb25zdCBjb250ZW50VHlwZUFjY2VwdCA9IGAke2pzb25Db250ZW50VHlwZX07YDtcblxuLyoqXG4gKiBKdXN0IGEgaGVscGVyIChgY29uZmlnW2tleV0gfHwgZGVmYXVsdGAgZG9lc24ndCB3b3JrIGJlY2F1c2Ugb2YgemVyb2VzKVxuICovXG5jb25zdCBzZXRDb25maWcgPSAoY29uZmlnLCBrZXksIGRlZik6IHN0cmluZyA9PiB7XG4gIHJldHVybiBfLmlzTmlsKGNvbmZpZ1trZXldKSA9PT0gZmFsc2UgPyBjb25maWdba2V5XSA6IGRlZjtcbn07XG5cbi8qKlxuICogSW1wbGVtZW50cyBTdG9yYWdlIGludGVyZmFjZVxuICogKHNhbWUgZm9yIHN0b3JhZ2UuanMsIGxvY2FsLXN0b3JhZ2UuanMsIHVwLXN0b3JhZ2UuanMpXG4gKi9cbmNsYXNzIFByb3h5U3RvcmFnZSBpbXBsZW1lbnRzIElQcm94eSB7XG4gIHB1YmxpYyBjb25maWc6IFVwTGlua0NvbmZMb2NhbDtcbiAgcHVibGljIGZhaWxlZF9yZXF1ZXN0czogbnVtYmVyO1xuICBwdWJsaWMgdXNlckFnZW50OiBzdHJpbmc7XG4gIHB1YmxpYyBjYTogc3RyaW5nIHwgdm9pZDtcbiAgcHVibGljIGxvZ2dlcjogTG9nZ2VyO1xuICBwdWJsaWMgc2VydmVyX2lkOiBzdHJpbmc7XG4gIHB1YmxpYyB1cmw6IGFueTtcbiAgcHVibGljIG1heGFnZTogbnVtYmVyO1xuICBwdWJsaWMgdGltZW91dDogbnVtYmVyO1xuICBwdWJsaWMgbWF4X2ZhaWxzOiBudW1iZXI7XG4gIHB1YmxpYyBmYWlsX3RpbWVvdXQ6IG51bWJlcjtcbiAgcHVibGljIGFnZW50X29wdGlvbnM6IGFueTtcbiAgLy8gRklYTUU6IHVwbmFtZSBpcyBhc3NpZ25lZCB0byBlYWNoIGluc3RhbmNlXG4gIC8vIEB0cy1pZ25vcmVcbiAgcHVibGljIHVwbmFtZTogc3RyaW5nO1xuICAvLyBGSVhNRTogcHJveHkgY2FuIGJlIGJvb2xlYW4gb3Igb2JqZWN0LCBzb21ldGhpbmcgc21lbGxzIGhlcmVcbiAgLy8gQHRzLWlnbm9yZVxuICBwdWJsaWMgcHJveHk6IHN0cmluZyB8IHZvaWQ7XG4gIC8vIEB0cy1pZ25vcmVcbiAgcHVibGljIGxhc3RfcmVxdWVzdF90aW1lOiBudW1iZXIgfCBudWxsO1xuICBwdWJsaWMgc3RyaWN0X3NzbDogYm9vbGVhbjtcblxuICAvKipcbiAgICogQ29uc3RydWN0b3JcbiAgICogQHBhcmFtIHsqfSBjb25maWdcbiAgICogQHBhcmFtIHsqfSBtYWluQ29uZmlnXG4gICAqL1xuICBwdWJsaW