mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
98b2b027af
* fix(linux): support CachyOS Hopper hosts * fix(config): reuse user-local Hopper launcher * fix(hopper): harden Linux demo dialog handling * chore: retrigger CI after PR title fix * fix(linux): align Hopper defaults and support docs --------- Co-authored-by: Ysopwnable <161784452+N0zoM1z0@users.noreply.github.com>
68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
import { accessSync, constants } from "node:fs";
|
|
import { homedir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import { ConfigurationError } from "../domain/configurationErrors.js";
|
|
import { ok, type Result } from "../domain/result.js";
|
|
import { parseEnvironment } from "./environment.js";
|
|
import { parseStringArray, parseLoaderArgs } from "./parsers.js";
|
|
import type { AppConfig } from "./types.js";
|
|
|
|
const DEFAULT_HOPPER_LAUNCHER_PATH =
|
|
"/Applications/Hopper Disassembler.app/Contents/MacOS/hopper";
|
|
const SYSTEM_LINUX_HOPPER = "/opt/hopper/bin/Hopper";
|
|
|
|
const executableAvailable = (path: string): boolean => {
|
|
try {
|
|
accessSync(path, constants.X_OK);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
export const defaultHopperLauncherPath = (
|
|
platform: NodeJS.Platform = process.platform,
|
|
homeDirectory: string = homedir(),
|
|
executable: (path: string) => boolean = executableAvailable,
|
|
): string => {
|
|
if (platform !== "linux") return DEFAULT_HOPPER_LAUNCHER_PATH;
|
|
if (executable(SYSTEM_LINUX_HOPPER)) return SYSTEM_LINUX_HOPPER;
|
|
const userLocal = join(homeDirectory, ".local/share/rea/hopper/bin/Hopper");
|
|
return executable(userLocal) ? userLocal : SYSTEM_LINUX_HOPPER;
|
|
};
|
|
|
|
/** Parse provider configuration and runtime prerequisites at the composition root. */
|
|
export const parseConfig = (
|
|
environment: Readonly<Record<string, string | undefined>>,
|
|
): Result<AppConfig, ConfigurationError> => {
|
|
const parsed = parseEnvironment(environment);
|
|
if (!parsed.ok) return parsed;
|
|
const env = parsed.value;
|
|
const loaderArgs = parseLoaderArgs(env.HOPPER_LOADER_ARGS_JSON);
|
|
if (!loaderArgs.ok) return loaderArgs;
|
|
const secretPatterns = parseStringArray(
|
|
env.REA_REFERENCE_SECRET_PATTERNS_JSON,
|
|
"REA_REFERENCE_SECRET_PATTERNS_JSON",
|
|
);
|
|
if (!secretPatterns.ok) return secretPatterns;
|
|
return ok({
|
|
analysisProvider: env.REA_ANALYSIS_PROVIDER,
|
|
...(env.REA_IDA_MCP_CONFIG === undefined
|
|
? {}
|
|
: { idaMcpConfigPath: env.REA_IDA_MCP_CONFIG }),
|
|
ghidraInstallDir: env.GHIDRA_INSTALL_DIR,
|
|
ghidraJavaHome: env.JAVA_HOME,
|
|
...(env.REA_GHIDRA_NATIVEAOT_JAR === undefined
|
|
? {}
|
|
: { ghidraNativeAotJar: env.REA_GHIDRA_NATIVEAOT_JAR }),
|
|
ilspyCmdPath: env.REA_ILSPY_CMD_PATH,
|
|
hopperLauncherPath: env.HOPPER_LAUNCHER_PATH ?? defaultHopperLauncherPath(),
|
|
hopperTargetPath: env.HOPPER_TARGET_PATH,
|
|
hopperTargetKind: env.HOPPER_TARGET_KIND,
|
|
hopperLoaderArgs: loaderArgs.value,
|
|
logLevel: env.REA_LOG_LEVEL,
|
|
referenceSourcePolicy: { secretPatterns: secretPatterns.value },
|
|
});
|
|
};
|