Server IP : 85.214.239.14 / Your IP : 18.220.144.56 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Mon Sep 30 15:36:27 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/2/task/2/root/usr/lib/node_modules/pm2/node_modules/@pm2/agent/src/ |
Upload File : |
'use strict' const os = require('os') const crypto = require('crypto') const dayjs = require('dayjs') const url = require('url') const ProxyAgent = require('proxy-agent') const cst = require('../constants.js') const interfaceType = { v4: { default: '127.0.0.1', family: 'IPv4' }, v6: { default: '::1', family: 'IPv6' } } /** * Search for public network adress * @param {String} type the type of network interface, can be either 'v4' or 'v6' */ const retrieveAddress = (type) => { let interfce = interfaceType[type] let ret = interfce.default let interfaces = os.networkInterfaces() Object.keys(interfaces).forEach(function (el) { interfaces[el].forEach(function (el2) { if (!el2.internal && el2.family === interfce.family) { ret = el2.address } }) }) return ret } /** * Simple cache implementation * * @param {Object} opts cache options * @param {Function} opts.miss function called when a key isn't found in the cache */ class Cache { constructor (opts) { this._cache = {} this._miss = opts.miss this._ttl_time = opts.ttl this._ttl = {} if (opts.ttl) { this._worker = setInterval(this.worker.bind(this), 1000) } } worker () { let keys = Object.keys(this._ttl) for (let i = 0; i < keys.length; i++) { let key = keys[i] let value = this._ttl[key] if (dayjs().isAfter(value)) { delete this._cache[key] delete this._ttl[key] } } } /** * Get a value from the cache * * @param {String} key */ get (key) { if (!key) return null let value = this._cache[key] if (value) return value value = this._miss(key) if (value) { this.set(key, value) } return value } /** * Set a value in the cache * * @param {String} key * @param {Mixed} value */ set (key, value) { if (!key || !value) return false this._cache[key] = value if (this._ttl_time) { this._ttl[key] = dayjs().add(this._ttl_time, 'seconds') } return true } reset () { this._cache = null this._cache = {} this._ttl = null this._ttl = {} } } /** * StackTraceParser is used to parse callsite from stacktrace * and get from FS the context of the error (if available) * * @param {Cache} cache cache implementation used to query file from FS and get context */ class StackTraceParser { constructor (opts) { this._cache = opts.cache this._context_size = opts.context } isAbsolute (path) { if (process.platform === 'win32') { // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56 let splitDeviceRe = /^([a-zA-Z]:|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)?([\\/])?([\s\S]*?)$/ let result = splitDeviceRe.exec(path) let device = result[1] || '' let isUnc = Boolean(device && device.charAt(1) !== ':') // UNC paths are always absolute return Boolean(result[2] || isUnc) } else { return path.charAt(0) === '/' } } parse (stack) { if (!stack || stack.length === 0) return false for (var i = 0, len = stack.length; i < len; i++) { var callsite = stack[i] // avoid null values if (typeof callsite !== 'object') continue if (!callsite.file_name || !callsite.line_number) continue var type = this.isAbsolute(callsite.file_name) || callsite.file_name[0] === '.' ? 'user' : 'core' // only use the callsite if its inside user space if (!callsite || type === 'core' || callsite.file_name.indexOf('node_modules') > -1 || callsite.file_name.indexOf('vxx') > -1) { continue } // get the whole context (all lines) and cache them if necessary var context = this._cache.get(callsite.file_name) var source = [] if (context && context.length > 0) { // get line before the call var preLine = callsite.line_number - this._context_size - 1 var pre = context.slice(preLine > 0 ? preLine : 0, callsite.line_number - 1) if (pre && pre.length > 0) { pre.forEach(function (line) { source.push(line.replace(/\t/g, ' ')) }) } // get the line where the call has been made if (context[callsite.line_number - 1]) { source.push(context[callsite.line_number - 1].replace(/\t/g, ' ').replace(' ', '>>')) } // and get the line after the call var postLine = callsite.line_number + this._context_size var post = context.slice(callsite.line_number, postLine) if (post && post.length > 0) { post.forEach(function (line) { source.push(line.replace(/\t/g, ' ')) }) } } return { context: source.length > 0 ? source.join('\n') : 'cannot retrieve source context', callsite: [ callsite.file_name, callsite.line_number ].join(':') } } return false } attachContext (error) { if (!error) return error // if pmx attached callsites we can parse them to retrieve the context if (typeof (error.stackframes) === 'object') { let result = this.parse(error.stackframes) // no need to send it since there is already the stacktrace delete error.stackframes delete error.__error_callsites if (result) { error.callsite = result.callsite error.context = result.context } } // if the stack is here we can parse it directly from the stack string // only if the context has been retrieved from elsewhere if (typeof error.stack === 'string' && !error.callsite) { let siteRegex = /(\/[^\\\n]*)/g let tmp let stack = [] // find matching groups while ((tmp = siteRegex.exec(error.stack))) { stack.push(tmp[1]) } // parse each callsite to match the format used by the stackParser stack = stack.map((callsite) => { // remove the trailing ) if present if (callsite[callsite.length - 1] === ')') { callsite = callsite.substr(0, callsite.length - 1) } let location = callsite.split(':') return location.length < 3 ? callsite : { file_name: location[0], line_number: parseInt(location[1]) } }) let finalCallsite = this.parse(stack) if (finalCallsite) { error.callsite = finalCallsite.callsite error.context = finalCallsite.context } } return error } } // EWMA = ExponentiallyWeightedMovingAverage from // https://github.com/felixge/node-measured/blob/master/lib/util/ExponentiallyMovingWeightedAverage.js // Copyright Felix Geisendörfer <felix@debuggable.com> under MIT license class EWMA { constructor () { this._timePeriod = 60000 this._tickInterval = 5000 this._alpha = 1 - Math.exp(-this._tickInterval / this._timePeriod) this._count = 0 this._rate = 0 this._interval = setInterval(_ => { this.tick() }, this._tickInterval) this._interval.unref() } update (n) { this._count += n || 1 } tick () { let instantRate = this._count / this._tickInterval this._count = 0 this._rate += (this._alpha * (instantRate - this._rate)) } rate (timeUnit) { return (this._rate || 0) * timeUnit } } class Cipher { static get CIPHER_ALGORITHM () { return 'aes256' } /** * Decipher data using 256 bits key (AES) * @param {Hex} data input data * @param {String} key 256 bits key * @return {Object} deciphered data parsed as json object */ static decipherMessage (msg, key) { try { let decipher = crypto.createDecipher(Cipher.CIPHER_ALGORITHM, key) let decipheredMessage = decipher.update(msg, 'hex', 'utf8') decipheredMessage += decipher.final('utf8') return JSON.parse(decipheredMessage) } catch (err) { console.error(err) return null } } /** * Cipher data using 256 bits key (AES) * @param {String} data input data * @param {String} key 256 bits key * @return {Hex} ciphered data */ static cipherMessage (data, key) { try { // stringify if not already done (fail safe) if (typeof data !== 'string') { data = JSON.stringify(data) } let cipher = crypto.createCipher(Cipher.CIPHER_ALGORITHM, key) let cipheredData = cipher.update(data, 'utf8', 'hex') cipheredData += cipher.final('hex') return cipheredData } catch (err) { console.error(err) } } } /** * HTTP wrapper */ class HTTPClient { /** * Return native module (HTTP/HTTPS) * @param {String} url */ getModule (url) { return url.match(/https:\/\//) ? require('https') : require('http') } /** * Send an HTTP request and return data or error if status > 200 * @param {Object} opts * @param {String} opts.url * @param {String} opts.method * @param {Object} [opts.data] * @param {Object} [opts.headers] * @param {Function} cb invoked with <err, body> */ open (opts, cb) { const http = this.getModule(opts.url) const parsedUrl = url.parse(opts.url) let data = null const options = { hostname: parsedUrl.hostname, path: parsedUrl.path, port: parsedUrl.port, method: opts.method, headers: opts.headers, agent: cst.PROXY ? new ProxyAgent(cst.PROXY) : undefined } if (opts.data) { data = JSON.stringify(opts.data) options.headers = Object.assign({ 'Content-Type': 'application/json', 'Content-Length': data.length }, opts.headers) } const req = http.request(options, (res) => { let body = '' res.setEncoding('utf8') res.on('data', (chunk) => { body += chunk.toString() }) res.on('end', () => { try { let jsonData = JSON.parse(body) return cb(null, jsonData) } catch (err) { return cb(err) } }) }) req.on('error', cb) if (data) { req.write(data) } req.end() } } module.exports = { EWMA: EWMA, Cache: Cache, StackTraceParser: StackTraceParser, serialize: require('fclone'), network: { getIP: retrieveAddress, v4: retrieveAddress('v4'), v6: retrieveAddress('v6') }, HTTPClient: HTTPClient, Cipher: Cipher, clone: require('fclone') }