Files
openclaw-zero-token/gateway/connection-details.ts
sjhu 571e14a236 feat: upgrade to upstream v2026.3.28
Major upgrade from e26988a38 to upstream v2026.3.28 (f9b107928).
Key changes:
- Upstream src/, ui/, extensions/ (89 bundled extensions)
- Zero-token web providers preserved in src/zero-token/
- AskOnce plugin restored and registered as CLI command
- Added missing packages: @anthropic-ai/vertex-sdk, @modelcontextprotocol/sdk
- Fixed tsconfig rootDir, skipLibCheck for plugin-sdk DTS build
- Added askonce to bundled plugin metadata and package.json exports
- Fixed AskOnce CLI command registration (missing commands metadata)
- Restored AskOnce adapter imports (correct 5-level relative paths)
- Removed stale migration artifacts from root directory
2026-03-30 17:58:12 +08:00

113 lines
4.0 KiB
TypeScript

import { resolveConfigPath, resolveGatewayPort } from "../config/paths.js";
import type { OpenClawConfig } from "../config/types.js";
import { isSecureWebSocketUrl } from "./net.js";
export type GatewayConnectionDetails = {
url: string;
urlSource: string;
bindDetail?: string;
remoteFallbackNote?: string;
message: string;
};
type GatewayConnectionDetailResolvers = {
loadConfig?: () => OpenClawConfig;
resolveConfigPath?: (env: NodeJS.ProcessEnv) => string;
resolveGatewayPort?: (cfg?: OpenClawConfig, env?: NodeJS.ProcessEnv) => number;
};
function trimToUndefined(value: string | undefined): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
}
export function buildGatewayConnectionDetailsWithResolvers(
options: {
config?: OpenClawConfig;
url?: string;
configPath?: string;
urlSource?: "cli" | "env";
} = {},
resolvers: GatewayConnectionDetailResolvers = {},
): GatewayConnectionDetails {
const config = options.config ?? resolvers.loadConfig?.() ?? {};
const configPath =
options.configPath ??
resolvers.resolveConfigPath?.(process.env) ??
resolveConfigPath(process.env);
const isRemoteMode = config.gateway?.mode === "remote";
const remote = isRemoteMode ? config.gateway?.remote : undefined;
const tlsEnabled = config.gateway?.tls?.enabled === true;
const localPort =
resolvers.resolveGatewayPort?.(config, process.env) ?? resolveGatewayPort(config);
const bindMode = config.gateway?.bind ?? "loopback";
const scheme = tlsEnabled ? "wss" : "ws";
const localUrl = `${scheme}://127.0.0.1:${localPort}`;
const cliUrlOverride =
typeof options.url === "string" && options.url.trim().length > 0
? options.url.trim()
: undefined;
const envUrlOverride = cliUrlOverride
? undefined
: trimToUndefined(process.env.OPENCLAW_GATEWAY_URL);
const urlOverride = cliUrlOverride ?? envUrlOverride;
const remoteUrl =
typeof remote?.url === "string" && remote.url.trim().length > 0 ? remote.url.trim() : undefined;
const remoteMisconfigured = isRemoteMode && !urlOverride && !remoteUrl;
const urlSourceHint =
options.urlSource ?? (cliUrlOverride ? "cli" : envUrlOverride ? "env" : undefined);
const url = urlOverride || remoteUrl || localUrl;
const urlSource = urlOverride
? urlSourceHint === "env"
? "env OPENCLAW_GATEWAY_URL"
: "cli --url"
: remoteUrl
? "config gateway.remote.url"
: remoteMisconfigured
? "missing gateway.remote.url (fallback local)"
: "local loopback";
const bindDetail = !urlOverride && !remoteUrl ? `Bind: ${bindMode}` : undefined;
const remoteFallbackNote = remoteMisconfigured
? "Warn: gateway.mode=remote but gateway.remote.url is missing; set gateway.remote.url or switch gateway.mode=local."
: undefined;
const allowPrivateWs = process.env.OPENCLAW_ALLOW_INSECURE_PRIVATE_WS === "1";
if (!isSecureWebSocketUrl(url, { allowPrivateWs })) {
throw new Error(
[
`SECURITY ERROR: Gateway URL "${url}" uses plaintext ws:// to a non-loopback address.`,
"Both credentials and chat data would be exposed to network interception.",
`Source: ${urlSource}`,
`Config: ${configPath}`,
"Fix: Use wss:// for remote gateway URLs.",
"Safe remote access defaults:",
"- keep gateway.bind=loopback and use an SSH tunnel (ssh -N -L 18789:127.0.0.1:18789 user@gateway-host)",
"- or use Tailscale Serve/Funnel for HTTPS remote access",
allowPrivateWs
? undefined
: "Break-glass (trusted private networks only): set OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1",
"Doctor: openclaw doctor --fix",
"Docs: https://docs.openclaw.ai/gateway/remote",
].join("\n"),
);
}
const message = [
`Gateway target: ${url}`,
`Source: ${urlSource}`,
`Config: ${configPath}`,
bindDetail,
remoteFallbackNote,
]
.filter(Boolean)
.join("\n");
return {
url,
urlSource,
bindDetail,
remoteFallbackNote,
message,
};
}