mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
* feat(electron): report V8 cachedData execution boundaries
analyze-javascript-application treated new vm.Script(source, {cachedData}) and vm.compileFunction(..., {cachedData}) as ordinary source. V8 deserializes previously compiled bytecode for those calls, so an Electron preload wrapper that delegates its whole contextBridge and IPC surface to a .cache/.jsc snapshot appeared to have been fully analyzed with zero exposed APIs.
Record each vm compilation with its inert cache path when the cachedData value traces to a readFileSync/readFile of path syntax, and project a cached-data execution unknown plus a loads edge from the owning source. Compilations without a cache stay recorded as no-cached-data so absence remains distinguishable from an unparsed snapshot. Count cachedData executions in the Electron summary and state the coverage limit in the graph limitations.
* style(cli): wrap the native data type path description
The `inspect-native-data-type` argument description line is 82 columns, over the repository's 80-column `.oxfmtrc.json` limit, so `npm run format:check` fails on main and on every branch merged from it. It came in with #9465 and the following commits to this file did not touch it. Reformat the one call the formatter objects to; no behaviour change.
* style(domain): reformat the pending dynamic-code accumulator field
`npm run format:check` fails on this branch, which is what `Static checks` reports: oxfmt wants the `pendingDynamicCode` union on one line. Applying it is the whole change; no behaviour is touched.
* fix(electron): preserve VM callable and cache source uncertainty
* docs(javascript): specify cached-data compilation boundaries
* fix(electron): exclude disabled caches from recovered boundaries
---------
Co-authored-by: 2SinceJuly <202121119+2SinceJuly@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
import * as t from "@babel/types";
|
|
|
|
import { inspectElectronBrowserNode } from "./electronStaticAnalysisBrowser.js";
|
|
import { deferElectronDynamicCode } from "./electronStaticAnalysisDynamicCode.js";
|
|
import { inspectElectronIpcNode } from "./electronStaticAnalysisIpc.js";
|
|
import { inspectElectronNativeNode } from "./electronStaticAnalysisNative.js";
|
|
import { inspectElectronProtocolNode } from "./electronStaticAnalysisProtocol.js";
|
|
import type { JavaScriptFindingContext } from "./javascriptStaticAnalysisState.js";
|
|
import {
|
|
electronCandidateAuthority,
|
|
electronCalleePath,
|
|
} from "./electronStaticAnalysisValues.js";
|
|
import { addLocatedFinding } from "./javascriptStaticAnalysisFindings.js";
|
|
import { range } from "./javascriptStaticAnalysisHelpers.js";
|
|
|
|
/** Collect Electron-specific syntax during the shared inert AST traversal. */
|
|
export const inspectElectronStaticNode = (
|
|
node: t.Node,
|
|
context: JavaScriptFindingContext,
|
|
): void => {
|
|
inspectElectronBrowserNode(node, context);
|
|
inspectElectronIpcNode(node, context);
|
|
inspectElectronNativeNode(node, context);
|
|
deferElectronDynamicCode(node, context);
|
|
const path =
|
|
t.isCallExpression(node) || t.isOptionalCallExpression(node)
|
|
? (electronCalleePath(node.callee, context) ??
|
|
context.electronInvocationPath?.(node))
|
|
: undefined;
|
|
const provenAppPathChange =
|
|
context.electronAppPathChangePossible?.(node) === true;
|
|
const candidateAppPathChange =
|
|
!provenAppPathChange &&
|
|
context.electronCandidateAppPathChangePossible?.(node) === true;
|
|
if (
|
|
(path !== undefined &&
|
|
path[0] === "app" &&
|
|
path[1] === "setAppPath" &&
|
|
path
|
|
.slice(2)
|
|
.every((member) => ["call", "apply", "bind"].includes(member))) ||
|
|
provenAppPathChange ||
|
|
candidateAppPathChange
|
|
)
|
|
// A bound or exported setter may escape this source before it changes the
|
|
// shared app path. Keep that possibility without claiming an invocation.
|
|
addLocatedFinding(context, {
|
|
collection: context.accumulator.appPathChanges,
|
|
key: "electron:app-path-change",
|
|
node,
|
|
value: {
|
|
...(candidateAppPathChange
|
|
? { loader_authority: "candidate" as const }
|
|
: {}),
|
|
...(t.isCallExpression(node) || t.isOptionalCallExpression(node)
|
|
? electronCandidateAuthority(node.callee, context)
|
|
: {}),
|
|
module_key: null,
|
|
location: range(node),
|
|
},
|
|
});
|
|
inspectElectronProtocolNode(node, context);
|
|
};
|