Merge 135b62cb69ec07976deef32d2f32ac4926fff9de into 8a05c05596ca9ba0735dafd8e359885de4c2c969

This commit is contained in:
ssdiwu 2026-03-21 13:54:41 +08:00 committed by GitHub
commit e15c915586
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 133 additions and 1 deletions

View File

@ -226,6 +226,132 @@ describe("loadSettings default gateway URL derivation", () => {
});
});
it("reuses a session token across loopback host aliases", async () => {
setTestLocation({
protocol: "http:",
host: "127.0.0.1:18789",
pathname: "/",
});
const { loadSettings, saveSettings } = await import("./storage.ts");
saveSettings({
gatewayUrl: "ws://127.0.0.1:18789",
token: "loopback-token",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
});
localStorage.setItem(
"openclaw.control.settings.v1",
JSON.stringify({
gatewayUrl: "ws://localhost:18789",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
}),
);
expect(loadSettings()).toMatchObject({
gatewayUrl: "ws://localhost:18789",
token: "loopback-token",
});
});
it("reuses a session token across IPv6 and IPv4 loopback aliases", async () => {
setTestLocation({
protocol: "http:",
host: "[::1]:18789",
pathname: "/",
});
const { loadSettings, saveSettings } = await import("./storage.ts");
saveSettings({
gatewayUrl: "ws://[::1]:18789",
token: "loopback-token",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
});
localStorage.setItem(
"openclaw.control.settings.v1",
JSON.stringify({
gatewayUrl: "ws://127.0.0.1:18789",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
}),
);
expect(loadSettings()).toMatchObject({
gatewayUrl: "ws://127.0.0.1:18789",
token: "loopback-token",
});
});
it("does not reuse a loopback token across different ports", async () => {
setTestLocation({
protocol: "http:",
host: "127.0.0.1:18789",
pathname: "/",
});
const { loadSettings, saveSettings } = await import("./storage.ts");
saveSettings({
gatewayUrl: "ws://127.0.0.1:18789",
token: "loopback-token",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
});
localStorage.setItem(
"openclaw.control.settings.v1",
JSON.stringify({
gatewayUrl: "ws://localhost:19999",
sessionKey: "main",
lastActiveSessionKey: "main",
theme: "system",
chatFocusMode: false,
chatShowThinking: true,
splitRatio: 0.6,
navCollapsed: false,
navGroupsCollapsed: {},
}),
);
expect(loadSettings()).toMatchObject({
gatewayUrl: "ws://localhost:19999",
token: "",
});
});
it("does not persist gateway tokens when saving settings", async () => {
setTestLocation({
protocol: "https:",

View File

@ -93,9 +93,15 @@ function normalizeGatewayTokenScope(gatewayUrl: string): string {
? `${location.protocol}//${location.host}${location.pathname || "/"}`
: undefined;
const parsed = base ? new URL(trimmed, base) : new URL(trimmed);
const host = parsed.hostname.trim().toLowerCase();
const isLoopbackHost =
host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host.startsWith("127.");
const pathname =
parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "") || parsed.pathname;
return `${parsed.protocol}//${parsed.host}${pathname}`;
const hostPort = isLoopbackHost
? `127.0.0.1${parsed.port ? `:${parsed.port}` : ""}`
: parsed.host;
return `${parsed.protocol}//${hostPort}${pathname}`;
} catch {
return trimmed;
}