Files
arestools/src/modules/antidelete.js
T
ros 0e19c84a6d 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>
2026-08-09 22:16:44 +03:00

35 lines
1.5 KiB
JavaScript

import { getCachedMessage } from '../core/db.js';
import { logger } from '../core/logger.js';
/**
* Ловит удаления. Telegram в событии deleted_business_messages присылает ТОЛЬКО
* id сообщений и чат — без содержимого. Поэтому восстанавливаем из кэша, который
* наполняет модуль [cache], по тройке (connId, chatId, msgId). Нашли — значит это
* было входящее в личке: сохраняем как перехват владельца и уведомляем его.
*/
export default {
name: 'antidelete',
description: 'Сохраняет удалённые собеседником сообщения и медиа',
async onDeleted({ connId, ownerId, ownerChatId, chatId, msgIds }, ctx) {
if (!msgIds?.length) return;
for (const id of msgIds) {
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,
text: cached.text,
mediaKind: cached.media_kind,
mediaPath: cached.media_path,
});
logger.info(`antidelete: восстановлено удалённое сообщение ${id} от ${cached.sender || '?'}`);
}
},
};