From 9617bfd31defd26ccd4f3b0b91c26d7457f075de Mon Sep 17 00:00:00 2001 From: Haze <709547807@qq.com> Date: Sat, 14 Mar 2026 18:13:32 +0800 Subject: [PATCH] refactor: use buildOpenClawControlUiUrl for generating gateway URLs --- electron/api/routes/gateway.ts | 3 ++- electron/main/ipc-handlers.ts | 4 ++-- electron/utils/openclaw-control-ui.ts | 17 +++++++++++++++++ tests/unit/openclaw-control-ui.test.ts | 15 +++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 electron/utils/openclaw-control-ui.ts create mode 100644 tests/unit/openclaw-control-ui.test.ts diff --git a/electron/api/routes/gateway.ts b/electron/api/routes/gateway.ts index 530e030..4f00dbc 100644 --- a/electron/api/routes/gateway.ts +++ b/electron/api/routes/gateway.ts @@ -1,5 +1,6 @@ import type { IncomingMessage, ServerResponse } from 'http'; import { PORTS } from '../../utils/config'; +import { buildOpenClawControlUiUrl } from '../../utils/openclaw-control-ui'; import { getSetting } from '../../utils/store'; import type { HostApiContext } from '../context'; import { parseJsonBody, sendJson } from '../route-utils'; @@ -68,7 +69,7 @@ export async function handleGatewayRoutes( const status = ctx.gatewayManager.getStatus(); const token = await getSetting('gatewayToken'); const port = status.port || PORTS.OPENCLAW_GATEWAY; - const urlValue = `http://127.0.0.1:${port}/?token=${encodeURIComponent(token)}`; + const urlValue = buildOpenClawControlUiUrl(port, token); sendJson(res, 200, { success: true, url: urlValue, token, port }); } catch (error) { sendJson(res, 500, { success: false, error: String(error) }); diff --git a/electron/main/ipc-handlers.ts b/electron/main/ipc-handlers.ts index dc855c5..49664a0 100644 --- a/electron/main/ipc-handlers.ts +++ b/electron/main/ipc-handlers.ts @@ -19,6 +19,7 @@ import { saveProviderKeyToOpenClaw, removeProviderFromOpenClaw, } from '../utils/openclaw-auth'; +import { buildOpenClawControlUiUrl } from '../utils/openclaw-control-ui'; import { logger } from '../utils/logger'; import { saveChannelConfig, @@ -1283,8 +1284,7 @@ function registerGatewayHandlers( const status = gatewayManager.getStatus(); const token = await getSetting('gatewayToken'); const port = status.port || 18789; - // Pass token as query param - Control UI will store it in localStorage - const url = `http://127.0.0.1:${port}/?token=${encodeURIComponent(token)}`; + const url = buildOpenClawControlUiUrl(port, token); return { success: true, url, port, token }; } catch (error) { return { success: false, error: String(error) }; diff --git a/electron/utils/openclaw-control-ui.ts b/electron/utils/openclaw-control-ui.ts new file mode 100644 index 0000000..11cffdb --- /dev/null +++ b/electron/utils/openclaw-control-ui.ts @@ -0,0 +1,17 @@ +/** + * Build the external OpenClaw Control UI URL. + * + * OpenClaw 2026.3.13 imports one-time auth tokens from the URL fragment + * (`#token=...`) and strips them after load. Query-string tokens are removed + * by the UI bootstrap but are not imported for auth. + */ +export function buildOpenClawControlUiUrl(port: number, token: string): string { + const url = new URL(`http://127.0.0.1:${port}/`); + const trimmedToken = token.trim(); + + if (trimmedToken) { + url.hash = new URLSearchParams({ token: trimmedToken }).toString(); + } + + return url.toString(); +} diff --git a/tests/unit/openclaw-control-ui.test.ts b/tests/unit/openclaw-control-ui.test.ts new file mode 100644 index 0000000..2a641ca --- /dev/null +++ b/tests/unit/openclaw-control-ui.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from 'vitest'; + +import { buildOpenClawControlUiUrl } from '@electron/utils/openclaw-control-ui'; + +describe('buildOpenClawControlUiUrl', () => { + it('uses the URL fragment for one-time token bootstrap', () => { + expect(buildOpenClawControlUiUrl(18789, 'clawx-test-token')).toBe( + 'http://127.0.0.1:18789/#token=clawx-test-token', + ); + }); + + it('omits the fragment when the token is blank', () => { + expect(buildOpenClawControlUiUrl(18789, ' ')).toBe('http://127.0.0.1:18789/'); + }); +});