diff --git a/src/channels/plugins/config-writes.ts b/src/channels/plugins/config-writes.ts index 3e3ef36ed04..4044ba1ec88 100644 --- a/src/channels/plugins/config-writes.ts +++ b/src/channels/plugins/config-writes.ts @@ -1,18 +1,17 @@ import type { OpenClawConfig } from "../../config/config.js"; import { resolveAccountEntry } from "../../routing/account-lookup.js"; -import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js"; -import { normalizeAccountId } from "../../routing/session-key.js"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js"; import { isInternalMessageChannel } from "../../utils/message-channel.js"; import type { ChannelId } from "./types.js"; -type ChannelConfigWithAccounts = { +type AccountConfigWithWrites = { configWrites?: boolean; - accounts?: Record; }; -function resolveAccountConfig(accounts: ChannelConfigWithAccounts["accounts"], accountId: string) { - return resolveAccountEntry(accounts, accountId); -} +type ChannelConfigWithAccounts = { + configWrites?: boolean; + accounts?: Record; +}; export type ConfigWriteScope = { channelId?: ChannelId | null; @@ -38,16 +37,11 @@ export function resolveChannelConfigWrites(params: { channelId?: ChannelId | null; accountId?: string | null; }): boolean { - if (!params.channelId) { - return true; - } - const channels = params.cfg.channels as Record | undefined; - const channelConfig = channels?.[params.channelId]; + const channelConfig = resolveChannelConfig(params.cfg, params.channelId); if (!channelConfig) { return true; } - const accountId = normalizeAccountId(params.accountId); - const accountConfig = resolveAccountConfig(channelConfig.accounts, accountId); + const accountConfig = resolveChannelAccountConfig(channelConfig, params.accountId); const value = accountConfig?.configWrites ?? channelConfig.configWrites; return value !== false; } @@ -181,3 +175,20 @@ function listConfigWriteTargetScopes(target?: ConfigWriteTarget): ConfigWriteSco } return [target.scope]; } + +function resolveChannelConfig( + cfg: OpenClawConfig, + channelId?: ChannelId | null, +): ChannelConfigWithAccounts | undefined { + if (!channelId) { + return undefined; + } + return (cfg.channels as Record | undefined)?.[channelId]; +} + +function resolveChannelAccountConfig( + channelConfig: ChannelConfigWithAccounts, + accountId?: string | null, +): AccountConfigWithWrites | undefined { + return resolveAccountEntry(channelConfig.accounts, normalizeAccountId(accountId)); +} diff --git a/src/channels/plugins/plugins-core.test.ts b/src/channels/plugins/plugins-core.test.ts index 641527c3cbd..6b3d8dfd886 100644 --- a/src/channels/plugins/plugins-core.test.ts +++ b/src/channels/plugins/plugins-core.test.ts @@ -505,6 +505,12 @@ describe("resolveChannelConfigWrites", () => { const cfg = makeSlackConfigWritesCfg("Work"); expect(resolveChannelConfigWrites({ cfg, channelId: "slack", accountId: "work" })).toBe(false); }); + + it("ignores account ids when the channel is missing", () => { + expect(resolveChannelConfigWrites({ cfg: {}, channelId: "slack", accountId: "work" })).toBe( + true, + ); + }); }); describe("authorizeConfigWrite", () => { diff --git a/src/media/inbound-path-policy.test.ts b/src/media/inbound-path-policy.test.ts index 3d7d300ec48..9a5bf8eb375 100644 --- a/src/media/inbound-path-policy.test.ts +++ b/src/media/inbound-path-policy.test.ts @@ -68,6 +68,25 @@ describe("inbound-path-policy", () => { ]); }); + it("matches iMessage account ids case-insensitively for attachment roots", () => { + const cfg = { + channels: { + imessage: { + accounts: { + Work: { + attachmentRoots: ["/Users/work/Library/Messages/Attachments"], + }, + }, + }, + }, + } as OpenClawConfig; + + expect(resolveIMessageAttachmentRoots({ cfg, accountId: "work" })).toEqual([ + "/Users/work/Library/Messages/Attachments", + ...DEFAULT_IMESSAGE_ATTACHMENT_ROOTS, + ]); + }); + it("falls back to default iMessage roots", () => { const cfg = {} as OpenClawConfig; expect(resolveIMessageAttachmentRoots({ cfg })).toEqual([...DEFAULT_IMESSAGE_ATTACHMENT_ROOTS]); diff --git a/src/media/inbound-path-policy.ts b/src/media/inbound-path-policy.ts index 7b98ece42f7..8c77fbe5c03 100644 --- a/src/media/inbound-path-policy.ts +++ b/src/media/inbound-path-policy.ts @@ -1,5 +1,7 @@ import path from "node:path"; import type { OpenClawConfig } from "../config/config.js"; +import { resolveAccountEntry } from "../routing/account-lookup.js"; +import { normalizeAccountId } from "../routing/session-key.js"; const WILDCARD_SEGMENT = "*"; const WINDOWS_DRIVE_ABS_RE = /^[A-Za-z]:\//; @@ -116,11 +118,11 @@ export function isInboundPathAllowed(params: { } function resolveIMessageAccountConfig(params: { cfg: OpenClawConfig; accountId?: string | null }) { - const accountId = params.accountId?.trim(); - if (!accountId) { + const accountId = normalizeAccountId(params.accountId); + if (!params.accountId?.trim()) { return undefined; } - return params.cfg.channels?.imessage?.accounts?.[accountId]; + return resolveAccountEntry(params.cfg.channels?.imessage?.accounts, accountId); } export function resolveIMessageAttachmentRoots(params: {