fix: telegram allowFrom matching and entity resolution
Fixes three critical bugs in Telegram integration:
1. Case-insensitive username matching
- Telegram usernames are case-insensitive, but the API returns them with original casing
- Now lowercase all usernames when extracting sender identifier to match config entries
- Fixes: messages from @ArneMoor now match config entry telegram:@arnemoor
2. Entity resolution for sending replies
- resolveEntity() now strips telegram: prefix before resolving users/chats
- Fixes: "Could not resolve Telegram entity: telegram:@username" errors when sending replies
3. Improved skip logging
- Messages skipped due to allowFrom filtering now always logged (not just in verbose mode)
- Uses clear emoji indicator: ⏭️ Skipped message from...
This commit is contained in:
parent
7290734f2b
commit
31246f0a34
@ -60,13 +60,14 @@ export async function convertTelegramMessage(
|
||||
* Extract sender identifier with telegram: prefix to prevent session ID collisions.
|
||||
*
|
||||
* Returns:
|
||||
* - telegram:@username (if username available)
|
||||
* - telegram:@username (if username available, lowercase for case-insensitive matching)
|
||||
* - telegram:+phone (if phone available, normalized to E.164)
|
||||
* - telegram:id (numeric Telegram ID as fallback)
|
||||
*/
|
||||
function extractSenderIdentifier(sender: Api.User | Api.Chat): string {
|
||||
if ("username" in sender && sender.username) {
|
||||
return `telegram:@${sender.username}`;
|
||||
// Lowercase username for case-insensitive matching (Telegram usernames are case-insensitive)
|
||||
return `telegram:@${sender.username.toLowerCase()}`;
|
||||
}
|
||||
if ("phone" in sender && sender.phone) {
|
||||
// Ensure phone has + prefix for E.164 format to match normalized allowFrom entries
|
||||
@ -209,6 +210,10 @@ export function isAllowedSender(
|
||||
return true; // No whitelist = allow all
|
||||
}
|
||||
|
||||
if (allowFrom.includes("*")) {
|
||||
return true; // Wildcard allows all senders
|
||||
}
|
||||
|
||||
const normalizedFrom = normalizeAllowFromEntry(message.from, "telegram");
|
||||
const normalizedAllowList = allowFrom.map((e) =>
|
||||
normalizeAllowFromEntry(e, "telegram"),
|
||||
|
||||
@ -170,11 +170,10 @@ async function handleInboundMessage(
|
||||
normalizeAllowFromEntry(e, "telegram"),
|
||||
);
|
||||
if (!normalizedAllowList.includes(normalizedFrom)) {
|
||||
if (isVerbose()) {
|
||||
logVerbose(
|
||||
`Skipping auto-reply: sender ${message.from} not in allowFrom list`,
|
||||
);
|
||||
}
|
||||
// Always log skipped messages (not just in verbose mode)
|
||||
runtime.log(
|
||||
`⏭️ Skipped message from ${message.from} (not in allowFrom list)`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,13 +6,17 @@ type Entity = Api.User | Api.Chat | Api.Channel;
|
||||
/**
|
||||
* Resolve Telegram entity (user/chat) from identifier.
|
||||
* Supports @username, phone number, or user ID.
|
||||
* Also handles telegram: prefix (e.g., telegram:@username).
|
||||
*/
|
||||
export async function resolveEntity(
|
||||
client: TelegramClient,
|
||||
identifier: string,
|
||||
): Promise<Entity> {
|
||||
// Clean identifier
|
||||
const clean = identifier.trim();
|
||||
// Clean identifier and strip telegram: prefix if present
|
||||
let clean = identifier.trim();
|
||||
if (clean.startsWith("telegram:")) {
|
||||
clean = clean.slice("telegram:".length);
|
||||
}
|
||||
|
||||
// Try as-is first (handles @username, phone, user ID)
|
||||
try {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user