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

@@ -411,6 +411,38 @@ describe("createTelegramBot", () => {
}
});
it("blocks group messages when telegram.groups is set without a wildcard", async () => {
onSpy.mockReset();
const replySpy = replyModule.__replySpy as unknown as ReturnType<
typeof vi.fn
>;
replySpy.mockReset();
loadConfig.mockReturnValue({
telegram: {
groups: {
"123": { requireMention: false },
},
},
});
createTelegramBot({ token: "tok" });
const handler = onSpy.mock.calls[0][1] as (
ctx: Record<string, unknown>,
) => Promise<void>;
await handler({
message: {
chat: { id: 456, type: "group", title: "Ops" },
text: "@clawdbot_bot hello",
date: 1736380800,
},
me: { username: "clawdbot_bot" },
getFile: async () => ({ download: async () => new Uint8Array() }),
});
expect(replySpy).not.toHaveBeenCalled();
});
it("skips group messages without mention when requireMention is enabled", async () => {
onSpy.mockReset();
const replySpy = replyModule.__replySpy as unknown as ReturnType<

View File

@@ -17,6 +17,10 @@ import { getReplyFromConfig } from "../auto-reply/reply.js";
import type { ReplyPayload } from "../auto-reply/types.js";
import type { ReplyToMode } from "../config/config.js";
import { loadConfig } from "../config/config.js";
import {
resolveProviderGroupPolicy,
resolveProviderGroupRequireMention,
} from "../config/group-policy.js";
import { resolveStorePath, updateLastRoute } from "../config/sessions.js";
import { danger, logVerbose, shouldLogVerbose } from "../globals.js";
import { formatErrorMessage } from "../infra/errors.js";
@@ -73,17 +77,20 @@ export function createTelegramBot(opts: TelegramBotOptions) {
(opts.mediaMaxMb ?? cfg.telegram?.mediaMaxMb ?? 5) * 1024 * 1024;
const logger = getChildLogger({ module: "telegram-auto-reply" });
const mentionRegexes = buildMentionRegexes(cfg);
const resolveGroupRequireMention = (chatId: string | number) => {
const groupId = String(chatId);
const groupConfig = cfg.telegram?.groups?.[groupId];
if (typeof groupConfig?.requireMention === "boolean") {
return groupConfig.requireMention;
}
const groupDefault = cfg.telegram?.groups?.["*"]?.requireMention;
if (typeof groupDefault === "boolean") return groupDefault;
if (typeof opts.requireMention === "boolean") return opts.requireMention;
return true;
};
const resolveGroupPolicy = (chatId: string | number) =>
resolveProviderGroupPolicy({
cfg,
surface: "telegram",
groupId: String(chatId),
});
const resolveGroupRequireMention = (chatId: string | number) =>
resolveProviderGroupRequireMention({
cfg,
surface: "telegram",
groupId: String(chatId),
requireMentionOverride: opts.requireMention,
overrideOrder: "after-config",
});
bot.on("message", async (ctx) => {
try {
@@ -93,6 +100,17 @@ export function createTelegramBot(opts: TelegramBotOptions) {
const isGroup =
msg.chat.type === "group" || msg.chat.type === "supergroup";
if (isGroup) {
const groupPolicy = resolveGroupPolicy(chatId);
if (groupPolicy.allowlistEnabled && !groupPolicy.allowed) {
logger.info(
{ chatId, title: msg.chat.title, reason: "not-allowed" },
"skipping group message",
);
return;
}
}
const sendTyping = async () => {
try {
await bot.api.sendChatAction(chatId, "typing");
@@ -143,16 +161,17 @@ export function createTelegramBot(opts: TelegramBotOptions) {
const hasAnyMention = (msg.entities ?? msg.caption_entities ?? []).some(
(ent) => ent.type === "mention",
);
const requireMention = resolveGroupRequireMention(chatId);
const shouldBypassMention =
isGroup &&
resolveGroupRequireMention(chatId) &&
requireMention &&
!wasMentioned &&
!hasAnyMention &&
commandAuthorized &&
hasControlCommand(msg.text ?? msg.caption ?? "");
const canDetectMention =
Boolean(botUsername) || mentionRegexes.length > 0;
if (isGroup && resolveGroupRequireMention(chatId) && canDetectMention) {
if (isGroup && requireMention && canDetectMention) {
if (!wasMentioned && !shouldBypassMention) {
logger.info(
{ chatId, reason: "no-mention" },