diff --git a/src/plugin.ts b/src/plugin.ts index c52e7ec..64aadb2 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -4,7 +4,7 @@ import { Application } from 'express'; import { CliArg, ISessionCapability, MockConfig, RecordConfig, RequestInfo, ReplayConfig, SniffConfig } from './types'; import { DefaultPluginArgs, IPluginArgs } from './interfaces'; import _ from 'lodash'; -import { configureWifiProxy, isRealDevice, getGlobalProxyValue, getAdbReverseTunnels } from './utils/adb'; +import { configureWifiProxy, isRealDevice, getCurrentWifiProxyConfig, getAdbReverseTunnels } from './utils/adb'; import { cleanUpProxyServer, sanitizeMockConfig, setupProxyServer } from './utils/proxy'; import proxyCache from './proxy-cache'; import logger from './logger'; @@ -107,8 +107,8 @@ export class AppiumInterceptorPlugin extends BasePlugin { return response; } const realDevice = await isRealDevice(adb, deviceUDID); - const currentGlobalProxy = await getGlobalProxyValue(adb, deviceUDID) - const proxy = await setupProxyServer(sessionId, deviceUDID, realDevice, certDirectory, currentGlobalProxy); + const currentWifiProxyConfig = await getCurrentWifiProxyConfig(adb, deviceUDID) + const proxy = await setupProxyServer(sessionId, deviceUDID, realDevice, certDirectory, currentWifiProxyConfig); await configureWifiProxy(adb, deviceUDID, realDevice, proxy.options); proxyCache.add(sessionId, proxy); } diff --git a/src/proxy.ts b/src/proxy.ts index b09eef5..5ec2d79 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -29,7 +29,7 @@ export interface ProxyOptions { certificatePath: string; port: number; ip: string; - previousGlobalProxy?: ProxyOptions; + previousConfig?: ProxyOptions; } export class Proxy { @@ -83,7 +83,7 @@ export class Proxy { } public get previousGlobalProxy(): ProxyOptions | undefined { - return this.options.previousGlobalProxy ?? undefined + return this.options.previousConfig ?? undefined } public async start(): Promise { diff --git a/src/utils/adb.ts b/src/utils/adb.ts index 07d996c..2bcc6f7 100644 --- a/src/utils/adb.ts +++ b/src/utils/adb.ts @@ -1,5 +1,6 @@ import ADB from 'appium-adb'; import { Proxy, ProxyOptions } from '../proxy'; +import logger from '../logger'; export type ADBInstance = ADB; export type UDID = string; @@ -25,17 +26,42 @@ export async function isRealDevice(adb: ADBInstance, udid: UDID): Promise { + logger.info(`configureWifiProxy(udid=${udid}, isRealDevice=${isRealDevice}, proxyConfig=${JSON.stringify(proxyConfig)})`) try { - const host = proxy ? `${proxy.ip}:${proxy.port}` : ':0'; + const isConfigValid = proxyConfig + && proxyConfig.ip + && proxyConfig.ip.trim().length > 0 + && !isNaN(proxyConfig.port) + && proxyConfig.port > 0; - if (realDevice && proxy) { - await adbExecWithDevice(adb, udid, ['reverse', `tcp:${proxy.port}`, `tcp:${proxy.port}`]); + if (!isConfigValid) { + logger.warn(`Invalid proxy config: ${JSON.stringify(proxyConfig)}. Proxy will be disabled for udid ${udid}.`); + } + + const host = isConfigValid ? `${proxyConfig.ip}:${proxyConfig.port}` : ':0'; + + if (isRealDevice && isConfigValid) { + await adbExecWithDevice(adb, udid, ['reverse', `tcp:${proxyConfig.port}`, `tcp:${proxyConfig.port}`]); } return await adbExecWithDevice(adb, udid, [ @@ -51,36 +77,66 @@ export async function configureWifiProxy( } } -export async function getGlobalProxyValue( +/** + * Retrieves the current global HTTP proxy settings from the target Android device via ADB. + * The function checks the 'http_proxy' setting in the 'global' namespace of the Android system settings. + * + * @param adb - The ADB instance established by Appium. + * @param udid - The Unique Device Identifier (UDID) of the Android device or emulator. + * @returns A Promise resolving to an object containing the IP and port of the proxy + * ({ ip: string, port: number }), or undefined if no proxy is configured, + * or if the configuration is invalid (e.g., malformed port). + * @throws {Error} Throws an error if the ADB command execution fails. + */ +export async function getCurrentWifiProxyConfig( adb: ADBInstance, udid: UDID -): Promise { +): Promise { + logger.info(`getCurrentWifiProxyConfig(udid=${udid})`); try { - const proxy = await adbExecWithDevice(adb, udid, [ + // Execute ADB command to get the current global HTTP proxy setting + const proxySettingsCommandResult = await adbExecWithDevice(adb, udid, [ 'shell', 'settings', 'get', 'global', - 'http_proxy' - ]) + 'http_proxy', + ]); - if(proxy == ":0" || proxy == "null") { - return { - port: 0 - } as ProxyOptions + // ADB returns ":0" or "null" when the proxy is disabled. + if (!proxySettingsCommandResult || proxySettingsCommandResult === ':0' || proxySettingsCommandResult === 'null') { + logger.info(`No active proxy for udid ${udid}.`); + return undefined; } - const [ip, portStr] = proxy.split(":"); + // Ensure the format is IP:PORT (must contain at least one ':'). + if (!proxySettingsCommandResult.includes(':')) { + logger.warn(`Invalid proxy settings format detected for udid ${udid}: '${proxySettingsCommandResult}'.`); + return undefined; + } + + // Split the string into IP and port + const [ip, portStr] = proxySettingsCommandResult.split(':', 2); const port = Number(portStr); - return { - ip: ip, - port: port - } as ProxyOptions + // Validate IP and port values. + // IP should not be empty after trimming, and port must be a valid number greater than 0. + if (!ip.trim() || isNaN(port) || port <= 0) { + logger.warn(`Invalid proxy settings detected for udid ${udid}: (ip=${ip}, port=${port})`); + return undefined; + } + + const proxyOptions: ProxyOptions = { + ip: ip.trim(), + port: port, + } as ProxyOptions; + + logger.info(`Found active proxy for udid ${udid}: ${JSON.stringify(proxyOptions)}`); + return proxyOptions; } catch (error: any) { - throw new Error(`Error get global proxy value ${udid}: ${error.message}`); - } + throw new Error(`Error getting wifi proxy settings for ${udid}: ${error.message}`); + } } /** diff --git a/src/utils/proxy.ts b/src/utils/proxy.ts index 5383fb8..d281395 100644 --- a/src/utils/proxy.ts +++ b/src/utils/proxy.ts @@ -113,12 +113,12 @@ export async function setupProxyServer( deviceUDID: string, isRealDevice: boolean, certDirectory: string, - currentGlobalProxy?: ProxyOptions + currentWifiProxyConfig?: ProxyOptions ) { 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, previousGlobalProxy: currentGlobalProxy }); + const proxy = new Proxy({ deviceUDID, sessionId, certificatePath, port, ip: _ip, previousConfig: currentWifiProxyConfig }); await proxy.start(); if (!proxy.isStarted()) { throw new Error('Unable to start the proxy server');