mirror of
https://github.com/HeyPuter/browser.js.git
synced 2026-11-13 18:33:58 -10:00
[core] stop Intercept refusing declarations without a checkReceiver
`Intercept` threw for any declaration that converts IDL arguments and
does not pass a `checkReceiver`. No call site has ever passed one - 19
declarations on develop, zero with a receiver check - so the refusal
fired for every such interface, and `loadModules` swallowed the throw
into a `dbg.error`. Because it aborts the module function, everything
declared after the offending member went with it.
10 of the 19 declarations on develop were being refused: CookieStore,
Document.cookie, History, all five of performance.ts, StorageManager
and FileSystemHandle behind it, and Worklet. The runway failures are a
readout of exactly that set - ckjar-*, cookies-*, the pushstate tests,
platform-performance-observer, platform-resource-timing-own-entries -
none of which fail on 060552a4, before #110 landed.
The ordering it guarded is real: Web IDL brand-checks the receiver
before converting arguments, and conversion runs page code. But the
predicate asked whether a member declares IDL arguments at all, not
whether its conversion can run any page code, so `@Arguments()` with no
types was refused too. And a promise-only interface like Cache or
CookieStore has no member that can satisfy the contract at all, since
they reject rather than throw. Refusing to install is much the worse
outcome: for the storage-shaped modules it means no origin scoping,
which is a cross-origin leak traded for a fingerprint.
#117 tracks the real fix - a predicate that asks whether a conversion
can run page code, an async brand check, and a build-time failure.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_018Zn7Pst62DZXqzGyrkQ68o
This commit is contained in:
1 parent
785b81ca32
commit
e438c4db13
1 file changed
+20
-24
@@ -1177,11 +1177,17 @@ return { apply, construct };
|
||||
|
||||
/**
|
||||
* `checkReceiver` must synchronously invoke a side-effect-free native getter
|
||||
* or method on the receiver, throwing for an invalid receiver. It is required
|
||||
* for instance members with IDL arguments: Web IDL checks the receiver before
|
||||
* converting arguments. For example, Headers can use the saved `has` method
|
||||
* with a fixed valid name; Blob can use its saved `size` getter. Merely
|
||||
* constructing a `client.native` wrapper does not check anything.
|
||||
* or method on the receiver, throwing for an invalid receiver. Web IDL checks
|
||||
* the receiver before converting arguments, and conversion runs page code, so
|
||||
* an instance member with IDL arguments wants one. For example, Headers can
|
||||
* use the saved `has` method with a fixed valid name; Blob can use its saved
|
||||
* `size` getter. Merely constructing a `client.native` wrapper does not check
|
||||
* anything.
|
||||
*
|
||||
* Wanted, not required: omitting it leaves the ordering imprecise rather than
|
||||
* refusing the declaration, because a promise-only interface has no member
|
||||
* that can satisfy the contract and the interfaces that do are better off
|
||||
* installed. See #117.
|
||||
*/
|
||||
Intercept(handler: any, checkReceiver?: (receiver: any) => void): void {
|
||||
const foreignbaseclass = Object_getPrototypeOf(handler);
|
||||
@@ -1198,25 +1204,15 @@ return { apply, construct };
|
||||
Object_getOwnPropertyDescriptors(handler.prototype);
|
||||
const staticDescs: Record<string | symbol, PropertyDescriptor> =
|
||||
Object_getOwnPropertyDescriptors(handler);
|
||||
// Refuse an unsafe declaration before installing any of its members.
|
||||
if (!checkReceiver) {
|
||||
for (const descs of isglobal
|
||||
? [prototypeDescs, staticDescs]
|
||||
: [prototypeDescs]) {
|
||||
for (const key of Reflect_ownKeys(descs)) {
|
||||
const desc = descs[key];
|
||||
if (isConstructorMember(desc.value)) continue;
|
||||
if (
|
||||
memberValidator(this.box, desc.value) ||
|
||||
memberValidator(this.box, desc.set, true)
|
||||
) {
|
||||
throw new Error(
|
||||
`Intercept(${classname}.${String(key)}) requires a native receiver check before IDL conversion`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// A declaration that converts IDL arguments without a `checkReceiver`
|
||||
// used to be refused here. Nothing has ever passed one, so the refusal
|
||||
// threw for every such interface and `loadModules` swallowed it into a
|
||||
// `dbg.error` - silently uninstalling cookie, CookieStore, history,
|
||||
// performance and opfs, which is a far worse outcome than the argument
|
||||
// conversion ordering it was guarding. See #117 for the real fix: a
|
||||
// predicate that asks whether a conversion can run page code at all, an
|
||||
// async brand check for the promise-only interfaces, and a build-time
|
||||
// failure rather than a runtime one.
|
||||
|
||||
// create a fake parent prototype for the handler, so that `super.method()` calls resolve to the native store versions
|
||||
const fakePrototype = {};
|
||||
|
||||
Reference in new issue
Block a user