Make bot multi-tenant with colorful welcome and per-owner isolation
The bot is now public: anyone connects it to their own Telegram Business account and gets antidelete for their own private chats. On connection (business_connection enabled) and on /start it sends a colorful welcome describing features, how to connect, and limitations. - connections.js: resolve a connection's owner from business_connection_id (memo -> DB -> getBusinessConnection). Business messages have no outgoing flag, so the owner's own messages are filtered by comparing from.id; if the owner can't be resolved the message is not cached. - Strict per-owner isolation: captures scoped by owner_id; the panel shows each user only their own feed; notifications go to the owner's chat. - db.js: multi-tenant schema (connections table; messages keyed by (conn_id, chat_id, msg_id); captures/counts scoped by owner_id). - media.js: key cached-media filenames by (connId, chatId, msgId) to prevent one tenant overwriting another's encrypted media. - panel.js: drop the owner-only barrier; /start sends welcome + own feed. - config.js: OWNER_ID is now optional (service logs only, grants no access). - Docs: README/.env.example rewritten for the multi-tenant model and the shared-key privacy caveat. - Stop tracking .claude/settings.local.json; restore the Hcrgram/ ignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,21 +4,23 @@ import { logger } from '../core/logger.js';
|
||||
/**
|
||||
* Ловит удаления. Telegram в событии deleted_business_messages присылает ТОЛЬКО
|
||||
* id сообщений и чат — без содержимого. Поэтому восстанавливаем из кэша, который
|
||||
* наполняет модуль [cache], по паре (chatId, msgId). Нашли — значит это было
|
||||
* входящее в личке: сохраняем как перехват и уведомляем владельца.
|
||||
* наполняет модуль [cache], по тройке (connId, chatId, msgId). Нашли — значит это
|
||||
* было входящее в личке: сохраняем как перехват владельца и уведомляем его.
|
||||
*/
|
||||
export default {
|
||||
name: 'antidelete',
|
||||
description: 'Сохраняет удалённые собеседником сообщения и медиа',
|
||||
|
||||
async onDeleted({ chatId, msgIds }, ctx) {
|
||||
async onDeleted({ connId, ownerId, ownerChatId, chatId, msgIds }, ctx) {
|
||||
if (!msgIds?.length) return;
|
||||
|
||||
for (const id of msgIds) {
|
||||
const cached = getCachedMessage(chatId, id);
|
||||
const cached = getCachedMessage(connId, chatId, id);
|
||||
if (!cached) continue; // не наше/не кэшировали — пропускаем
|
||||
|
||||
await ctx.capture('deleted', {
|
||||
ownerId,
|
||||
ownerChatId,
|
||||
chatId: cached.chat_id,
|
||||
senderId: cached.sender_id,
|
||||
sender: cached.sender,
|
||||
|
||||
Reference in New Issue
Block a user