allproxy
Version:
AllProxy: MITM HTTP Debugging Tool.
207 lines • 9.47 kB
JavaScript
;
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