mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
refactor: dedupe auth session readers
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import crypto from "node:crypto";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { loadAuthProfileStoreForRuntime } from "./auth-profiles/store.js";
|
||||
import type { AuthProfileCredential, AuthProfileStore } from "./auth-profiles/types.js";
|
||||
import {
|
||||
@@ -137,7 +138,7 @@ export async function resolveCliAuthEpoch(params: {
|
||||
authProfileId?: string;
|
||||
}): Promise<string | undefined> {
|
||||
const provider = params.provider.trim();
|
||||
const authProfileId = params.authProfileId?.trim() || undefined;
|
||||
const authProfileId = normalizeOptionalString(params.authProfileId);
|
||||
const parts: string[] = [];
|
||||
|
||||
const localFingerprint = getLocalCliCredentialFingerprint(provider);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { sleepWithAbort } from "../../infra/backoff.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||
import { enqueueCommandInLane } from "../../process/command-queue.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { sanitizeForLog } from "../../terminal/ansi.js";
|
||||
import { isMarkdownCapableMessageChannel } from "../../utils/message-channel.js";
|
||||
import { resolveOpenClawAgentDir } from "../agent-paths.js";
|
||||
@@ -118,7 +119,7 @@ function backfillSessionKey(params: {
|
||||
sessionKey?: string;
|
||||
agentId?: string;
|
||||
}): string | undefined {
|
||||
const trimmed = params.sessionKey?.trim() || undefined;
|
||||
const trimmed = normalizeOptionalString(params.sessionKey);
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
@@ -126,7 +127,7 @@ function backfillSessionKey(params: {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const resolved = params.agentId?.trim()
|
||||
const resolved = normalizeOptionalString(params.agentId)
|
||||
? resolveStoredSessionKeyForSessionId({
|
||||
cfg: params.config,
|
||||
sessionId: params.sessionId,
|
||||
@@ -136,7 +137,7 @@ function backfillSessionKey(params: {
|
||||
cfg: params.config,
|
||||
sessionId: params.sessionId,
|
||||
});
|
||||
return resolved.sessionKey?.trim() || undefined;
|
||||
return normalizeOptionalString(resolved.sessionKey);
|
||||
} catch (err) {
|
||||
log.warn(
|
||||
`[backfillSessionKey] Failed to resolve sessionKey for sessionId=${redactRunIdentifier(sanitizeForLog(params.sessionId))}: ${formatErrorMessage(err)}`,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
logSessionStateChange,
|
||||
} from "../../logging/diagnostic.js";
|
||||
import { resolveGlobalSingleton } from "../../shared/global-singleton.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
|
||||
export type EmbeddedPiQueueHandle = {
|
||||
kind?: "embedded";
|
||||
@@ -57,7 +58,8 @@ const embeddedRunState = resolveGlobalSingleton(EMBEDDED_RUN_STATE_KEY, () => ({
|
||||
modelSwitchRequests: new Map<string, EmbeddedRunModelSwitchRequest>(),
|
||||
}));
|
||||
const ACTIVE_EMBEDDED_RUNS =
|
||||
embeddedRunState.activeRuns ?? (embeddedRunState.activeRuns = new Map<string, EmbeddedPiQueueHandle>());
|
||||
embeddedRunState.activeRuns ??
|
||||
(embeddedRunState.activeRuns = new Map<string, EmbeddedPiQueueHandle>());
|
||||
const ACTIVE_EMBEDDED_RUN_SNAPSHOTS =
|
||||
embeddedRunState.snapshots ??
|
||||
(embeddedRunState.snapshots = new Map<string, ActiveEmbeddedRunSnapshot>());
|
||||
@@ -65,7 +67,8 @@ const ACTIVE_EMBEDDED_RUN_SESSION_IDS_BY_KEY =
|
||||
embeddedRunState.sessionIdsByKey ??
|
||||
(embeddedRunState.sessionIdsByKey = new Map<string, string>());
|
||||
const EMBEDDED_RUN_WAITERS =
|
||||
embeddedRunState.waiters ?? (embeddedRunState.waiters = new Map<string, Set<EmbeddedRunWaiter>>());
|
||||
embeddedRunState.waiters ??
|
||||
(embeddedRunState.waiters = new Map<string, Set<EmbeddedRunWaiter>>());
|
||||
const EMBEDDED_RUN_MODEL_SWITCH_REQUESTS =
|
||||
embeddedRunState.modelSwitchRequests ??
|
||||
(embeddedRunState.modelSwitchRequests = new Map<string, EmbeddedRunModelSwitchRequest>());
|
||||
@@ -242,8 +245,10 @@ export function requestEmbeddedRunModelSwitch(
|
||||
EMBEDDED_RUN_MODEL_SWITCH_REQUESTS.set(normalizedSessionId, {
|
||||
provider,
|
||||
model,
|
||||
authProfileId: request.authProfileId?.trim() || undefined,
|
||||
authProfileIdSource: request.authProfileId?.trim() ? request.authProfileIdSource : undefined,
|
||||
authProfileId: normalizeOptionalString(request.authProfileId),
|
||||
authProfileIdSource: normalizeOptionalString(request.authProfileId)
|
||||
? request.authProfileIdSource
|
||||
: undefined,
|
||||
});
|
||||
diag.debug(
|
||||
`model switch requested: sessionId=${normalizedSessionId} provider=${provider} model=${model}`,
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
type ResolvedBrowserConfig,
|
||||
} from "../../plugin-sdk/browser-profiles.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { BROWSER_BRIDGES } from "./browser-bridges.js";
|
||||
import { computeSandboxBrowserConfigHash } from "./config-hash.js";
|
||||
import { resolveSandboxBrowserDockerCreateConfig } from "./config.js";
|
||||
@@ -295,8 +296,8 @@ export async function ensureSandboxBrowser(params: {
|
||||
? resolveProfile(existing.bridge.state.resolved, DEFAULT_OPENCLAW_BROWSER_PROFILE_NAME)
|
||||
: null;
|
||||
|
||||
let desiredAuthToken = params.bridgeAuth?.token?.trim() || undefined;
|
||||
let desiredAuthPassword = params.bridgeAuth?.password?.trim() || undefined;
|
||||
let desiredAuthToken = normalizeOptionalString(params.bridgeAuth?.token);
|
||||
let desiredAuthPassword = normalizeOptionalString(params.bridgeAuth?.password);
|
||||
if (!desiredAuthToken && !desiredAuthPassword) {
|
||||
// Always require auth for the sandbox bridge server, even if gateway auth
|
||||
// mode doesn't produce a shared secret (e.g. trusted-proxy).
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import crypto from "node:crypto";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
|
||||
export const NOVNC_PASSWORD_ENV_KEY = "OPENCLAW_BROWSER_NOVNC_PASSWORD"; // pragma: allowlist secret
|
||||
const NOVNC_TOKEN_TTL_MS = 60 * 1000;
|
||||
@@ -65,7 +66,7 @@ export function issueNoVncObserverToken(params: {
|
||||
const token = crypto.randomBytes(24).toString("hex");
|
||||
NO_VNC_OBSERVER_TOKENS.set(token, {
|
||||
noVncPort: params.noVncPort,
|
||||
password: params.password?.trim() || undefined,
|
||||
password: normalizeOptionalString(params.password),
|
||||
expiresAt: now + Math.max(1, params.ttlMs ?? NOVNC_TOKEN_TTL_MS),
|
||||
});
|
||||
return token;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
signalVerifiedGatewayPidSync,
|
||||
} from "../../infra/gateway-processes.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { theme } from "../../terminal/theme.js";
|
||||
import { formatCliCommand } from "../command-format.js";
|
||||
import { recoverInstalledLaunchAgent } from "./launchd-recovery.js";
|
||||
@@ -77,8 +78,8 @@ async function assertUnmanagedGatewayRestartEnabled(port: number): Promise<void>
|
||||
const probe = await probeGateway({
|
||||
url: `${scheme}://127.0.0.1:${port}`,
|
||||
auth: {
|
||||
token: process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined,
|
||||
password: process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() || undefined,
|
||||
token: normalizeOptionalString(process.env.OPENCLAW_GATEWAY_TOKEN),
|
||||
password: normalizeOptionalString(process.env.OPENCLAW_GATEWAY_PASSWORD),
|
||||
},
|
||||
timeoutMs: 1_000,
|
||||
}).catch(() => null);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { normalizeFingerprint } from "../infra/tls/fingerprint.js";
|
||||
import { rawDataToString } from "../infra/ws.js";
|
||||
import { logDebug, logError } from "../logger.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
GATEWAY_CLIENT_MODES,
|
||||
GATEWAY_CLIENT_NAMES,
|
||||
@@ -526,7 +527,7 @@ export class GatewayClient {
|
||||
err instanceof GatewayClientRequestError ? readConnectErrorDetailCode(err.details) : null;
|
||||
const shouldRetryWithDeviceToken = this.shouldRetryWithStoredDeviceToken({
|
||||
error: err,
|
||||
explicitGatewayToken: this.opts.token?.trim() || undefined,
|
||||
explicitGatewayToken: normalizeOptionalString(this.opts.token),
|
||||
resolvedDeviceToken,
|
||||
storedToken: storedToken ?? undefined,
|
||||
});
|
||||
@@ -661,10 +662,10 @@ export class GatewayClient {
|
||||
}
|
||||
|
||||
private selectConnectAuth(role: string): SelectedConnectAuth {
|
||||
const explicitGatewayToken = this.opts.token?.trim() || undefined;
|
||||
const explicitBootstrapToken = this.opts.bootstrapToken?.trim() || undefined;
|
||||
const explicitDeviceToken = this.opts.deviceToken?.trim() || undefined;
|
||||
const authPassword = this.opts.password?.trim() || undefined;
|
||||
const explicitGatewayToken = normalizeOptionalString(this.opts.token);
|
||||
const explicitBootstrapToken = normalizeOptionalString(this.opts.bootstrapToken);
|
||||
const explicitDeviceToken = normalizeOptionalString(this.opts.deviceToken);
|
||||
const authPassword = normalizeOptionalString(this.opts.password);
|
||||
const storedAuth = this.loadStoredDeviceAuth(role);
|
||||
const storedToken = storedAuth?.token ?? null;
|
||||
const storedScopes = storedAuth?.scopes;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
type ExplicitGatewayAuth,
|
||||
isGatewaySecretRefUnavailableError,
|
||||
@@ -28,8 +29,8 @@ function resolveExplicitProbeAuth(explicitAuth?: ExplicitGatewayAuth): {
|
||||
token?: string;
|
||||
password?: string;
|
||||
} {
|
||||
const token = explicitAuth?.token?.trim() || undefined;
|
||||
const password = explicitAuth?.password?.trim() || undefined;
|
||||
const token = normalizeOptionalString(explicitAuth?.token);
|
||||
const password = normalizeOptionalString(explicitAuth?.password);
|
||||
return { token, password };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ReplyPayload } from "../auto-reply/types.js";
|
||||
import type { InteractiveReply, InteractiveReplyButton } from "../interactive/payload.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
describeNativeExecApprovalClientSetup,
|
||||
listNativeExecApprovalClientLabels,
|
||||
@@ -348,9 +349,9 @@ export function buildExecApprovalPendingReplyPayload(
|
||||
approvalId: params.approvalId,
|
||||
approvalSlug: params.approvalSlug,
|
||||
approvalKind: "exec",
|
||||
agentId: params.agentId?.trim() || undefined,
|
||||
agentId: normalizeOptionalString(params.agentId),
|
||||
allowedDecisions,
|
||||
sessionKey: params.sessionKey?.trim() || undefined,
|
||||
sessionKey: normalizeOptionalString(params.sessionKey),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
toAgentStoreSessionKey,
|
||||
} from "../routing/session-key.js";
|
||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { escapeRegExp } from "../utils.js";
|
||||
import { formatErrorMessage, hasErrnoCode } from "./errors.js";
|
||||
import { isWithinActiveHours } from "./heartbeat-active-hours.js";
|
||||
@@ -1191,7 +1192,7 @@ export function startHeartbeatRunner(opts: {
|
||||
|
||||
const reason = params?.reason;
|
||||
const requestedAgentId = params?.agentId ? normalizeAgentId(params.agentId) : undefined;
|
||||
const requestedSessionKey = params?.sessionKey?.trim() || undefined;
|
||||
const requestedSessionKey = normalizeOptionalString(params?.sessionKey);
|
||||
const isInterval = reason === "interval";
|
||||
const startedAt = Date.now();
|
||||
const now = startedAt;
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
isRfc1918Ipv4Address,
|
||||
parseCanonicalIpAddress,
|
||||
} from "../shared/net/ip.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { resolveTailnetHostWithRunner } from "../shared/tailscale-status.js";
|
||||
|
||||
export type PairingSetupPayload = {
|
||||
@@ -214,11 +215,11 @@ function pickTailnetIPv4(
|
||||
}
|
||||
|
||||
function resolveGatewayTokenFromEnv(env: NodeJS.ProcessEnv): string | undefined {
|
||||
return env.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined;
|
||||
return normalizeOptionalString(env.OPENCLAW_GATEWAY_TOKEN);
|
||||
}
|
||||
|
||||
function resolveGatewayPasswordFromEnv(env: NodeJS.ProcessEnv): string | undefined {
|
||||
return env.OPENCLAW_GATEWAY_PASSWORD?.trim() || undefined;
|
||||
return normalizeOptionalString(env.OPENCLAW_GATEWAY_PASSWORD);
|
||||
}
|
||||
|
||||
function resolvePairingSetupAuthLabel(
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
type PluginApprovalRequest,
|
||||
type PluginApprovalResolved,
|
||||
} from "../infra/plugin-approvals.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
const DEFAULT_ALLOWED_DECISIONS = ["allow-once", "allow-always", "deny"] as const;
|
||||
|
||||
@@ -34,9 +35,9 @@ export function buildApprovalPendingReplyPayload(params: {
|
||||
approvalId: params.approvalId,
|
||||
approvalSlug: params.approvalSlug,
|
||||
approvalKind: params.approvalKind ?? "exec",
|
||||
agentId: params.agentId?.trim() || undefined,
|
||||
agentId: normalizeOptionalString(params.agentId),
|
||||
allowedDecisions,
|
||||
sessionKey: params.sessionKey?.trim() || undefined,
|
||||
sessionKey: normalizeOptionalString(params.sessionKey),
|
||||
state: "pending",
|
||||
},
|
||||
...params.channelData,
|
||||
|
||||
Reference in New Issue
Block a user