mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 17:03:43 +00:00
refactor(shared): extract reused path and normalization helpers
This commit is contained in:
@@ -1,35 +1,11 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import { sanitizeUntrustedFileName } from "./safe-filename.js";
|
||||||
function sanitizeFileNameTail(fileName: string): string {
|
|
||||||
const trimmed = String(fileName ?? "").trim();
|
|
||||||
if (!trimmed) {
|
|
||||||
return "output.bin";
|
|
||||||
}
|
|
||||||
let base = path.posix.basename(trimmed);
|
|
||||||
base = path.win32.basename(base);
|
|
||||||
let cleaned = "";
|
|
||||||
for (let i = 0; i < base.length; i++) {
|
|
||||||
const code = base.charCodeAt(i);
|
|
||||||
if (code < 0x20 || code === 0x7f) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cleaned += base[i];
|
|
||||||
}
|
|
||||||
base = cleaned.trim();
|
|
||||||
if (!base || base === "." || base === "..") {
|
|
||||||
return "output.bin";
|
|
||||||
}
|
|
||||||
if (base.length > 200) {
|
|
||||||
base = base.slice(0, 200);
|
|
||||||
}
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildSiblingTempPath(targetPath: string): string {
|
function buildSiblingTempPath(targetPath: string): string {
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
const safeTail = sanitizeFileNameTail(path.basename(targetPath));
|
const safeTail = sanitizeUntrustedFileName(path.basename(targetPath), "output.bin");
|
||||||
return path.join(path.dirname(targetPath), `.openclaw-output-${id}-${safeTail}.part`);
|
return path.join(path.dirname(targetPath), `.openclaw-output-${id}-${safeTail}.part`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,39 +19,11 @@ import {
|
|||||||
requireRef,
|
requireRef,
|
||||||
toAIFriendlyError,
|
toAIFriendlyError,
|
||||||
} from "./pw-tools-core.shared.js";
|
} from "./pw-tools-core.shared.js";
|
||||||
|
import { sanitizeUntrustedFileName } from "./safe-filename.js";
|
||||||
function sanitizeDownloadFileName(fileName: string): string {
|
|
||||||
const trimmed = String(fileName ?? "").trim();
|
|
||||||
if (!trimmed) {
|
|
||||||
return "download.bin";
|
|
||||||
}
|
|
||||||
|
|
||||||
// `suggestedFilename()` is untrusted (influenced by remote servers). Force a basename so
|
|
||||||
// path separators/traversal can't escape the downloads dir on any platform.
|
|
||||||
let base = path.posix.basename(trimmed);
|
|
||||||
base = path.win32.basename(base);
|
|
||||||
let cleaned = "";
|
|
||||||
for (let i = 0; i < base.length; i++) {
|
|
||||||
const code = base.charCodeAt(i);
|
|
||||||
if (code < 0x20 || code === 0x7f) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cleaned += base[i];
|
|
||||||
}
|
|
||||||
base = cleaned.trim();
|
|
||||||
|
|
||||||
if (!base || base === "." || base === "..") {
|
|
||||||
return "download.bin";
|
|
||||||
}
|
|
||||||
if (base.length > 200) {
|
|
||||||
base = base.slice(0, 200);
|
|
||||||
}
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildTempDownloadPath(fileName: string): string {
|
function buildTempDownloadPath(fileName: string): string {
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
const safeName = sanitizeDownloadFileName(fileName);
|
const safeName = sanitizeUntrustedFileName(fileName, "download.bin");
|
||||||
return path.join(resolvePreferredOpenClawTmpDir(), "downloads", `${id}-${safeName}`);
|
return path.join(resolvePreferredOpenClawTmpDir(), "downloads", `${id}-${safeName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
src/browser/safe-filename.ts
Normal file
26
src/browser/safe-filename.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
export function sanitizeUntrustedFileName(fileName: string, fallbackName: string): string {
|
||||||
|
const trimmed = String(fileName ?? "").trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return fallbackName;
|
||||||
|
}
|
||||||
|
let base = path.posix.basename(trimmed);
|
||||||
|
base = path.win32.basename(base);
|
||||||
|
let cleaned = "";
|
||||||
|
for (let i = 0; i < base.length; i++) {
|
||||||
|
const code = base.charCodeAt(i);
|
||||||
|
if (code < 0x20 || code === 0x7f) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cleaned += base[i];
|
||||||
|
}
|
||||||
|
base = cleaned.trim();
|
||||||
|
if (!base || base === "." || base === "..") {
|
||||||
|
return fallbackName;
|
||||||
|
}
|
||||||
|
if (base.length > 200) {
|
||||||
|
base = base.slice(0, 200);
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
type ResolvedGatewayAuth,
|
type ResolvedGatewayAuth,
|
||||||
} from "../auth.js";
|
} from "../auth.js";
|
||||||
import { CANVAS_CAPABILITY_TTL_MS } from "../canvas-capability.js";
|
import { CANVAS_CAPABILITY_TTL_MS } from "../canvas-capability.js";
|
||||||
import { sendGatewayAuthFailure } from "../http-common.js";
|
import { authorizeGatewayBearerRequestOrReply } from "../http-auth-helpers.js";
|
||||||
import { getBearerToken } from "../http-utils.js";
|
import { getBearerToken } from "../http-utils.js";
|
||||||
import { GATEWAY_CLIENT_MODES, normalizeGatewayClientMode } from "../protocol/client-info.js";
|
import { GATEWAY_CLIENT_MODES, normalizeGatewayClientMode } from "../protocol/client-info.js";
|
||||||
import type { GatewayWsClient } from "./ws-types.js";
|
import type { GatewayWsClient } from "./ws-types.js";
|
||||||
@@ -113,18 +113,5 @@ export async function enforcePluginRouteGatewayAuth(params: {
|
|||||||
allowRealIpFallback: boolean;
|
allowRealIpFallback: boolean;
|
||||||
rateLimiter?: AuthRateLimiter;
|
rateLimiter?: AuthRateLimiter;
|
||||||
}): Promise<boolean> {
|
}): Promise<boolean> {
|
||||||
const token = getBearerToken(params.req);
|
return await authorizeGatewayBearerRequestOrReply(params);
|
||||||
const authResult = await authorizeHttpGatewayConnect({
|
|
||||||
auth: params.auth,
|
|
||||||
connectAuth: token ? { token, password: token } : null,
|
|
||||||
req: params.req,
|
|
||||||
trustedProxies: params.trustedProxies,
|
|
||||||
allowRealIpFallback: params.allowRealIpFallback,
|
|
||||||
rateLimiter: params.rateLimiter,
|
|
||||||
});
|
|
||||||
if (!authResult.ok) {
|
|
||||||
sendGatewayAuthFailure(params.res, authResult);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,10 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import type { SystemRunApprovalBinding, SystemRunApprovalPlan } from "./exec-approvals.js";
|
import type { SystemRunApprovalBinding, SystemRunApprovalPlan } from "./exec-approvals.js";
|
||||||
import { normalizeEnvVarKey } from "./host-env-security.js";
|
import { normalizeEnvVarKey } from "./host-env-security.js";
|
||||||
|
import { normalizeNonEmptyString, normalizeStringArray } from "./system-run-normalize.js";
|
||||||
|
|
||||||
type NormalizedSystemRunEnvEntry = [key: string, value: string];
|
type NormalizedSystemRunEnvEntry = [key: string, value: string];
|
||||||
|
|
||||||
function normalizeString(value: unknown): string | null {
|
|
||||||
if (typeof value !== "string") {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const trimmed = value.trim();
|
|
||||||
return trimmed ? trimmed : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeStringArray(value: unknown): string[] {
|
|
||||||
return Array.isArray(value) ? value.map((entry) => String(entry)) : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function normalizeSystemRunApprovalPlan(value: unknown): SystemRunApprovalPlan | null {
|
export function normalizeSystemRunApprovalPlan(value: unknown): SystemRunApprovalPlan | null {
|
||||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -27,10 +16,10 @@ export function normalizeSystemRunApprovalPlan(value: unknown): SystemRunApprova
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
argv,
|
argv,
|
||||||
cwd: normalizeString(candidate.cwd),
|
cwd: normalizeNonEmptyString(candidate.cwd),
|
||||||
rawCommand: normalizeString(candidate.rawCommand),
|
rawCommand: normalizeNonEmptyString(candidate.rawCommand),
|
||||||
agentId: normalizeString(candidate.agentId),
|
agentId: normalizeNonEmptyString(candidate.agentId),
|
||||||
sessionKey: normalizeString(candidate.sessionKey),
|
sessionKey: normalizeNonEmptyString(candidate.sessionKey),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +71,9 @@ export function buildSystemRunApprovalBinding(params: {
|
|||||||
return {
|
return {
|
||||||
binding: {
|
binding: {
|
||||||
argv: normalizeStringArray(params.argv),
|
argv: normalizeStringArray(params.argv),
|
||||||
cwd: normalizeString(params.cwd),
|
cwd: normalizeNonEmptyString(params.cwd),
|
||||||
agentId: normalizeString(params.agentId),
|
agentId: normalizeNonEmptyString(params.agentId),
|
||||||
sessionKey: normalizeString(params.sessionKey),
|
sessionKey: normalizeNonEmptyString(params.sessionKey),
|
||||||
envHash: envBinding.envHash,
|
envHash: envBinding.envHash,
|
||||||
},
|
},
|
||||||
envKeys: envBinding.envKeys,
|
envKeys: envBinding.envKeys,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { SystemRunApprovalPlan } from "./exec-approvals.js";
|
import type { SystemRunApprovalPlan } from "./exec-approvals.js";
|
||||||
import { normalizeSystemRunApprovalPlan } from "./system-run-approval-binding.js";
|
import { normalizeSystemRunApprovalPlan } from "./system-run-approval-binding.js";
|
||||||
import { formatExecCommand, resolveSystemRunCommand } from "./system-run-command.js";
|
import { formatExecCommand, resolveSystemRunCommand } from "./system-run-command.js";
|
||||||
|
import { normalizeNonEmptyString, normalizeStringArray } from "./system-run-normalize.js";
|
||||||
|
|
||||||
type PreparedRunPayload = {
|
type PreparedRunPayload = {
|
||||||
cmdText: string;
|
cmdText: string;
|
||||||
@@ -32,18 +33,6 @@ type SystemRunApprovalRuntimeContext =
|
|||||||
details?: Record<string, unknown>;
|
details?: Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function normalizeString(value: unknown): string | null {
|
|
||||||
if (typeof value !== "string") {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const trimmed = value.trim();
|
|
||||||
return trimmed ? trimmed : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeStringArray(value: unknown): string[] {
|
|
||||||
return Array.isArray(value) ? value.map((entry) => String(entry)) : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeCommandText(value: unknown): string {
|
function normalizeCommandText(value: unknown): string {
|
||||||
return typeof value === "string" ? value : "";
|
return typeof value === "string" ? value : "";
|
||||||
}
|
}
|
||||||
@@ -53,7 +42,7 @@ export function parsePreparedSystemRunPayload(payload: unknown): PreparedRunPayl
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const raw = payload as { cmdText?: unknown; plan?: unknown };
|
const raw = payload as { cmdText?: unknown; plan?: unknown };
|
||||||
const cmdText = normalizeString(raw.cmdText);
|
const cmdText = normalizeNonEmptyString(raw.cmdText);
|
||||||
const plan = normalizeSystemRunApprovalPlan(raw.plan);
|
const plan = normalizeSystemRunApprovalPlan(raw.plan);
|
||||||
if (!cmdText || !plan) {
|
if (!cmdText || !plan) {
|
||||||
return null;
|
return null;
|
||||||
@@ -70,7 +59,7 @@ export function resolveSystemRunApprovalRequestContext(params: {
|
|||||||
agentId?: unknown;
|
agentId?: unknown;
|
||||||
sessionKey?: unknown;
|
sessionKey?: unknown;
|
||||||
}): SystemRunApprovalRequestContext {
|
}): SystemRunApprovalRequestContext {
|
||||||
const host = normalizeString(params.host) ?? "";
|
const host = normalizeNonEmptyString(params.host) ?? "";
|
||||||
const plan = host === "node" ? normalizeSystemRunApprovalPlan(params.systemRunPlan) : null;
|
const plan = host === "node" ? normalizeSystemRunApprovalPlan(params.systemRunPlan) : null;
|
||||||
const fallbackArgv = normalizeStringArray(params.commandArgv);
|
const fallbackArgv = normalizeStringArray(params.commandArgv);
|
||||||
const fallbackCommand = normalizeCommandText(params.command);
|
const fallbackCommand = normalizeCommandText(params.command);
|
||||||
@@ -78,9 +67,9 @@ export function resolveSystemRunApprovalRequestContext(params: {
|
|||||||
plan,
|
plan,
|
||||||
commandArgv: plan?.argv ?? (fallbackArgv.length > 0 ? fallbackArgv : undefined),
|
commandArgv: plan?.argv ?? (fallbackArgv.length > 0 ? fallbackArgv : undefined),
|
||||||
commandText: plan ? (plan.rawCommand ?? formatExecCommand(plan.argv)) : fallbackCommand,
|
commandText: plan ? (plan.rawCommand ?? formatExecCommand(plan.argv)) : fallbackCommand,
|
||||||
cwd: plan?.cwd ?? normalizeString(params.cwd),
|
cwd: plan?.cwd ?? normalizeNonEmptyString(params.cwd),
|
||||||
agentId: plan?.agentId ?? normalizeString(params.agentId),
|
agentId: plan?.agentId ?? normalizeNonEmptyString(params.agentId),
|
||||||
sessionKey: plan?.sessionKey ?? normalizeString(params.sessionKey),
|
sessionKey: plan?.sessionKey ?? normalizeNonEmptyString(params.sessionKey),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,9 +104,9 @@ export function resolveSystemRunApprovalRuntimeContext(params: {
|
|||||||
ok: true,
|
ok: true,
|
||||||
plan: null,
|
plan: null,
|
||||||
argv: command.argv,
|
argv: command.argv,
|
||||||
cwd: normalizeString(params.cwd),
|
cwd: normalizeNonEmptyString(params.cwd),
|
||||||
agentId: normalizeString(params.agentId),
|
agentId: normalizeNonEmptyString(params.agentId),
|
||||||
sessionKey: normalizeString(params.sessionKey),
|
sessionKey: normalizeNonEmptyString(params.sessionKey),
|
||||||
rawCommand: normalizeString(params.rawCommand),
|
rawCommand: normalizeNonEmptyString(params.rawCommand),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/infra/system-run-normalize.ts
Normal file
11
src/infra/system-run-normalize.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export function normalizeNonEmptyString(value: unknown): string | null {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const trimmed = value.trim();
|
||||||
|
return trimmed ? trimmed : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeStringArray(value: unknown): string[] {
|
||||||
|
return Array.isArray(value) ? value.map((entry) => String(entry)) : [];
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ import fs from "node:fs";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { isDeepStrictEqual } from "node:util";
|
import { isDeepStrictEqual } from "node:util";
|
||||||
import { listAgentIds, resolveAgentDir } from "../agents/agent-scope.js";
|
|
||||||
import { loadAuthProfileStoreForSecretsRuntime } from "../agents/auth-profiles.js";
|
import { loadAuthProfileStoreForSecretsRuntime } from "../agents/auth-profiles.js";
|
||||||
import { resolveAuthStorePath } from "../agents/auth-profiles/paths.js";
|
import { resolveAuthStorePath } from "../agents/auth-profiles/paths.js";
|
||||||
import { normalizeProviderId } from "../agents/model-selection.js";
|
import { normalizeProviderId } from "../agents/model-selection.js";
|
||||||
@@ -10,6 +9,7 @@ import { resolveStateDir, type OpenClawConfig } from "../config/config.js";
|
|||||||
import type { ConfigWriteOptions } from "../config/io.js";
|
import type { ConfigWriteOptions } from "../config/io.js";
|
||||||
import type { SecretProviderConfig } from "../config/types.secrets.js";
|
import type { SecretProviderConfig } from "../config/types.secrets.js";
|
||||||
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
||||||
|
import { collectAuthStorePaths } from "./auth-store-paths.js";
|
||||||
import { createSecretsConfigIO } from "./config-io.js";
|
import { createSecretsConfigIO } from "./config-io.js";
|
||||||
import {
|
import {
|
||||||
type SecretsApplyPlan,
|
type SecretsApplyPlan,
|
||||||
@@ -172,36 +172,6 @@ function scrubEnvRaw(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectAuthStorePaths(config: OpenClawConfig, stateDir: string): string[] {
|
|
||||||
const paths = new Set<string>();
|
|
||||||
// Scope default auth store discovery to the provided stateDir instead of
|
|
||||||
// ambient process env, so apply does not touch unrelated host-global stores.
|
|
||||||
paths.add(path.join(resolveUserPath(stateDir), "agents", "main", "agent", "auth-profiles.json"));
|
|
||||||
|
|
||||||
const agentsRoot = path.join(resolveUserPath(stateDir), "agents");
|
|
||||||
if (fs.existsSync(agentsRoot)) {
|
|
||||||
for (const entry of fs.readdirSync(agentsRoot, { withFileTypes: true })) {
|
|
||||||
if (!entry.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
paths.add(path.join(agentsRoot, entry.name, "agent", "auth-profiles.json"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const agentId of listAgentIds(config)) {
|
|
||||||
if (agentId === "main") {
|
|
||||||
paths.add(
|
|
||||||
path.join(resolveUserPath(stateDir), "agents", "main", "agent", "auth-profiles.json"),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const agentDir = resolveAgentDir(config, agentId);
|
|
||||||
paths.add(resolveUserPath(resolveAuthStorePath(agentDir)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [...paths];
|
|
||||||
}
|
|
||||||
|
|
||||||
function collectAuthJsonPaths(stateDir: string): string[] {
|
function collectAuthJsonPaths(stateDir: string): string[] {
|
||||||
const out: string[] = [];
|
const out: string[] = [];
|
||||||
const agentsRoot = path.join(resolveUserPath(stateDir), "agents");
|
const agentsRoot = path.join(resolveUserPath(stateDir), "agents");
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { listAgentIds, resolveAgentDir } from "../agents/agent-scope.js";
|
|
||||||
import { resolveAuthStorePath } from "../agents/auth-profiles/paths.js";
|
|
||||||
import { normalizeProviderId } from "../agents/model-selection.js";
|
import { normalizeProviderId } from "../agents/model-selection.js";
|
||||||
import { resolveStateDir, type OpenClawConfig } from "../config/config.js";
|
import { resolveStateDir, type OpenClawConfig } from "../config/config.js";
|
||||||
import { coerceSecretRef, type SecretRef } from "../config/types.secrets.js";
|
import { coerceSecretRef, type SecretRef } from "../config/types.secrets.js";
|
||||||
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
||||||
|
import { collectAuthStorePaths } from "./auth-store-paths.js";
|
||||||
import { createSecretsConfigIO } from "./config-io.js";
|
import { createSecretsConfigIO } from "./config-io.js";
|
||||||
import { listKnownSecretEnvVarNames } from "./provider-env-vars.js";
|
import { listKnownSecretEnvVarNames } from "./provider-env-vars.js";
|
||||||
import { secretRefKey } from "./ref-contract.js";
|
import { secretRefKey } from "./ref-contract.js";
|
||||||
@@ -306,36 +305,6 @@ function collectConfigSecrets(params: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectAuthStorePaths(config: OpenClawConfig, stateDir: string): string[] {
|
|
||||||
const paths = new Set<string>();
|
|
||||||
// Scope default auth store discovery to the provided stateDir instead of
|
|
||||||
// ambient process env, so audits do not include unrelated host-global stores.
|
|
||||||
paths.add(path.join(resolveUserPath(stateDir), "agents", "main", "agent", "auth-profiles.json"));
|
|
||||||
|
|
||||||
const agentsRoot = path.join(resolveUserPath(stateDir), "agents");
|
|
||||||
if (fs.existsSync(agentsRoot)) {
|
|
||||||
for (const entry of fs.readdirSync(agentsRoot, { withFileTypes: true })) {
|
|
||||||
if (!entry.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
paths.add(path.join(agentsRoot, entry.name, "agent", "auth-profiles.json"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const agentId of listAgentIds(config)) {
|
|
||||||
if (agentId === "main") {
|
|
||||||
paths.add(
|
|
||||||
path.join(resolveUserPath(stateDir), "agents", "main", "agent", "auth-profiles.json"),
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const agentDir = resolveAgentDir(config, agentId);
|
|
||||||
paths.add(resolveUserPath(resolveAuthStorePath(agentDir)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [...paths];
|
|
||||||
}
|
|
||||||
|
|
||||||
function collectAuthStoreSecrets(params: {
|
function collectAuthStoreSecrets(params: {
|
||||||
authStorePath: string;
|
authStorePath: string;
|
||||||
collector: AuditCollector;
|
collector: AuditCollector;
|
||||||
|
|||||||
36
src/secrets/auth-store-paths.ts
Normal file
36
src/secrets/auth-store-paths.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { listAgentIds, resolveAgentDir } from "../agents/agent-scope.js";
|
||||||
|
import { resolveAuthStorePath } from "../agents/auth-profiles/paths.js";
|
||||||
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
|
import { resolveUserPath } from "../utils.js";
|
||||||
|
|
||||||
|
export function collectAuthStorePaths(config: OpenClawConfig, stateDir: string): string[] {
|
||||||
|
const paths = new Set<string>();
|
||||||
|
// Scope default auth store discovery to the provided stateDir instead of
|
||||||
|
// ambient process env, so callers do not touch unrelated host-global stores.
|
||||||
|
paths.add(path.join(resolveUserPath(stateDir), "agents", "main", "agent", "auth-profiles.json"));
|
||||||
|
|
||||||
|
const agentsRoot = path.join(resolveUserPath(stateDir), "agents");
|
||||||
|
if (fs.existsSync(agentsRoot)) {
|
||||||
|
for (const entry of fs.readdirSync(agentsRoot, { withFileTypes: true })) {
|
||||||
|
if (!entry.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
paths.add(path.join(agentsRoot, entry.name, "agent", "auth-profiles.json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const agentId of listAgentIds(config)) {
|
||||||
|
if (agentId === "main") {
|
||||||
|
paths.add(
|
||||||
|
path.join(resolveUserPath(stateDir), "agents", "main", "agent", "auth-profiles.json"),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const agentDir = resolveAgentDir(config, agentId);
|
||||||
|
paths.add(resolveUserPath(resolveAuthStorePath(agentDir)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...paths];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user