# telegrambusiness Личный Telegram-бот на Node.js, работающий через **официальное бизнес-подключение** Telegram (Business API). Бот подключается к вашему аккаунту как чат-бот для бизнеса и сохраняет то, что собеседник удалил: - **antidelete** — сообщения (и медиа), которые собеседник удалил в личке. Всё управление и все перехваты приходят в этого же бота — в личку владельца. Наружу бот ничего не пишет, слеш-команд в чатах нет. > ✅ **Без сессии, по правилам Telegram.** Проект **не хранит строку сессии** и не использует MTProto-юзербот. Работает исключительно через штатную функцию «Telegram для бизнеса» — обычный бот от [@BotFather](https://t.me/BotFather) с включённым Business Mode. Это соответствует ToS. > ⚠️ **Дисклеймер.** Инструмент для личного использования на **своём** аккаунте и своей переписке. Не применяйте против других людей. ## Как устроено (важно понимать до запуска) Telegram в бизнес-событии удаления (`deleted_business_messages`) присылает **только id сообщений** — без текста и без медиа. Поэтому «сохранить удалённое» реактивно невозможно: бот **заранее кэширует каждое входящее** в личке, а при удалении достаёт его из своего кэша. То же с медиа — файл качается **в момент прихода**, после удаления ссылка мертва. Отсюда следствия: - тексты и метаданные пишутся в локальную БД (`node:sqlite`), **зашифрованы** (AES-256-GCM); - медиа лежат отдельными **зашифрованными** файлами в `data/media/`; - всё чистится по `RETENTION_DAYS`. ### Чего этот подход НЕ умеет - **Одноразовые медиа** («просмотр один раз», самоуничтожающиеся) перехватить **невозможно**: сервер Bot API отбрасывает такие сообщения ещё до доставки боту. Это ограничение платформы, обойти его без юзербота нельзя — а от юзербота мы отказались сознательно. - **Медиа больше ~20 МБ** не скачиваются: у Bot API (`getFile`) лимит на размер файла. Такое медиа сохранится только как пометка о типе. ## Установка Нужен Node.js ≥ 22.5 (для встроенного `node:sqlite`). ```bash npm install cp .env.example .env ``` Заполните `.env`: 1. **BOT_TOKEN** — новый бот у [@BotFather](https://t.me/BotFather). 2. **OWNER_ID** — ваш id (напишите [@userinfobot](https://t.me/userinfobot)). 3. **ENCRYPTION_KEY** — сгенерируйте: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`. Включите боту режим бизнеса и подключите его к аккаунту: 1. [@BotFather](https://t.me/BotFather) → `/mybots` → выберите бота → **Bot Settings** → **Business Mode** → **Enable**. 2. В приложении Telegram: **Настройки → Telegram для бизнеса → Чат-боты** → добавьте своего бота. Дайте ему право читать/управлять сообщениями. Запуск: ```bash npm run dev ``` Откройте своего бота, нажмите **Start** — появится панель. Когда собеседник удалит сообщение, бот пришлёт уведомление с кнопкой «Открыть». `npm run dev` — с автоперезапуском, `npm start` — обычный запуск. ## Как добавить модуль Модуль — файл в `src/modules/`. Загрузчик обходит папку рекурсивно; файлы на `_` игнорируются. Объявляйте только нужные хуки: ```js // src/modules/keywords.js export default { name: 'keywords', description: 'Уведомлять, если во входящем есть ключевое слово', async onMessage(msg, ctx) { if (!msg.isPrivateIncoming) return; if (/срочно/i.test(msg.text ?? '')) { await ctx.capture('deleted', { // переиспользуем ленту перехватов chatId: msg.chatId, senderId: msg.senderId, sender: msg.sender, text: msg.text, }); } }, }; ``` Хук получает **нормализованное** сообщение: `{ chatId, msgId, senderId, sender, text, media, isPrivateIncoming }`. | Хук | Когда вызывается | | --- | --- | | `setup(_, ctx)` | Один раз при старте | | `onMessage(msg, ctx)` | Новое бизнес-сообщение (`business_message`) | | `onEdited(msg, ctx)` | Правка (`edited_business_message`) | | `onDeleted(event, ctx)` | Удаление; `event.chatId`, `event.msgIds` | `ctx` даёт: `api` (grammY `bot.api`), `registry` и `capture(kind, data)` — сохранить перехват и уведомить владельца. Ошибка в одном модуле не роняет остальные ([registry.js](src/core/registry.js) — `runHook`). ## Устройство ``` src/ index.js сборка: бот + модули + чистка config.js .env, проверка на старте core/ crypto.js AES-256-GCM (шифр текста и медиа) db.js node:sqlite: кэш входящих + лента перехватов media.js тип медиа, скачать через getFile + шифровать loader.js обход src/modules registry.js реестр модулей, runHook logger.js business/ events.js подписка business_message/edited/deleted → модули context.js ctx.capture — мост модуль↔БД↔бот modules/ cache.js кэширует входящие (основа antidelete) antidelete.js удаление → достать из кэша → перехват bot/ panel.js бот: инлайн-панель, лента, выдача медиа ``` Поток: входящее (`business_message`) → `cache` кэширует текст и качает медиа → при удалении (`deleted_business_messages`) `antidelete` поднимает из кэша → `ctx.capture` пишет в БД и шлёт уведомление → панель показывает и отдаёт расшифрованный файл. ## Что стоит учесть - Перехватываются только **входящие в личных диалогах**. Свои сообщения — нет (см. `isPrivateIncoming` в [events.js](src/business/events.js)). - Id сообщения в Bot API уникален **только внутри чата**, поэтому в БД составной ключ `(chat_id, msg_id)`. - Если вы отключите бизнес-подключение в настройках Telegram, перехват приостановится (бот залогирует это по апдейту `business_connection`). - `CACHE_MEDIA=1` качает медиа каждого входящего, чтобы восстанавливать удалённые картинки. Это ест диск — при `=0` останется только текст и пометка о типе медиа. - Ключ шифрования — в `.env`. Потеряете ключ — расшифровать хранилище нельзя. - Хранилище локальное; `data/` в `.gitignore`.