UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

185 lines (184 loc) • 7.79 kB
import { f as isLoopbackIpAddress } from "./ip-ja-e24jU.mjs"; import { i as isWebSocketUrl, n as isHttpUrl } from "./url-protocol-OU3K-ySz.mjs"; import { i as logWarn, r as logInfo } from "./logger-CYgsNcie.mjs"; import { a as stopActiveManagedProxyRegistration, i as registerActiveManagedProxyUrl, r as getActiveManagedProxyUrl, t as getActiveManagedProxyLoopbackMode } from "./active-proxy-state-fUgx64cL.mjs"; import { a as resolveManagedProxyCaFileForUrl, i as loadManagedProxyTlsOptionsSync, r as loadManagedProxyTlsOptions } from "./managed-proxy-undici-BZEfvh5e.mjs"; import { a as forceResetGlobalDispatcher } from "./undici-global-dispatcher-CPCsqe0k.mjs"; import { installGlobalProxy } from "@openclaw/proxyline"; //#region src/infra/net/proxy/proxy-lifecycle.ts const PROXY_ENV_KEYS = [ "http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY" ]; const NO_PROXY_ENV_KEYS = ["no_proxy", "NO_PROXY"]; const LOOPBACK_NO_PROXY = "127.0.0.1,localhost,localhost.,::1,[::1],127.0.0.0/8"; const managedLoopbackBypassPolicy = ({ url }) => getActiveManagedProxyLoopbackMode() === "gateway-only" && isLoopbackProxyUrl(url); const PROXY_ACTIVE_KEYS = [ "OPENCLAW_PROXY_ACTIVE", "OPENCLAW_PROXY_LOOPBACK_MODE", "OPENCLAW_PROXY_CA_FILE" ]; const ALL_PROXY_ENV_KEYS = [ ...PROXY_ENV_KEYS, ...NO_PROXY_ENV_KEYS, ...PROXY_ACTIVE_KEYS ]; let baseProxyEnvSnapshot = null; let proxylineHandle = null; const MANAGED_PROXY_UNDICI_OPTIONS = Object.freeze({ allowH2: false }); function captureProxyEnv() { return { http_proxy: process.env["http_proxy"], https_proxy: process.env["https_proxy"], HTTP_PROXY: process.env["HTTP_PROXY"], HTTPS_PROXY: process.env["HTTPS_PROXY"], no_proxy: process.env["no_proxy"], NO_PROXY: process.env["NO_PROXY"], OPENCLAW_PROXY_ACTIVE: process.env["OPENCLAW_PROXY_ACTIVE"], OPENCLAW_PROXY_LOOPBACK_MODE: process.env["OPENCLAW_PROXY_LOOPBACK_MODE"], OPENCLAW_PROXY_CA_FILE: process.env["OPENCLAW_PROXY_CA_FILE"] }; } function applyProxyEnv(proxyUrl, loopbackMode, proxyCaFile) { for (const key of PROXY_ENV_KEYS) process.env[key] = proxyUrl; process.env["OPENCLAW_PROXY_ACTIVE"] = "1"; process.env["OPENCLAW_PROXY_LOOPBACK_MODE"] = loopbackMode; if (proxyCaFile) process.env["OPENCLAW_PROXY_CA_FILE"] = proxyCaFile; else delete process.env["OPENCLAW_PROXY_CA_FILE"]; for (const key of NO_PROXY_ENV_KEYS) process.env[key] = loopbackMode === "gateway-only" ? LOOPBACK_NO_PROXY : ""; } function restoreProxyEnv(snapshot) { for (const key of ALL_PROXY_ENV_KEYS) { const value = snapshot[key]; if (value === void 0) delete process.env[key]; else process.env[key] = value; } } function restoreInactiveProxyRuntime(snapshot) { try { proxylineHandle?.stop(); } catch (err) { logWarn(`proxy: failed to stop Proxyline: ${String(err)}`); } proxylineHandle = null; restoreProxyEnv(snapshot); forceResetGlobalDispatcher(); ensureInheritedManagedProxyRoutingActive(); } function stopActiveProxyRegistration(registration) { if (registration.stopped) return; stopActiveManagedProxyRegistration(registration); if (getActiveManagedProxyUrl()) return; const restoreSnapshot = baseProxyEnvSnapshot ?? captureProxyEnv(); baseProxyEnvSnapshot = null; restoreInactiveProxyRuntime(restoreSnapshot); } function createProxyHandle(proxyUrl, registration) { return { proxyUrl, stop: async () => stopActiveProxyRegistration(registration), kill: () => stopActiveProxyRegistration(registration) }; } function resolveProxyUrl(config) { const candidate = config?.proxyUrl?.trim() || process.env["OPENCLAW_PROXY_URL"]?.trim(); if (!candidate) throw new Error("proxy: enabled but no HTTP proxy URL is configured; set proxy.proxyUrl or OPENCLAW_PROXY_URL to an http:// or https:// forward proxy."); if (!isHttpUrl(candidate)) throw new Error("proxy: enabled but proxy URL is invalid; set proxy.proxyUrl or OPENCLAW_PROXY_URL to an http:// or https:// forward proxy."); return candidate; } function redactProxyUrlForLog(value) { try { return new URL(value).origin; } catch { return "<invalid proxy URL>"; } } /** Reinstalls Proxyline routing in child processes that inherited active proxy env. */ function ensureInheritedManagedProxyRoutingActive() { if (process.env["OPENCLAW_PROXY_ACTIVE"] !== "1") return; const proxyUrl = process.env["HTTP_PROXY"]; if (!proxyUrl || !isHttpUrl(proxyUrl)) return; const proxyCaFile = resolveManagedProxyCaFileForUrl({ proxyUrl, caFileOverride: process.env["OPENCLAW_PROXY_CA_FILE"] }); const proxyTls = loadManagedProxyTlsOptionsSync(proxyCaFile); applyProxyEnv(proxyUrl, getActiveManagedProxyLoopbackMode() ?? "gateway-only", proxyCaFile); proxylineHandle = installGlobalProxy({ mode: "managed", proxyUrl, ...proxyTls ? { proxyTls } : {}, ifActive: "reuse-compatible", bypassPolicy: managedLoopbackBypassPolicy, undici: MANAGED_PROXY_UNDICI_OPTIONS }); forceResetGlobalDispatcher({ preserveProxylineManaged: true }); } /** Starts process-wide managed proxy routing and returns the owner stop handle. */ async function startProxy(config) { if (config?.enabled === false || !config?.proxyUrl?.trim() && !process.env["OPENCLAW_PROXY_URL"]?.trim()) return null; const proxyUrl = resolveProxyUrl(config); const loopbackMode = config?.loopbackMode ?? "gateway-only"; const proxyCaFile = resolveManagedProxyCaFileForUrl({ proxyUrl, config }); const proxyTls = await loadManagedProxyTlsOptions(proxyCaFile); if (getActiveManagedProxyUrl()) return createProxyHandle(proxyUrl, registerActiveManagedProxyUrl(new URL(proxyUrl), { loopbackMode, proxyTls })); baseProxyEnvSnapshot ??= captureProxyEnv(); const lifecycleBaseEnvSnapshot = baseProxyEnvSnapshot; let registration = null; try { applyProxyEnv(proxyUrl, loopbackMode, proxyCaFile); proxylineHandle = installGlobalProxy({ mode: "managed", proxyUrl, ...proxyTls ? { proxyTls } : {}, ifActive: "replace", bypassPolicy: managedLoopbackBypassPolicy, undici: MANAGED_PROXY_UNDICI_OPTIONS }); forceResetGlobalDispatcher({ preserveProxylineManaged: true }); registration = registerActiveManagedProxyUrl(new URL(proxyUrl), { loopbackMode, proxyTls }); } catch (err) { if (registration) stopActiveManagedProxyRegistration(registration); restoreInactiveProxyRuntime(lifecycleBaseEnvSnapshot); baseProxyEnvSnapshot = null; throw new Error(`proxy: failed to activate external proxy routing: ${String(err)}`, { cause: err }); } logInfo(`proxy: routing process HTTP traffic through external proxy ${redactProxyUrlForLog(proxyUrl)}`); return createProxyHandle(proxyUrl, registration); } /** Stops a managed proxy handle if one was started. */ async function stopProxy(handle) { if (!handle) return; await handle.stop(); } function isLoopbackProxyUrl(value) { try { const url = new URL(value); const hostname = url.hostname.toLowerCase().replace(/\.+$/, ""); return (isHttpUrl(url) || isWebSocketUrl(url)) && (hostname === "localhost" || isLoopbackIpAddress(hostname)); } catch { return false; } } function assertManagedProxyAllowsLoopback(url, surface) { if (isLoopbackProxyUrl(url) && getActiveManagedProxyLoopbackMode() === "block") throw new Error(`proxy: ${surface} connections are blocked by proxy.loopbackMode; run openclaw config set proxy.loopbackMode gateway-only to allow local runtime traffic.`); } function registerManagedProxyGatewayLoopbackBypass(url) { assertManagedProxyAllowsLoopback(url, "Gateway loopback control-plane"); } function registerManagedProxyBrowserCdpBypass(url) { assertManagedProxyAllowsLoopback(url, "Browser loopback CDP"); } //#endregion export { stopProxy as a, startProxy as i, registerManagedProxyBrowserCdpBypass as n, registerManagedProxyGatewayLoopbackBypass as r, ensureInheritedManagedProxyRoutingActive as t };