mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 01:13:39 +00:00
fix(electron): select nested handlers by source coordinates
This commit is contained in:
1 parent
5d5fef7391
commit
319fee4691
2 files changed
+60
-24
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
compareJavaScriptSourcePoints,
|
||||
javascriptSourceRangeKey,
|
||||
javascriptSourceRangeContains,
|
||||
} from "../../domain/javascript/javascriptSourceCoordinates.js";
|
||||
@@ -381,31 +382,29 @@ const containingHandler = (
|
||||
records: readonly ElectronIpcRecord[],
|
||||
file: JavaScriptArtifactFile,
|
||||
validation: ElectronSenderValidationFinding,
|
||||
): ElectronIpcRecord | undefined =>
|
||||
records
|
||||
.filter(
|
||||
(record) =>
|
||||
record.file.path === file.path &&
|
||||
record.finding.handler_location !== null &&
|
||||
javascriptSourceRangeContains(
|
||||
record.finding.handler_location,
|
||||
validation.location,
|
||||
),
|
||||
): ElectronIpcRecord | undefined => {
|
||||
let selected: ElectronIpcRecord | undefined;
|
||||
for (const record of records) {
|
||||
const location = record.finding.handler_location;
|
||||
if (
|
||||
record.file.path !== file.path ||
|
||||
location === null ||
|
||||
!javascriptSourceRangeContains(location, validation.location)
|
||||
)
|
||||
.sort(
|
||||
(left, right) =>
|
||||
rangeMagnitude(left.finding.handler_location) -
|
||||
rangeMagnitude(right.finding.handler_location),
|
||||
)[0];
|
||||
|
||||
const rangeMagnitude = (
|
||||
range: ElectronIpcRecord["finding"]["handler_location"],
|
||||
): number =>
|
||||
range === null
|
||||
? Number.MAX_SAFE_INTEGER
|
||||
: (range.end.line - range.start.line) * 1_000_000 +
|
||||
range.end.column -
|
||||
range.start.column;
|
||||
continue;
|
||||
const previous = selected?.finding.handler_location;
|
||||
// Parsed handler ranges nest: the innermost starts latest, then ends
|
||||
// earliest. Columns have no fixed upper bound in minified JavaScript.
|
||||
if (
|
||||
previous == null ||
|
||||
compareJavaScriptSourcePoints(location.start, previous.start) > 0 ||
|
||||
(compareJavaScriptSourcePoints(location.start, previous.start) === 0 &&
|
||||
compareJavaScriptSourcePoints(location.end, previous.end) < 0)
|
||||
)
|
||||
selected = record;
|
||||
}
|
||||
return selected;
|
||||
};
|
||||
|
||||
const coverageFor = (
|
||||
context: JavaScriptArtifactGraphContext,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { addElectronIpcBoundaries } from "./ElectronBoundaryGraphIpc.js";
|
||||
import { createElectronIpcContext } from "./ElectronBoundaryAnalysis.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
@@ -443,3 +445,38 @@ it.each([
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("attaches sender validation to the innermost handler after a long minified line", () => {
|
||||
const source = `const {ipcMain}=require('electron');/*${"x".repeat(2_000_010)}*/ipcMain.handle('outer', event=>{
|
||||
ipcMain.handle('inner', event=>{ if(event.senderFrame.url === 'https://trusted.test') return true; });
|
||||
});`;
|
||||
const file = {
|
||||
...skippedFile(),
|
||||
bytes: Buffer.byteLength(source),
|
||||
text: { included: true as const, value: source },
|
||||
};
|
||||
const javascript = analyzeJavaScriptStaticSource(source);
|
||||
expect(javascript.electron.sender_validations).toHaveLength(1);
|
||||
const analysis = analysisFor([{ file, javascript, semantic: null }]);
|
||||
const context = contextFor(file, analysis);
|
||||
addJavaScriptArtifactFiles(context);
|
||||
addElectronIpcBoundaries(
|
||||
context,
|
||||
createElectronIpcContext(analysis, () => "app"),
|
||||
);
|
||||
const handlers = context.accumulator
|
||||
.nodes()
|
||||
.filter(({ kind }) => kind === "ipc-handler");
|
||||
const validated = handlers.filter(({ observations }) =>
|
||||
observations.some(
|
||||
({ properties }) =>
|
||||
properties.fact_kind === "sender-validation-candidate",
|
||||
),
|
||||
);
|
||||
expect(validated).toHaveLength(1);
|
||||
expect(
|
||||
validated[0]?.observations.some(
|
||||
({ properties }) => properties.channel === "inner",
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
Reference in new issue
Block a user