mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 03:40:21 +00:00
refactor(gateway): dedupe origin seeding and plugin route auth matching
This commit is contained in:
91
src/config/gateway-control-ui-origins.ts
Normal file
91
src/config/gateway-control-ui-origins.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import type { OpenClawConfig } from "./config.js";
|
||||
import { DEFAULT_GATEWAY_PORT } from "./paths.js";
|
||||
|
||||
export type GatewayNonLoopbackBindMode = "lan" | "tailnet" | "custom";
|
||||
|
||||
export function isGatewayNonLoopbackBindMode(bind: unknown): bind is GatewayNonLoopbackBindMode {
|
||||
return bind === "lan" || bind === "tailnet" || bind === "custom";
|
||||
}
|
||||
|
||||
export function hasConfiguredControlUiAllowedOrigins(params: {
|
||||
allowedOrigins: unknown;
|
||||
dangerouslyAllowHostHeaderOriginFallback: unknown;
|
||||
}): boolean {
|
||||
if (params.dangerouslyAllowHostHeaderOriginFallback === true) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
Array.isArray(params.allowedOrigins) &&
|
||||
params.allowedOrigins.some((origin) => typeof origin === "string" && origin.trim().length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveGatewayPortWithDefault(
|
||||
port: unknown,
|
||||
fallback = DEFAULT_GATEWAY_PORT,
|
||||
): number {
|
||||
return typeof port === "number" && port > 0 ? port : fallback;
|
||||
}
|
||||
|
||||
export function buildDefaultControlUiAllowedOrigins(params: {
|
||||
port: number;
|
||||
bind: unknown;
|
||||
customBindHost?: string;
|
||||
}): string[] {
|
||||
const origins = new Set<string>([
|
||||
`http://localhost:${params.port}`,
|
||||
`http://127.0.0.1:${params.port}`,
|
||||
]);
|
||||
const customBindHost = params.customBindHost?.trim();
|
||||
if (params.bind === "custom" && customBindHost) {
|
||||
origins.add(`http://${customBindHost}:${params.port}`);
|
||||
}
|
||||
return [...origins];
|
||||
}
|
||||
|
||||
export function ensureControlUiAllowedOriginsForNonLoopbackBind(
|
||||
config: OpenClawConfig,
|
||||
opts?: { defaultPort?: number; requireControlUiEnabled?: boolean },
|
||||
): {
|
||||
config: OpenClawConfig;
|
||||
seededOrigins: string[] | null;
|
||||
bind: GatewayNonLoopbackBindMode | null;
|
||||
} {
|
||||
const bind = config.gateway?.bind;
|
||||
if (!isGatewayNonLoopbackBindMode(bind)) {
|
||||
return { config, seededOrigins: null, bind: null };
|
||||
}
|
||||
if (opts?.requireControlUiEnabled && config.gateway?.controlUi?.enabled === false) {
|
||||
return { config, seededOrigins: null, bind };
|
||||
}
|
||||
if (
|
||||
hasConfiguredControlUiAllowedOrigins({
|
||||
allowedOrigins: config.gateway?.controlUi?.allowedOrigins,
|
||||
dangerouslyAllowHostHeaderOriginFallback:
|
||||
config.gateway?.controlUi?.dangerouslyAllowHostHeaderOriginFallback,
|
||||
})
|
||||
) {
|
||||
return { config, seededOrigins: null, bind };
|
||||
}
|
||||
|
||||
const port = resolveGatewayPortWithDefault(config.gateway?.port, opts?.defaultPort);
|
||||
const seededOrigins = buildDefaultControlUiAllowedOrigins({
|
||||
port,
|
||||
bind,
|
||||
customBindHost: config.gateway?.customBindHost,
|
||||
});
|
||||
return {
|
||||
config: {
|
||||
...config,
|
||||
gateway: {
|
||||
...config.gateway,
|
||||
controlUi: {
|
||||
...config.gateway?.controlUi,
|
||||
allowedOrigins: seededOrigins,
|
||||
},
|
||||
},
|
||||
},
|
||||
seededOrigins,
|
||||
bind,
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
import {
|
||||
buildDefaultControlUiAllowedOrigins,
|
||||
hasConfiguredControlUiAllowedOrigins,
|
||||
isGatewayNonLoopbackBindMode,
|
||||
resolveGatewayPortWithDefault,
|
||||
} from "./gateway-control-ui-origins.js";
|
||||
import {
|
||||
ensureAgentEntry,
|
||||
ensureRecord,
|
||||
@@ -31,34 +37,30 @@ export const LEGACY_CONFIG_MIGRATIONS_PART_3: LegacyConfigMigration[] = [
|
||||
return;
|
||||
}
|
||||
const bind = gateway.bind;
|
||||
if (bind !== "lan" && bind !== "tailnet" && bind !== "custom") {
|
||||
if (!isGatewayNonLoopbackBindMode(bind)) {
|
||||
return;
|
||||
}
|
||||
const controlUi = getRecord(gateway.controlUi) ?? {};
|
||||
const existingOrigins = controlUi.allowedOrigins;
|
||||
const hasConfiguredOrigins =
|
||||
Array.isArray(existingOrigins) &&
|
||||
existingOrigins.some((origin) => typeof origin === "string" && origin.trim().length > 0);
|
||||
if (hasConfiguredOrigins) {
|
||||
return; // already configured
|
||||
}
|
||||
if (controlUi.dangerouslyAllowHostHeaderOriginFallback === true) {
|
||||
return; // already opted into fallback
|
||||
}
|
||||
const port =
|
||||
typeof gateway.port === "number" && gateway.port > 0 ? gateway.port : DEFAULT_GATEWAY_PORT;
|
||||
const origins = new Set<string>([`http://localhost:${port}`, `http://127.0.0.1:${port}`]);
|
||||
if (
|
||||
bind === "custom" &&
|
||||
typeof gateway.customBindHost === "string" &&
|
||||
gateway.customBindHost.trim()
|
||||
hasConfiguredControlUiAllowedOrigins({
|
||||
allowedOrigins: controlUi.allowedOrigins,
|
||||
dangerouslyAllowHostHeaderOriginFallback:
|
||||
controlUi.dangerouslyAllowHostHeaderOriginFallback,
|
||||
})
|
||||
) {
|
||||
origins.add(`http://${gateway.customBindHost.trim()}:${port}`);
|
||||
return;
|
||||
}
|
||||
gateway.controlUi = { ...controlUi, allowedOrigins: [...origins] };
|
||||
const port = resolveGatewayPortWithDefault(gateway.port, DEFAULT_GATEWAY_PORT);
|
||||
const origins = buildDefaultControlUiAllowedOrigins({
|
||||
port,
|
||||
bind,
|
||||
customBindHost:
|
||||
typeof gateway.customBindHost === "string" ? gateway.customBindHost : undefined,
|
||||
});
|
||||
gateway.controlUi = { ...controlUi, allowedOrigins: origins };
|
||||
raw.gateway = gateway;
|
||||
changes.push(
|
||||
`Seeded gateway.controlUi.allowedOrigins ${JSON.stringify([...origins])} for bind=${String(bind)}. ` +
|
||||
`Seeded gateway.controlUi.allowedOrigins ${JSON.stringify(origins)} for bind=${String(bind)}. ` +
|
||||
"Required since v2026.2.26. Add other machine origins to gateway.controlUi.allowedOrigins if needed.",
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user