refactor: share missing-sender matched allowlist evaluation

This commit is contained in:
Peter Steinberger
2026-03-07 23:54:46 +00:00
parent 2b54070526
commit 566a821e5d
6 changed files with 113 additions and 33 deletions

View File

@@ -180,6 +180,25 @@ describe("evaluateTelegramGroupPolicyAccess chat allowlist vs sender allowli
expect(result).toEqual({ allowed: true, groupPolicy: "allowlist" });
});
it("blocks allowlist groups without sender identity before sender matching", () => {
const result = runAccess({
senderId: undefined,
senderUsername: undefined,
effectiveGroupAllow: senderAllow,
resolveGroupPolicy: () => ({
allowlistEnabled: true,
allowed: true,
groupConfig: { requireMention: false },
}),
});
expect(result).toEqual({
allowed: false,
reason: "group-policy-allowlist-no-sender",
groupPolicy: "allowlist",
});
});
it("allows authorized sender in wildcard-matched group with sender entries", () => {
const result = runAccess({
effectiveGroupAllow: senderAllow, // entries: ["111"]

View File

@@ -7,6 +7,7 @@ import type {
TelegramGroupConfig,
TelegramTopicConfig,
} from "../config/types.js";
import { evaluateMatchedGroupAccessForPolicy } from "../plugin-sdk/group-access.js";
import { isSenderAllowed, type NormalizedAllowFrom } from "./bot-access.js";
import { firstDefined } from "./bot-access.js";
@@ -174,31 +175,29 @@ export const evaluateTelegramGroupPolicyAccess = (params: {
}
if (groupPolicy === "allowlist" && params.enforceAllowlistAuthorization) {
const senderId = params.senderId ?? "";
if (params.requireSenderForAllowlistAuthorization && !senderId) {
const senderAuthorization = evaluateMatchedGroupAccessForPolicy({
groupPolicy,
requireMatchInput: params.requireSenderForAllowlistAuthorization,
hasMatchInput: Boolean(senderId),
allowlistConfigured:
chatExplicitlyAllowed ||
params.allowEmptyAllowlistEntries ||
params.effectiveGroupAllow.hasEntries,
allowlistMatched:
(chatExplicitlyAllowed && !params.effectiveGroupAllow.hasEntries) ||
isSenderAllowed({
allow: params.effectiveGroupAllow,
senderId,
senderUsername: params.senderUsername ?? "",
}),
});
if (!senderAuthorization.allowed && senderAuthorization.reason === "missing_match_input") {
return { allowed: false, reason: "group-policy-allowlist-no-sender", groupPolicy };
}
// Skip the "empty allowlist" guard when the chat itself is explicitly
// listed in the groups config — the group ID acts as the allowlist entry.
if (
!chatExplicitlyAllowed &&
!params.allowEmptyAllowlistEntries &&
!params.effectiveGroupAllow.hasEntries
) {
if (!senderAuthorization.allowed && senderAuthorization.reason === "empty_allowlist") {
return { allowed: false, reason: "group-policy-allowlist-empty", groupPolicy };
}
// When the chat is explicitly allowed and there are no sender-level entries,
// skip the sender check — the group ID itself is the authorization.
if (chatExplicitlyAllowed && !params.effectiveGroupAllow.hasEntries) {
return { allowed: true, groupPolicy };
}
const senderUsername = params.senderUsername ?? "";
if (
!isSenderAllowed({
allow: params.effectiveGroupAllow,
senderId,
senderUsername,
})
) {
if (!senderAuthorization.allowed && senderAuthorization.reason === "not_allowlisted") {
return { allowed: false, reason: "group-policy-allowlist-unauthorized", groupPolicy };
}
}