UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

280 lines (279 loc) 10.4 kB
import { h as normalizeSecretInputString, v as resolveSecretInputRef } from "./types.secrets-kC0nOetj.js"; import { n as ensureControlUiAllowedOriginsForNonLoopbackBind } from "./gateway-control-ui-origins-dIyw_yYs.js"; import { n as findTailscaleBinary } from "./tailscale-Boe4Jx-9.js"; import { t as randomToken } from "./random-token-B1woZa_H.js"; import { o as formatPortRangeHint } from "./error-format-Cae7EwnT.js"; import { t as parsePort } from "./parse-port-Dw2bUWKg.js"; import { t as resolveSecretInputModeForEnvSelection } from "./provider-auth-mode-7FOSjRoY.js"; import { n as t } from "./i18n-hynzGFbD.js"; import { f as validateGatewayPasswordInput, s as normalizeGatewayTokenInput } from "./onboard-helpers-BDY-6Z-t.js"; import { t as maskApiKey } from "./secret-mask-BEdLuCrN.js"; import { t as validateDottedDecimalIPv4Input } from "./ipv4-DSCxlk4V.js"; import { i as maybeAddTailnetOriginToControlUiAllowedOrigins, n as TAILSCALE_EXPOSURE_OPTIONS } from "./gateway-config-prompts.shared-Ds1yKtWH.js"; import { n as promptSecretRefForSetup } from "./provider-auth-ref-BgqISDYR.js"; import { t as resolveSetupSecretInputString } from "./setup.secret-input-Dtx44qLw.js"; import { t as provisionGatewayTokenStoreRef } from "./auth-token-store-ref-B_2FhDbE.js"; //#region src/wizard/setup.gateway-config.ts function getLocalizedTailscaleExposureOptions() { return TAILSCALE_EXPOSURE_OPTIONS.map((option) => ({ hint: t(`wizard.gatewayTailscale.${option.value}Hint`), label: t(`wizard.gatewayTailscale.${option.value}`), value: option.value })); } function normalizeWizardTextInput(value) { return typeof value === "string" ? value.trim() : ""; } function validateGatewayPortInput(value) { if (parsePort(value) === null) return formatPortRangeHint(); } async function configureGatewayForSetup(opts) { const { flow, localPort, quickstartGateway, prompter } = opts; let { nextConfig } = opts; const port = flow === "quickstart" ? quickstartGateway.port : parsePort(await prompter.text({ message: t("wizard.gateway.port"), initialValue: String(localPort), validate: validateGatewayPortInput })); if (port === null) throw new Error(formatPortRangeHint()); let bind = flow === "quickstart" ? quickstartGateway.bind : await prompter.select({ message: t("wizard.gateway.bindAddress"), options: [ { value: "loopback", label: t("wizard.gateway.bindLoopback"), hint: t("wizard.gateway.bindLoopbackHint") }, { value: "lan", label: t("wizard.gateway.bindLan"), hint: t("wizard.gateway.bindLanHint") }, { value: "tailnet", label: t("wizard.gateway.bindTailnet"), hint: t("wizard.gateway.bindTailnetHint") }, { value: "auto", label: t("wizard.gateway.bindAuto"), hint: t("wizard.gateway.bindAutoHint") }, { value: "custom", label: t("wizard.gateway.bindCustom"), hint: t("wizard.gateway.bindCustomHint") } ], initialValue: quickstartGateway.bind }); let customBindHost = quickstartGateway.customBindHost; if (bind === "custom") { if (flow !== "quickstart" || !customBindHost) { const input = await prompter.text({ message: t("wizard.gateway.bindCustomIp"), placeholder: "192.168.1.100", initialValue: customBindHost ?? "", validate: validateDottedDecimalIPv4Input }); customBindHost = typeof input === "string" ? input.trim() : void 0; } } let authMode = flow === "quickstart" ? quickstartGateway.authMode : await prompter.select({ message: t("wizard.gateway.accessProtection"), options: [{ value: "token", label: t("common.tokenRecommended"), hint: t("wizard.gateway.plaintextTokenHint") }, { value: "password", label: t("common.password") }], initialValue: quickstartGateway.authMode }); const tailscaleMode = flow === "quickstart" ? quickstartGateway.tailscaleMode : await prompter.select({ message: t("wizard.gateway.tailscaleExposure"), options: getLocalizedTailscaleExposureOptions(), initialValue: quickstartGateway.tailscaleMode }); let tailscaleBin = null; if (tailscaleMode !== "off") { tailscaleBin = await findTailscaleBinary(); if (!tailscaleBin) await prompter.note(t("wizard.gatewayTailscale.missingBinNote"), t("wizard.gatewayTailscale.warningTitle")); } if (tailscaleMode !== "off" && flow !== "quickstart") await prompter.note(t("wizard.gatewayTailscale.docsNote"), "Tailscale"); if (tailscaleMode !== "off" && bind !== "loopback") { await prompter.note(t("wizard.gatewayNotes.tailscaleBindLoopback"), t("wizard.gatewayNotes.bindTitle")); bind = "loopback"; customBindHost = void 0; } if (tailscaleMode === "funnel" && authMode !== "password") { await prompter.note(t("wizard.gatewayNotes.tailscaleFunnelPassword"), t("wizard.gateway.auth")); authMode = "password"; } let gatewayToken; let gatewayTokenInput; if (authMode === "token") { const quickstartTokenString = normalizeSecretInputString(quickstartGateway.token); const quickstartTokenRef = resolveSecretInputRef({ value: quickstartGateway.token, defaults: nextConfig.secrets?.defaults }).ref; const tokenMode = quickstartTokenRef ? "ref" : flow === "quickstart" && opts.secretInputMode !== "ref" ? "plaintext" : await resolveSecretInputModeForEnvSelection({ prompter, explicitMode: opts.secretInputMode, copy: { modeMessage: t("wizard.gateway.authTokenMode"), plaintextLabel: t("wizard.gateway.plaintextTokenLabel"), plaintextHint: t("wizard.gateway.plaintextTokenHint"), refLabel: t("wizard.gateway.refLabel"), refHint: t("wizard.gateway.refHint") } }); const ambientToken = normalizeGatewayTokenInput(process.env.OPENCLAW_GATEWAY_TOKEN); if (tokenMode === "ref") { if (quickstartTokenRef) { gatewayTokenInput = quickstartTokenRef; gatewayToken = await resolveSetupSecretInputString({ config: nextConfig, value: quickstartTokenRef, path: "gateway.auth.token", env: process.env }); } else if (!quickstartTokenString && !ambientToken) { const provisioned = provisionGatewayTokenStoreRef({ config: nextConfig }); gatewayTokenInput = provisioned.ref; gatewayToken = provisioned.token; await prompter.note(t("wizard.gateway.tokenStoreProvisioned", { name: provisioned.ref.id }), t("wizard.gateway.auth")); } else { const resolved = await promptSecretRefForSetup({ provider: "gateway-auth-token", config: nextConfig, prompter, preferredEnvVar: "OPENCLAW_GATEWAY_TOKEN", copy: { sourceMessage: t("wizard.gateway.authTokenStoredMessage"), envVarPlaceholder: "OPENCLAW_GATEWAY_TOKEN" } }); gatewayTokenInput = resolved.ref; gatewayToken = resolved.resolvedValue; } } else if (flow === "quickstart") { gatewayToken = (quickstartTokenString ?? ambientToken) || randomToken(); gatewayTokenInput = gatewayToken; } else { const existingToken = quickstartTokenString ?? ambientToken; let tokenInput; if (existingToken) tokenInput = await prompter.confirm({ message: t("wizard.gateway.existingTokenConfirm", { token: maskApiKey(existingToken) }), initialValue: true }) ? existingToken : await prompter.text({ message: t("wizard.gateway.tokenPromptGenerate"), placeholder: t("wizard.gateway.tokenPlaceholder"), sensitive: true }); else tokenInput = await prompter.text({ message: t("wizard.gateway.tokenPromptGenerate"), placeholder: t("wizard.gateway.tokenPlaceholder"), sensitive: true }); gatewayToken = normalizeGatewayTokenInput(tokenInput) || randomToken(); gatewayTokenInput = gatewayToken; } } if (authMode === "password") { const existingPassword = normalizeSecretInputString(quickstartGateway.password); const existingPasswordRef = resolveSecretInputRef({ value: quickstartGateway.password, defaults: nextConfig.secrets?.defaults }).ref; const quickstartNeedsPasswordRef = flow === "quickstart" && opts.secretInputMode === "ref" && !existingPasswordRef && quickstartGateway.password !== opts.baseConfig.gateway?.auth?.password; let password = flow === "quickstart" && !quickstartNeedsPasswordRef ? quickstartGateway.password : existingPasswordRef ?? void 0; if (!password) { if (await resolveSecretInputModeForEnvSelection({ prompter, explicitMode: opts.secretInputMode, copy: { modeMessage: t("wizard.gateway.authPasswordMode"), plaintextLabel: t("wizard.gateway.plaintextPasswordLabel"), plaintextHint: t("wizard.gateway.plaintextPasswordHint") } }) === "ref") password = (await promptSecretRefForSetup({ provider: "gateway-auth-password", config: nextConfig, prompter, preferredEnvVar: "OPENCLAW_GATEWAY_PASSWORD", copy: { sourceMessage: t("wizard.gateway.authPasswordStoredMessage"), envVarPlaceholder: "OPENCLAW_GATEWAY_PASSWORD" } })).ref; else { let passwordInput; if (existingPassword) passwordInput = await prompter.confirm({ message: t("wizard.gateway.existingPasswordConfirm", { password: maskApiKey(existingPassword) }), initialValue: true }) ? existingPassword : void 0; password = passwordInput ?? normalizeWizardTextInput(await prompter.text({ message: t("wizard.gateway.passwordPrompt"), validate: validateGatewayPasswordInput, sensitive: true })); } } nextConfig = { ...nextConfig, gateway: { ...nextConfig.gateway, auth: { ...nextConfig.gateway?.auth, mode: "password", password } } }; } else if (authMode === "token") nextConfig = { ...nextConfig, gateway: { ...nextConfig.gateway, auth: { ...nextConfig.gateway?.auth, mode: "token", token: gatewayTokenInput } } }; nextConfig = { ...nextConfig, gateway: { ...nextConfig.gateway, port, bind, ...bind === "custom" && customBindHost ? { customBindHost } : {}, tailscale: { ...nextConfig.gateway?.tailscale, mode: tailscaleMode } } }; nextConfig = ensureControlUiAllowedOriginsForNonLoopbackBind(nextConfig, { requireControlUiEnabled: true }).config; nextConfig = await maybeAddTailnetOriginToControlUiAllowedOrigins({ config: nextConfig, tailscaleMode, tailscaleBin }); return { nextConfig, settings: { port, bind, customBindHost: bind === "custom" ? customBindHost : void 0, authMode, gatewayToken, tailscaleMode } }; } //#endregion export { configureGatewayForSetup };