diff --git a/test/interception-proxy/InterceptionContext.ts b/test/interception-proxy/InterceptionContext.ts index 26ea059d4..2ce6a5802 100644 --- a/test/interception-proxy/InterceptionContext.ts +++ b/test/interception-proxy/InterceptionContext.ts @@ -1,4 +1,3 @@ -import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; import { ClientMethods, createTransformInterceptedMessageParamsDTO, @@ -19,6 +18,7 @@ import { ProxyMessage } from './Proxy'; import { ProxyServer } from './ProxyServer'; import { webSocketMessageDataLoggingDescription } from './WebSocketMessageData'; import { TypedJSONRPCServerAndClient, JSONRPCClient, JSONRPCServer, JSONRPCServerAndClient } from 'json-rpc-2.0'; +import { MitmproxyLauncher } from './MitmproxyLauncher'; type ServerParams = { controlServerConnection: ControlServerConnection; @@ -29,7 +29,7 @@ export class InterceptionContext { proxyServer: ProxyServer | null = null; private jsonRPC: TypedJSONRPCServerAndClient; private interceptedMessagesQueue = new InterceptedMessagesQueue(); - private onMitmproxyReady: (() => void) | null = null; + private mitmproxyLauncher: MitmproxyLauncher | null = null; constructor() { this.jsonRPC = new JSONRPCServerAndClient( @@ -42,7 +42,7 @@ export class InterceptionContext { this.jsonRPC.addMethod('startInterception', (params, serverParams) => this.startInterception(params, serverParams.controlServerConnection), ); - this.jsonRPC.addMethod('mitmproxyReady', () => this.onMitmproxyReady?.()); + this.jsonRPC.addMethod('mitmproxyReady', () => this.mitmproxyLauncher?.onMitmproxyReady()); } onControlWebSocketMessage(data: string, controlServerConnection: ControlServerConnection) { @@ -52,81 +52,9 @@ export class InterceptionContext { async startInterception(params: InterceptionModeDTO, controlServerConnection: ControlServerConnection): Promise<{}> { this.controlServer!.setActiveConnection(controlServerConnection); - - console.log('starting mitmdump, mode', params.mode); - - let mitmdumpBinary: string; - let mitmdumpMode: string | null; - - // TODO this is currently written on the assumption that darwin means running locally and linux means running in GitHub action; sort out so that you can run (locally or on CI) on (macOS or Linux) - switch (process.platform) { - case 'darwin': - mitmdumpBinary = 'mitmdump'; - switch (params.mode) { - case 'local': - mitmdumpMode = `local:${params.pid}`; - break; - case 'proxy': - mitmdumpMode = null; - break; - } - break; - case 'linux': - // Currently we expect that you set up the iptables rules externally - mitmdumpBinary = '/opt/pipx_bin/mitmdump'; - switch (params.mode) { - case 'local': - mitmdumpMode = 'transparent'; - break; - case 'proxy': - mitmdumpMode = null; - break; - } - break; - default: - throw new Error(`Don’t know how to set up mitmdump interception for platform ${process.platform}`); - } - - // sounds like we don’t need to explicitly stop this when we stop the current process: https://nodejs.org/api/child_process.html#optionsdetached - const mitmdump = spawn(mitmdumpBinary, [ - '--set', - 'stream_large_bodies=1', - ...(mitmdumpMode === null ? [] : ['--mode', mitmdumpMode]), - '-s', - 'test/mitmproxy_addon_2.py', - '--set', - // "full request URL with response status code and HTTP headers" (the default truncates the URL) - 'flow_detail=2', - ]); - - const formatMitmdumpOutput = (source: string, data: Buffer) => { - const text = data.toString('utf-8'); - const lines = text.split('\n'); - return lines.map((line) => `mitmdump ${source}: ${line}`).join('\n'); - }; - - mitmdump.stdout.on('data', (data) => { - console.log(formatMitmdumpOutput('stdout', data)); - }); - - mitmdump.stderr.on('data', (data) => { - console.log(formatMitmdumpOutput('stderr', data)); - }); - - console.log(`Waiting for mitmdump to start`); - - let resolveResult: () => void; - const result = new Promise<{}>((resolve) => { - resolveResult = () => resolve({}); - }); - - this.onMitmproxyReady = () => { - this.onMitmproxyReady = null; - console.log(`mitmdump has started`); - resolveResult(); - }; - - return result; + this.mitmproxyLauncher = new MitmproxyLauncher(); + await this.mitmproxyLauncher.launch(params); + return {}; } private handleTransformInterceptedMessageResponse( diff --git a/test/interception-proxy/MitmproxyLauncher.ts b/test/interception-proxy/MitmproxyLauncher.ts new file mode 100644 index 000000000..9f3ce88c9 --- /dev/null +++ b/test/interception-proxy/MitmproxyLauncher.ts @@ -0,0 +1,87 @@ +import { spawn } from 'child_process'; +import { InterceptionModeDTO } from './ControlRPC'; + +export class MitmproxyLauncher { + private _onMitmproxyReady: (() => void) | null = null; + + async launch(mode: InterceptionModeDTO) { + console.log('starting mitmdump, mode', mode); + + let mitmdumpBinary: string; + let mitmdumpMode: string | null; + + // TODO this is currently written on the assumption that darwin means running locally and linux means running in GitHub action; sort out so that you can run (locally or on CI) on (macOS or Linux) + switch (process.platform) { + case 'darwin': + mitmdumpBinary = 'mitmdump'; + switch (mode.mode) { + case 'local': + mitmdumpMode = `local:${mode.pid}`; + break; + case 'proxy': + mitmdumpMode = null; + break; + } + break; + case 'linux': + // Currently we expect that you set up the iptables rules externally + mitmdumpBinary = '/opt/pipx_bin/mitmdump'; + switch (mode.mode) { + case 'local': + mitmdumpMode = 'transparent'; + break; + case 'proxy': + mitmdumpMode = null; + break; + } + break; + default: + throw new Error(`Don’t know how to set up mitmdump interception for platform ${process.platform}`); + } + + // sounds like we don’t need to explicitly stop this when we stop the current process: https://nodejs.org/api/child_process.html#optionsdetached + const mitmdump = spawn(mitmdumpBinary, [ + '--set', + 'stream_large_bodies=1', + ...(mitmdumpMode === null ? [] : ['--mode', mitmdumpMode]), + '-s', + 'test/mitmproxy_addon_2.py', + '--set', + // "full request URL with response status code and HTTP headers" (the default truncates the URL) + 'flow_detail=2', + ]); + + const formatMitmdumpOutput = (source: string, data: Buffer) => { + const text = data.toString('utf-8'); + const lines = text.split('\n'); + return lines.map((line) => `mitmdump ${source}: ${line}`).join('\n'); + }; + + mitmdump.stdout.on('data', (data) => { + console.log(formatMitmdumpOutput('stdout', data)); + }); + + mitmdump.stderr.on('data', (data) => { + console.log(formatMitmdumpOutput('stderr', data)); + }); + + console.log(`Waiting for mitmdump to start`); + + let resolveResult: () => void; + const result = new Promise<{}>((resolve) => { + resolveResult = () => resolve({}); + }); + + this._onMitmproxyReady = () => { + this._onMitmproxyReady = null; + console.log(`mitmdump has started`); + resolveResult(); + }; + + return result; + } + + onMitmproxyReady() { + this._onMitmproxyReady?.(); + } +}