Skip to content

Commit

Permalink
Fixes #18: Use cache folder instead of __dirname for Python deps
Browse files Browse the repository at this point in the history
  • Loading branch information
baltpeter committed Apr 13, 2023
1 parent 23ff62d commit ad4de25
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 71 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# The default folder to put you mitmproxy addons to import
mitmproxy-addons/har_dump.py
.venv/

tmp/
*.tmp
tmp.*
Expand Down
18 changes: 9 additions & 9 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Functions that can be used to instrument the device and analyze apps.

#### Defined in

[cyanoacrylate/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)

___

Expand All @@ -83,7 +83,7 @@ The options for the `startAnalysis()` function.

#### Defined in

[cyanoacrylate/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)

___

Expand Down Expand Up @@ -114,7 +114,7 @@ Metadata about an app.

#### Defined in

[cyanoacrylate/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)

___

Expand Down Expand Up @@ -148,7 +148,7 @@ Functions that can be used to control an app analysis.

#### Defined in

[cyanoacrylate/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)

___

Expand All @@ -167,7 +167,7 @@ The result of an app analysis.

#### Defined in

[cyanoacrylate/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)

___

Expand Down Expand Up @@ -292,7 +292,7 @@ The options for a specific platform/run target combination.

#### Defined in

[cyanoacrylate/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)

___

Expand All @@ -310,7 +310,7 @@ A capability supported by this library.

#### Defined in

[cyanoacrylate/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)

___

Expand Down Expand Up @@ -356,7 +356,7 @@ Options for a traffic collection that specifies which apps to collect traffic fr

#### Defined in

[cyanoacrylate/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

Expand Down Expand Up @@ -435,4 +435,4 @@ An object that can be used to instrument the device and analyze apps.

#### Defined in

[cyanoacrylate/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)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@
"dependencies": {
"@types/har-format": "^1.2.10",
"appstraction": "^0.1.2",
"cross-dirname": "^0.1.0",
"cross-fetch": "^3.1.5",
"execa": "^7.0.0",
"global-cache-dir": "^4.4.0",
"js-ini": "^1.6.0",
"p-timeout": "^6.1.1",
"tempy": "^3.0.0"
Expand Down
79 changes: 79 additions & 0 deletions scripts/common/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 });

// Create a venv and install all python requirements
await execa('python', ['-m', 'venv', venvDir], { stdio: 'inherit' });
await execa(`${venvDir}/bin/pip`, ['install', '-r', 'requirements.txt'], { stdio: 'inherit' });

// Download the har_dump.py addon corresponding to the current mitmproxy version
const mitmproxyVersion = await execa(`${venvDir}/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(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(`${venvDir}/bin/mitmdump`, [
'-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();
};
46 changes: 2 additions & 44 deletions scripts/postinstall.js
Original file line number Diff line number Diff line change
@@ -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();
})();
18 changes: 10 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
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';
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 SupportedPlatform> = Platform extends 'android'
? 'frida' | 'certificate-pinning-bypass'
Expand Down Expand Up @@ -301,16 +300,19 @@ export function startAnalysis<
targetOptions: analysisOptions.targetOptions as any,
} as unknown as PlatformApiOptions<Platform, RunTarget, Capabilities>;

const venvPath = join(__dirname, '../.venv/bin');
process.env['PATH'] = `${venvPath}:${process.env['PATH']}`;

const platform = platformApi(platformOptions);

let emulatorProcess: ExecaChildProcess | undefined;
let trafficCollectionInProgress = false;
let mitmproxyState: { proc: ExecaChildProcess; harOutputPath: string; wireguardConf?: string } | undefined;

const startTrafficCollection = async (options: TrafficCollectionOptions | undefined) => {
await ensurePythonDependencies();

const cacheDir = await globalCacheDir('cyanoacrylate');
const venvPath = join(cacheDir, '.venv/bin');
process.env['PATH'] = `${venvPath}:${process.env['PATH']}`;

if (trafficCollectionInProgress)
throw new Error('Cannot start new traffic collection. A previous one is still running.');

Expand All @@ -323,9 +325,9 @@ export function startAnalysis<
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',
Expand Down
File renamed without changes.
23 changes: 18 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,11 @@ bytestreamjs@^2.0.0:
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"
Expand Down Expand Up @@ -1653,11 +1658,6 @@ create-require@^1.1.0:
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"
Expand Down Expand Up @@ -2511,6 +2511,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"
Expand Down Expand Up @@ -3819,6 +3827,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"
Expand Down

0 comments on commit ad4de25

Please sign in to comment.