From f67370ce038c6dfec2f57f5e6ab7027dc1ccb74b Mon Sep 17 00:00:00 2001 From: Haze <709547807@qq.com> Date: Fri, 6 Feb 2026 03:40:47 +0800 Subject: [PATCH] fix(app): scope header overrides to gateway URLs only - The session.webRequest.onHeadersReceived was stripping X-Frame-Options and modifying CSP for ALL responses including the Vite dev server, which could break the main app rendering. Now only applies to gateway URLs (127.0.0.1:18789 / localhost:18789). - Dashboard: only fetch channels/skills when gateway is running - Dashboard: guard against non-array channels/skills data - Gateway store: use dynamic import() instead of require() for chat store to avoid ESM/CJS issues in Vite --- electron/main/index.ts | 13 ++++++++++--- src/pages/Dashboard/index.tsx | 20 ++++++++++++-------- src/stores/gateway.ts | 19 ++++++++++++------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/electron/main/index.ts b/electron/main/index.ts index 6514038fc..a772329d8 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -75,12 +75,19 @@ async function initialize(): Promise { // Create system tray createTray(mainWindow); - // Override security headers for the OpenClaw Control UI webview + // Override security headers ONLY for the OpenClaw Gateway Control UI // The Control UI sets X-Frame-Options: DENY and CSP frame-ancestors 'none' - // which prevents embedding in an Electron webview + // which prevents embedding in an iframe. Only apply to gateway URLs. session.defaultSession.webRequest.onHeadersReceived((details, callback) => { + const isGatewayUrl = details.url.includes('127.0.0.1:18789') || details.url.includes('localhost:18789'); + + if (!isGatewayUrl) { + callback({ responseHeaders: details.responseHeaders }); + return; + } + const headers = { ...details.responseHeaders }; - // Remove X-Frame-Options to allow embedding in webview + // Remove X-Frame-Options to allow embedding in iframe delete headers['X-Frame-Options']; delete headers['x-frame-options']; // Remove restrictive CSP frame-ancestors diff --git a/src/pages/Dashboard/index.tsx b/src/pages/Dashboard/index.tsx index 2729a44ae..cfcca0028 100644 --- a/src/pages/Dashboard/index.tsx +++ b/src/pages/Dashboard/index.tsx @@ -26,15 +26,19 @@ export function Dashboard() { const { channels, fetchChannels } = useChannelsStore(); const { skills, fetchSkills } = useSkillsStore(); - // Fetch data on mount - useEffect(() => { - fetchChannels(); - fetchSkills(); - }, [fetchChannels, fetchSkills]); + const isGatewayRunning = gatewayStatus.state === 'running'; - // Calculate statistics - const connectedChannels = channels.filter((c) => c.status === 'connected').length; - const enabledSkills = skills.filter((s) => s.enabled).length; + // Fetch data only when gateway is running + useEffect(() => { + if (isGatewayRunning) { + fetchChannels(); + fetchSkills(); + } + }, [fetchChannels, fetchSkills, isGatewayRunning]); + + // Calculate statistics safely + const connectedChannels = Array.isArray(channels) ? channels.filter((c) => c.status === 'connected').length : 0; + const enabledSkills = Array.isArray(skills) ? skills.filter((s) => s.enabled).length : 0; // Calculate uptime const uptime = gatewayStatus.connectedAt diff --git a/src/stores/gateway.ts b/src/stores/gateway.ts index 2d81d6016..f46370fb1 100644 --- a/src/stores/gateway.ts +++ b/src/stores/gateway.ts @@ -62,13 +62,18 @@ export const useGatewayStore = create((set, get) => ({ // Listen for chat events from the gateway and forward to chat store window.electron.ipcRenderer.on('gateway:chat-message', (data) => { - const { useChatStore } = require('./chat'); - const chatData = data as { message?: Record } | Record; - // The event payload may be nested under 'message' or directly on data - const event = ('message' in chatData && typeof chatData.message === 'object') - ? chatData.message as Record - : chatData as Record; - useChatStore.getState().handleChatEvent(event); + try { + // Dynamic import to avoid circular dependency + import('./chat').then(({ useChatStore }) => { + const chatData = data as { message?: Record } | Record; + const event = ('message' in chatData && typeof chatData.message === 'object') + ? chatData.message as Record + : chatData as Record; + useChatStore.getState().handleChatEvent(event); + }); + } catch (err) { + console.warn('Failed to forward chat event:', err); + } }); } catch (error) {