


























@@ -61,7 +61,6 @@ import {
6161} from "./bot-handlers.debounce-key.js";
6262import {
6363hasInboundMedia,
64-hasReplyTargetMedia,
6564isMediaSizeLimitError,
6665isRecoverableMediaGroupError,
6766resolveInboundMediaFileId,
@@ -103,7 +102,7 @@ import {
103102resolveTelegramConversationBaseSessionKey,
104103resolveTelegramConversationRoute,
105104} from "./conversation-route.js";
106-import { enforceTelegramDmAccess } from "./dm-access.js";
105+import { enforceTelegramDmAccess, isTelegramDmAccessAllowed } from "./dm-access.js";
107106import { resolveTelegramExecApproval } from "./exec-approval-resolver.js";
108107import {
109108isTelegramExecApprovalApprover,
@@ -2744,13 +2743,127 @@ export const registerTelegramHandlers = ({
27442743} as Message;
27452744};
274627452747-const recordEditedMessageForReplyChain = async (
2748-ctxForDedupe: TelegramUpdateKeyContext,
2749-msg: Message,
2750-) => {
2751-if (shouldSkipUpdate(ctxForDedupe)) {
2746+type TelegramInboundGate =
2747+| { allowed: false }
2748+| {
2749+allowed: true;
2750+context: TelegramEventAuthorizationContext;
2751+effectiveDmAllow: NormalizedAllowFrom;
2752+};
2753+2754+// Single authorization gate for every message-like update that can reach the
2755+// reply-chain cache or dispatch: fresh messages, edits, channel posts. Must run
2756+// before any cache/dedupe side effect so blocked content is never recorded.
2757+// dmAccess "challenge" may send a pairing reply; "silent" only decides (edits
2758+// must never reply).
2759+const authorizeInboundMessage = async (params: {
2760+msg: Message;
2761+chatId: number;
2762+isGroup: boolean;
2763+isForum: boolean;
2764+messageThreadId?: number;
2765+senderId: string;
2766+senderUsername: string;
2767+requireConfiguredGroup: boolean;
2768+dmAccess: "challenge" | "silent";
2769+}): Promise<TelegramInboundGate> => {
2770+const context = await resolveTelegramEventAuthorizationContext({
2771+chatId: params.chatId,
2772+isGroup: params.isGroup,
2773+isForum: params.isForum,
2774+senderId: params.senderId,
2775+messageThreadId: params.messageThreadId,
2776+});
2777+const {
2778+ dmPolicy,
2779+ resolvedThreadId,
2780+ dmThreadId,
2781+ storeAllowFrom,
2782+ groupConfig,
2783+ topicConfig,
2784+ groupAllowOverride,
2785+ effectiveGroupAllow,
2786+ hasGroupAllowOverride,
2787+} = context;
2788+// For DMs, prefer per-DM/topic allowFrom (groupAllowOverride) over account-level allowFrom
2789+const expandedDmAllowFrom = await expandTelegramAllowFromWithAccessGroups({
2790+ cfg,
2791+allowFrom: groupAllowOverride ?? allowFrom,
2792+ accountId,
2793+senderId: params.senderId,
2794+});
2795+const effectiveDmAllow = normalizeDmAllowFromWithStore({
2796+allowFrom: expandedDmAllowFrom,
2797+ storeAllowFrom,
2798+ dmPolicy,
2799+});
2800+2801+if (params.requireConfiguredGroup && (!groupConfig || groupConfig.enabled === false)) {
2802+logVerbose(`Blocked telegram channel ${params.chatId} (channel disabled)`);
2803+return { allowed: false };
2804+}
2805+2806+if (
2807+shouldSkipGroupMessage({
2808+isGroup: params.isGroup,
2809+chatId: params.chatId,
2810+chatTitle: params.msg.chat.title,
2811+ resolvedThreadId,
2812+senderId: params.senderId,
2813+senderUsername: params.senderUsername,
2814+ effectiveGroupAllow,
2815+ hasGroupAllowOverride,
2816+ groupConfig,
2817+ topicConfig,
2818+})
2819+) {
2820+return { allowed: false };
2821+}
2822+2823+if (!params.isGroup) {
2824+const requireTopic =
2825+groupConfig && "requireTopic" in groupConfig ? groupConfig.requireTopic : undefined;
2826+if (requireTopic === true && dmThreadId == null) {
2827+logVerbose(`Blocked telegram DM ${params.chatId}: requireTopic=true but no topic present`);
2828+return { allowed: false };
2829+}
2830+const dmAuthorized =
2831+params.dmAccess === "challenge"
2832+ ? await enforceTelegramDmAccess({
2833+isGroup: params.isGroup,
2834+ dmPolicy,
2835+msg: params.msg,
2836+chatId: params.chatId,
2837+ effectiveDmAllow,
2838+ accountId,
2839+ bot,
2840+ logger,
2841+upsertPairingRequest: telegramDeps.upsertChannelPairingRequest,
2842+})
2843+ : await isTelegramDmAccessAllowed({
2844+ dmPolicy,
2845+msg: params.msg,
2846+chatId: params.chatId,
2847+ effectiveDmAllow,
2848+ accountId,
2849+});
2850+if (!dmAuthorized) {
2851+return { allowed: false };
2852+}
2853+}
2854+2855+return { allowed: true, context, effectiveDmAllow };
2856+};
2857+2858+const recordEditedMessageForReplyChain = async (params: {
2859+ctxForDedupe: TelegramUpdateKeyContext;
2860+msg: Message;
2861+requireConfiguredGroup: boolean;
2862+}) => {
2863+if (shouldSkipUpdate(params.ctxForDedupe)) {
27522864return;
27532865}
2866+const msg = params.msg;
27542867const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
27552868const isForum = await resolveTelegramForumFlag({
27562869chatId: msg.chat.id,
@@ -2761,11 +2874,21 @@ export const registerTelegramHandlers = ({
27612874 getChat,
27622875});
27632876const normalizedMsg = withResolvedTelegramForumFlag(msg, isForum);
2764-const resolvedThreadId = resolveTelegramForumThreadId({
2877+const gate = await authorizeInboundMessage({
2878+msg: normalizedMsg,
2879+chatId: normalizedMsg.chat.id,
2880+ isGroup,
27652881 isForum,
27662882messageThreadId: normalizedMsg.message_thread_id,
2883+senderId: normalizedMsg.from?.id != null ? String(normalizedMsg.from.id) : "",
2884+senderUsername: normalizedMsg.from?.username ?? "",
2885+requireConfiguredGroup: params.requireConfiguredGroup,
2886+dmAccess: "silent",
27672887});
2768-const dmThreadId = !isGroup ? normalizedMsg.message_thread_id : undefined;
2888+if (!gate.allowed) {
2889+return;
2890+}
2891+const { resolvedThreadId, dmThreadId } = gate.context;
27692892await recordMessageForReplyChain(normalizedMsg, resolvedThreadId ?? dmThreadId);
27702893};
27712894@@ -2775,76 +2898,30 @@ export const registerTelegramHandlers = ({
27752898if (shouldSkipUpdate(event.ctxForDedupe)) {
27762899return;
27772900}
2778-const eventAuthContext = await resolveTelegramEventAuthorizationContext({
2901+const gate = await authorizeInboundMessage({
2902+msg: event.msg,
27792903chatId: event.chatId,
27802904isGroup: event.isGroup,
27812905isForum: event.isForum,
2782-senderId: event.senderId,
27832906messageThreadId: event.messageThreadId,
2907+senderId: event.senderId,
2908+senderUsername: event.senderUsername,
2909+requireConfiguredGroup: event.requireConfiguredGroup,
2910+dmAccess: "challenge",
27842911});
2912+if (!gate.allowed) {
2913+return;
2914+}
2915+const { effectiveDmAllow } = gate;
27852916const {
27862917 dmPolicy,
27872918 resolvedThreadId,
27882919 dmThreadId,
27892920 storeAllowFrom,
27902921 groupConfig,
27912922 topicConfig,
2792- groupAllowOverride,
27932923 effectiveGroupAllow,
2794- hasGroupAllowOverride,
2795-} = eventAuthContext;
2796-// For DMs, prefer per-DM/topic allowFrom (groupAllowOverride) over account-level allowFrom
2797-const dmAllowFrom = groupAllowOverride ?? allowFrom;
2798-const expandedDmAllowFrom = await expandTelegramAllowFromWithAccessGroups({
2799- cfg,
2800-allowFrom: dmAllowFrom,
2801- accountId,
2802-senderId: event.senderId,
2803-});
2804-const effectiveDmAllow = normalizeDmAllowFromWithStore({
2805-allowFrom: expandedDmAllowFrom,
2806- storeAllowFrom,
2807- dmPolicy,
2808-});
2809-2810-if (event.requireConfiguredGroup && (!groupConfig || groupConfig.enabled === false)) {
2811-logVerbose(`Blocked telegram channel ${event.chatId} (channel disabled)`);
2812-return;
2813-}
2814-2815-if (
2816-shouldSkipGroupMessage({
2817-isGroup: event.isGroup,
2818-chatId: event.chatId,
2819-chatTitle: event.msg.chat.title,
2820- resolvedThreadId,
2821-senderId: event.senderId,
2822-senderUsername: event.senderUsername,
2823- effectiveGroupAllow,
2824- hasGroupAllowOverride,
2825- groupConfig,
2826- topicConfig,
2827-})
2828-) {
2829-return;
2830-}
2831-2832-if (!event.isGroup && (hasInboundMedia(event.msg) || hasReplyTargetMedia(event.msg))) {
2833-const dmAuthorized = await enforceTelegramDmAccess({
2834-isGroup: event.isGroup,
2835- dmPolicy,
2836-msg: event.msg,
2837-chatId: event.chatId,
2838- effectiveDmAllow,
2839- accountId,
2840- bot,
2841- logger,
2842-upsertPairingRequest: telegramDeps.upsertChannelPairingRequest,
2843-});
2844-if (!dmAuthorized) {
2845-return;
2846-}
2847-}
2924+} = gate.context;
2848292528492926const promptContextMinTimestampMs = normalizePromptContextMinTimestampMs(
28502927resolveTelegramSessionState({
@@ -2950,7 +3027,11 @@ export const registerTelegramHandlers = ({
29503027if (!msg) {
29513028return;
29523029}
2953-await recordEditedMessageForReplyChain(ctx, msg);
3030+await recordEditedMessageForReplyChain({
3031+ctxForDedupe: ctx,
3032+ msg,
3033+requireConfiguredGroup: false,
3034+});
29543035});
2955303629563037// Handle channel posts — enables bot-to-bot communication via Telegram channels.
@@ -2991,6 +3072,10 @@ export const registerTelegramHandlers = ({
29913072if (!post) {
29923073return;
29933074}
2994-await recordEditedMessageForReplyChain(ctx, normalizeChannelPostMessage(post));
3075+await recordEditedMessageForReplyChain({
3076+ctxForDedupe: ctx,
3077+msg: normalizeChannelPostMessage(post),
3078+requireConfiguredGroup: true,
3079+});
29953080});
29963081};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。