refactor: share allowFrom formatter scaffolding
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
collectOpenGroupPolicyRestrictSendersWarnings,
|
||||
formatNormalizedAllowFromEntries,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import type {
|
||||
ChannelAccountSnapshot,
|
||||
@@ -118,11 +119,10 @@ export const bluebubblesPlugin: ChannelPlugin<ResolvedBlueBubblesAccount> = {
|
||||
String(entry),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.replace(/^bluebubbles:/i, ""))
|
||||
.map((entry) => normalizeBlueBubblesHandle(entry)),
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom,
|
||||
normalizeEntry: (entry) => normalizeBlueBubblesHandle(entry.replace(/^bluebubbles:/i, "")),
|
||||
}),
|
||||
},
|
||||
actions: bluebubblesMessageActions,
|
||||
security: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
collectOpenGroupPolicyConfiguredRouteWarnings,
|
||||
formatAllowFromLowercase,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
applyAccountNameToChannelSection,
|
||||
@@ -116,11 +117,7 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
|
||||
(resolveDiscordAccount({ cfg, accountId }).config.dm?.allowFrom ?? []).map((entry) =>
|
||||
String(entry),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.toLowerCase()),
|
||||
formatAllowFrom: ({ allowFrom }) => formatAllowFromLowercase({ allowFrom }),
|
||||
resolveDefaultTo: ({ cfg, accountId }) =>
|
||||
resolveDiscordAccount({ cfg, accountId }).config.defaultTo?.trim() || undefined,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { collectOpenGroupPolicyRestrictSendersWarnings } from "openclaw/plugin-sdk";
|
||||
import {
|
||||
collectOpenGroupPolicyRestrictSendersWarnings,
|
||||
formatAllowFromLowercase,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import type { ChannelMeta, ChannelPlugin, ClawdbotConfig } from "openclaw/plugin-sdk/feishu";
|
||||
import {
|
||||
buildProbeChannelStatusSummary,
|
||||
@@ -251,11 +254,7 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
||||
const account = resolveFeishuAccount({ cfg, accountId });
|
||||
return (account.config?.allowFrom ?? []).map((entry) => String(entry));
|
||||
},
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.toLowerCase()),
|
||||
formatAllowFrom: ({ allowFrom }) => formatAllowFromLowercase({ allowFrom }),
|
||||
},
|
||||
security: {
|
||||
collectWarnings: ({ cfg, accountId }) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
buildOpenGroupPolicyConfigureRouteAllowlistWarning,
|
||||
formatNormalizedAllowFromEntries,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
applyAccountNameToChannelSection,
|
||||
@@ -72,10 +73,10 @@ export const googlechatDock: ChannelDock = {
|
||||
String(entry),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry))
|
||||
.filter(Boolean)
|
||||
.map(formatAllowFromEntry),
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom,
|
||||
normalizeEntry: formatAllowFromEntry,
|
||||
}),
|
||||
},
|
||||
groups: {
|
||||
resolveRequireMention: resolveGoogleChatGroupRequireMention,
|
||||
@@ -183,10 +184,10 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
|
||||
}).config.dm?.allowFrom ?? []
|
||||
).map((entry) => String(entry)),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry))
|
||||
.filter(Boolean)
|
||||
.map(formatAllowFromEntry),
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom,
|
||||
normalizeEntry: formatAllowFromEntry,
|
||||
}),
|
||||
resolveDefaultTo: ({ cfg, accountId }) =>
|
||||
resolveGoogleChatAccount({ cfg, accountId }).config.defaultTo?.trim() || undefined,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
buildOpenGroupPolicyWarning,
|
||||
formatNormalizedAllowFromEntries,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
buildBaseAccountStatusSnapshot,
|
||||
@@ -118,7 +119,10 @@ export const ircPlugin: ChannelPlugin<ResolvedIrcAccount, IrcProbe> = {
|
||||
(entry) => String(entry),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom.map((entry) => normalizeIrcAllowEntry(String(entry))).filter(Boolean),
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom,
|
||||
normalizeEntry: normalizeIrcAllowEntry,
|
||||
}),
|
||||
resolveDefaultTo: ({ cfg, accountId }) =>
|
||||
resolveIrcAccount({ cfg: cfg as CoreConfig, accountId }).config.defaultTo?.trim() ||
|
||||
undefined,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
collectOpenGroupPolicyRestrictSendersWarnings,
|
||||
formatNormalizedAllowFromEntries,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
applyAccountNameToChannelSection,
|
||||
@@ -279,7 +280,10 @@ export const mattermostPlugin: ChannelPlugin<ResolvedMattermostAccount> = {
|
||||
String(entry),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom.map((entry) => formatAllowEntry(String(entry))).filter(Boolean),
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom,
|
||||
normalizeEntry: formatAllowEntry,
|
||||
}),
|
||||
},
|
||||
security: {
|
||||
resolveDmPolicy: ({ cfg, accountId, account }) => {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { collectOpenGroupPolicyRestrictSendersWarnings } from "openclaw/plugin-sdk";
|
||||
import {
|
||||
collectOpenGroupPolicyRestrictSendersWarnings,
|
||||
formatAllowFromLowercase,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import type {
|
||||
ChannelMessageActionName,
|
||||
ChannelPlugin,
|
||||
@@ -126,11 +129,7 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
|
||||
configured: account.configured,
|
||||
}),
|
||||
resolveAllowFrom: ({ cfg }) => cfg.channels?.msteams?.allowFrom ?? [],
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.toLowerCase()),
|
||||
formatAllowFrom: ({ allowFrom }) => formatAllowFromLowercase({ allowFrom }),
|
||||
resolveDefaultTo: ({ cfg }) => cfg.channels?.msteams?.defaultTo?.trim() || undefined,
|
||||
},
|
||||
security: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
collectOpenGroupPolicyRouteAllowlistWarnings,
|
||||
formatAllowFromLowercase,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
applyAccountNameToChannelSection,
|
||||
@@ -112,11 +113,10 @@ export const nextcloudTalkPlugin: ChannelPlugin<ResolvedNextcloudTalkAccount> =
|
||||
resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId }).config.allowFrom ?? []
|
||||
).map((entry) => String(entry).toLowerCase()),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.replace(/^(nextcloud-talk|nc-talk|nc):/i, ""))
|
||||
.map((entry) => entry.toLowerCase()),
|
||||
formatAllowFromLowercase({
|
||||
allowFrom,
|
||||
stripPrefixRe: /^(nextcloud-talk|nc-talk|nc):/i,
|
||||
}),
|
||||
},
|
||||
security: {
|
||||
resolveDmPolicy: ({ cfg, accountId, account }) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
collectOpenGroupPolicyConfiguredRouteWarnings,
|
||||
formatAllowFromLowercase,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
applyAccountNameToChannelSection,
|
||||
@@ -166,11 +167,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
|
||||
}),
|
||||
resolveAllowFrom: ({ cfg, accountId }) =>
|
||||
(resolveSlackAccount({ cfg, accountId }).dm?.allowFrom ?? []).map((entry) => String(entry)),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.toLowerCase()),
|
||||
formatAllowFrom: ({ allowFrom }) => formatAllowFromLowercase({ allowFrom }),
|
||||
resolveDefaultTo: ({ cfg, accountId }) =>
|
||||
resolveSlackAccount({ cfg, accountId }).config.defaultTo?.trim() || undefined,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
buildAccountScopedDmSecurityPolicy,
|
||||
collectOpenGroupPolicyRouteAllowlistWarnings,
|
||||
formatAllowFromLowercase,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
applyAccountNameToChannelSection,
|
||||
@@ -179,11 +180,7 @@ export const telegramPlugin: ChannelPlugin<ResolvedTelegramAccount, TelegramProb
|
||||
String(entry),
|
||||
),
|
||||
formatAllowFrom: ({ allowFrom }) =>
|
||||
allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => entry.replace(/^(telegram|tg):/i, ""))
|
||||
.map((entry) => entry.toLowerCase()),
|
||||
formatAllowFromLowercase({ allowFrom, stripPrefixRe: /^(telegram|tg):/i }),
|
||||
resolveDefaultTo: ({ cfg, accountId }) => {
|
||||
const val = resolveTelegramAccount({ cfg, accountId }).config.defaultTo;
|
||||
return val != null ? String(val) : undefined;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isAllowedParsedChatSender, isNormalizedSenderAllowed } from "./allow-from.js";
|
||||
import {
|
||||
formatAllowFromLowercase,
|
||||
formatNormalizedAllowFromEntries,
|
||||
isAllowedParsedChatSender,
|
||||
isNormalizedSenderAllowed,
|
||||
} from "./allow-from.js";
|
||||
|
||||
function parseAllowTarget(
|
||||
entry: string,
|
||||
@@ -102,3 +107,34 @@ describe("isNormalizedSenderAllowed", () => {
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatAllowFromLowercase", () => {
|
||||
it("trims, strips prefixes, and lowercases entries", () => {
|
||||
expect(
|
||||
formatAllowFromLowercase({
|
||||
allowFrom: [" Telegram:UserA ", "tg:UserB", " "],
|
||||
stripPrefixRe: /^(telegram|tg):/i,
|
||||
}),
|
||||
).toEqual(["usera", "userb"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatNormalizedAllowFromEntries", () => {
|
||||
it("applies custom normalization after trimming", () => {
|
||||
expect(
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom: [" @Alice ", "", " @Bob "],
|
||||
normalizeEntry: (entry) => entry.replace(/^@/, "").toLowerCase(),
|
||||
}),
|
||||
).toEqual(["alice", "bob"]);
|
||||
});
|
||||
|
||||
it("filters empty normalized entries", () => {
|
||||
expect(
|
||||
formatNormalizedAllowFromEntries({
|
||||
allowFrom: ["@", "valid"],
|
||||
normalizeEntry: (entry) => entry.replace(/^@$/, ""),
|
||||
}),
|
||||
).toEqual(["valid"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,17 @@ export function formatAllowFromLowercase(params: {
|
||||
.map((entry) => entry.toLowerCase());
|
||||
}
|
||||
|
||||
export function formatNormalizedAllowFromEntries(params: {
|
||||
allowFrom: Array<string | number>;
|
||||
normalizeEntry: (entry: string) => string | undefined | null;
|
||||
}): string[] {
|
||||
return params.allowFrom
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => params.normalizeEntry(entry))
|
||||
.filter((entry): entry is string => Boolean(entry));
|
||||
}
|
||||
|
||||
export function isNormalizedSenderAllowed(params: {
|
||||
senderId: string | number;
|
||||
allowFrom: Array<string | number>;
|
||||
|
||||
@@ -274,6 +274,7 @@ export {
|
||||
} from "../routing/session-key.js";
|
||||
export {
|
||||
formatAllowFromLowercase,
|
||||
formatNormalizedAllowFromEntries,
|
||||
isAllowedParsedChatSender,
|
||||
isNormalizedSenderAllowed,
|
||||
} from "./allow-from.js";
|
||||
|
||||
Reference in New Issue
Block a user