diff --git a/.gitignore b/.gitignore index 4efb3b9..5e42f50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ -# The default folder to put you mitmproxy addons to import -mitmproxy-addons/har_dump.py -.venv/ - tmp/ *.tmp tmp.* diff --git a/README.md b/README.md index d61de60..2750325 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ The current features include: - Collecting HTTP(S) traffic in HAR format - Automatic CA management and WireGuard mitmproxy setup -**Currently, this module only supports POSIX environments. It will not run on Windows out of the box.** - ## Installation You can install cyanoacrylate using yarn or npm: @@ -42,7 +40,7 @@ The following example collects the traffic for an app in the Android emulator. I ```ts (async () => { - const analysis = startAnalysis({ + const analysis = await startAnalysis({ platform: 'android', runTarget: 'emulator', capabilities: [], diff --git a/docs/README.md b/docs/README.md index 1e5e0df..70ba058 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,7 +63,7 @@ Functions that can be used to instrument the device and analyze apps. #### Defined in -[src/index.ts:42](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L42) +[cyanoacrylate/src/index.ts:41](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L41) ___ @@ -83,7 +83,7 @@ The options for the `startAnalysis()` function. #### Defined in -[src/index.ts:252](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L252) +[cyanoacrylate/src/index.ts:251](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L251) ___ @@ -95,7 +95,7 @@ An ID of a known permission on Android. #### Defined in -node_modules/appstraction/dist/index.d.ts:35 +appstraction/dist/index.d.ts:36 ___ @@ -114,7 +114,7 @@ Metadata about an app. #### Defined in -[src/index.ts:26](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L26) +[cyanoacrylate/src/index.ts:25](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L25) ___ @@ -148,7 +148,7 @@ Functions that can be used to control an app analysis. #### Defined in -[src/index.ts:115](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L115) +[cyanoacrylate/src/index.ts:114](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L114) ___ @@ -167,7 +167,7 @@ The result of an app analysis. #### Defined in -[src/index.ts:201](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L201) +[cyanoacrylate/src/index.ts:200](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L200) ___ @@ -185,7 +185,7 @@ A supported attribute for the `getDeviceAttribute()` function, depending on the #### Defined in -node_modules/appstraction/dist/index.d.ts:302 +appstraction/dist/index.d.ts:305 ___ @@ -204,7 +204,7 @@ The options for each attribute available through the `getDeviceAttribute()` func #### Defined in -node_modules/appstraction/dist/index.d.ts:304 +appstraction/dist/index.d.ts:307 ___ @@ -216,7 +216,7 @@ An ID of a known permission on iOS. #### Defined in -node_modules/appstraction/dist/index.d.ts:39 +appstraction/dist/index.d.ts:40 ___ @@ -260,7 +260,7 @@ Functions that are available for the platforms. #### Defined in -node_modules/appstraction/dist/index.d.ts:45 +appstraction/dist/index.d.ts:46 ___ @@ -292,7 +292,7 @@ The options for a specific platform/run target combination. #### Defined in -[src/index.ts:213](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L213) +[cyanoacrylate/src/index.ts:212](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L212) ___ @@ -310,7 +310,7 @@ A capability supported by this library. #### Defined in -[src/index.ts:19](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L19) +[cyanoacrylate/src/index.ts:18](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L18) ___ @@ -322,7 +322,7 @@ A platform that is supported by this library. #### Defined in -node_modules/appstraction/dist/index.d.ts:41 +appstraction/dist/index.d.ts:42 ___ @@ -340,7 +340,7 @@ A run target that is supported by this library for the given platform. #### Defined in -node_modules/appstraction/dist/index.d.ts:43 +appstraction/dist/index.d.ts:44 ___ @@ -356,7 +356,7 @@ Options for a traffic collection that specifies which apps to collect traffic fr #### Defined in -[src/index.ts:40](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L40) +[cyanoacrylate/src/index.ts:39](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L39) ## Variables @@ -368,7 +368,7 @@ The IDs of known permissions on Android. #### Defined in -node_modules/appstraction/dist/index.d.ts:33 +appstraction/dist/index.d.ts:34 ___ @@ -380,7 +380,7 @@ The IDs of known permissions on iOS. #### Defined in -node_modules/appstraction/dist/index.d.ts:37 +appstraction/dist/index.d.ts:38 ## Functions @@ -402,13 +402,13 @@ Pause for a given duration. #### Defined in -node_modules/appstraction/dist/index.d.ts:8 +appstraction/dist/index.d.ts:9 ___ ### startAnalysis -▸ **startAnalysis**<`Platform`, `RunTarget`, `Capabilities`\>(`analysisOptions`): [`Analysis`](README.md#analysis)<`Platform`, `RunTarget`, `Capabilities`\> +▸ **startAnalysis**<`Platform`, `RunTarget`, `Capabilities`\>(`analysisOptions`): `Promise`<[`Analysis`](README.md#analysis)<`Platform`, `RunTarget`, `Capabilities`\>\> Initialize an analysis for the given platform and run target. Remember to call `stop()` on the returned object when you want to end the analysis. @@ -429,10 +429,10 @@ you want to end the analysis. #### Returns -[`Analysis`](README.md#analysis)<`Platform`, `RunTarget`, `Capabilities`\> +`Promise`<[`Analysis`](README.md#analysis)<`Platform`, `RunTarget`, `Capabilities`\>\> An object that can be used to instrument the device and analyze apps. #### Defined in -[src/index.ts:286](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L286) +[cyanoacrylate/src/index.ts:285](https://github.com/tweaselORG/cyanoacrylate/blob/main/src/index.ts#L285) diff --git a/examples/multiple-apps.ts b/examples/multiple-apps.ts index 17cc476..3058813 100644 --- a/examples/multiple-apps.ts +++ b/examples/multiple-apps.ts @@ -11,7 +11,7 @@ import { pause, startAnalysis } from '../src/index'; const snapshotName = process.argv[3] || 'snapshot-with-setup-emu'; const apkFolder = process.argv[4] || 'path/to/app-files'; - const analysis = startAnalysis({ + const analysis = await startAnalysis({ platform: 'android', runTarget: 'emulator', capabilities: ['frida', 'certificate-pinning-bypass'], diff --git a/package.json b/package.json index aa422ac..9aaed9b 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ "types": "dist/index.d.ts", "files": [ "/dist", - "/mitmproxy-addons/ipcEventsAddon.py", "requirements.txt", - "/scripts" + "/scripts", + "/src/ipcEventsAddon.py" ], "scripts": { "build": "parcel build", @@ -55,10 +55,11 @@ "prettier": "@baltpeter/prettier-config", "dependencies": { "@types/har-format": "^1.2.10", - "appstraction": "^0.1.2", - "cross-dirname": "^0.1.0", + "appstraction": "^0.2.0", "cross-fetch": "^3.1.5", + "ctrlc-windows": "^2.1.0", "execa": "^7.0.0", + "global-cache-dir": "^4.4.0", "js-ini": "^1.6.0", "p-timeout": "^6.1.1", "tempy": "^3.0.0" diff --git a/scripts/common/setup.js b/scripts/common/setup.js new file mode 100644 index 0000000..014be44 --- /dev/null +++ b/scripts/common/setup.js @@ -0,0 +1,85 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck + +import { Buffer } from 'buffer'; +import fetch from 'cross-fetch'; +import { execa } from 'execa'; +import { existsSync } from 'fs'; +import { copyFile, mkdir, writeFile } from 'fs/promises'; +import globalCacheDir from 'global-cache-dir'; +import { homedir } from 'os'; +import { join } from 'path'; + +// Set up our Python dependencies (a venv with the modules from `requirements.txt` and the mitmproxy addons). +// This is meant to be run in the `postinstall` script. It will always install the full set of dependencies, regardless +// of whether they are already installed. +export const setupPythonDependencies = async () => { + const cacheDir = await globalCacheDir('cyanoacrylate'); + + const venvDir = join(cacheDir, 'venv'); + const mitmproxyAddonsDir = join(cacheDir, 'mitmproxy-addons'); + await mkdir(mitmproxyAddonsDir, { recursive: true }); + + // eslint-disable-next-line no-undef + const pipBinary = process.platform === 'win32' ? join(venvDir, 'Scripts/pip.exe') : join(venvDir, 'bin/pip'); + const mitmdumpBinary = + // eslint-disable-next-line no-undef + process.platform === 'win32' ? join(venvDir, 'Scripts/mitmdump.exe') : join(venvDir, 'bin/mitmdump'); + + // Create a venv and install all python requirements + await execa('python', ['-m', 'venv', venvDir], { stdio: 'inherit' }); + await execa(pipBinary, ['install', '-r', 'requirements.txt'], { stdio: 'inherit' }); + + // Download the har_dump.py addon corresponding to the current mitmproxy version + const mitmproxyVersion = await execa(mitmdumpBinary, ['--version']).then( + ({ stdout }) => stdout.match(/Mitmproxy: ([0-9.]+)/)?.[1] + ); + const mitmproxyCommitSha = await fetch( + `https://api.github.com/repos/mitmproxy/mitmproxy/git/ref/tags/${mitmproxyVersion}` + ) + .then((res) => res.json()) + .then((ref) => ref.object.sha); + await fetch( + `https://raw.githubusercontent.com/mitmproxy/mitmproxy/${mitmproxyCommitSha}/examples/contrib/har_dump.py` + ) + .then((res) => res.arrayBuffer()) + .then((hardumpScript) => writeFile(join(mitmproxyAddonsDir, 'har_dump.py'), Buffer.from(hardumpScript))); + + // Copy the ipcEventsAddon.py addon to the mitmproxy addons directory + await copyFile( + // eslint-disable-next-line no-undef + new URL('../../src/ipcEventsAddon.py', import.meta.url), + join(mitmproxyAddonsDir, 'ipcEventsAddon.py') + ); + + // Start mitmproxy once to create certificate files if they don't exist, yet. + if (!existsSync(join(homedir(), '.mitmproxy'))) { + const mitmproxyProcess = execa(mitmdumpBinary, [ + '-q', + '-s', + join(mitmproxyAddonsDir, 'ipcEventsAddon.py'), + '--set', + 'ipcPipeFd=1', + ]); + mitmproxyProcess.stdout?.addListener('data', (data) => { + const msg = JSON.parse(data); + if (msg.status === 'running') mitmproxyProcess.kill(); + }); + } +}; + +// This is a lighter version of `setupPythonDependencies`. It only installs if certain key files are missing. +// This isn't an exhaustive check but many orders of magnitude faster in the regular case (i.e. the dependencies are +// already installed). It is meant to always be run before an analysis is started. +export const ensurePythonDependencies = async () => { + const pathsThatNeedToExist = [ + // The one file that exists both in Windows and *nix venvs. + 'venv/pyvenv.cfg', + 'mitmproxy-addons/har_dump.py', + 'mitmproxy-addons/ipcEventsAddon.py', + ]; + + const cacheDir = await globalCacheDir('cyanoacrylate'); + + if (pathsThatNeedToExist.some((path) => !existsSync(join(cacheDir, path)))) await setupPythonDependencies(); +}; diff --git a/scripts/postinstall.js b/scripts/postinstall.js index 9c4ff3a..722f1c0 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -1,47 +1,5 @@ -import { Buffer } from 'buffer'; -import fetch from 'cross-fetch'; -import { execa } from 'execa'; -import { existsSync } from 'fs'; -import { writeFile } from 'fs/promises'; -import { homedir } from 'os'; -import { join } from 'path'; +import { setupPythonDependencies } from './common/setup.js'; (async () => { - // Lifecycle scripts are always run from the project root, so this is always the same path (https://docs.npmjs.com/cli/v9/using-npm/scripts#best-practices). - const venvRoot = '.venv'; - - // Create a venv and install all python requirements - await execa('python', ['-m', 'venv', venvRoot], { stdio: 'inherit' }); - await execa(`${venvRoot}/bin/pip`, ['install', '-r', 'requirements.txt'], { - stdio: 'inherit', - }); - - // Download the har_dump.py addon corresponding to the current mitmproxy version - const mitmproxyVersion = await execa(`${venvRoot}/bin/mitmdump`, ['--version']).then( - ({ stdout }) => stdout.match(/Mitmproxy: ([0-9.]+)/)[1] - ); - const mitmproxyCommitSha = await fetch( - `https://api.github.com/repos/mitmproxy/mitmproxy/git/ref/tags/${mitmproxyVersion}` - ) - .then((res) => res.json()) - .then((ref) => ref.object.sha); - await fetch( - `https://raw.githubusercontent.com/mitmproxy/mitmproxy/${mitmproxyCommitSha}/examples/contrib/har_dump.py` - ) - .then((res) => res.arrayBuffer()) - .then((hardumpScript) => writeFile('mitmproxy-addons/har_dump.py', Buffer.from(hardumpScript))); - - // Start mitmproxy once to create certificate files if they don't exist, yet. - if (!existsSync(join(homedir(), '.mitmproxy'))) { - const mitmproxyProcess = execa( - `${venvRoot}/bin/mitmdump`, - ['-s', 'mitmproxy-addons/ipcEventsAddon.py', '--set', 'ipcPipeFd=3'], - { - stdio: ['inherit', 'inherit', 'inherit', 'ipc'], - } - ); - mitmproxyProcess.on('message', (msg) => { - if (msg.status === 'running') mitmproxyProcess.kill(); - }); - } + await setupPythonDependencies(); })(); diff --git a/src/index.ts b/src/index.ts index 9616046..59ee4d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ import type { PlatformApi, PlatformApiOptions, SupportedPlatform, SupportedRunTarget } from 'appstraction'; import { parseAppMeta, platformApi } from 'appstraction'; -import { getDirname } from 'cross-dirname'; import type { ExecaChildProcess } from 'execa'; import { execa } from 'execa'; import { readFile } from 'fs/promises'; +import globalCacheDir from 'global-cache-dir'; import type { Har } from 'har-format'; import { parse as parseIni, stringify as stringifyIni } from 'js-ini'; import { homedir } from 'os'; @@ -11,10 +11,9 @@ import timeout, { TimeoutError } from 'p-timeout'; import { join } from 'path'; import process from 'process'; import { temporaryFile } from 'tempy'; +import { ensurePythonDependencies } from '../scripts/common/setup'; import { awaitMitmproxyEvent, awaitProcessClose, dnsLookup, killProcess } from './util'; -const __dirname = getDirname(); - /** A capability supported by this library. */ export type SupportedCapability = Platform extends 'android' ? 'frida' | 'certificate-pinning-bypass' @@ -283,11 +282,19 @@ export type AnalysisOptions< * * @returns An object that can be used to instrument the device and analyze apps. */ -export function startAnalysis< +export async function startAnalysis< Platform extends SupportedPlatform, RunTarget extends SupportedRunTarget, Capabilities extends SupportedCapability[] ->(analysisOptions: AnalysisOptions): Analysis { +>( + analysisOptions: AnalysisOptions +): Promise> { + await ensurePythonDependencies(); + + const cacheDir = await globalCacheDir('cyanoacrylate'); + const venvPath = join(cacheDir, 'venv', process.platform === 'win32' ? 'Scripts' : 'bin'); + process.env['PATH'] = `${venvPath}${process.platform === 'win32' ? ';' : ':'}${process.env['PATH']}`; + const platformOptions = { platform: analysisOptions.platform, runTarget: analysisOptions.runTarget, @@ -301,9 +308,6 @@ export function startAnalysis< targetOptions: analysisOptions.targetOptions as any, } as unknown as PlatformApiOptions; - const venvPath = join(__dirname, '../.venv/bin'); - process.env['PATH'] = `${venvPath}:${process.env['PATH']}`; - const platform = platformApi(platformOptions); let emulatorProcess: ExecaChildProcess | undefined; @@ -321,21 +325,20 @@ export function startAnalysis< const harOutputPath = temporaryFile({ extension: 'har' }); const mitmproxyOptions = [ + '--quiet', // We cannot reliably read the mitmproxy stdout anyway, so we suppress it. (See: https://github.com/tweaselORG/cyanoacrylate/issues/5) '-s', - join(__dirname, '../mitmproxy-addons/ipcEventsAddon.py'), + join(cacheDir, 'mitmproxy-addons/ipcEventsAddon.py'), '-s', - join(__dirname, '../mitmproxy-addons/har_dump.py'), + join(cacheDir, 'mitmproxy-addons/har_dump.py'), '--set', `hardump=${harOutputPath}`, '--set', - 'ipcPipeFd=3', + 'ipcPipeFd=1', // Write the ipc events to stdout (which is always fd 1) ]; if (analysisOptions.platform === 'android') mitmproxyOptions.push('--mode', 'wireguard'); mitmproxyState = { - proc: execa('mitmdump', mitmproxyOptions, { - stdio: ['pipe', 'pipe', 'pipe', 'ipc'], - }), + proc: execa('mitmdump', mitmproxyOptions), harOutputPath, }; @@ -499,7 +502,7 @@ export function startAnalysis< // Sometimes, the Android emulator gets stuck and doesn't accept any commands anymore. In this case, we // restart it. - await timeout(this.ensureDevice({ killExisting: true }), { milliseconds: 60 * 1000 }); + await timeout((await this).ensureDevice({ killExisting: true }), { milliseconds: 60 * 1000 }); await timeout(platform.resetDevice(snapshotName), { milliseconds: 5 * 60 * 1000 }); }); }, @@ -523,7 +526,8 @@ export function startAnalysis< let inProgressTrafficCollectionName: string | undefined; const cleanUpAppAnalysis = async () => { - platform._internal?.objectionProcesses?.forEach((proc) => killProcess(proc)); + if ('objectionProcesses' in platform._internal) + platform._internal?.objectionProcesses?.forEach((proc) => killProcess(proc)); }; if (options?.resetApp) { diff --git a/mitmproxy-addons/ipcEventsAddon.py b/src/ipcEventsAddon.py similarity index 95% rename from mitmproxy-addons/ipcEventsAddon.py rename to src/ipcEventsAddon.py index 5f29114..61db844 100644 --- a/mitmproxy-addons/ipcEventsAddon.py +++ b/src/ipcEventsAddon.py @@ -29,7 +29,7 @@ def load(self, loader): def _sendIpcMessage(self, message): """Takes a dict and sends it through a pipe as JSON.""" if(ctx.options.ipcPipeFd is not None): - os.write(ctx.options.ipcPipeFd, bytes(json.dumps(message) + '\n', 'utf8')) + os.write(ctx.options.ipcPipeFd, bytes("cyanoacrylate:" + json.dumps(message) + '\n', 'utf8')) def running(self): self._sendIpcMessage({"status": "running"}) diff --git a/src/util.ts b/src/util.ts index f250181..52d47ba 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,3 +1,4 @@ +import { ctrlc } from 'ctrlc-windows'; import dns from 'dns'; import type { ExecaChildProcess } from 'execa'; import timeout from 'p-timeout'; @@ -82,7 +83,8 @@ export const dnsLookup = promisify(dns.lookup); */ export const killProcess = async (proc?: ExecaChildProcess) => { if (proc) { - proc.kill(); + if (process.platform === 'win32' && proc.pid) ctrlc(proc.pid); + else proc.kill(); await timeout(proc, { milliseconds: 15000 }).catch(() => proc.kill(9)); } }; @@ -97,14 +99,20 @@ export const killProcess = async (proc?: ExecaChildProcess) => { */ export const awaitMitmproxyEvent = (proc: ExecaChildProcess, condition: (msg: MitmproxyEvent) => boolean) => new Promise((res) => { - const listener = (msg: MitmproxyEvent) => { - if (condition(msg)) { - proc.removeListener('message', listener); - res(msg); + const listener = (chunk: string | Buffer | undefined) => { + const lines = chunk?.toString().split('\n') || []; + for (const line of lines) { + if (!line.startsWith('cyanoacrylate:')) continue; + + const msg = JSON.parse(line.replace(/^cyanoacrylate:/, '')) as MitmproxyEvent; + if (condition(msg)) { + proc.stdout?.removeListener('message', listener); + res(msg); + } } }; - proc.on('message', listener); + proc.stdout?.addListener('data', listener); }); /** diff --git a/yarn.lock b/yarn.lock index d8403da..4a78a0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1022,6 +1022,11 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== +"@types/node@^18.11.18": + version "18.15.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" + integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== + "@types/node@^18.15.10": version "18.15.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.10.tgz#4ee2171c3306a185d1208dad5f44dae3dee4cfe3" @@ -1042,6 +1047,13 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/ssh2@^1.11.9": + version "1.11.11" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.11.11.tgz#02fb707d821890a655fd27c2d842b0c7114078fb" + integrity sha512-LdnE7UBpvHCgUznvn2fwLt2hkaENcKPFqOyXGkvyTLfxCXBN6roc1RmECNYuzzbHePzD3PaAov5rri9hehzx9Q== + dependencies: + "@types/node" "^18.11.18" + "@types/unist@*", "@types/unist@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -1239,10 +1251,10 @@ ap@~0.2.0: resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" integrity sha512-ImdvquIuBSVpWRWhB441UjvTcZqic1RL+lTQaUKGdGEp1aiTvt/phAvY8Vvs32qya5FJBI8U+tzNBYzFDQY/lQ== -appstraction@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/appstraction/-/appstraction-0.1.2.tgz#45eb3a48b866c2a37a7f2c2e804a0c30dc864d0a" - integrity sha512-hzt2sP0xH+oBxsIkpN9/yPquWNYKunEeQKamw4850lGELHyL1c77H0fACm1F9UMxkft0WTa4rJ3svBqcIlKLlA== +appstraction@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/appstraction/-/appstraction-0.2.0.tgz#938dbac69e4229d6555766ec5474d56e7e56aab8" + integrity sha512-ttbvwo22+DuIEG3pCOw8BYkPvBQJbUBH4vSQvjjcNsAcSSw8xEYol8uW2Hi6NB6pbAcAl2jXo66cwLksamP+5w== dependencies: "@napi-rs/lzma" "^1.1.2" cross-fetch "^3.1.5" @@ -1250,6 +1262,7 @@ appstraction@^0.1.2: frida "^16.0.8" fs-extra "^11.1.0" ipa-extract-info "^1.2.6" + node-ssh "^13.1.0" p-retry "^5.1.2" pkijs "^3.0.14" semver "^7.3.8" @@ -1302,6 +1315,13 @@ array.prototype.flatmap@^1.3.1: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +asn1@^0.2.4: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + asn1js@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" @@ -1343,6 +1363,13 @@ base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + big-integer@^1.6.7: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" @@ -1457,11 +1484,21 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buildcheck@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.5.tgz#5b7c0830b25dc61422032eeb5c18bfcaa9eebb8d" + integrity sha512-jYWpRy8eedl/JZqkOeq0X0bNcaK04hXKhIi4gYsDKZUJWRjJJWViYfsMXO0BJQ40zSLcdLoa+iqe48Kz2PtQag== + bytestreamjs@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/bytestreamjs/-/bytestreamjs-2.0.1.tgz#a32947c7ce389a6fa11a09a9a563d0a45889535e" integrity sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ== +cachedir@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" + integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -1648,16 +1685,19 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" +cpu-features@~0.0.4: + version "0.0.6" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.6.tgz#607e82a4d563343f64b7dd90a33f2b1d821214b5" + integrity sha512-Rj33pk//oVNh25YjsBaKtOkXNW7IARYxejWJosJkXqVPpbK+FrdpThPk6f4m3d+CEh2qMlkGx/SFt2Y1XSWN6g== + dependencies: + buildcheck "0.0.5" + nan "^2.17.0" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-dirname@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cross-dirname/-/cross-dirname-0.1.0.tgz#b899599f30a5389f59e78c150e19f957ad16a37c" - integrity sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q== - cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" @@ -1712,6 +1752,11 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" +ctrlc-windows@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ctrlc-windows/-/ctrlc-windows-2.1.0.tgz#f2096a96ac1d03181e0ec808c2c8a67fdc20b300" + integrity sha512-OrX5KI+K+2NMN91QIhYZdW7VDO2YsSdTZW494pA7Nvw/wBdU2hz+MGP006bR978zOTrG6Q8EIeJvLJmLqc6MsQ== + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2511,6 +2556,14 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +global-cache-dir@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global-cache-dir/-/global-cache-dir-4.4.0.tgz#8921295d32abe0f7768e96acdf7f40a9874050b7" + integrity sha512-bk0gI6IbbphRjAaCJJn5H+T/CcEck5B3a5KBO2BXSDzjFSV+API17w8GA7YPJ6IXJiasW8M0VsEIig1PCHdfOQ== + dependencies: + cachedir "^2.3.0" + path-exists "^5.0.0" + globals@^13.19.0, globals@^13.2.0: version "13.20.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" @@ -2889,6 +2942,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" @@ -3200,6 +3258,13 @@ magic-string@^0.22.4: dependencies: vlq "^0.2.2" +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -3554,6 +3619,11 @@ msgpackr@^1.5.4: optionalDependencies: msgpackr-extract "^3.0.0" +nan@^2.16.0, nan@^2.17.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" + integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== + napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -3611,6 +3681,19 @@ node-releases@^2.0.8: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== +node-ssh@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/node-ssh/-/node-ssh-13.1.0.tgz#fca947200d61db9a5f9915e27c252e133b79e6bf" + integrity sha512-GLcw49yFd9+rUpP+FgX6wrF/N90cmuDl2n0i8d3L828b6riRjkb9w3SS+XvviRWbrAhLxuMKywFqxvQDZQ1bug== + dependencies: + "@types/ssh2" "^1.11.9" + is-stream "^2.0.0" + make-dir "^3.1.0" + sb-promise-queue "^2.1.0" + sb-scandir "^3.1.0" + shell-escape "^0.2.0" + ssh2 "^1.11.0" + normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -3819,6 +3902,11 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -4199,6 +4287,23 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sb-promise-queue@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sb-promise-queue/-/sb-promise-queue-2.1.0.tgz#7e44bebef643f75d809a3db7f605b815d877a04d" + integrity sha512-zwq4YuP1FQFkGx2Q7GIkZYZ6PqWpV+bg0nIO1sJhWOyGyhqbj0MsTvK6lCFo5TQwX5pZr6SCQ75e8PCDCuNvkg== + +sb-scandir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/sb-scandir/-/sb-scandir-3.1.0.tgz#31c346abb5184b73c5a25b286858f4299aa8756c" + integrity sha512-70BVm2xz9jn94zSQdpvYrEG101/UV9TVGcfWr9T5iob3QhCK4lYXeculfBqPGFv3XTeKgx4dpWyYIDeZUqo4kg== + dependencies: + sb-promise-queue "^2.1.0" + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -4214,7 +4319,7 @@ semver@^5.7.0, semver@^5.7.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -4243,6 +4348,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-escape@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/shell-escape/-/shell-escape-0.2.0.tgz#68fd025eb0490b4f567a027f0bf22480b5f84133" + integrity sha512-uRRBT2MfEOyxuECseCZd28jC1AJ8hmqqneWQ4VWUTgCAFvb3wKU1jLqj6egC4Exrr88ogg3dp+zroH4wJuaXzw== + shiki@^0.14.1: version "0.14.1" resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.1.tgz#9fbe082d0a8aa2ad63df4fbf2ee11ec924aa7ee1" @@ -4364,6 +4474,17 @@ srcset@4: resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== +ssh2@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.11.0.tgz#ce60186216971e12f6deb553dcf82322498fe2e4" + integrity sha512-nfg0wZWGSsfUe/IBJkXVll3PEZ//YH2guww+mP88gTpuSU4FtZN7zu9JoeTGOyCNx2dTDtT9fOpWwlzyj4uOOw== + dependencies: + asn1 "^0.2.4" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.4" + nan "^2.16.0" + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -4697,6 +4818,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"