UNPKG

whistle

Version:

HTTP, HTTP2, HTTPS, Websocket debugging proxy

200 lines (176 loc) 5.88 kB
var cp = require('child_process'); var program = require('starting'); var util = require('util'); var os = require('os'); var fs = require('fs'); var config = require('../lib/config'); var common = require('../lib/util/common'); var colors = require('colors/safe'); var path = require('path'); var extend = require('extend'); var createHmac = require('crypto').createHmac; var joinIpPort = common.joinIpPort; var DEFAULT_OPTIONS = { host: '127.0.0.1', port: 8899 }; exports.joinIpPort = joinIpPort; exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS; /*eslint no-console: "off"*/ var CHECK_RUNNING_CMD = process.platform === 'win32' ? 'tasklist /fi "PID eq %s" | findstr /i "node.exe"' : 'ps -f -p %s | grep "node"'; var isWin = process.platform === 'win32'; function isRunning(pid, callback) { pid ? cp.exec(util.format(CHECK_RUNNING_CMD, pid), function (err, stdout, stderr) { callback(!err && !!stdout.toString().trim()); }) : callback(); } exports.isRunning = isRunning; function getIpList() { var ipList = []; var ifaces = os.networkInterfaces(); Object.keys(ifaces).forEach(function(ifname) { ifaces[ifname].forEach(function (iface) { if (iface.family == 'IPv4' || iface.family === 4) { ipList.push(iface.address); } }); }); var index = ipList.indexOf('127.0.0.1'); if (index !== -1) { ipList.splice(index, 1); } ipList.unshift('127.0.0.1'); return ipList; } function error(msg) { console.log(colors.red(msg)); } function warn(msg) { console.log(colors.yellow(msg)); } function info(msg) { console.log(colors.green(msg)); } exports.error = error; exports.warn = warn; exports.info = info; function showKillError() { error('[!] Cannot kill ' + config.appName + ' owned by root'); info('[i] Try to run command ' + (isWin ? 'as an administrator' : 'with sudo')); } exports.showKillError = showKillError; function showUsage(isRunning, options, restart) { var rcConf; if (isRunning) { if (restart) { showKillError(); } else { warn('[!] ' + config.appName + '@' + config.version + ' is running'); } } else { rcConf = common.readWhistleRc(options); if (rcConf) { var rcStr = JSON.stringify(rcConf); if (rcStr.length > 30) { rcStr = rcStr.substring(0, 27) + '...'; } info('[i] Load configuration from ~/.whistlerc: ' + rcStr); } info('[i] ' + config.appName + '@' + config.version + (restart ? ' restarted' : ' started')); } options = options ? extend({}, rcConf, options) : rcConf; options = formatOptions(options); var port = /^\d+$/.test(options.port) && options.port > 0 ? options.port : config.port; var list = common.isString(options.host) ? [options.host] : getIpList(); var oneIp = list.length === 1; var index = 0; if (!oneIp) { info('[i] ' + (++index) + '. Use your device to visit these URLs and note which one works:'); info(list.map(function(ip) { return ' http://' + colors.bold(joinIpPort(ip, port != 80 && port)) + '/'; }).join('\n')); warn(' Note: If none are accessible, check your firewall settings'); warn(' For help, see ' + colors.bold('https://github.com/avwo/whistle')); } info('[i] ' + (++index) + '. Set your device\'s HTTP PROXY to ' + colors.bold((oneIp ? 'IP(' + list[0] + ')' : 'the working IP') + ' & PORT(' + port + ')')); info('[i] ' + (++index) + '. Open ' + colors.bold('Chrome') + ' and visit ' + colors.bold('http://' + (options.localUIHost || config.localUIHost) + '/') + ' to begin'); var bypass = program.init; if (bypass == null) { return; } return { host: options.host || '127.0.0.1', port: port, bypass: typeof bypass === 'string' ? bypass : undefined }; } exports.showUsage = showUsage; function getDataDir() { return path.resolve(common.getHomedir(), '.startingAppData'); } function formatOptions(options) { if (!options || (!/^(?:([\w.-]+):)?([1-9]\d{0,4})$/.test(options.port) && !/^\[([\w.:]+)\]:([1-9]\d{0,4})$/.test(options.port))) { return options; } options.host = options.host || RegExp.$1; options.port = parseInt(RegExp.$2, 10); return options; } function getConfigFile(storage) { var dataDir = getDataDir(); return path.join(dataDir, encodeURIComponent('#' + (storage ? storage + '#' : ''))); } exports.getConfigFile = getConfigFile; exports.formatOptions = formatOptions; function readConfig(storage) { var configFile = getConfigFile(storage); var conf = common.readJsonSync(configFile); conf && formatOptions(conf.options); return conf; } function readConfigList() { var dataDir = getDataDir(); var result = []; try { fs.readdirSync(dataDir).forEach(function(dir) { try { dir = decodeURIComponent(dir); var lastIndex = dir.length - 1; if (dir[0] === '#' && dir[lastIndex] === '#') { dir = dir.substring(1, lastIndex || 1); var config = readConfig(dir); if (config && config.pid && config.options) { result.push(config); } } } catch(e) {} }); } catch(e) {} return result; } exports.readConfig = readConfig; exports.readConfigList = readConfigList; exports.getHash = function(str) { var hmac = createHmac('sha256', '5b6af7b9884e1165'); return hmac.update(str).digest('hex'); }; exports.getDefaultPort = function () { var conf = readConfig(); conf = conf && conf.options; var port = conf && conf.port; return port > 0 ? port : 8899; }; exports.getBody = function (res, callback) { var resBody; res.on('data', function(data) { resBody = resBody ? Buffer.concat([resBody, data]) : data; }); res.on('end', function() { if (res.statusCode != 200) { callback('Bad response (' + res.statusCode + ')'); } else { callback(null, JSON.parse(resBody + '')); } }); };