mirror of
https://github.com/morluto/rea.git
synced 2026-10-28 10:25:42 +00:00
* perf(graph): avoid repeated traversal edge scans and copies * fix(android)!: preserve JVM settings and reuse metadata sessions Read class metadata without generating application source, retain immutable serialized APK sessions, and join owned cleanup on cancellation and shutdown. BREAKING CHANGE: Android analysis now requires a full JDK 17 or newer with its compiler module for the packaged Java source bridge.
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import { constants, createReadStream } from "node:fs";
|
|
import { chmod, copyFile } from "node:fs/promises";
|
|
import { createHash } from "node:crypto";
|
|
import { join } from "node:path";
|
|
import {
|
|
AnalysisInputError,
|
|
AnalysisCapabilityUnavailableError,
|
|
} from "../domain/analysisErrorCore.js";
|
|
import type { AndroidOperation } from "../domain/android/androidAnalysis.js";
|
|
|
|
/** Stream a local file digest without retaining the APK or JAR in memory. */
|
|
export const hashAndroidFile = async (path: string): Promise<string> => {
|
|
const hash = createHash("sha256");
|
|
for await (const chunk of createReadStream(path)) hash.update(chunk);
|
|
return hash.digest("hex");
|
|
};
|
|
|
|
/** Bind decompiler input to the admitted artifact, even if the original changes. */
|
|
export const snapshotAndroidTarget = async (
|
|
path: string,
|
|
sha256: string,
|
|
root: string,
|
|
operation: AndroidOperation,
|
|
): Promise<string> => {
|
|
const snapshot = join(root, "target.apk");
|
|
await copyFile(path, snapshot, constants.COPYFILE_EXCL);
|
|
await chmod(snapshot, 0o400);
|
|
if ((await hashAndroidFile(snapshot)) !== sha256)
|
|
throw new AnalysisInputError(operation, undefined, [
|
|
{
|
|
path: ["path"],
|
|
reason: "invalid_value",
|
|
message:
|
|
"APK bytes changed after admission; retry against a stable file.",
|
|
},
|
|
]);
|
|
return snapshot;
|
|
};
|
|
|
|
/** Fingerprint the actual immutable engine bytes executed for this observation. */
|
|
export const snapshotAndroidEngine = async (
|
|
source: string,
|
|
sha256: string,
|
|
root: string,
|
|
operation: AndroidOperation,
|
|
): Promise<{ path: string; sha256: string }> => {
|
|
const path = join(root, "engine.jar");
|
|
await copyFile(source, path, constants.COPYFILE_EXCL);
|
|
await chmod(path, 0o400);
|
|
if ((await hashAndroidFile(path)) !== sha256)
|
|
throw new AnalysisCapabilityUnavailableError(
|
|
"jadx",
|
|
operation,
|
|
"REA_JADX_MCP_JAR bytes changed during admission; retry with a stable engine file.",
|
|
);
|
|
return { path, sha256 };
|
|
};
|