diff --git a/packages/core/src/runtime/bridge.test.ts b/packages/core/src/runtime/bridge.test.ts index ae94404c7e..bdde120c57 100644 --- a/packages/core/src/runtime/bridge.test.ts +++ b/packages/core/src/runtime/bridge.test.ts @@ -27,11 +27,54 @@ function createMockDeps() { function makeControlMessage(action: string, extra?: Record) { return new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", action, ...extra }, }); } describe("installRuntimeControlBridge", () => { + it("rejects foreign and null senders before dispatching controls", () => { + const foreign = document.createElement("iframe"); + document.body.append(foreign); + const deps = createMockDeps(); + const handler = installRuntimeControlBridge(deps); + try { + for (const source of [foreign.contentWindow, null]) { + handler( + new MessageEvent("message", { + source, + data: { source: "hf-parent", type: "control", action: "play" }, + }), + ); + } + expect(deps.onPlay).not.toHaveBeenCalled(); + handler( + new MessageEvent("message", { + source: window, + data: { source: "hf-parent", type: "control", action: "play" }, + }), + ); + expect(deps.onPlay).toHaveBeenCalledOnce(); + } finally { + window.removeEventListener("message", handler); + foreign.remove(); + } + }); + it("accepts an embedding parent distinct from the runtime window", () => { + const frame = document.createElement("iframe"); + document.body.append(frame); + vi.stubGlobal("parent", frame.contentWindow); + const deps = createMockDeps(); + const handler = installRuntimeControlBridge(deps); + try { + handler(makeControlMessage("play")); + expect(deps.onPlay).toHaveBeenCalledOnce(); + } finally { + window.removeEventListener("message", handler); + vi.unstubAllGlobals(); + frame.remove(); + } + }); it("dispatches play command", () => { const deps = createMockDeps(); const handler = installRuntimeControlBridge(deps); diff --git a/packages/core/src/runtime/bridge.ts b/packages/core/src/runtime/bridge.ts index 4de5ff306d..8ed2ac3191 100644 --- a/packages/core/src/runtime/bridge.ts +++ b/packages/core/src/runtime/bridge.ts @@ -123,6 +123,7 @@ function handleFlashElements(data: BridgeControlData): void { export function installRuntimeControlBridge(deps: BridgeDeps): (event: MessageEvent) => void { const handler = (event: MessageEvent) => { + if (event.source !== window.parent && event.source !== window) return; const data = event.data as BridgeControlData | null; if (!data || data.source !== "hf-parent" || data.type !== "control") return; if (rejectUnsupportedProtocol(data)) return; diff --git a/packages/core/src/runtime/init.test.ts b/packages/core/src/runtime/init.test.ts index e40335dac3..7a8991ac6f 100644 --- a/packages/core/src/runtime/init.test.ts +++ b/packages/core/src/runtime/init.test.ts @@ -169,6 +169,7 @@ describe("initSandboxRuntimeModular", () => { window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", action: "set-volume", volume: 1 }, }), ); @@ -239,6 +240,7 @@ describe("initSandboxRuntimeModular", () => { window.addEventListener("error", onError); window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", action: "set-volume", volume: 1 }, }), ); @@ -2846,6 +2848,7 @@ describe("initSandboxRuntimeModular", () => { if (payload.source !== "hf-preview" || payload.type !== "ready") return; window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", @@ -2856,6 +2859,7 @@ describe("initSandboxRuntimeModular", () => { ); window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", @@ -3049,6 +3053,7 @@ describe("initSandboxRuntimeModular", () => { window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", action: "set-muted", muted: false }, }), ); @@ -3058,6 +3063,7 @@ describe("initSandboxRuntimeModular", () => { window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", action: "set-muted", muted: true }, }), ); @@ -3067,6 +3073,7 @@ describe("initSandboxRuntimeModular", () => { window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", action: "set-muted", muted: false }, }), ); @@ -3100,6 +3107,7 @@ describe("initSandboxRuntimeModular", () => { window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control", @@ -3148,6 +3156,7 @@ describe("initSandboxRuntimeModular", () => { window.dispatchEvent( new MessageEvent("message", { + source: window.parent, data: { source: "hf-parent", type: "control",