mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-08-02 18:59:36 -04:00
webapi: Fix cross-origin MessageEvent.source WindowProxy identity
MessageEvent.getSource returned the bare *Window, the only window accessor that did not go through Window.Access.init. Every other accessor (iframe.contentWindow, window.parent, window.top) wraps a cross-origin target as *CrossOriginWindow. JS object identity is keyed by Zig pointer (identity_map), so cross-origin event.source (the *Window) and iframe.contentWindow (&window._cross_origin_wrapper) resolved to different JS objects: `event.source === iframe.contentWindow` was false cross-origin while true same-origin. The WHATWG HTML spec requires these to be the same object regardless of origin (one WindowProxy per browsing context; MessageEvent.source is that WindowProxy). The mismatch breaks postMessage handshakes that authenticate the sender by reference identity, e.g. keycloak-js's 3rd-party-cookie check (`if (iframe.contentWindow !== event.source) return;`), which then times out and fails OIDC init. Route getSource through Window.Access.init(frame.window, source) — exactly like IFrame.getContentWindow — so both paths resolve to the same per-frame proxy. Same-origin behaviour is unchanged. Verified against Chrome 149 (identity holds cross- and same-origin). Adds a regression test, cross_origin_message_source.html. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
49
src/browser/tests/frames/cross_origin_message_source.html
Normal file
49
src/browser/tests/frames/cross_origin_message_source.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../testing.js"></script>
|
||||
|
||||
<!--
|
||||
MessageEvent.source is the WindowProxy of the frame the message came from, so it
|
||||
is reference-equal to that frame's iframe.contentWindow — for a cross-origin
|
||||
sender as well as a same-origin one. The two children below differ only by origin:
|
||||
localhost is cross-origin to the 127.0.0.1 test page, 127.0.0.1 is same-origin;
|
||||
both must satisfy event.source === iframe.contentWindow.
|
||||
-->
|
||||
|
||||
<script id="message_source_identity" type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
const ALT_BASE = testing.BASE_URL.replace('127.0.0.1', 'localhost');
|
||||
const ALT_ORIGIN = testing.ORIGIN.replace('127.0.0.1', 'localhost');
|
||||
|
||||
function loadAndAwait(src, expectedOrigin) {
|
||||
return new Promise((resolve) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
const onmsg = (e) => {
|
||||
if (e.origin !== expectedOrigin) return;
|
||||
window.removeEventListener('message', onmsg);
|
||||
resolve({ iframe, event: e });
|
||||
};
|
||||
window.addEventListener('message', onmsg);
|
||||
iframe.src = src;
|
||||
document.documentElement.appendChild(iframe);
|
||||
});
|
||||
}
|
||||
|
||||
// localhost is a different origin than the 127.0.0.1 test page: cross-origin sender.
|
||||
const cross = await loadAndAwait(ALT_BASE + 'frames/support/post_to_parent.html', ALT_ORIGIN);
|
||||
// 127.0.0.1 is the test page's own origin: same-origin control.
|
||||
const same = await loadAndAwait(testing.BASE_URL + 'frames/support/post_to_parent.html', testing.ORIGIN);
|
||||
state.resolve();
|
||||
|
||||
await state.done(() => {
|
||||
testing.expectEqual('hello', cross.event.data);
|
||||
testing.expectEqual(ALT_ORIGIN, cross.event.origin);
|
||||
testing.expectFalse(cross.event.source === null);
|
||||
testing.expectTrue(cross.event.source === cross.iframe.contentWindow);
|
||||
|
||||
testing.expectEqual('hello', same.event.data);
|
||||
testing.expectEqual(testing.ORIGIN, same.event.origin);
|
||||
testing.expectTrue(same.event.source === same.iframe.contentWindow);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
4
src/browser/tests/frames/support/post_to_parent.html
Normal file
4
src/browser/tests/frames/support/post_to_parent.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
parent.postMessage('hello', '*');
|
||||
</script>
|
||||
@@ -21,6 +21,7 @@ const lp = @import("lightpanda");
|
||||
|
||||
const js = @import("../../js/js.zig");
|
||||
const Page = @import("../../Page.zig");
|
||||
const Frame = @import("../../Frame.zig");
|
||||
|
||||
const Event = @import("../Event.zig");
|
||||
const MessagePort = @import("../MessagePort.zig");
|
||||
@@ -116,8 +117,9 @@ pub fn getOrigin(self: *const MessageEvent) []const u8 {
|
||||
return self._origin;
|
||||
}
|
||||
|
||||
pub fn getSource(self: *const MessageEvent) ?*Window {
|
||||
return self._source;
|
||||
pub fn getSource(self: *const MessageEvent, frame: *Frame) ?Window.Access {
|
||||
const source = self._source orelse return null;
|
||||
return Window.Access.init(frame.window, source);
|
||||
}
|
||||
|
||||
pub fn getPorts(self: *const MessageEvent) []const *MessagePort {
|
||||
|
||||
Reference in New Issue
Block a user