frida-test 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -116,10 +116,10 @@ frida-test -i org.owasp.mastestapp.MASTestApp-iOS ./tests/ios ./tests/shared
|
|
|
116
116
|
|
|
117
117
|
`frida-test` automatically bundles the test suites, and compiles them together with the testing framework into a Frida agent.
|
|
118
118
|
|
|
119
|
-
If you only want to compile this agent, use `frida-test-
|
|
119
|
+
If you only want to compile this agent, use `frida-test-compile`:
|
|
120
120
|
|
|
121
121
|
```sh
|
|
122
|
-
frida-test-
|
|
122
|
+
frida-test-compile [options] <dir...>
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
| Option | Description |
|
|
@@ -127,12 +127,12 @@ frida-test-compiler [options] <dir...>
|
|
|
127
127
|
| `-o, --out <path>` | Path of the output file for JSON reporter (default: disabled) |
|
|
128
128
|
| `-h, --help` | Shows the help message |
|
|
129
129
|
|
|
130
|
-
### `frida-test-
|
|
130
|
+
### `frida-test-compile` Examples
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
133
|
# Collects all tests in ./tests, compiles the frida-test agent, and print it to stdout
|
|
134
|
-
frida-test-
|
|
134
|
+
frida-test-compile ./tests
|
|
135
135
|
|
|
136
136
|
# Collects all tests in ./tests, compile the frida-test agent, and stores it in the path ./frida-test-agent.js
|
|
137
|
-
frida-test-
|
|
137
|
+
frida-test-compile ./tests -o ./frida-test-agent.js
|
|
138
138
|
```
|
package/dist/bundler.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
7
|
const IMPORT_MARKER = "/// IMPORT TESTS SUITES ///";
|
|
8
|
-
const execFileAsync = promisify(execFile);
|
|
9
8
|
const AGENT_ENTRYPOINT_FILENAME = "agentRuntime.ts";
|
|
10
|
-
const AGENT_ENTRYPOINT_BASENAME = path.
|
|
9
|
+
const AGENT_ENTRYPOINT_BASENAME = path.parse(AGENT_ENTRYPOINT_FILENAME).name;
|
|
11
10
|
const AGENT_BUNDLE_FILENAME = `${AGENT_ENTRYPOINT_BASENAME}.bundle.js`;
|
|
12
|
-
function
|
|
11
|
+
function getProjectRoot() {
|
|
12
|
+
const startDir = process.cwd();
|
|
13
13
|
let dir = startDir;
|
|
14
14
|
while (true) {
|
|
15
15
|
if (existsSync(path.join(dir, "package.json")))
|
|
@@ -20,45 +20,40 @@ function resolveProjectRoot(startDir = process.cwd()) {
|
|
|
20
20
|
dir = parent;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
let cachedAgentRuntimeSrcDir;
|
|
32
|
-
let cachedFridaCompileBin;
|
|
33
|
-
function getProjectRoot() {
|
|
34
|
-
cachedProjectRoot ??= resolveProjectRoot();
|
|
35
|
-
return cachedProjectRoot;
|
|
36
|
-
}
|
|
37
|
-
function getAgentRuntimeSrcDir(projectRoot) {
|
|
38
|
-
if (!cachedAgentRuntimeSrcDir) {
|
|
39
|
-
const dir = resolveAgentRuntimePath(projectRoot);
|
|
40
|
-
if (!existsSync(dir)) {
|
|
41
|
-
throw new Error(`Agent runtime source directory not found at "${dir}".`);
|
|
23
|
+
function getPackageRoot() {
|
|
24
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
while (true) {
|
|
26
|
+
if (existsSync(path.join(dir, "package.json")))
|
|
27
|
+
return dir;
|
|
28
|
+
const parent = path.dirname(dir);
|
|
29
|
+
if (parent === dir) {
|
|
30
|
+
throw new Error("Could not locate frida-test's own package.json.");
|
|
42
31
|
}
|
|
43
|
-
|
|
32
|
+
dir = parent;
|
|
44
33
|
}
|
|
45
|
-
return cachedAgentRuntimeSrcDir;
|
|
46
34
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
function getAgentRuntimeSrcDir() {
|
|
36
|
+
const dir = path.join(getPackageRoot(), "src", "agent-runtime");
|
|
37
|
+
if (!existsSync(dir)) {
|
|
38
|
+
throw new Error(`Agent runtime source directory not found at "${dir}".`);
|
|
51
39
|
}
|
|
52
|
-
return
|
|
40
|
+
return dir;
|
|
41
|
+
}
|
|
42
|
+
function getFridaCompileBin(projectRoot) {
|
|
43
|
+
const binName = process.platform === "win32" ? "frida-compile.cmd" : "frida-compile";
|
|
44
|
+
const localBin = path.join(projectRoot, "node_modules", ".bin", binName);
|
|
45
|
+
return existsSync(localBin) ? { path: localBin, useLocal: true } : { path: "npx", useLocal: false };
|
|
53
46
|
}
|
|
54
47
|
async function createWorkDir(projectRoot) {
|
|
55
|
-
const
|
|
56
|
-
await mkdir(
|
|
57
|
-
const gitignorePath = path.join(
|
|
48
|
+
const workdirRoot = path.join(projectRoot, ".frida-test-cache");
|
|
49
|
+
await mkdir(workdirRoot, { recursive: true });
|
|
50
|
+
const gitignorePath = path.join(workdirRoot, ".gitignore");
|
|
58
51
|
if (!existsSync(gitignorePath)) {
|
|
59
52
|
await writeFile(gitignorePath, "*\n", "utf8");
|
|
60
53
|
}
|
|
61
|
-
|
|
54
|
+
const workdir = await mkdtemp(workdirRoot + path.sep);
|
|
55
|
+
logger.info(`Temporary workdir created at ${workdir}`);
|
|
56
|
+
return workdir;
|
|
62
57
|
}
|
|
63
58
|
async function deleteWorkDir(workDir) {
|
|
64
59
|
try {
|
|
@@ -68,19 +63,6 @@ async function deleteWorkDir(workDir) {
|
|
|
68
63
|
logger.warn(`Failed to remove temporary work dir "${workDir}": ${err.message}`);
|
|
69
64
|
}
|
|
70
65
|
}
|
|
71
|
-
async function copyDirRecursive(srcDir, destDir) {
|
|
72
|
-
await mkdir(destDir, { recursive: true });
|
|
73
|
-
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
74
|
-
await Promise.all(entries.map(async (entry) => {
|
|
75
|
-
const srcPath = path.join(srcDir, entry.name);
|
|
76
|
-
const destPath = path.join(destDir, entry.name);
|
|
77
|
-
if (entry.isDirectory()) {
|
|
78
|
-
await copyDirRecursive(srcPath, destPath);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
await copyFile(srcPath, destPath);
|
|
82
|
-
}));
|
|
83
|
-
}
|
|
84
66
|
export async function bundleAgent(testSuitePaths, keep = false) {
|
|
85
67
|
if (testSuitePaths.length === 0) {
|
|
86
68
|
throw new Error("bundleAgent requires at least one test suite path.");
|
|
@@ -88,8 +70,9 @@ export async function bundleAgent(testSuitePaths, keep = false) {
|
|
|
88
70
|
const projectRoot = getProjectRoot();
|
|
89
71
|
const workDir = await createWorkDir(projectRoot);
|
|
90
72
|
try {
|
|
91
|
-
const agentRuntimeSrcDir = getAgentRuntimeSrcDir(
|
|
92
|
-
|
|
73
|
+
const agentRuntimeSrcDir = getAgentRuntimeSrcDir();
|
|
74
|
+
logger.info(`Agent runtime found in ${agentRuntimeSrcDir}`);
|
|
75
|
+
await cp(agentRuntimeSrcDir, workDir, { recursive: true });
|
|
93
76
|
const entrypointPath = path.join(workDir, AGENT_ENTRYPOINT_FILENAME);
|
|
94
77
|
const agentSource = await readFile(entrypointPath, "utf8");
|
|
95
78
|
if (!agentSource.includes(IMPORT_MARKER)) {
|
|
@@ -106,26 +89,24 @@ export async function bundleAgent(testSuitePaths, keep = false) {
|
|
|
106
89
|
await writeFile(entrypointPath, agentSource.replace(IMPORT_MARKER, importStatements), "utf8");
|
|
107
90
|
const outfilePath = path.join(workDir, AGENT_BUNDLE_FILENAME);
|
|
108
91
|
const fridaCompile = getFridaCompileBin(projectRoot);
|
|
109
|
-
|
|
110
|
-
let stderr;
|
|
92
|
+
const args = fridaCompile.useLocal ? [entrypointPath, "-o", outfilePath] : ["frida-compile", entrypointPath, "-o", outfilePath];
|
|
111
93
|
try {
|
|
112
|
-
|
|
113
|
-
({ stdout, stderr } = await execFileAsync(fridaCompile.path, args, {
|
|
94
|
+
execFileSync(fridaCompile.path, args, {
|
|
114
95
|
cwd: projectRoot,
|
|
115
96
|
shell: process.platform === "win32",
|
|
116
|
-
|
|
97
|
+
encoding: "utf8",
|
|
98
|
+
});
|
|
117
99
|
}
|
|
118
100
|
catch (err) {
|
|
119
|
-
|
|
101
|
+
const stderr = err.stderr?.toString().trim();
|
|
102
|
+
throw new Error(`frida-compile failed for entrypoint "${entrypointPath}" with suites [${testSuitePaths.join(", ")}]: ${stderr || err.message}`, { cause: err });
|
|
120
103
|
}
|
|
121
|
-
|
|
122
|
-
logger.log(`[frida-compile] ${stdout.trim()}`);
|
|
123
|
-
if (stderr.trim())
|
|
124
|
-
logger.warn(`[frida-compile] ${stderr.trim()}`);
|
|
104
|
+
logger.info(`Agent bundle sucessfully created and saved at ${outfilePath}.`);
|
|
125
105
|
return await readFile(outfilePath, "utf8");
|
|
126
106
|
}
|
|
127
107
|
finally {
|
|
128
108
|
if (!keep) {
|
|
109
|
+
logger.info(`Cleaning up workdir.`);
|
|
129
110
|
await deleteWorkDir(workDir);
|
|
130
111
|
}
|
|
131
112
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { bundleAgent } from "./bundler.js";
|
|
5
|
+
import { collectTestSuitePaths } from "./collector.js";
|
|
6
|
+
import { logger } from "./logger.js";
|
|
1
7
|
const usage = `
|
|
2
8
|
Usage: frida-test-compiler [options] <src_path>...
|
|
3
9
|
|
|
@@ -5,34 +11,43 @@ const usage = `
|
|
|
5
11
|
-o, --out <path> Path of the output file for JSON reporter (default: disabled)
|
|
6
12
|
-h, --help Show this help message
|
|
7
13
|
`;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
class CliError extends Error {
|
|
15
|
+
}
|
|
16
|
+
function fail(message) {
|
|
17
|
+
throw new CliError(message);
|
|
18
|
+
}
|
|
19
|
+
async function main() {
|
|
20
|
+
const { values, positionals } = parseArgs({
|
|
21
|
+
allowPositionals: true,
|
|
22
|
+
options: {
|
|
23
|
+
out: { type: "string", short: "o" },
|
|
24
|
+
help: { type: "boolean", short: "h", default: false },
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
if (values.help) {
|
|
20
28
|
console.log(usage);
|
|
21
|
-
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (positionals.length === 0) {
|
|
32
|
+
fail("Missing required argument <src_path>...");
|
|
33
|
+
}
|
|
34
|
+
const testSuitePaths = await collectTestSuitePaths(positionals);
|
|
35
|
+
const bundle = await bundleAgent(testSuitePaths);
|
|
36
|
+
if (values.out) {
|
|
37
|
+
await writeFile(values.out, bundle, "utf8");
|
|
22
38
|
}
|
|
23
39
|
else {
|
|
24
|
-
|
|
40
|
+
console.log(bundle);
|
|
25
41
|
}
|
|
26
42
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
43
|
+
main().catch((error) => {
|
|
44
|
+
if (error instanceof CliError) {
|
|
45
|
+
logger.error(error.message);
|
|
46
|
+
console.log(chalk.dim(usage));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
50
|
+
logger.error(`Fatal error: ${msg}`);
|
|
51
|
+
}
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frida-test",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"homepage": "https://github.com/bernhste/frida-test/blob/main/README.md",
|
|
@@ -20,14 +20,15 @@
|
|
|
20
20
|
},
|
|
21
21
|
"bin": {
|
|
22
22
|
"frida-test": "bin/frida-test.js",
|
|
23
|
-
"frida-test-
|
|
23
|
+
"frida-test-compile": "bin/frida-test-compile.js"
|
|
24
24
|
},
|
|
25
25
|
"types": "./src/agent-runtime/globals.d.ts",
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
28
28
|
"types": "./src/agent-runtime/globals.d.ts",
|
|
29
29
|
"default": "./src/agent-runtime/globals.ts"
|
|
30
|
-
}
|
|
30
|
+
},
|
|
31
|
+
"./protocol.js": "./src/protocol.js"
|
|
31
32
|
},
|
|
32
33
|
"files": [
|
|
33
34
|
"dist/",
|
|
@@ -35,10 +36,11 @@
|
|
|
35
36
|
"src/agent-runtime"
|
|
36
37
|
],
|
|
37
38
|
"scripts": {
|
|
38
|
-
"build": "
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
39
|
+
"build": "tsc -b",
|
|
40
|
+
"watch": "tsc -b --watch",
|
|
41
|
+
"clean": "tsc -b --clean && rimraf dist",
|
|
42
|
+
"test:android": "npm run build && frida-test -U -i 'com.google.android.dialer' ./tests/",
|
|
43
|
+
"prepublishOnly": "npm run clean && npm run build && npm run test:android"
|
|
42
44
|
},
|
|
43
45
|
"allowScripts": {
|
|
44
46
|
"frida": true
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// AUTO-GENERATED by frida-test - do not edit
|
|
2
|
-
|
|
2
|
+
/// <reference types="frida-gum" />
|
|
3
|
+
import type { AgentMessage, RunSummary } from "frida-test/protocol.js";
|
|
3
4
|
import "./globals.js";
|
|
4
5
|
import "./matchers.js";
|
|
5
6
|
import { registry, runTests } from "./registry.js";
|
|
File without changes
|