fix(iframe): validate trusted parent messages

This commit is contained in:
wchino
2026-07-21 23:41:18 +08:00
parent 9b3eae1896
commit 5ef2e09b04
3 changed files with 64 additions and 31 deletions

View File

@@ -5,9 +5,10 @@ import { useEffect, useCallback, type ReactNode } from "react";
import { usePlayerSessionStore } from "@/stores/player-session-store";
import { setPlayerBearerToken } from "@/lib/lottery-auth";
import {
isIframeOriginAllowed,
loadIframeAllowedOrigins,
messageToken,
resolvePostMessageTargetOrigin,
resolveTrustedParentMessage,
} from "@/lib/iframe-origins";
function sanitizeUrlForParent(href: string): string {
@@ -123,39 +124,38 @@ export function IframeBridge({ children }: { children: ReactNode }): ReactNode {
console.log("[IframeBridge] Setting up iframe communication");
const handleMessage = async (event: MessageEvent): Promise<void> => {
if (!isIframeOriginAllowed(event.origin)) {
await loadIframeAllowedOrigins(true);
if (!isIframeOriginAllowed(event.origin)) {
console.warn("[IframeBridge] Rejected message from:", event.origin);
return;
}
const data = await resolveTrustedParentMessage(event);
if (data === null) {
console.warn("[IframeBridge] Rejected untrusted parent message from:", event.origin);
return;
}
const { data } = event;
if (!data || typeof data !== "object") return;
console.log("[IframeBridge] Received message:", data.type);
switch (data.type) {
// 主站发送初始化 Token
case "MAIN_INIT_TOKEN":
if (data.token) {
case "MAIN_INIT_TOKEN": {
const token = messageToken(data);
if (token !== null) {
console.log("[IframeBridge] Received initial token");
setBearerToken(data.token);
setPlayerBearerToken(data.token);
setBearerToken(token);
setPlayerBearerToken(token);
// 勿再 notifyReady(),否则主站会重复 MAIN_INIT_TOKEN 导致消息刷屏
}
break;
}
// 主站刷新 Token
case "MAIN_REFRESH_TOKEN":
if (data.token) {
case "MAIN_REFRESH_TOKEN": {
const token = messageToken(data);
if (token !== null) {
console.log("[IframeBridge] Received refreshed token");
setBearerToken(data.token);
setPlayerBearerToken(data.token);
setBearerToken(token);
setPlayerBearerToken(token);
notifyTokenRefreshed();
}
break;
}
// 主站通知 Token 即将过期
case "MAIN_TOKEN_EXPIRING":
@@ -173,7 +173,7 @@ export function IframeBridge({ children }: { children: ReactNode }): ReactNode {
// 主站导航请求
case "MAIN_NAVIGATE":
if (data.path && typeof data.path === "string") {
if (typeof data.path === "string") {
const nextPath = resolveSafeInAppPath(data.path);
if (nextPath) {
window.history.pushState({}, "", nextPath);