Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ Example of `blacklisteddomains`: all the calls go through the proxy, except the

Note: `whitelisteddomains` and `blacklisteddomains` are two different approach and are not supposed to be used together. If both are present, `blacklisteddomains` will be ignored.

#### 👉 Upstream proxy

To forward all intercepted traffic through another proxy, start Appium with the `upstreamproxy` argument:

`appium server -ka 800 --use-plugins=appium-interceptor --plugin-appium-interceptor-upstreamproxy="http://proxy-host:3128" -pa /wd/hub`

### Capabilities

To control the plugin behavior, you can use the following capabilities:
Expand Down
6 changes: 5 additions & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ To enable network interception, configure your Appium session using the `appium:

👉 Once the proxy is successfully started (either automatically or manually), you can manage API mocking, recording, and sniffing using the commands detailed below.

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.
To route emulator traffic through another proxy, pass the Appium plugin argument `upstreamproxy` when starting the server, for example:

`appium server -ka 800 --use-plugins=appium-interceptor --plugin-appium-interceptor-upstreamproxy="http://proxy-host:3128" -pa /wd/hub`

All traffic from the emulator will then be forwarded to the specified upstream proxy.

### Mock Configuration
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.
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
},
"blacklisteddomains": {
"type": "string"
},
"upstreamproxy": {
"type": "string"
}
},
"title": "Appium interceptor plugin",
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ export interface IPluginArgs {
certdirectory: string;
whitelisteddomains: string[] | string;
blacklisteddomains: string[] | string;
upstreamproxy: string | null;
}

export const DefaultPluginArgs: IPluginArgs = {
certdirectory: path.join(__dirname, '..', 'certificate'),
whitelisteddomains: [],
blacklisteddomains: [],
upstreamproxy: null,
};
6 changes: 6 additions & 0 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ export class AppiumInterceptorPlugin extends BasePlugin {
? this.pluginArgs.blacklisteddomains
: parseJson(this.pluginArgs.blacklisteddomains),
);
const upstreamProxy =
typeof this.pluginArgs.upstreamproxy === 'string' &&
this.pluginArgs.upstreamproxy.trim().length > 0
? this.pluginArgs.upstreamproxy.trim()
: null;
const proxy = await setupProxyServer(
sessionId,
deviceUDID,
Expand All @@ -290,6 +295,7 @@ export class AppiumInterceptorPlugin extends BasePlugin {
currentGlobalProxy,
whitelistedDomains,
blacklistedDomains,
upstreamProxy,
);

await configureWifiProxy(adb, deviceUDID, realDevice, proxy.options);
Expand Down
7 changes: 4 additions & 3 deletions src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface ProxyOptions {
certificatePath: string;
port: number;
ip: string;
upstreamProxy?: string | null;
previousConfig?: ProxyOptions;
whitelistedDomains?: string[];
blacklistedDomains?: string[];
Expand Down Expand Up @@ -271,15 +272,15 @@ export class Proxy {
}

private async setupProxyChainUpstream(): Promise<void> {
const upstreamEnv = process.env.UPSTREAM_PROXY || process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
if (!upstreamEnv) return;
const upstreamProxy = this.options.upstreamProxy?.toString().trim();
if (!upstreamProxy) return;
try {
const proxyChain = require('proxy-chain');
if (!proxyChain || !proxyChain.anonymizeProxy) {
log.warn('proxy-chain not available; skipping upstream setup');
return;
}
const localUrl: string = await proxyChain.anonymizeProxy(upstreamEnv);
const localUrl: string = await proxyChain.anonymizeProxy(upstreamProxy);
this.proxyChainLocalUrl = localUrl;
this.closeProxyChain = proxyChain.closeAnonymizedProxy;
this.upstreamAgent = new ProxyAgent({ getProxyForUrl: () => localUrl });
Expand Down
15 changes: 13 additions & 2 deletions src/utils/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,23 @@ export async function setupProxyServer(
certDirectory: string,
currentWifiProxyConfig?: ProxyOptions,
whitelistedDomains?: string[],
blacklistedDomains?: string[]
blacklistedDomains?: string[],
upstreamProxy?: string | null,
) {
const certificatePath = prepareCertificate(sessionId, certDirectory);
const port = await getPort();
const _ip = isRealDevice ? 'localhost' : ip.address('public', 'ipv4');
const proxy = new Proxy({ deviceUDID, sessionId, certificatePath, port, ip: _ip, previousConfig: currentWifiProxyConfig, whitelistedDomains, blacklistedDomains});
const proxy = new Proxy({
deviceUDID,
sessionId,
certificatePath,
port,
ip: _ip,
previousConfig: currentWifiProxyConfig,
whitelistedDomains,
blacklistedDomains,
upstreamProxy: upstreamProxy ?? null,
});
await proxy.start();
if (!proxy.isStarted()) {
throw new Error('Unable to start the proxy server');
Expand Down