import { fileURLToPath } from 'node:url'; const req = (name) => { const value = process.env[name]; if (!value) throw new Error(`${name} не задан в .env (см. .env.example).`); return value; }; const num = (name) => { const value = Number(process.env[name]); if (!Number.isInteger(value)) throw new Error(`${name} должен быть целым числом.`); return value; }; /** * Конфиг бота. Работает через официальное бизнес-подключение Telegram — * никакой строки сессии, только токен бота от @BotFather. Всё чувствительное * (токен, ключ шифрования) живёт только в .env и никуда не уходит. * * Мультитенант: любой может подключить бота к своему бизнес-аккаунту. Доступ * к перехватам изолирован по владельцу (см. db.js), поэтому OWNER_ID больше * ничего не открывает и не обязателен. */ export const config = { // Бот (@BotFather, Business Mode). К нему пользователи подключают свои // бизнес-аккаунты (Настройки → Telegram для бизнеса → Чат-боты). botToken: () => req('BOT_TOKEN'), // Необязательный id «оператора» бота — только для служебных логов, доступ // к чужим данным он НЕ даёт (строгая изоляция). null, если не задан. ownerId: () => (process.env.OWNER_ID ? num('OWNER_ID') : null), // Ключ шифрования локального хранилища (32+ байта, hex или ascii). encryptionKey: () => req('ENCRYPTION_KEY'), // Сколько дней держать перехваченное, прежде чем чистить (0 — бессрочно). retentionDays: Number(process.env.RETENTION_DAYS ?? 30), // Качать ли медиа входящих сразу (нужно, чтобы восстанавливать удалённые // картинки/видео — при удалении file_id уже не приходит). Ест диск. cacheMedia: process.env.CACHE_MEDIA !== '0', dataDir: new URL('../data/', import.meta.url), mediaDir: new URL('../data/media/', import.meta.url), logLevel: process.env.LOG_LEVEL ?? 'info', }; export const dataPath = () => fileURLToPath(config.dataDir); export const mediaPath = () => fileURLToPath(config.mediaDir); /** Проверяем всё, что нужно для старта, одним махом — понятная ошибка вместо падения в рантайме. */ export function assertConfig() { config.botToken(); const key = config.encryptionKey(); if (Buffer.from(key, key.match(/^[0-9a-f]+$/i) ? 'hex' : 'utf8').length < 32) { throw new Error('ENCRYPTION_KEY должен быть не короче 32 байт (64 hex-символа).'); } }