Skip to content

Commit de8cb8b

Browse files
authored
fix: domains whitelist and blacklist (#80)
* WhiteBlackList * Readme * bump up version
1 parent 4ecd28d commit de8cb8b

7 files changed

Lines changed: 98 additions & 4 deletions

File tree

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ If you need to use a custom certificate, it can be done by passing `certdirector
3030

3131
Please keep the same directory structure as the existing certificate folder.
3232

33+
## Whitelist/Blacklist
34+
35+
If you need to limit the calls going through the proxy, it can be done by passing `whitelisteddomains` and `blacklisteddomains` as an argument of the plugin:
36+
37+
Example of `whitelisteddomains`: only the calls for the domain `*.mydomain.com` got through the proxy.
38+
39+
`appium server -ka 800 --use-plugins=appium-interceptor --plugin-appium-interceptor-whitelisteddomains='["*.mydomain.com"]' -pa /wd/hub`
40+
41+
Example of `blacklisteddomains`: all the calls go through the proxy, except the calls for `*.otherdomain.com`.
42+
43+
`appium server -ka 800 --use-plugins=appium-interceptor --plugin-appium-interceptor-blacklisteddomains='["*.otherdomain.com"]' -pa /wd/hub`
44+
45+
Note: `whitelisteddomains` and `blacklisteddomains` are two different approach and are not supposed to be used together. If both are present, `blacklisteddomains` will be ignored.
46+
3347
## what does this plugin do?
3448

3549
For every appium session, interceptor plugin will start a proxy server and updates the device proxy settings to pass all network traffic to proxy server. Mocking is disabled by default and can be enabled from the test by passing `appium:intercept : true` in the desired capability while creating a new appium session.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@
7878
"properties": {
7979
"certdirectory": {
8080
"type": "string"
81+
},
82+
"whitelisteddomains": {
83+
"type": "string"
84+
},
85+
"blacklisteddomains": {
86+
"type": "string"
8187
}
8288
},
8389
"title": "Appium interceptor plugin",

src/interfaces.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import path from 'path';
22

33
export interface IPluginArgs {
44
certdirectory: string;
5+
whitelisteddomains: string[] | string;
6+
blacklisteddomains: string[] | string;
57
}
68

79
export const DefaultPluginArgs: IPluginArgs = {
810
certdirectory: path.join(__dirname, '..', 'certificate'),
11+
whitelisteddomains: [],
12+
blacklisteddomains: [],
913
};

src/plugin.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
getAdbReverseTunnels,
2020
removeReverseTunnel,
2121
} from './utils/adb';
22-
import { cleanUpProxyServer, sanitizeMockConfig, setupProxyServer } from './utils/proxy';
22+
import { cleanUpProxyServer, parseJson, sanitizeMockConfig, setupProxyServer } from './utils/proxy';
2323
import proxyCache from './proxy-cache';
2424
import logger from './logger';
2525
import log from './logger';
@@ -112,6 +112,19 @@ export class AppiumInterceptorPlugin extends BasePlugin {
112112
const interceptFlag = mergedCaps['appium:intercept'];
113113
const { deviceUDID, platformName } = response.value[1];
114114
const certDirectory = this.pluginArgs.certdirectory;
115+
const whitelistedDomains =
116+
((domains) =>
117+
Array.isArray(domains) ? domains : typeof domains === 'string' ? [domains] : [])(
118+
typeof this.pluginArgs.whitelisteddomains === 'string'
119+
? parseJson(this.pluginArgs.whitelisteddomains)
120+
: this.pluginArgs.whitelisteddomains
121+
);
122+
const blacklistedDomains =
123+
((domains) => (Array.isArray(domains) ? domains : typeof domains === 'string' ? [domains] : []))(
124+
typeof this.pluginArgs.blacklisteddomains === 'string'
125+
? parseJson(this.pluginArgs.blacklisteddomains)
126+
: this.pluginArgs.blacklisteddomains
127+
);
115128
const sessionId = response.value[0];
116129
const adb = driver.sessions[sessionId]?.adb;
117130

@@ -130,6 +143,8 @@ export class AppiumInterceptorPlugin extends BasePlugin {
130143
realDevice,
131144
certDirectory,
132145
currentWifiProxyConfig,
146+
whitelistedDomains,
147+
blacklistedDomains
133148
);
134149
await configureWifiProxy(adb, deviceUDID, realDevice, proxy.options);
135150
proxyCache.add(sessionId, proxy);

src/proxy.ts

Lines changed: 53 additions & 0 deletions
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 * as net from 'net';
34
import { ProxyAgent } from 'proxy-agent';
45
import { v4 as uuid } from 'uuid';
56
import {
@@ -30,6 +31,8 @@ export interface ProxyOptions {
3031
port: number;
3132
ip: string;
3233
previousConfig?: ProxyOptions;
34+
whitelistedDomains?: string[];
35+
blacklistedDomains?: string[];
3336
}
3437

3538
export class Proxy {
@@ -103,6 +106,56 @@ export class Proxy {
103106
log.info('Routing traffic via proxy-chain upstream agent');
104107
}
105108

109+
this.httpProxy.onConnect((req, clientToProxySocket, head, callback) => {
110+
const [hostname, port] = req.url!.split(':');
111+
const whitelistedDomains = this.options.whitelistedDomains ?? [];
112+
const blacklistedDomains = this.options.blacklistedDomains ?? [];
113+
114+
let shouldIntercept = true;
115+
if (whitelistedDomains.length > 0) {
116+
shouldIntercept = whitelistedDomains.some((domain) => doesUrlMatch(domain, hostname));
117+
} else if (blacklistedDomains.length > 0) {
118+
shouldIntercept = !blacklistedDomains.some((domain) => doesUrlMatch(domain, hostname));
119+
}
120+
if (shouldIntercept) {
121+
return callback();
122+
} else {
123+
clientToProxySocket.on('error', (err) => {
124+
log.error(`Client socket error for ${hostname}: ${err.message}`);
125+
});
126+
127+
const proxyToServerSocket = net.connect(
128+
{
129+
host: hostname,
130+
port: Number(port || 80),
131+
},
132+
() => {
133+
clientToProxySocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
134+
if (head && head.length > 0) {
135+
proxyToServerSocket.write(head);
136+
}
137+
proxyToServerSocket.pipe(clientToProxySocket);
138+
clientToProxySocket.pipe(proxyToServerSocket);
139+
}
140+
);
141+
142+
proxyToServerSocket.on('close', () => {
143+
clientToProxySocket.end();
144+
});
145+
146+
clientToProxySocket.on('close', () => {
147+
proxyToServerSocket.end();
148+
});
149+
150+
proxyToServerSocket.on('error', (err) => {
151+
log.error(`[Tunnel] Server socket error for ${hostname}: ${err.message}`);
152+
clientToProxySocket.end();
153+
});
154+
155+
return;
156+
}
157+
});
158+
106159
this.httpProxy.onRequest(
107160
RequestInterceptor((requestData: any) => {
108161
for (const sniffer of this.sniffers.values()) {

src/utils/proxy.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,14 @@ export async function setupProxyServer(
113113
deviceUDID: string,
114114
isRealDevice: boolean,
115115
certDirectory: string,
116-
currentWifiProxyConfig?: ProxyOptions
116+
currentWifiProxyConfig?: ProxyOptions,
117+
whitelistedDomains?: string[],
118+
blacklistedDomains?: string[]
117119
) {
118120
const certificatePath = prepareCertificate(sessionId, certDirectory);
119121
const port = await getPort();
120122
const _ip = isRealDevice ? 'localhost' : ip.address('public', 'ipv4');
121-
const proxy = new Proxy({ deviceUDID, sessionId, certificatePath, port, ip: _ip, previousConfig: currentWifiProxyConfig });
123+
const proxy = new Proxy({ deviceUDID, sessionId, certificatePath, port, ip: _ip, previousConfig: currentWifiProxyConfig, whitelistedDomains, blacklistedDomains});
122124
await proxy.start();
123125
if (!proxy.isStarted()) {
124126
throw new Error('Unable to start the proxy server');

0 commit comments

Comments
 (0)