feat: add dm allowlist match metadata logs
Co-authored-by: thewilloftheshadow <thewilloftheshadow@users.noreply.github.com>
This commit is contained in:
@@ -10,23 +10,49 @@ function normalizeMatrixUser(raw?: string | null): string {
|
|||||||
return (raw ?? "").trim().toLowerCase();
|
return (raw ?? "").trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MatrixAllowListMatch = {
|
||||||
|
allowed: boolean;
|
||||||
|
matchKey?: string;
|
||||||
|
matchSource?: "wildcard" | "id" | "prefixed-id" | "prefixed-user" | "name" | "localpart";
|
||||||
|
};
|
||||||
|
|
||||||
|
export function resolveMatrixAllowListMatch(params: {
|
||||||
|
allowList: string[];
|
||||||
|
userId?: string;
|
||||||
|
userName?: string;
|
||||||
|
}): MatrixAllowListMatch {
|
||||||
|
const allowList = params.allowList;
|
||||||
|
if (allowList.length === 0) return { allowed: false };
|
||||||
|
if (allowList.includes("*")) {
|
||||||
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
||||||
|
}
|
||||||
|
const userId = normalizeMatrixUser(params.userId);
|
||||||
|
const userName = normalizeMatrixUser(params.userName);
|
||||||
|
const localPart = userId.startsWith("@") ? (userId.slice(1).split(":")[0] ?? "") : "";
|
||||||
|
const candidates: Array<{ value?: string; source: MatrixAllowListMatch["matchSource"] }> = [
|
||||||
|
{ value: userId, source: "id" },
|
||||||
|
{ value: userId ? `matrix:${userId}` : "", source: "prefixed-id" },
|
||||||
|
{ value: userId ? `user:${userId}` : "", source: "prefixed-user" },
|
||||||
|
{ value: userName, source: "name" },
|
||||||
|
{ value: localPart, source: "localpart" },
|
||||||
|
];
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
if (!candidate.value) continue;
|
||||||
|
if (allowList.includes(candidate.value)) {
|
||||||
|
return {
|
||||||
|
allowed: true,
|
||||||
|
matchKey: candidate.value,
|
||||||
|
matchSource: candidate.source,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveMatrixAllowListMatches(params: {
|
export function resolveMatrixAllowListMatches(params: {
|
||||||
allowList: string[];
|
allowList: string[];
|
||||||
userId?: string;
|
userId?: string;
|
||||||
userName?: string;
|
userName?: string;
|
||||||
}) {
|
}) {
|
||||||
const allowList = params.allowList;
|
return resolveMatrixAllowListMatch(params).allowed;
|
||||||
if (allowList.length === 0) return false;
|
|
||||||
if (allowList.includes("*")) return true;
|
|
||||||
const userId = normalizeMatrixUser(params.userId);
|
|
||||||
const userName = normalizeMatrixUser(params.userName);
|
|
||||||
const localPart = userId.startsWith("@") ? (userId.slice(1).split(":")[0] ?? "") : "";
|
|
||||||
const candidates = [
|
|
||||||
userId,
|
|
||||||
userId ? `matrix:${userId}` : "",
|
|
||||||
userId ? `user:${userId}` : "",
|
|
||||||
userName,
|
|
||||||
localPart,
|
|
||||||
].filter(Boolean);
|
|
||||||
return candidates.some((value) => allowList.includes(value));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,11 @@ import {
|
|||||||
parsePollStartContent,
|
parsePollStartContent,
|
||||||
} from "../poll-types.js";
|
} from "../poll-types.js";
|
||||||
import { reactMatrixMessage, sendMessageMatrix, sendTypingMatrix } from "../send.js";
|
import { reactMatrixMessage, sendMessageMatrix, sendTypingMatrix } from "../send.js";
|
||||||
import { resolveMatrixAllowListMatches, normalizeAllowListLower } from "./allowlist.js";
|
import {
|
||||||
|
resolveMatrixAllowListMatch,
|
||||||
|
resolveMatrixAllowListMatches,
|
||||||
|
normalizeAllowListLower,
|
||||||
|
} from "./allowlist.js";
|
||||||
import { registerMatrixAutoJoin } from "./auto-join.js";
|
import { registerMatrixAutoJoin } from "./auto-join.js";
|
||||||
import { createDirectRoomTracker } from "./direct.js";
|
import { createDirectRoomTracker } from "./direct.js";
|
||||||
import { downloadMatrixMedia } from "./media.js";
|
import { downloadMatrixMedia } from "./media.js";
|
||||||
@@ -210,14 +214,15 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||||||
if (isDirectMessage) {
|
if (isDirectMessage) {
|
||||||
if (!dmEnabled || dmPolicy === "disabled") return;
|
if (!dmEnabled || dmPolicy === "disabled") return;
|
||||||
if (dmPolicy !== "open") {
|
if (dmPolicy !== "open") {
|
||||||
const permitted =
|
const allowMatch = resolveMatrixAllowListMatch({
|
||||||
effectiveAllowFrom.length > 0 &&
|
allowList: effectiveAllowFrom,
|
||||||
resolveMatrixAllowListMatches({
|
userId: senderId,
|
||||||
allowList: effectiveAllowFrom,
|
userName: senderName,
|
||||||
userId: senderId,
|
});
|
||||||
userName: senderName,
|
const allowMatchMeta = `matchKey=${allowMatch.matchKey ?? "none"} matchSource=${
|
||||||
});
|
allowMatch.matchSource ?? "none"
|
||||||
if (!permitted) {
|
}`;
|
||||||
|
if (!allowMatch.allowed) {
|
||||||
if (dmPolicy === "pairing") {
|
if (dmPolicy === "pairing") {
|
||||||
const { code, created } = await upsertChannelPairingRequest({
|
const { code, created } = await upsertChannelPairingRequest({
|
||||||
channel: "matrix",
|
channel: "matrix",
|
||||||
@@ -225,6 +230,9 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||||||
meta: { name: senderName },
|
meta: { name: senderName },
|
||||||
});
|
});
|
||||||
if (created) {
|
if (created) {
|
||||||
|
logVerbose(
|
||||||
|
`matrix pairing request sender=${senderId} name=${senderName ?? "unknown"} (${allowMatchMeta})`,
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
await sendMessageMatrix(
|
await sendMessageMatrix(
|
||||||
`room:${roomId}`,
|
`room:${roomId}`,
|
||||||
@@ -243,6 +251,11 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dmPolicy !== "pairing") {
|
||||||
|
logVerbose(
|
||||||
|
`matrix: blocked dm sender ${senderId} (dmPolicy=${dmPolicy}, ${allowMatchMeta})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,6 +274,9 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isRoom) {
|
||||||
|
logVerbose(`matrix: allow room ${roomId} (${roomMatchMeta})`);
|
||||||
|
}
|
||||||
|
|
||||||
const rawBody = content.body.trim();
|
const rawBody = content.body.trim();
|
||||||
let media: {
|
let media: {
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ export type DiscordAllowList = {
|
|||||||
names: Set<string>;
|
names: Set<string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DiscordAllowListMatch = {
|
||||||
|
allowed: boolean;
|
||||||
|
matchKey?: string;
|
||||||
|
matchSource?: "wildcard" | "id" | "name" | "tag";
|
||||||
|
};
|
||||||
|
|
||||||
export type DiscordGuildEntryResolved = {
|
export type DiscordGuildEntryResolved = {
|
||||||
id?: string;
|
id?: string;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
@@ -92,6 +98,28 @@ export function allowListMatches(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveDiscordAllowListMatch(params: {
|
||||||
|
allowList: DiscordAllowList;
|
||||||
|
candidate: { id?: string; name?: string; tag?: string };
|
||||||
|
}): DiscordAllowListMatch {
|
||||||
|
const { allowList, candidate } = params;
|
||||||
|
if (allowList.allowAll) {
|
||||||
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
||||||
|
}
|
||||||
|
if (candidate.id && allowList.ids.has(candidate.id)) {
|
||||||
|
return { allowed: true, matchKey: candidate.id, matchSource: "id" };
|
||||||
|
}
|
||||||
|
const nameSlug = candidate.name ? normalizeDiscordSlug(candidate.name) : "";
|
||||||
|
if (nameSlug && allowList.names.has(nameSlug)) {
|
||||||
|
return { allowed: true, matchKey: nameSlug, matchSource: "name" };
|
||||||
|
}
|
||||||
|
const tagSlug = candidate.tag ? normalizeDiscordSlug(candidate.tag) : "";
|
||||||
|
if (tagSlug && allowList.names.has(tagSlug)) {
|
||||||
|
return { allowed: true, matchKey: tagSlug, matchSource: "tag" };
|
||||||
|
}
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveDiscordUserAllowed(params: {
|
export function resolveDiscordUserAllowed(params: {
|
||||||
allowList?: Array<string | number>;
|
allowList?: Array<string | number>;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
isDiscordGroupAllowedByPolicy,
|
isDiscordGroupAllowedByPolicy,
|
||||||
normalizeDiscordAllowList,
|
normalizeDiscordAllowList,
|
||||||
normalizeDiscordSlug,
|
normalizeDiscordSlug,
|
||||||
|
resolveDiscordAllowListMatch,
|
||||||
resolveDiscordChannelConfigWithFallback,
|
resolveDiscordChannelConfigWithFallback,
|
||||||
resolveDiscordGuildEntry,
|
resolveDiscordGuildEntry,
|
||||||
resolveDiscordShouldRequireMention,
|
resolveDiscordShouldRequireMention,
|
||||||
@@ -89,13 +90,20 @@ export async function preflightDiscordMessage(
|
|||||||
const storeAllowFrom = await readChannelAllowFromStore("discord").catch(() => []);
|
const storeAllowFrom = await readChannelAllowFromStore("discord").catch(() => []);
|
||||||
const effectiveAllowFrom = [...(params.allowFrom ?? []), ...storeAllowFrom];
|
const effectiveAllowFrom = [...(params.allowFrom ?? []), ...storeAllowFrom];
|
||||||
const allowList = normalizeDiscordAllowList(effectiveAllowFrom, ["discord:", "user:"]);
|
const allowList = normalizeDiscordAllowList(effectiveAllowFrom, ["discord:", "user:"]);
|
||||||
const permitted = allowList
|
const allowMatch = allowList
|
||||||
? allowListMatches(allowList, {
|
? resolveDiscordAllowListMatch({
|
||||||
id: author.id,
|
allowList,
|
||||||
name: author.username,
|
candidate: {
|
||||||
tag: formatDiscordUserTag(author),
|
id: author.id,
|
||||||
|
name: author.username,
|
||||||
|
tag: formatDiscordUserTag(author),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
: false;
|
: { allowed: false };
|
||||||
|
const allowMatchMeta = `matchKey=${allowMatch.matchKey ?? "none"} matchSource=${
|
||||||
|
allowMatch.matchSource ?? "none"
|
||||||
|
}`;
|
||||||
|
const permitted = allowMatch.allowed;
|
||||||
if (!permitted) {
|
if (!permitted) {
|
||||||
commandAuthorized = false;
|
commandAuthorized = false;
|
||||||
if (dmPolicy === "pairing") {
|
if (dmPolicy === "pairing") {
|
||||||
@@ -109,7 +117,7 @@ export async function preflightDiscordMessage(
|
|||||||
});
|
});
|
||||||
if (created) {
|
if (created) {
|
||||||
logVerbose(
|
logVerbose(
|
||||||
`discord pairing request sender=${author.id} tag=${formatDiscordUserTag(author)}`,
|
`discord pairing request sender=${author.id} tag=${formatDiscordUserTag(author)} (${allowMatchMeta})`,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await sendMessageDiscord(
|
await sendMessageDiscord(
|
||||||
@@ -130,7 +138,9 @@ export async function preflightDiscordMessage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logVerbose(`Blocked unauthorized discord sender ${author.id} (dmPolicy=${dmPolicy})`);
|
logVerbose(
|
||||||
|
`Blocked unauthorized discord sender ${author.id} (dmPolicy=${dmPolicy}, ${allowMatchMeta})`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,22 +14,48 @@ export function normalizeAllowListLower(list?: Array<string | number>) {
|
|||||||
return normalizeAllowList(list).map((entry) => entry.toLowerCase());
|
return normalizeAllowList(list).map((entry) => entry.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function allowListMatches(params: { allowList: string[]; id?: string; name?: string }) {
|
export type SlackAllowListMatch = {
|
||||||
|
allowed: boolean;
|
||||||
|
matchKey?: string;
|
||||||
|
matchSource?: "wildcard" | "id" | "prefixed-id" | "prefixed-user" | "name" | "prefixed-name" | "slug";
|
||||||
|
};
|
||||||
|
|
||||||
|
export function resolveSlackAllowListMatch(params: {
|
||||||
|
allowList: string[];
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
}): SlackAllowListMatch {
|
||||||
const allowList = params.allowList;
|
const allowList = params.allowList;
|
||||||
if (allowList.length === 0) return false;
|
if (allowList.length === 0) return { allowed: false };
|
||||||
if (allowList.includes("*")) return true;
|
if (allowList.includes("*")) {
|
||||||
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
||||||
|
}
|
||||||
const id = params.id?.toLowerCase();
|
const id = params.id?.toLowerCase();
|
||||||
const name = params.name?.toLowerCase();
|
const name = params.name?.toLowerCase();
|
||||||
const slug = normalizeSlackSlug(name);
|
const slug = normalizeSlackSlug(name);
|
||||||
const candidates = [
|
const candidates: Array<{ value?: string; source: SlackAllowListMatch["matchSource"] }> = [
|
||||||
id,
|
{ value: id, source: "id" },
|
||||||
id ? `slack:${id}` : undefined,
|
{ value: id ? `slack:${id}` : undefined, source: "prefixed-id" },
|
||||||
id ? `user:${id}` : undefined,
|
{ value: id ? `user:${id}` : undefined, source: "prefixed-user" },
|
||||||
name,
|
{ value: name, source: "name" },
|
||||||
name ? `slack:${name}` : undefined,
|
{ value: name ? `slack:${name}` : undefined, source: "prefixed-name" },
|
||||||
slug,
|
{ value: slug, source: "slug" },
|
||||||
].filter(Boolean) as string[];
|
];
|
||||||
return candidates.some((value) => allowList.includes(value));
|
for (const candidate of candidates) {
|
||||||
|
if (!candidate.value) continue;
|
||||||
|
if (allowList.includes(candidate.value)) {
|
||||||
|
return {
|
||||||
|
allowed: true,
|
||||||
|
matchKey: candidate.value,
|
||||||
|
matchSource: candidate.source,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { allowed: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function allowListMatches(params: { allowList: string[]; id?: string; name?: string }) {
|
||||||
|
return resolveSlackAllowListMatch(params).allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveSlackUserAllowed(params: {
|
export function resolveSlackUserAllowed(params: {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { reactSlackMessage } from "../../actions.js";
|
|||||||
import { sendMessageSlack } from "../../send.js";
|
import { sendMessageSlack } from "../../send.js";
|
||||||
import type { SlackMessageEvent } from "../../types.js";
|
import type { SlackMessageEvent } from "../../types.js";
|
||||||
|
|
||||||
import { allowListMatches, resolveSlackUserAllowed } from "../allow-list.js";
|
import { resolveSlackAllowListMatch, resolveSlackUserAllowed } from "../allow-list.js";
|
||||||
import { resolveSlackEffectiveAllowFrom } from "../auth.js";
|
import { resolveSlackEffectiveAllowFrom } from "../auth.js";
|
||||||
import { resolveSlackChannelConfig } from "../channel-config.js";
|
import { resolveSlackChannelConfig } from "../channel-config.js";
|
||||||
import { normalizeSlackChannelType, type SlackMonitorContext } from "../context.js";
|
import { normalizeSlackChannelType, type SlackMonitorContext } from "../context.js";
|
||||||
@@ -121,11 +121,14 @@ export async function prepareSlackMessage(params: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (ctx.dmPolicy !== "open") {
|
if (ctx.dmPolicy !== "open") {
|
||||||
const permitted = allowListMatches({
|
const allowMatch = resolveSlackAllowListMatch({
|
||||||
allowList: allowFromLower,
|
allowList: allowFromLower,
|
||||||
id: directUserId,
|
id: directUserId,
|
||||||
});
|
});
|
||||||
if (!permitted) {
|
const allowMatchMeta = `matchKey=${allowMatch.matchKey ?? "none"} matchSource=${
|
||||||
|
allowMatch.matchSource ?? "none"
|
||||||
|
}`;
|
||||||
|
if (!allowMatch.allowed) {
|
||||||
if (ctx.dmPolicy === "pairing") {
|
if (ctx.dmPolicy === "pairing") {
|
||||||
const sender = await ctx.resolveUserName(directUserId);
|
const sender = await ctx.resolveUserName(directUserId);
|
||||||
const senderName = sender?.name ?? undefined;
|
const senderName = sender?.name ?? undefined;
|
||||||
@@ -136,7 +139,9 @@ export async function prepareSlackMessage(params: {
|
|||||||
});
|
});
|
||||||
if (created) {
|
if (created) {
|
||||||
logVerbose(
|
logVerbose(
|
||||||
`slack pairing request sender=${directUserId} name=${senderName ?? "unknown"}`,
|
`slack pairing request sender=${directUserId} name=${
|
||||||
|
senderName ?? "unknown"
|
||||||
|
} (${allowMatchMeta})`,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await sendMessageSlack(
|
await sendMessageSlack(
|
||||||
@@ -158,7 +163,7 @@ export async function prepareSlackMessage(params: {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logVerbose(
|
logVerbose(
|
||||||
`Blocked unauthorized slack sender ${message.user} (dmPolicy=${ctx.dmPolicy})`,
|
`Blocked unauthorized slack sender ${message.user} (dmPolicy=${ctx.dmPolicy}, ${allowMatchMeta})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -225,11 +230,11 @@ export async function prepareSlackMessage(params: {
|
|||||||
surface: "slack",
|
surface: "slack",
|
||||||
});
|
});
|
||||||
|
|
||||||
const ownerAuthorized = allowListMatches({
|
const ownerAuthorized = resolveSlackAllowListMatch({
|
||||||
allowList: allowFromLower,
|
allowList: allowFromLower,
|
||||||
id: senderId,
|
id: senderId,
|
||||||
name: senderName,
|
name: senderName,
|
||||||
});
|
}).allowed;
|
||||||
const channelUsersAllowlistConfigured =
|
const channelUsersAllowlistConfigured =
|
||||||
isRoom && Array.isArray(channelConfig?.users) && channelConfig.users.length > 0;
|
isRoom && Array.isArray(channelConfig?.users) && channelConfig.users.length > 0;
|
||||||
const channelCommandAuthorized =
|
const channelCommandAuthorized =
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ export type NormalizedAllowFrom = {
|
|||||||
hasEntries: boolean;
|
hasEntries: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AllowFromMatch = {
|
||||||
|
allowed: boolean;
|
||||||
|
matchKey?: string;
|
||||||
|
matchSource?: "wildcard" | "id" | "username";
|
||||||
|
};
|
||||||
|
|
||||||
export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAllowFrom => {
|
export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAllowFrom => {
|
||||||
const entries = (list ?? []).map((value) => String(value).trim()).filter(Boolean);
|
const entries = (list ?? []).map((value) => String(value).trim()).filter(Boolean);
|
||||||
const hasWildcard = entries.includes("*");
|
const hasWildcard = entries.includes("*");
|
||||||
@@ -40,3 +46,27 @@ export const isSenderAllowed = (params: {
|
|||||||
if (!username) return false;
|
if (!username) return false;
|
||||||
return allow.entriesLower.some((entry) => entry === username || entry === `@${username}`);
|
return allow.entriesLower.some((entry) => entry === username || entry === `@${username}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const resolveSenderAllowMatch = (params: {
|
||||||
|
allow: NormalizedAllowFrom;
|
||||||
|
senderId?: string;
|
||||||
|
senderUsername?: string;
|
||||||
|
}): AllowFromMatch => {
|
||||||
|
const { allow, senderId, senderUsername } = params;
|
||||||
|
if (allow.hasWildcard) {
|
||||||
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
||||||
|
}
|
||||||
|
if (!allow.hasEntries) return { allowed: false };
|
||||||
|
if (senderId && allow.entries.includes(senderId)) {
|
||||||
|
return { allowed: true, matchKey: senderId, matchSource: "id" };
|
||||||
|
}
|
||||||
|
const username = senderUsername?.toLowerCase();
|
||||||
|
if (!username) return { allowed: false };
|
||||||
|
const entry = allow.entriesLower.find(
|
||||||
|
(candidate) => candidate === username || candidate === `@${username}`,
|
||||||
|
);
|
||||||
|
if (entry) {
|
||||||
|
return { allowed: true, matchKey: entry, matchSource: "username" };
|
||||||
|
}
|
||||||
|
return { allowed: false };
|
||||||
|
};
|
||||||
|
|||||||
@@ -34,7 +34,12 @@ import {
|
|||||||
hasBotMention,
|
hasBotMention,
|
||||||
resolveTelegramForumThreadId,
|
resolveTelegramForumThreadId,
|
||||||
} from "./bot/helpers.js";
|
} from "./bot/helpers.js";
|
||||||
import { firstDefined, isSenderAllowed, normalizeAllowFrom } from "./bot-access.js";
|
import {
|
||||||
|
firstDefined,
|
||||||
|
isSenderAllowed,
|
||||||
|
normalizeAllowFrom,
|
||||||
|
resolveSenderAllowMatch,
|
||||||
|
} from "./bot-access.js";
|
||||||
import { upsertTelegramPairingRequest } from "./pairing-store.js";
|
import { upsertTelegramPairingRequest } from "./pairing-store.js";
|
||||||
import type { TelegramContext } from "./bot/types.js";
|
import type { TelegramContext } from "./bot/types.js";
|
||||||
|
|
||||||
@@ -174,14 +179,16 @@ export const buildTelegramMessageContext = async ({
|
|||||||
if (dmPolicy !== "open") {
|
if (dmPolicy !== "open") {
|
||||||
const candidate = String(chatId);
|
const candidate = String(chatId);
|
||||||
const senderUsername = msg.from?.username ?? "";
|
const senderUsername = msg.from?.username ?? "";
|
||||||
|
const allowMatch = resolveSenderAllowMatch({
|
||||||
|
allow: effectiveDmAllow,
|
||||||
|
senderId: candidate,
|
||||||
|
senderUsername,
|
||||||
|
});
|
||||||
|
const allowMatchMeta = `matchKey=${allowMatch.matchKey ?? "none"} matchSource=${
|
||||||
|
allowMatch.matchSource ?? "none"
|
||||||
|
}`;
|
||||||
const allowed =
|
const allowed =
|
||||||
effectiveDmAllow.hasWildcard ||
|
effectiveDmAllow.hasWildcard || (effectiveDmAllow.hasEntries && allowMatch.allowed);
|
||||||
(effectiveDmAllow.hasEntries &&
|
|
||||||
isSenderAllowed({
|
|
||||||
allow: effectiveDmAllow,
|
|
||||||
senderId: candidate,
|
|
||||||
senderUsername,
|
|
||||||
}));
|
|
||||||
if (!allowed) {
|
if (!allowed) {
|
||||||
if (dmPolicy === "pairing") {
|
if (dmPolicy === "pairing") {
|
||||||
try {
|
try {
|
||||||
@@ -207,6 +214,8 @@ export const buildTelegramMessageContext = async ({
|
|||||||
username: from?.username,
|
username: from?.username,
|
||||||
firstName: from?.first_name,
|
firstName: from?.first_name,
|
||||||
lastName: from?.last_name,
|
lastName: from?.last_name,
|
||||||
|
matchKey: allowMatch.matchKey ?? "none",
|
||||||
|
matchSource: allowMatch.matchSource ?? "none",
|
||||||
},
|
},
|
||||||
"telegram pairing request",
|
"telegram pairing request",
|
||||||
);
|
);
|
||||||
@@ -228,7 +237,9 @@ export const buildTelegramMessageContext = async ({
|
|||||||
logVerbose(`telegram pairing reply failed for chat ${chatId}: ${String(err)}`);
|
logVerbose(`telegram pairing reply failed for chat ${chatId}: ${String(err)}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logVerbose(`Blocked unauthorized telegram sender ${candidate} (dmPolicy=${dmPolicy})`);
|
logVerbose(
|
||||||
|
`Blocked unauthorized telegram sender ${candidate} (dmPolicy=${dmPolicy}, ${allowMatchMeta})`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user