Skip to content

Commit b7c6d82

Browse files
authored
fix: custom certificate directory as a plugin argument (#77)
* customCertificate * Readme update * hotfix
1 parent 1305816 commit b7c6d82

File tree

9 files changed

+45
-20
lines changed

9 files changed

+45
-20
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ The plugin will not be active unless turned on when invoking the Appium server:
2222

2323
`appium server -ka 800 --use-plugins=appium-interceptor -pa /wd/hub`
2424

25+
## Custom certificate
26+
27+
If you need to use a custom certificate, it can be done by passing `certdirectory` as an argument of the plugin:
28+
29+
`appium server -ka 800 --use-plugins=appium-interceptor --plugin-appium-interceptor-certdirectory="<YOUR DIRECTORY>" -pa /wd/hub`
30+
31+
Please keep the same directory structure as the existing certificate folder.
32+
2533
## what does this plugin do?
2634

2735
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.

docs/commands.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Mock configuration is a json object that defines the specification for filtering
3333
| statusCode | number | no | Updates the response status code with the given value | To simulate any unexpected error you can send some of the below statusCode <br> 1. `500` - Internal server error <br> 2. `400` - Bad request <br> 3. `401` - Unauthorized |
3434
| responseHeaders | object | no | Map of key value pairs to be added or removed from the response header | Same syntax as `headers` key. But this will update the response header |
3535
| responseBody | object | no | This will replace the original response data returned by the api server and updates it with new data | Passing the config as `{"url" : "/api/login/g" , "responseBody": "{\"error\": \"User account locked\"}", `statusCode`: 400 }` will simulate a error scenario when logged in with any user credentilas |
36-
| updateResponseBody | string | no | This is similar to responseBody but instead of fully mocking the server response, you can replace any value in the response using Regular expression or jsonpath | Consider you application returns user data as `{\"username\": \"someusername\", \"email\": \"someemail@email.com\", \"isAdmin\" : \"false\"}` as a response for get user api request and you want to update the values for email and IsAdmin fiels, then you can pass <br> `{"updateRequestBody": [{ "jsonPath": "$.email", "newemail@email.com" }, { "jsonPath": "$.isAdmin", "true" }]}` and it will update the email and isAdmin field before sending the response back to the application|
36+
| updateResponseBody | string | no | This is similar to responseBody but instead of fully mocking the server response, you can replace any value in the response using Regular expression or jsonpath | Consider you application returns user data as `{\"username\": \"someusername\", \"email\": \"someemail@email.com\", \"isAdmin\" : \"false\"}` as a response for get user api request and you want to update the values for email and IsAdmin fiels, then you can pass <br> `{"updateRequestBody": [{ "jsonPath": "$.email", value: "newemail@email.com" }, { "jsonPath": "$.isAdmin", value: "true" }]}` and it will update the email and isAdmin field before sending the response back to the application|
3737

3838

3939
## Commands:

package-lock.json

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

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@
7575
"$schema": "http://json-schema.org/draft-07/schema",
7676
"additionalProperties": false,
7777
"description": "Appium configuration schema for the interceptor plugin.",
78-
"properties": {},
78+
"properties": {
79+
"certdirectory": {
80+
"type": "string"
81+
}
82+
},
7983
"title": "Appium interceptor plugin",
8084
"type": "object"
8185
},

src/config.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/interfaces.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import path from 'path';
2+
3+
export interface IPluginArgs {
4+
certdirectory: string;
5+
}
6+
7+
export const DefaultPluginArgs: IPluginArgs = {
8+
certdirectory: path.join(__dirname, '..', 'certificate'),
9+
};

src/plugin.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { BasePlugin } from 'appium/plugin';
22
import http from 'http';
33
import { Application } from 'express';
44
import { CliArg, ISessionCapability, MockConfig, RecordConfig, RequestInfo, ReplayConfig, SniffConfig } from './types';
5+
import { DefaultPluginArgs, IPluginArgs } from './interfaces';
56
import _ from 'lodash';
67
import { configureWifiProxy, isRealDevice, getGlobalProxyValue } from './utils/adb';
78
import { cleanUpProxyServer, sanitizeMockConfig, setupProxyServer } from './utils/proxy';
@@ -10,7 +11,7 @@ import logger from './logger';
1011
import log from './logger';
1112

1213
export class AppiumInterceptorPlugin extends BasePlugin {
13-
14+
private pluginArgs: IPluginArgs = Object.assign({}, DefaultPluginArgs);
1415
static executeMethodMap = {
1516
'interceptor: addMock': {
1617
command: 'addMock',
@@ -69,7 +70,9 @@ export class AppiumInterceptorPlugin extends BasePlugin {
6970
};
7071

7172
constructor(name: string, cliArgs: CliArg) {
73+
log.debug(`📱 Plugin Args: ${JSON.stringify(cliArgs)}`);
7274
super(name, cliArgs);
75+
this.pluginArgs = Object.assign({}, DefaultPluginArgs, cliArgs as unknown as IPluginArgs);
7376
}
7477

7578
static async updateServer(expressApp: Application, httpServer: http.Server, cliArgs: CliArg) {}
@@ -90,6 +93,7 @@ export class AppiumInterceptorPlugin extends BasePlugin {
9093
const mergedCaps = { ...caps.alwaysMatch, ..._.get(caps, 'firstMatch[0]', {}) };
9194
const interceptFlag = mergedCaps['appium:intercept'];
9295
const { deviceUDID, platformName } = response.value[1];
96+
const certDirectory = this.pluginArgs.certdirectory;
9397
const sessionId = response.value[0];
9498
const adb = driver.sessions[sessionId]?.adb;
9599

@@ -100,8 +104,7 @@ export class AppiumInterceptorPlugin extends BasePlugin {
100104
}
101105
const realDevice = await isRealDevice(adb, deviceUDID);
102106
const currentGlobalProxy = await getGlobalProxyValue(adb, deviceUDID)
103-
104-
const proxy = await setupProxyServer(sessionId, deviceUDID, realDevice, currentGlobalProxy);
107+
const proxy = await setupProxyServer(sessionId, deviceUDID, realDevice, certDirectory, currentGlobalProxy);
105108
await configureWifiProxy(adb, deviceUDID, realDevice, proxy.options);
106109
proxyCache.add(sessionId, proxy);
107110
}

src/scripts/test-connection.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import { ADBInstance, UDID, configureWifiProxy, isRealDevice, openUrl } from '..
77
import { v4 as uuid } from 'uuid';
88
import { setupProxyServer } from '../utils/proxy';
99
import { Proxy } from '../proxy';
10+
import path from 'path';
1011

1112
type VerifyOptions = {
1213
udid: string;
14+
certdirectory: string;
1315
};
1416

1517
const defaultOptions: VerifyOptions = {
1618
udid: '',
19+
certdirectory: path.join(__dirname, '..', 'certificate'),
1720
};
1821

1922
const MOCK_BACKEND_HTML = `<html><head><title>Appium Mock</title></head>
@@ -76,9 +79,9 @@ async function addMock(proxy: Proxy) {
7679
});
7780
}
7881

79-
async function verifyDeviceConnection(adb: ADBInstance, udid: UDID) {
82+
async function verifyDeviceConnection(adb: ADBInstance, udid: UDID, certDirectory: string) {
8083
const realDevice = await isRealDevice(adb, udid);
81-
const proxy = await setupProxyServer(uuid(), udid, realDevice);
84+
const proxy = await setupProxyServer(uuid(), udid, realDevice, certDirectory);
8285
addMock(proxy);
8386
await configureWifiProxy(adb, udid, realDevice, proxy.options);
8487
await openUrl(adb, udid, MOCK_BACKEND_URL);
@@ -102,7 +105,7 @@ async function main() {
102105
const options = getOptions();
103106
const udid = await pickDeviceToTest(adb, options);
104107
await registerExitHook(adb, udid);
105-
await verifyDeviceConnection(adb, udid);
108+
await verifyDeviceConnection(adb, udid, options.certdirectory);
106109
}
107110

108111
main().catch(console.log);

src/utils/proxy.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { Proxy, ProxyOptions } from '../proxy';
1313
import ip from 'ip';
1414
import os from 'os';
1515
import path from 'path';
16-
import config from '../config';
1716
import fs from 'fs-extra';
1817
import { minimatch } from 'minimatch';
1918
import http from 'http';
@@ -113,9 +112,10 @@ export async function setupProxyServer(
113112
sessionId: string,
114113
deviceUDID: string,
115114
isRealDevice: boolean,
115+
certDirectory: string,
116116
currentGlobalProxy?: ProxyOptions
117117
) {
118-
const certificatePath = prepareCertificate(sessionId);
118+
const certificatePath = prepareCertificate(sessionId, certDirectory);
119119
const port = await getPort();
120120
const _ip = isRealDevice ? 'localhost' : ip.address('public', 'ipv4');
121121
const proxy = new Proxy({ deviceUDID, sessionId, certificatePath, port, ip: _ip, previousGlobalProxy: currentGlobalProxy });
@@ -132,9 +132,12 @@ export async function cleanUpProxyServer(proxy: Proxy) {
132132
fs.rmdirSync(proxy.certificatePath, { recursive: true, force: true });
133133
}
134134

135-
function prepareCertificate(sessionId: string) {
135+
function prepareCertificate(sessionId: string, certDirectory: string) {
136136
const sessionCertDirectory = path.join(os.tmpdir(), sessionId);
137-
fs.copySync(config.certDirectory, sessionCertDirectory);
137+
if(!fs.existsSync(certDirectory)){
138+
throw new Error(`Error certDirectory doesn't exist (${certDirectory})`);
139+
}
140+
fs.copySync(certDirectory, sessionCertDirectory);
138141
return sessionCertDirectory;
139142
}
140143

@@ -204,7 +207,7 @@ export function doesUrlMatch(pattern: UrlPattern, url: string) {
204207
? jsonOrStringUrl.test(url)
205208
: minimatch(url, jsonOrStringUrl);
206209
} catch (err) {
207-
log.error(`Error validaing url ${pattern} against url ${url}`);
210+
log.error(`Error validating url ${pattern} against url ${url}`);
208211
return false;
209212
}
210213
}

0 commit comments

Comments
 (0)