import type { AgentElevatedAllowFromConfig, OpenClawConfig } from "../../config/config.js"; import type { MsgContext } from "../templating.js"; import { resolveAgentConfig } from "../../agents/agent-scope.js"; import { getChannelDock } from "../../channels/dock.js"; import { normalizeChannelId } from "../../channels/plugins/index.js"; import { CHAT_CHANNEL_ORDER } from "../../channels/registry.js"; import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js"; export { formatElevatedUnavailableMessage } from "./elevated-unavailable.js"; function normalizeAllowToken(value?: string) { if (!value) { return ""; } return value.trim().toLowerCase(); } function slugAllowToken(value?: string) { if (!value) { return ""; } let text = value.trim().toLowerCase(); if (!text) { return ""; } text = text.replace(/^[@#]+/, ""); text = text.replace(/[\s_]+/g, "-"); text = text.replace(/[^a-z0-9-]+/g, "-"); return text.replace(/-{2,}/g, "-").replace(/^-+|-+$/g, ""); } const SENDER_PREFIXES = [ ...CHAT_CHANNEL_ORDER, INTERNAL_MESSAGE_CHANNEL, "user", "group", "channel", ]; const SENDER_PREFIX_RE = new RegExp(`^(${SENDER_PREFIXES.join("|")}):`, "i"); function stripSenderPrefix(value?: string) { if (!value) { return ""; } const trimmed = value.trim(); return trimmed.replace(SENDER_PREFIX_RE, ""); } function resolveElevatedAllowList( allowFrom: AgentElevatedAllowFromConfig | undefined, provider: string, fallbackAllowFrom?: Array, ): Array | undefined { if (!allowFrom) { return fallbackAllowFrom; } const value = allowFrom[provider]; return Array.isArray(value) ? value : fallbackAllowFrom; } function isApprovedElevatedSender(params: { provider: string; ctx: MsgContext; allowFrom?: AgentElevatedAllowFromConfig; fallbackAllowFrom?: Array; }): boolean { const rawAllow = resolveElevatedAllowList( params.allowFrom, params.provider, params.fallbackAllowFrom, ); if (!rawAllow || rawAllow.length === 0) { return false; } const allowTokens = rawAllow.map((entry) => String(entry).trim()).filter(Boolean); if (allowTokens.length === 0) { return false; } if (allowTokens.some((entry) => entry === "*")) { return true; } const tokens = new Set(); const addToken = (value?: string) => { if (!value) { return; } const trimmed = value.trim(); if (!trimmed) { return; } tokens.add(trimmed); const normalized = normalizeAllowToken(trimmed); if (normalized) { tokens.add(normalized); } const slugged = slugAllowToken(trimmed); if (slugged) { tokens.add(slugged); } }; addToken(params.ctx.SenderName); addToken(params.ctx.SenderUsername); addToken(params.ctx.SenderTag); addToken(params.ctx.SenderE164); addToken(params.ctx.From); addToken(stripSenderPrefix(params.ctx.From)); addToken(params.ctx.To); addToken(stripSenderPrefix(params.ctx.To)); for (const rawEntry of allowTokens) { const entry = rawEntry.trim(); if (!entry) { continue; } const stripped = stripSenderPrefix(entry); if (tokens.has(entry) || tokens.has(stripped)) { return true; } const normalized = normalizeAllowToken(stripped); if (normalized && tokens.has(normalized)) { return true; } const slugged = slugAllowToken(stripped); if (slugged && tokens.has(slugged)) { return true; } } return false; } export function resolveElevatedPermissions(params: { cfg: OpenClawConfig; agentId: string; ctx: MsgContext; provider: string; }): { enabled: boolean; allowed: boolean; failures: Array<{ gate: string; key: string }>; } { const globalConfig = params.cfg.tools?.elevated; const agentConfig = resolveAgentConfig(params.cfg, params.agentId)?.tools?.elevated; const globalEnabled = globalConfig?.enabled !== false; const agentEnabled = agentConfig?.enabled !== false; const enabled = globalEnabled && agentEnabled; const failures: Array<{ gate: string; key: string }> = []; if (!globalEnabled) { failures.push({ gate: "enabled", key: "tools.elevated.enabled" }); } if (!agentEnabled) { failures.push({ gate: "enabled", key: "agents.list[].tools.elevated.enabled", }); } if (!enabled) { return { enabled, allowed: false, failures }; } if (!params.provider) { failures.push({ gate: "provider", key: "ctx.Provider" }); return { enabled, allowed: false, failures }; } const normalizedProvider = normalizeChannelId(params.provider); const dockFallbackAllowFrom = normalizedProvider ? getChannelDock(normalizedProvider)?.elevated?.allowFromFallback?.({ cfg: params.cfg, accountId: params.ctx.AccountId, }) : undefined; const fallbackAllowFrom = dockFallbackAllowFrom; const globalAllowed = isApprovedElevatedSender({ provider: params.provider, ctx: params.ctx, allowFrom: globalConfig?.allowFrom, fallbackAllowFrom, }); if (!globalAllowed) { failures.push({ gate: "allowFrom", key: `tools.elevated.allowFrom.${params.provider}`, }); return { enabled, allowed: false, failures }; } const agentAllowed = agentConfig?.allowFrom ? isApprovedElevatedSender({ provider: params.provider, ctx: params.ctx, allowFrom: agentConfig.allowFrom, fallbackAllowFrom, }) : true; if (!agentAllowed) { failures.push({ gate: "allowFrom", key: `agents.list[].tools.elevated.allowFrom.${params.provider}`, }); } return { enabled, allowed: globalAllowed && agentAllowed, failures }; }