fix: honor telegram pairing allowlists for native commands
This commit is contained in:
@@ -24,6 +24,17 @@ export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAll
|
||||
};
|
||||
};
|
||||
|
||||
export const normalizeAllowFromWithStore = (params: {
|
||||
allowFrom?: Array<string | number>;
|
||||
storeAllowFrom?: string[];
|
||||
}): NormalizedAllowFrom => {
|
||||
const combined = [
|
||||
...(params.allowFrom ?? []),
|
||||
...(params.storeAllowFrom ?? []),
|
||||
].map((value) => String(value).trim()).filter(Boolean);
|
||||
return normalizeAllowFrom(combined);
|
||||
};
|
||||
|
||||
export const firstDefined = <T>(...values: Array<T | undefined>) => {
|
||||
for (const value of values) {
|
||||
if (typeof value !== "undefined") return value;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { danger, logVerbose, warn } from "../globals.js";
|
||||
import { resolveMedia } from "./bot/delivery.js";
|
||||
import { resolveTelegramForumThreadId } from "./bot/helpers.js";
|
||||
import type { TelegramMessage } from "./bot/types.js";
|
||||
import { firstDefined, isSenderAllowed, normalizeAllowFrom } from "./bot-access.js";
|
||||
import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
|
||||
import { MEDIA_GROUP_TIMEOUT_MS, type MediaGroupEntry } from "./bot-updates.js";
|
||||
import { migrateTelegramGroupConfig } from "./group-migration.js";
|
||||
import { resolveTelegramInlineButtonsScope } from "./inline-buttons.js";
|
||||
@@ -205,14 +205,14 @@ export const registerTelegramHandlers = ({
|
||||
const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
|
||||
const storeAllowFrom = await readTelegramAllowFromStore().catch(() => []);
|
||||
const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
|
||||
const effectiveGroupAllow = normalizeAllowFrom([
|
||||
...(groupAllowOverride ?? groupAllowFrom ?? []),
|
||||
...storeAllowFrom,
|
||||
]);
|
||||
const effectiveDmAllow = normalizeAllowFrom([
|
||||
...(telegramCfg.allowFrom ?? []),
|
||||
...storeAllowFrom,
|
||||
]);
|
||||
const effectiveGroupAllow = normalizeAllowFromWithStore({
|
||||
allowFrom: groupAllowOverride ?? groupAllowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const effectiveDmAllow = normalizeAllowFromWithStore({
|
||||
allowFrom: telegramCfg.allowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const dmPolicy = telegramCfg.dmPolicy ?? "pairing";
|
||||
const senderId = callback.from?.id ? String(callback.from.id) : "";
|
||||
const senderUsername = callback.from?.username ?? "";
|
||||
@@ -393,10 +393,10 @@ export const registerTelegramHandlers = ({
|
||||
const storeAllowFrom = await readTelegramAllowFromStore().catch(() => []);
|
||||
const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
|
||||
const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
|
||||
const effectiveGroupAllow = normalizeAllowFrom([
|
||||
...(groupAllowOverride ?? groupAllowFrom ?? []),
|
||||
...storeAllowFrom,
|
||||
]);
|
||||
const effectiveGroupAllow = normalizeAllowFromWithStore({
|
||||
allowFrom: groupAllowOverride ?? groupAllowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
||||
|
||||
if (isGroup) {
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
import {
|
||||
firstDefined,
|
||||
isSenderAllowed,
|
||||
normalizeAllowFrom,
|
||||
normalizeAllowFromWithStore,
|
||||
resolveSenderAllowMatch,
|
||||
} from "./bot-access.js";
|
||||
import { upsertTelegramPairingRequest } from "./pairing-store.js";
|
||||
@@ -138,12 +138,12 @@ export const buildTelegramMessageContext = async ({
|
||||
},
|
||||
});
|
||||
const mentionRegexes = buildMentionRegexes(cfg, route.agentId);
|
||||
const effectiveDmAllow = normalizeAllowFrom([...(allowFrom ?? []), ...storeAllowFrom]);
|
||||
const effectiveDmAllow = normalizeAllowFromWithStore({ allowFrom, storeAllowFrom });
|
||||
const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
|
||||
const effectiveGroupAllow = normalizeAllowFrom([
|
||||
...(groupAllowOverride ?? groupAllowFrom ?? []),
|
||||
...storeAllowFrom,
|
||||
]);
|
||||
const effectiveGroupAllow = normalizeAllowFromWithStore({
|
||||
allowFrom: groupAllowOverride ?? groupAllowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
||||
|
||||
if (isGroup && groupConfig?.enabled === false) {
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
buildTelegramGroupPeerId,
|
||||
resolveTelegramForumThreadId,
|
||||
} from "./bot/helpers.js";
|
||||
import { firstDefined, isSenderAllowed, normalizeAllowFrom } from "./bot-access.js";
|
||||
import { firstDefined, isSenderAllowed, normalizeAllowFromWithStore } from "./bot-access.js";
|
||||
import { readTelegramAllowFromStore } from "./pairing-store.js";
|
||||
|
||||
type TelegramNativeCommandContext = Context & { match?: string };
|
||||
@@ -132,10 +132,10 @@ export const registerTelegramNativeCommands = ({
|
||||
const storeAllowFrom = await readTelegramAllowFromStore().catch(() => []);
|
||||
const { groupConfig, topicConfig } = resolveTelegramGroupConfig(chatId, resolvedThreadId);
|
||||
const groupAllowOverride = firstDefined(topicConfig?.allowFrom, groupConfig?.allowFrom);
|
||||
const effectiveGroupAllow = normalizeAllowFrom([
|
||||
...(groupAllowOverride ?? groupAllowFrom ?? []),
|
||||
...storeAllowFrom,
|
||||
]);
|
||||
const effectiveGroupAllow = normalizeAllowFromWithStore({
|
||||
allowFrom: groupAllowOverride ?? groupAllowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
||||
|
||||
if (isGroup && groupConfig?.enabled === false) {
|
||||
@@ -194,12 +194,12 @@ export const registerTelegramNativeCommands = ({
|
||||
}
|
||||
}
|
||||
|
||||
const allowFromList = Array.isArray(allowFrom)
|
||||
? allowFrom.map((entry) => String(entry).trim()).filter(Boolean)
|
||||
: [];
|
||||
const senderId = msg.from?.id ? String(msg.from.id) : "";
|
||||
const senderUsername = msg.from?.username ?? "";
|
||||
const dmAllow = normalizeAllowFrom(allowFromList);
|
||||
const dmAllow = normalizeAllowFromWithStore({
|
||||
allowFrom: allowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const senderAllowed = isSenderAllowed({
|
||||
allow: dmAllow,
|
||||
senderId,
|
||||
|
||||
@@ -2138,6 +2138,49 @@ describe("createTelegramBot", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("allows native DM commands for paired users", async () => {
|
||||
onSpy.mockReset();
|
||||
sendMessageSpy.mockReset();
|
||||
commandSpy.mockReset();
|
||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
||||
replySpy.mockReset();
|
||||
replySpy.mockResolvedValue({ text: "response" });
|
||||
|
||||
loadConfig.mockReturnValue({
|
||||
commands: { native: true },
|
||||
channels: {
|
||||
telegram: {
|
||||
dmPolicy: "pairing",
|
||||
},
|
||||
},
|
||||
});
|
||||
readTelegramAllowFromStore.mockResolvedValueOnce(["12345"]);
|
||||
|
||||
createTelegramBot({ token: "tok" });
|
||||
const handler = commandSpy.mock.calls.find((call) => call[0] === "status")?.[1] as
|
||||
| ((ctx: Record<string, unknown>) => Promise<void>)
|
||||
| undefined;
|
||||
if (!handler) throw new Error("status command handler missing");
|
||||
|
||||
await handler({
|
||||
message: {
|
||||
chat: { id: 12345, type: "private" },
|
||||
from: { id: 12345, username: "testuser" },
|
||||
text: "/status",
|
||||
date: 1736380800,
|
||||
message_id: 42,
|
||||
},
|
||||
match: "",
|
||||
});
|
||||
|
||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
sendMessageSpy.mock.calls.some(
|
||||
(call) => call[1] === "You are not authorized to use this command.",
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("streams tool summaries for native slash commands", async () => {
|
||||
onSpy.mockReset();
|
||||
sendMessageSpy.mockReset();
|
||||
|
||||
Reference in New Issue
Block a user