UNPKG

allproxy

Version:

AllProxy: MITM HTTP Debugging Tool.

207 lines 9.47 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.windowsKill = exports.windowsClose = exports.waitForExit = exports.listRunningProcesses = exports.spawnToResult = void 0; const _ = __importStar(require("lodash")); const path = __importStar(require("path")); const child_process_1 = require("child_process"); const promise_1 = require("./promise"); // Spawn a command, and resolve with all output as strings when it terminates function spawnToResult(command, args = [], options = {}, inheritOutput = false) { return new Promise((resolve, reject) => { const childProc = (0, child_process_1.spawn)(command, args, Object.assign({ stdio: 'pipe' }, options)); const { stdout, stderr } = childProc; const stdoutData = []; stdout.on('data', (d) => stdoutData.push(d)); const stderrData = []; stderr.on('data', (d) => stderrData.push(d)); if (inheritOutput) { stdout.pipe(process.stdout); stderr.pipe(process.stderr); } childProc.once('error', reject); childProc.once('close', (code) => { // Note that we do _not_ check the error code, we just return it resolve({ exitCode: code, stdout: Buffer.concat(stdoutData).toString(), stderr: Buffer.concat(stderrData).toString() }); }); }); } exports.spawnToResult = spawnToResult; ; const getOutputLines = (stdout) => stdout .split('\n') .map(line => line.trim()) .filter(line => !!line); /** * Attempts to get a list of pid + command + binary + args for every process running * on the machine owned by the current user (not *all* processes!). * * This is best efforts, due to the lack of guarantees on 'ps'. Notably args may be * undefined, if we're unable to work out which part of the command is the command * and which is args. */ function listRunningProcesses() { return __awaiter(this, void 0, void 0, function* () { if (process.platform !== 'win32') { const [psCommResult, psFullResult] = yield Promise.all([ spawnToResult('ps', ['xo', 'pid=,comm=']), spawnToResult('ps', ['xo', 'pid=,command=']), // Prints pid + command + args ]); if (psCommResult.exitCode !== 0 || psFullResult.exitCode !== 0) { throw new Error(`Could not list running processes, ps exited with code ${psCommResult.exitCode || psFullResult.exitCode}`); } const processes = getOutputLines(psCommResult.stdout).map(line => { const firstSpaceIndex = line.indexOf(' '); if (firstSpaceIndex === -1) { throw new Error('No space in PS output'); } const pid = parseInt(line.substring(0, firstSpaceIndex), 10); const command = line.substring(firstSpaceIndex + 1); return { pid, command }; }); const processesByPid = _.keyBy(processes, p => p.pid); getOutputLines(psFullResult.stdout).forEach(line => { const firstSpaceIndex = line.indexOf(' '); if (firstSpaceIndex === -1) throw new Error('No space in PS output'); const pid = parseInt(line.substring(0, firstSpaceIndex), 10); const binAndArgs = line.substring(firstSpaceIndex + 1); const proc = processesByPid[pid]; if (!proc) return; if (proc.command.includes(path.sep)) { // Proc.command is a fully qualified path (as on Mac) if (binAndArgs.startsWith(proc.command)) { proc.bin = proc.command; proc.args = binAndArgs.substring(proc.bin.length + 1); } } else { // Proc.command is a plain binary name (as on Linux) const commandMatch = binAndArgs.match( // Best guess: first instance of the command name followed by a space new RegExp(_.escapeRegExp(proc.command) + '( |$)')); if (!commandMatch) { // We can't work out which bit is the command, don't set args, treat // the whole command line as the command and give up proc.command = binAndArgs; return; } const commandIndex = commandMatch.index; proc.bin = binAndArgs.substring(0, commandIndex + proc.command.length); proc.args = binAndArgs.substring(proc.bin.length + 1); } }); return processes; } else { const wmicOutput = yield spawnToResult('wmic', [ 'Process', 'Get', 'processid,commandline' ]); if (wmicOutput.exitCode !== 0) { throw new Error(`WMIC exited with unexpected error code ${wmicOutput.exitCode}`); } return getOutputLines(wmicOutput.stdout) .slice(1) // Skip the header line .filter((line) => line.includes(' ')) // Skip lines where the command line isn't available (just pids) .map((line) => { const pidIndex = line.lastIndexOf(' ') + 1; const pid = parseInt(line.substring(pidIndex), 10); const command = line.substring(0, pidIndex).trim(); const bin = command[0] === '"' ? command.substring(1, command.substring(1).indexOf('"') + 1) : command.substring(0, command.indexOf(' ')); const args = command[0] === '"' ? command.substring(bin.length + 3) : command.substring(bin.length + 1); return { pid, command, bin, args }; }); } }); } exports.listRunningProcesses = listRunningProcesses; function waitForExit(pid, timeout = 5000) { return __awaiter(this, void 0, void 0, function* () { const startTime = Date.now(); while (true) { try { process.kill(pid, 0); // Didn't throw. If we haven't timed out, check again after 250ms: if (Date.now() - startTime > timeout) { throw new Error("Process did not exit before timeout"); } yield (0, promise_1.delay)(250); } catch (e) { if (e.code === 'ESRCH') { return; // Process doesn't exist! We're done. } else throw e; } } }); } exports.waitForExit = waitForExit; // Cleanly close (simulate closing the main window) on a specific windows process function windowsClose(pid) { return __awaiter(this, void 0, void 0, function* () { yield spawnToResult('taskkill', [ '/pid', pid.toString(), ]); }); } exports.windowsClose = windowsClose; // Harshly kill a windows process by some WMIC matching string e.g. // "processId=..." or "CommandLine Like '%...%'" function windowsKill(processMatcher) { return __awaiter(this, void 0, void 0, function* () { yield spawnToResult('wmic', [ 'Path', 'win32_process', 'Where', processMatcher, 'Call', 'Terminate' ], {}, true); }); } exports.windowsKill = windowsKill; //# sourceMappingURL=process-management.js.map