refactor: unify group allowlist policy

This commit is contained in:
Peter Steinberger
2026-01-06 04:27:21 +01:00
parent b1bb3ff6a6
commit ca8f66f844
10 changed files with 298 additions and 71 deletions

View File

@@ -1045,6 +1045,57 @@ describe("web auto-reply", () => {
resetLoadConfigMock();
});
it("blocks group messages when whatsapp groups is set without a wildcard", async () => {
const sendMedia = vi.fn();
const reply = vi.fn().mockResolvedValue(undefined);
const sendComposing = vi.fn();
const resolver = vi.fn().mockResolvedValue({ text: "ok" });
setLoadConfigMock(() => ({
whatsapp: {
allowFrom: ["*"],
groups: { "999@g.us": { requireMention: false } },
},
routing: { groupChat: { mentionPatterns: ["@clawd"] } },
}));
let capturedOnMessage:
| ((msg: import("./inbound.js").WebInboundMessage) => Promise<void>)
| undefined;
const listenerFactory = async (opts: {
onMessage: (
msg: import("./inbound.js").WebInboundMessage,
) => Promise<void>;
}) => {
capturedOnMessage = opts.onMessage;
return { close: vi.fn() };
};
await monitorWebProvider(false, listenerFactory, false, resolver);
expect(capturedOnMessage).toBeDefined();
await capturedOnMessage?.({
body: "@clawd hello",
from: "123@g.us",
conversationId: "123@g.us",
chatId: "123@g.us",
chatType: "group",
to: "+2",
id: "g-allowlist-block",
senderE164: "+111",
senderName: "Alice",
mentionedJids: ["999@s.whatsapp.net"],
selfE164: "+999",
selfJid: "999@s.whatsapp.net",
sendComposing,
reply,
sendMedia,
});
expect(resolver).not.toHaveBeenCalled();
resetLoadConfigMock();
});
it("honors per-group mention overrides when conversationId uses session key", async () => {
const sendMedia = vi.fn();
const reply = vi.fn().mockResolvedValue(undefined);

View File

@@ -20,6 +20,10 @@ import { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import { waitForever } from "../cli/wait.js";
import { loadConfig } from "../config/config.js";
import {
resolveProviderGroupPolicy,
resolveProviderGroupRequireMention,
} from "../config/group-policy.js";
import {
DEFAULT_IDLE_MINUTES,
loadSessionStore,
@@ -850,16 +854,24 @@ export async function monitorWebProvider(
Surface: "whatsapp",
});
const resolveGroupPolicyFor = (conversationId: string) => {
const groupId =
resolveGroupResolution(conversationId)?.id ?? conversationId;
return resolveProviderGroupPolicy({
cfg,
surface: "whatsapp",
groupId,
});
};
const resolveGroupRequireMentionFor = (conversationId: string) => {
const groupId =
resolveGroupResolution(conversationId)?.id ?? conversationId;
const groupConfig = cfg.whatsapp?.groups?.[groupId];
if (typeof groupConfig?.requireMention === "boolean") {
return groupConfig.requireMention;
}
const groupDefault = cfg.whatsapp?.groups?.["*"]?.requireMention;
if (typeof groupDefault === "boolean") return groupDefault;
return true;
return resolveProviderGroupRequireMention({
cfg,
surface: "whatsapp",
groupId,
});
};
const resolveGroupActivationFor = (conversationId: string) => {
@@ -1275,6 +1287,13 @@ export async function monitorWebProvider(
}
if (msg.chatType === "group") {
const groupPolicy = resolveGroupPolicyFor(conversationId);
if (groupPolicy.allowlistEnabled && !groupPolicy.allowed) {
logVerbose(
`Skipping group message ${conversationId} (not in allowlist)`,
);
return;
}
noteGroupMember(conversationId, msg.senderE164, msg.senderName);
const commandBody = stripMentionsForCommand(msg.body, msg.selfE164);
const activationCommand = parseActivationCommand(commandBody);