mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 00:40:21 +00:00
refactor: unify account-scoped dm security policy resolver
This commit is contained in:
95
src/channels/plugins/helpers.test.ts
Normal file
95
src/channels/plugins/helpers.test.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { buildAccountScopedDmSecurityPolicy, formatPairingApproveHint } from "./helpers.js";
|
||||
|
||||
function cfgWithChannel(channelKey: string, accounts?: Record<string, unknown>): OpenClawConfig {
|
||||
return {
|
||||
channels: {
|
||||
[channelKey]: accounts ? { accounts } : {},
|
||||
},
|
||||
} as unknown as OpenClawConfig;
|
||||
}
|
||||
|
||||
describe("buildAccountScopedDmSecurityPolicy", () => {
|
||||
it("builds top-level dm policy paths when no account config exists", () => {
|
||||
expect(
|
||||
buildAccountScopedDmSecurityPolicy({
|
||||
cfg: cfgWithChannel("telegram"),
|
||||
channelKey: "telegram",
|
||||
fallbackAccountId: "default",
|
||||
policy: "pairing",
|
||||
allowFrom: ["123"],
|
||||
policyPathSuffix: "dmPolicy",
|
||||
}),
|
||||
).toEqual({
|
||||
policy: "pairing",
|
||||
allowFrom: ["123"],
|
||||
policyPath: "channels.telegram.dmPolicy",
|
||||
allowFromPath: "channels.telegram.",
|
||||
approveHint: formatPairingApproveHint("telegram"),
|
||||
normalizeEntry: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("uses account-scoped paths when account config exists", () => {
|
||||
expect(
|
||||
buildAccountScopedDmSecurityPolicy({
|
||||
cfg: cfgWithChannel("signal", { work: {} }),
|
||||
channelKey: "signal",
|
||||
accountId: "work",
|
||||
fallbackAccountId: "default",
|
||||
policy: "allowlist",
|
||||
allowFrom: ["+12125551212"],
|
||||
policyPathSuffix: "dmPolicy",
|
||||
}),
|
||||
).toEqual({
|
||||
policy: "allowlist",
|
||||
allowFrom: ["+12125551212"],
|
||||
policyPath: "channels.signal.accounts.work.dmPolicy",
|
||||
allowFromPath: "channels.signal.accounts.work.",
|
||||
approveHint: formatPairingApproveHint("signal"),
|
||||
normalizeEntry: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("supports nested dm paths without explicit policyPath", () => {
|
||||
expect(
|
||||
buildAccountScopedDmSecurityPolicy({
|
||||
cfg: cfgWithChannel("discord", { work: {} }),
|
||||
channelKey: "discord",
|
||||
accountId: "work",
|
||||
policy: "pairing",
|
||||
allowFrom: [],
|
||||
allowFromPathSuffix: "dm.",
|
||||
}),
|
||||
).toEqual({
|
||||
policy: "pairing",
|
||||
allowFrom: [],
|
||||
policyPath: undefined,
|
||||
allowFromPath: "channels.discord.accounts.work.dm.",
|
||||
approveHint: formatPairingApproveHint("discord"),
|
||||
normalizeEntry: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("supports custom defaults and approve hints", () => {
|
||||
expect(
|
||||
buildAccountScopedDmSecurityPolicy({
|
||||
cfg: cfgWithChannel("synology-chat"),
|
||||
channelKey: "synology-chat",
|
||||
fallbackAccountId: "default",
|
||||
allowFrom: ["user-1"],
|
||||
defaultPolicy: "allowlist",
|
||||
policyPathSuffix: "dmPolicy",
|
||||
approveHint: "openclaw pairing approve synology-chat <code>",
|
||||
}),
|
||||
).toEqual({
|
||||
policy: "allowlist",
|
||||
allowFrom: ["user-1"],
|
||||
policyPath: "channels.synology-chat.dmPolicy",
|
||||
allowFromPath: "channels.synology-chat.",
|
||||
approveHint: "openclaw pairing approve synology-chat <code>",
|
||||
normalizeEntry: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import { formatCliCommand } from "../../cli/command-format.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
|
||||
import type { ChannelSecurityDmPolicy } from "./types.core.js";
|
||||
import type { ChannelPlugin } from "./types.js";
|
||||
|
||||
// Channel docking helper: use this when selecting the default account for a plugin.
|
||||
@@ -18,3 +19,40 @@ export function formatPairingApproveHint(channelId: string): string {
|
||||
const approveCmd = formatCliCommand(`openclaw pairing approve ${channelId} <code>`);
|
||||
return `Approve via: ${listCmd} / ${approveCmd}`;
|
||||
}
|
||||
|
||||
export function buildAccountScopedDmSecurityPolicy(params: {
|
||||
cfg: OpenClawConfig;
|
||||
channelKey: string;
|
||||
accountId?: string | null;
|
||||
fallbackAccountId?: string | null;
|
||||
policy?: string | null;
|
||||
allowFrom?: Array<string | number> | null;
|
||||
defaultPolicy?: string;
|
||||
allowFromPathSuffix?: string;
|
||||
policyPathSuffix?: string;
|
||||
approveChannelId?: string;
|
||||
approveHint?: string;
|
||||
normalizeEntry?: (raw: string) => string;
|
||||
}): ChannelSecurityDmPolicy {
|
||||
const resolvedAccountId = params.accountId ?? params.fallbackAccountId ?? DEFAULT_ACCOUNT_ID;
|
||||
const channelConfig = (params.cfg.channels as Record<string, unknown> | undefined)?.[
|
||||
params.channelKey
|
||||
] as { accounts?: Record<string, unknown> } | undefined;
|
||||
const useAccountPath = Boolean(channelConfig?.accounts?.[resolvedAccountId]);
|
||||
const basePath = useAccountPath
|
||||
? `channels.${params.channelKey}.accounts.${resolvedAccountId}.`
|
||||
: `channels.${params.channelKey}.`;
|
||||
const allowFromPath = `${basePath}${params.allowFromPathSuffix ?? ""}`;
|
||||
const policyPath =
|
||||
params.policyPathSuffix != null ? `${basePath}${params.policyPathSuffix}` : undefined;
|
||||
|
||||
return {
|
||||
policy: params.policy ?? params.defaultPolicy ?? "pairing",
|
||||
allowFrom: params.allowFrom ?? [],
|
||||
policyPath,
|
||||
allowFromPath,
|
||||
approveHint:
|
||||
params.approveHint ?? formatPairingApproveHint(params.approveChannelId ?? params.channelKey),
|
||||
normalizeEntry: params.normalizeEntry,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -537,7 +537,10 @@ export {
|
||||
buildOpenGroupPolicyRestrictSendersWarning,
|
||||
buildOpenGroupPolicyWarning,
|
||||
} from "../channels/plugins/group-policy-warnings.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
formatPairingApproveHint,
|
||||
} from "../channels/plugins/helpers.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";
|
||||
|
||||
export type {
|
||||
|
||||
Reference in New Issue
Block a user