fix(openclaw controller): use buildOpenClawControlUiUrl for generating gateway URLs (#493)

This commit is contained in:
Haze
2026-03-14 18:57:43 +08:00
committed by GitHub
Unverified
parent 61291ff83f
commit 315ff6b9de
5 changed files with 38 additions and 5 deletions

View File

@@ -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) });

View File

@@ -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) };

View File

@@ -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();
}

View File

@@ -1,6 +1,6 @@
{
"name": "clawx",
"version": "0.2.3-beta.2",
"version": "0.2.3-beta.3",
"pnpm": {
"onlyBuiltDependencies": [
"@discordjs/opus",
@@ -120,4 +120,4 @@
"zx": "^8.8.5"
},
"packageManager": "pnpm@10.31.0+sha512.e3927388bfaa8078ceb79b748ffc1e8274e84d75163e67bc22e06c0d3aed43dd153151cbf11d7f8301ff4acb98c68bdc5cadf6989532801ffafe3b3e4a63c268"
}
}

View File

@@ -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/');
});
});