refactor: share gateway auth and approval helpers

This commit is contained in:
Peter Steinberger
2026-04-06 07:40:16 +01:00
parent 1d8d2ddaa1
commit bb01e49192
31 changed files with 1768 additions and 1347 deletions

View File

@@ -1,14 +1,10 @@
import os from "node:os";
import { resolveGatewayPort } from "../config/paths.js";
import type { OpenClawConfig } from "../config/types.js";
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
resolveSecretInputRef,
} from "../config/types.secrets.js";
import { normalizeSecretInputString, resolveSecretInputRef } from "../config/types.secrets.js";
import { materializeGatewayAuthSecretRefs } from "../gateway/auth-config-utils.js";
import { assertExplicitGatewayAuthModeWhenBothConfigured } from "../gateway/auth-mode-policy.js";
import { isLoopbackHost, isSecureWebSocketUrl } from "../gateway/net.js";
import { resolveRequiredConfiguredSecretRefInputString } from "../gateway/resolve-configured-secret-input-string.js";
import { issueDeviceBootstrapToken } from "../infra/device-bootstrap.js";
import {
pickMatchingExternalInterfaceAddress,
@@ -268,94 +264,6 @@ function resolvePairingSetupAuthLabel(
return { error: "Gateway auth is not configured (no token or password)." };
}
async function resolveGatewayTokenSecretRef(
cfg: OpenClawConfig,
env: NodeJS.ProcessEnv,
): Promise<OpenClawConfig> {
const hasTokenEnvCandidate = Boolean(resolveGatewayTokenFromEnv(env));
if (hasTokenEnvCandidate) {
return cfg;
}
const mode = cfg.gateway?.auth?.mode;
if (mode === "password" || mode === "none" || mode === "trusted-proxy") {
return cfg;
}
if (mode !== "token") {
const hasPasswordEnvCandidate = Boolean(env.OPENCLAW_GATEWAY_PASSWORD?.trim());
if (hasPasswordEnvCandidate) {
return cfg;
}
}
const token = await resolveRequiredConfiguredSecretRefInputString({
config: cfg,
env,
value: cfg.gateway?.auth?.token,
path: "gateway.auth.token",
});
if (!token) {
return cfg;
}
return {
...cfg,
gateway: {
...cfg.gateway,
auth: {
...cfg.gateway?.auth,
token,
},
},
};
}
async function resolveGatewayPasswordSecretRef(
cfg: OpenClawConfig,
env: NodeJS.ProcessEnv,
): Promise<OpenClawConfig> {
const hasPasswordEnvCandidate = Boolean(resolveGatewayPasswordFromEnv(env));
if (hasPasswordEnvCandidate) {
return cfg;
}
const mode = cfg.gateway?.auth?.mode;
if (mode === "token" || mode === "none" || mode === "trusted-proxy") {
return cfg;
}
if (mode !== "password") {
const hasTokenCandidate =
Boolean(resolveGatewayTokenFromEnv(env)) ||
hasConfiguredSecretInput(cfg.gateway?.auth?.token, cfg.secrets?.defaults);
if (hasTokenCandidate) {
return cfg;
}
}
const password = await resolveRequiredConfiguredSecretRefInputString({
config: cfg,
env,
value: cfg.gateway?.auth?.password,
path: "gateway.auth.password",
});
if (!password) {
return cfg;
}
return {
...cfg,
gateway: {
...cfg.gateway,
auth: {
...cfg.gateway?.auth,
password,
},
},
};
}
async function materializePairingSetupAuthConfig(
cfg: OpenClawConfig,
env: NodeJS.ProcessEnv,
): Promise<OpenClawConfig> {
const cfgWithToken = await resolveGatewayTokenSecretRef(cfg, env);
return await resolveGatewayPasswordSecretRef(cfgWithToken, env);
}
async function resolveGatewayUrl(
cfg: OpenClawConfig,
opts: {
@@ -430,7 +338,13 @@ export async function resolvePairingSetupFromConfig(
): Promise<PairingSetupResolution> {
assertExplicitGatewayAuthModeWhenBothConfigured(cfg);
const env = options.env ?? process.env;
const cfgForAuth = await materializePairingSetupAuthConfig(cfg, env);
const cfgForAuth = await materializeGatewayAuthSecretRefs({
cfg,
env,
mode: cfg.gateway?.auth?.mode,
hasTokenCandidate: Boolean(resolveGatewayTokenFromEnv(env)),
hasPasswordCandidate: Boolean(resolveGatewayPasswordFromEnv(env)),
});
const authLabel = resolvePairingSetupAuthLabel(cfgForAuth, env);
if (authLabel.error) {
return { ok: false, error: authLabel.error };