Files
reverse-engineering-anything/src/browser/CdpAuthorizedMainFrame.ts
T
0154141304 fix(browser): preserve frame identity across captures (#4040)
* fix(browser): preserve capture evidence fidelity

* fix(browser): align frame identity comparisons

* fix(browser): retain historical frame evidence

* fix(electron): retain same-document script owners

* fix(electron): bind frame proof to tree reads

* fix(browser): retain malformed frame scope

* fix(browser): retain WebMCP event scope

* fix(browser): retain malformed timeline identity

* fix(browser): unify frame identity and scope

* fix(electron): prove enclosing frame ancestry

* fix(electron): separate ancestry from file policy

* fix(browser): preserve transient fragment semantics

* fix(browser): retry uncertain initial frame scope

* fix(browser): preserve runtime frame identity

* refactor(browser): separate independent capture fixes

* fix(electron): detect tree-first document replacement

* fix(electron): retain same-document tree authority

---------

Co-authored-by: eco-null <eco-null@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-23 17:19:35 +08:00

46 lines
1.7 KiB
TypeScript

import type { BrowserObservationOperation } from "../domain/browserObservationErrors.js";
import { BrowserObservationError } from "../domain/browserObservationError.js";
import type { CdpConnection } from "./CdpConnection.js";
import {
classifyCdpFrameUrl,
observeMainFrameUrl,
} from "./CdpCaptureDocuments.js";
import { delayWithCancellation } from "./CdpCaptureValues.js";
interface AuthorizedMainFrameOptions {
readonly connection: CdpConnection;
readonly sessionId: string | undefined;
readonly signal: AbortSignal | undefined;
readonly allowedOrigins: ReadonlySet<string>;
readonly operation: BrowserObservationOperation;
}
/** Wait for the attached target's main frame to enter its approved origin. */
export const authorizedMainFrame = async ({
connection,
sessionId,
signal,
allowedOrigins,
operation,
}: AuthorizedMainFrameOptions): Promise<unknown> => {
for (let attempt = 0; attempt < 80; attempt += 1) {
const result = await connection.send(
"Page.getFrameTree",
{},
sessionId,
signal,
);
const observed = observeMainFrameUrl(result);
const facts = classifyCdpFrameUrl(observed, allowedOrigins);
if (facts.scope === "outside_policy")
throw new BrowserObservationError(operation, "target_not_allowed");
if (facts.scope === "approved" && observed.kind === "invalid_fragment")
throw new BrowserObservationError(operation, "protocol_error");
if (facts.url !== undefined) return result;
// Unsupported or missing base evidence cannot establish a policy exit.
// Keep the bounded startup retry even when the fragment is malformed.
await delayWithCancellation(25, operation, signal);
}
throw new BrowserObservationError(operation, "target_not_allowed");
};