Files
arestools/README.md
T
ros 8bd13b4dd5 Перевести проект на Telegram Business (без хранения сессии)
Смена архитектуры с MTProto-юзербота (GramJS + строка сессии) на
официальное бизнес-подключение Telegram (Bot API). Проект больше НЕ
хранит сессию — работает только через бота с включённым Business Mode,
подключённого в Настройках → Telegram для бизнеса → Чат-боты. Это
соответствует ToS.

Изменения:
- удалено: scripts/login.js, src/userbot/client.js, модуль onetime
- src/userbot/ → src/business/: events.js подписывает business_message /
  edited / deleted / connection и нормализует сообщение; context.js даёт
  ctx.api = bot.api
- core/media.js: скачивание через getFile + fetch вместо GramJS
- core/db.js: составной ключ PRIMARY KEY (chat_id, msg_id) — в Bot API
  message_id уникален только внутри чата
- bot/panel.js: барьер владельца пропускает бизнес-апдейты (у них ctx.from
  это собеседник); убран UI одноразовых
- index.js: сборка только на grammY, явный allowed_updates с бизнес-типами
- config.js: убраны API_ID/API_HASH/SESSION, проверки на старте почищены
- package.json: убраны зависимости telegram и input, скрипт login
- README и .env.example переписаны под бизнес-подключение

Границы: onetime невозможен через Business API (сервер отбрасывает
self-destruct до доставки боту), медиа >~20 МБ не выгружаются (лимит
getFile), перехват — только личные 1-на-1 чаты.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 21:00:22 +03:00

8.5 KiB
Raw Blame History

telegrambusiness

Личный Telegram-бот на Node.js, работающий через официальное бизнес-подключение Telegram (Business API). Бот подключается к вашему аккаунту как чат-бот для бизнеса и сохраняет то, что собеседник удалил:

  • antidelete — сообщения (и медиа), которые собеседник удалил в личке.

Всё управление и все перехваты приходят в этого же бота — в личку владельца. Наружу бот ничего не пишет, слеш-команд в чатах нет.

Без сессии, по правилам Telegram. Проект не хранит строку сессии и не использует MTProto-юзербот. Работает исключительно через штатную функцию «Telegram для бизнеса» — обычный бот от @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).

npm install
cp .env.example .env

Заполните .env:

  1. BOT_TOKEN — новый бот у @BotFather.
  2. OWNER_ID — ваш id (напишите @userinfobot).
  3. ENCRYPTION_KEY — сгенерируйте: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))".

Включите боту режим бизнеса и подключите его к аккаунту:

  1. @BotFather/mybots → выберите бота → Bot SettingsBusiness ModeEnable.
  2. В приложении Telegram: Настройки → Telegram для бизнеса → Чат-боты → добавьте своего бота. Дайте ему право читать/управлять сообщениями.

Запуск:

npm run dev

Откройте своего бота, нажмите Start — появится панель. Когда собеседник удалит сообщение, бот пришлёт уведомление с кнопкой «Открыть».

npm run dev — с автоперезапуском, npm start — обычный запуск.

Как добавить модуль

Модуль — файл в src/modules/. Загрузчик обходит папку рекурсивно; файлы на _ игнорируются. Объявляйте только нужные хуки:

// 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.jsrunHook).

Устройство

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).
  • Id сообщения в Bot API уникален только внутри чата, поэтому в БД составной ключ (chat_id, msg_id).
  • Если вы отключите бизнес-подключение в настройках Telegram, перехват приостановится (бот залогирует это по апдейту business_connection).
  • CACHE_MEDIA=1 качает медиа каждого входящего, чтобы восстанавливать удалённые картинки. Это ест диск — при =0 останется только текст и пометка о типе медиа.
  • Ключ шифрования — в .env. Потеряете ключ — расшифровать хранилище нельзя.
  • Хранилище локальное; data/ в .gitignore.