Skip to content

Commit 7ed5e05

Browse files
authored
Upstream proxy (#74)
1 parent b73d8a2 commit 7ed5e05

File tree

4 files changed

+64
-29
lines changed

4 files changed

+64
-29
lines changed

docs/commands.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Create the appium session by passing `appium:intercept : true` option in the desired capability. Once the session is successfully created, tests can manage the api mocking using below commands.
44

5+
To route emulator traffic through another proxy, set one of the environment variables UPSTREAM_PROXY, HTTPS_PROXY, or HTTP_PROXY. All traffic from the emulator will then be forwarded to the specified upstream proxy.
6+
57
### Mock Configuration
68
Mock configuration is a json object that defines the specification for filtering and applying various updates to the api request and below is the structure for the config object.
79

package-lock.json

Lines changed: 19 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@
122122
"queue-typescript": "^1.0.1",
123123
"regex-parser": "^2.3.1",
124124
"uuid": "^11.1.0",
125-
"yargs": "^18.0.0"
125+
"yargs": "^18.0.0",
126+
"proxy-chain": "2.5.9",
127+
"proxy-agent": "6.5.0"
126128
}
127129
}

src/proxy.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { MockConfig, RecordConfig, RequestInfo, SniffConfig } from './types';
22
import { Proxy as HttpProxy, IContext, IProxyOptions } from 'http-mitm-proxy';
3+
import { ProxyAgent } from 'proxy-agent';
34
import { v4 as uuid } from 'uuid';
45
import {
56
addDefaultMocks,
@@ -38,6 +39,9 @@ export class Proxy {
3839

3940
private readonly httpProxy: HttpProxy;
4041
private readonly recordingManager: RecordingManager;
42+
private proxyChainLocalUrl?: string;
43+
private closeProxyChain?: (url: string, closeConnections?: boolean) => Promise<void>;
44+
private upstreamAgent?: any;
4145

4246
public isStarted(): boolean {
4347
return this._started;
@@ -87,6 +91,13 @@ export class Proxy {
8791
forceSNI: true,
8892
};
8993

94+
await this.setupProxyChainUpstream();
95+
if (this.upstreamAgent) {
96+
proxyOptions.httpAgent = this.upstreamAgent;
97+
proxyOptions.httpsAgent = this.upstreamAgent;
98+
log.info('Routing traffic via proxy-chain upstream agent');
99+
}
100+
90101
this.httpProxy.onRequest(
91102
RequestInterceptor((requestData: any) => {
92103
for (const sniffer of this.sniffers.values()) {
@@ -112,6 +123,14 @@ export class Proxy {
112123

113124
public async stop(): Promise<void> {
114125
this.httpProxy.close();
126+
if (this.proxyChainLocalUrl && this.closeProxyChain) {
127+
try {
128+
await this.closeProxyChain(this.proxyChainLocalUrl, true);
129+
log.info('proxy-chain anonymized proxy closed');
130+
} catch (e) {
131+
log.warn(`Failed to close proxy-chain anonymized proxy: ${String(e)}`);
132+
}
133+
}
115134
}
116135

117136
public addMock(mockConfig: MockConfig): string {
@@ -193,6 +212,26 @@ export class Proxy {
193212
}
194213
}
195214

215+
private async setupProxyChainUpstream(): Promise<void> {
216+
const upstreamEnv = process.env.UPSTREAM_PROXY || process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
217+
if (!upstreamEnv) return;
218+
try {
219+
const proxyChain = require('proxy-chain');
220+
if (!proxyChain || !proxyChain.anonymizeProxy) {
221+
log.warn('proxy-chain not available; skipping upstream setup');
222+
return;
223+
}
224+
const localUrl: string = await proxyChain.anonymizeProxy(upstreamEnv);
225+
this.proxyChainLocalUrl = localUrl;
226+
this.closeProxyChain = proxyChain.closeAnonymizedProxy;
227+
this.upstreamAgent = new ProxyAgent({ getProxyForUrl: () => localUrl });
228+
log.info(`proxy-chain upstream initialized at ${localUrl}`);
229+
} catch (e) {
230+
log.error(`Failed to initialize proxy-chain upstream: ${String(e)}`);
231+
}
232+
}
233+
234+
196235
private async findMatchingMocks(ctx: IContext): Promise<MockConfig[]> {
197236
const request = ctx.clientToProxyRequest;
198237
if (!request.headers?.host || !request.url) {
@@ -249,4 +288,4 @@ export class Proxy {
249288
next();
250289
}
251290
}
252-
}
291+
}

0 commit comments

Comments
 (0)