umbot
    Preparing search index...

    Конфигурация и безопасность

    Для безопасного хранения токенов и других чувствительных данных, вы можете использовать два подхода:

    bot.setAppConfig({ env: './.env' });
    

    Пример файла .env:

    # Токены платформ
    TELEGRAM_TOKEN=123456:ABC-DEF...
    VK_TOKEN=vk1.a.abc123...
    VK_CONFIRMATION_TOKEN=abcdef       # обязательно для VK (для подтверждения вебхука)
    VK_SECRET_KEY=abc123...              # опционально: секретный ключ VK для проверки подлинности запросов
    VIBER_TOKEN=1234567890-ABCDEF...
    ALISA_TOKEN=y0_AgAAAAA...          # OAuth-токен навыка (для аплоада медиа), без префикса "OAuth "
    MARUSIA_TOKEN=abc.123...
    MAX_TOKEN=abc123...
    SMARTAPP_TOKEN=...                  # токен Сбер SmartApp (генерируется CLI; для работы адаптера не обязателен)
    
    # Секреты вебхука (см. раздел «Проверка подписи вебхука» ниже).
    # ВАЖНО: фреймворк не читает их из env автоматически — передайте в setAppConfig
    # вручную: tokens.telegram.webhookSecret / tokens.max_app.webhookSecret.
    TELEGRAM_WEBHOOK_SECRET=...
    MAX_WEBHOOK_SECRET=...
    
    # Yandex SpeechKit — для TTS на чат-ботах (Telegram/VK/Max).
    # Значение автоматически записывается в speech_kit_token всех трёх платформ.
    # Рекомендуется API-ключ сервисного аккаунта (уходит как `Api-Key`); IAM-токен `t1.…`
    # тоже принимается (уходит как `Bearer`), но живёт не больше 12 часов.
    SPEECH_KIT_TOKEN=AQVN...
    
    # Подключение к MongoDB (если используете MongoAdapter)
    DB_HOST=mongodb://localhost:27017
    DB_USER=root
    DB_PASSWORD=secret
    DB_NAME=umbot
    

    Важно! Никогда не добавляйте .env файлы в репозиторий Git. Используйте разные токены для разработки и продакшена. Значение ALISA_TOKEN указывайте без префикса OAuth — фреймворк добавит его сам. Устаревшее имя YANDEX_TOKEN поддерживается для обратной совместимости, но приоритет у ALISA_TOKEN.

    Что будет, если файл не найден? Фреймворк попробует получить токены из process.env. Если и там их нет — в лог-файле будет выведено сообщение об ошибке. Адаптер при этом остаётся зарегистрированным, но операции, требующие токена (отправка сообщений, загрузка медиа), работать не будут.

    Переменные окружения без env. Если env не настроен вовсе, фреймворк всё равно тихо попробует прочитать известные переменные (TELEGRAM_TOKEN, VK_TOKEN, ...) из process.env и дозаполнить ими токены — это позволяет передавать токены через docker run -e или окружение serverless-функции без env: 'local'. Уже заданные токены при этом не перезаписываются.

    bot.setAppConfig({
    db: {
    host: 'mongodb://localhost:27017',
    user: 'bot_user',
    pass: 'secure_password',
    database: 'bot_database',
    },
    tokens: {
    telegram: {
    token: 'your-telegram-token',
    },
    vk: {
    token: 'your-vk-token',
    },
    },
    });

    Механика такая: токен конструктора адаптера (new TelegramAdapter('token')) записывается в конфиг при вызове bot.use()init() адаптера). Дальше решает env:

    1. Явно настроенный env (файл или 'local') — setAppConfig({ env }) и каждый последующий setPlatformParams вызывают перезапись токенов из env: значения из .env/process.env перезапишут и токен конструктора, и inline-tokens (не важно, вызван ли setAppConfig до или после bot.use()).
    2. Аргумент конструктора адаптера — побеждает, если env не настроен вовсе: тогда setPlatformParams лишь дозаполняет отсутствующие токены из process.env, не перезаписывая заданные.
    3. Inline-объект tokens в setAppConfig — сливается с существующими токенами платформы.
    4. process.env без настроенного env — только дозаполняет отсутствующие токены, ничего не перезаписывая.

    Практический совет: не смешивайте способы для одной платформы. Либо передавайте токен в конструкторе адаптера и не настраивайте env, либо используйте .env/process.env и создавайте адаптеры без токена.

    Сценарий Рекомендация
    Разработка, прототип env: '.env' — просто и безопасно
    Production на сервере env: 'local' + переменные окружения на сервере
    Тесты Прямая передача в config.tokens или в конструкторе адаптера
    Несколько сред (dev/prod) .env файлы с разными токенами, передавайте через env

    Метод setAppConfig принимает объект Partial<IAppConfig>:

    Поле Тип Описание
    error_log string Путь к папке для логов ошибок (error.log, warn.log)
    json string Путь к папке для JSON-данных (используется FileAdapter)
    db IAppDB Параметры подключения к БД
    isLocalStorage boolean Использовать локальное хранилище платформы вместо БД
    memorySession IMemorySessionConfig | false Сессия userData в памяти процесса для Telegram/VK/MAX/Viber без БД при isLocalStorage: true. По умолчанию { maxSize: 10000, ttl: 86400000 }; false — выключить
    env string Путь к .env файлу ИЛИ строка 'local' для process.env
    tokens ITokenPlatform Токены платформ (для адаптеров, если не переданы через конструктор)
    bot.setAppConfig({
    json: './data', // папка для JSON-файлов (FileAdapter)
    error_log: './errors', // папка для логов
    isLocalStorage: true, // локальное хранилище (для голосовых платформ)
    env: '.env', // путь к файлу с токенами
    db: {
    // подключение к MongoDB (если не isLocalStorage)
    host: 'mongodb://localhost:27017',
    database: 'umbot',
    },
    });

    На Telegram/VK/MAX/Viber локального хранилища нет: при isLocalStorage: true без DB-адаптера userData хранится в памяти процесса (memorySession). Данные теряются при перезапуске и не разделяются между процессами, репликами и вызовами serverless-функции — для продакшена с шагами диалога подключите БД.


    Метод setPlatformParams принимает объект IAppParam:

    Поле Тип Описание
    intents IAppIntent[] | null Обязательное. Список интентов для распознавания команд
    welcome_text string | string[] Текст приветствия (при messageId === 0)
    help_text string | string[] Текст помощи (при команде "помощь")
    empty_text string | string[] Текст при отсутствии подходящих команд
    isAuthUser boolean Требуется ли авторизация пользователя
    utm_text string | null UTM-метки для ссылок (при null к кнопкам-ссылкам без UTM автоматически добавляется utm_source=umbot&utm_medium=cpc&utm_campaign=phone; строка заменяет эти метки целиком)
    bot.setPlatformParams({
    welcome_text: 'Привет! Я умею считать.',
    help_text: 'Это игра в математику.',
    empty_text: 'Не поняла. Скажите "помощь".',
    intents: [
    { name: 'game', slots: ['игра', 'начать игру'] },
    { name: 'bye', slots: ['пока', 'до свидания'] },
    { name: 'phone', slots: ['\\+?\\d{11}'], is_pattern: true }, // слот как regex
    ],
    });

    Важно: поле intents обязательно даже если оно пустое: intents: []. Без него TypeScript выдаст ошибку типа.


    Режим Логи ReDoS-проверка Когда использовать
    dev Подробные Warn, но не блокирует Разработка, BotTest
    prod Минимальные Warn, но не блокирует (режим небезопасен, оставлен для обратной совместимости) Pre-prod
    strict_prod Минимальные Блокировка опасных Production

    Что делает strict_prod:

    • Отключает опасные RegExp. При регистрации команды с потенциально уязвимым регулярным выражением фреймворк пишет ошибку в лог и исключает опасные слоты: если среди слотов остались безопасные — команда регистрируется по ним (по уязвимому выражению совпадать перестает, исключение не бросается). Если опасны ВСЕ слоты команды — команда не регистрируется вовсе. В режимах dev и prod опасные RegExp используются как есть: с предупреждением, если установлен re2, и с ошибкой в логах, если нет (без re2 штатный движок Node уязвим к катастрофическому бэктрекингу).
    • Сокращает логи. Только ошибки и предупреждения.

    Маскировка секретов в логах (токены, пароли заменяются на ***) работает во всех режимах и отключается только кастомным логгером с maskSecrets: false.


    Вебхук — единственная точка входа вашего приложения. Пока проверка подписи не включена, любой, кто узнает URL вебхука, может отправлять запросы от имени любого пользователя: обходить авторизацию по userId, читать и перезаписывать чужие userData, управлять чужими диалоговыми шагами и расходовать квоты API. URL вебхука — не секрет (он виден платформе, логам, реестрам доменов), поэтому подпись — не опция, а обязательный шаг настройки.

    Проверка подписи включается автоматически, как только задан секрет — отдельно «включать» ничего не нужно. Фреймворк предупредит в логе при старте, если для подключённой платформы секрет не задан.

    Платформа Что задать Где секрет живёт на стороне платформы
    Telegram tokens.telegram.webhookSecret поле secret_token при вызове setWebhook
    VK tokens.vk.secret_key (или vk_secret_key) настройка «Секретный ключ» в настройках группы (VK Callback API)
    MAX tokens.max_app.webhookSecret (или secret) секрет, выданный при создании бота/подписки
    Viber tokens.viber.token токен бота — он же ключ HMAC (x-viber-content-signature)
    Алиса, Маруся, SmartApp платформа не подписывает запросы в принципе (см. ниже)

    Сгенерировать секрет можно любой командой:

    node -e "console.log(require('crypto').randomBytes(24).toString('base64url'))"
    # или: openssl rand -base64 24
    # 1. Секрет — одна и та же строка в обоих местах
    curl "https://api.telegram.org/bot<ТОКЕН>/setWebhook" \
    -d "url=https://ваш-домен/webhook" \
    -d "secret_token=<СЕКРЕТ>"
    // 2. Тот же секрет в конфигурации приложения
    bot.use(new TelegramAdapter('YOUR_BOT_TOKEN'));
    bot.setAppConfig({
    tokens: {
    telegram: { token: 'YOUR_BOT_TOKEN', webhookSecret: process.env.TELEGRAM_WEBHOOK_SECRET },
    },
    });

    Без webhookSecret адаптер принимает любой запрос с полем update_id — это допустимо только для локальной отладки. С заданным секретом запросы без заголовка x-telegram-bot-api-secret-token (или с неверным значением) отклоняются с 401 до выполнения какой-либо логики.

    Включите «Секретный ключ» в настройках группы (Управление → Работа с API → Callback API) и передайте то же значение:

    bot.use(new VkAdapter('YOUR_VK_TOKEN', { vk_secret_key: 'YOUR_SECRET' }));
    // или через конфиг: tokens.vk.secret_key

    VK присылает secret в теле каждого callback-запроса; адаптер сверяет его константным по времени сравнением (timingSafeEqual). Если секрет в группе не включён — проверку включить нельзя (нечем сверять), см. ниже про ipFilter.

    MAX передаёт секрет заголовком x-max-bot-api-secret:

    bot.use(new MaxAdapter('YOUR_MAX_TOKEN', { secret: 'YOUR_SECRET' }));
    // или через конфиг: tokens.max_app.webhookSecret

    Алиса, Маруся и SmartApp не предоставляют механизм подписи вебхука — всё содержимое payload, включая user_id, контролирует отправитель запроса. Это ограничение платформ, а не фреймворка:

    • никогда не считайте userId голосовой платформы аутентифицированной идентичностью;
    • для чувствительных данных вводите собственную верификацию пользователя (PIN-код, привязка внешнего аккаунта);
    • не храните в userData голосовых платформ данные, потеря или подмена которых критична.

    Дополнительный слой для любых платформ — ipFilter (см. middleware.md): ограничение входящих запросов по диапазонам IP платформ (например, только для Telegram: 149.154.160.0/20, 91.108.4.0/22).


    Фреймворк поддерживает работу с re2. За счет использования данной библиотеки, можно добиться существенного ускорения обработки регулярных выражений, а также сокращения потребления памяти. Потребление памяти уменьшается примерно в 3-7 раз, а время выполнения уменьшается в среднем в 2-15 раз.

    npm install re2
    

    Фреймворк автоматически определит, установлен ли re2, и будет использовать его.

    Не рекомендуется использовать в релизной версии приложения файловую базу данных, так как данный подход может привести к падению приложения при большом количестве записей. Связано это с тем, что в файловой базе данные хранятся в оперативной памяти.

    Для корректного сохранения данных в БД:

    1. Подключите готовый адаптер (например MongoAdapter), или создайте свой (bot.use(new MyAdapter()))
    2. Укажите данные для подключения к базе данных bot.setAppConfig({db:{...}}), либо в конструкторе при подключении адаптера.

    1. Проверьте, что файл .env существует по указанному пути
    2. Переменные можно писать с пробелами вокруг = — парсер обрезает их (TELEGRAM_TOKEN = abc работает так же, как TELEGRAM_TOKEN=abc; кавычки вокруг значения допускаются — парсер их снимет)
    3. Включите режим dev для подробных логов: bot.setAppMode('dev')
    1. Проверьте формат db.host: должен содержать протокол (mongodb://localhost:27017, а не localhost:27017)
    2. Убедитесь, что MongoDB запущена и доступна
    3. Проверьте логи: error_log покажет ошибку подключения
    1. Убедитесь, что intents передан в setPlatformParams (даже если пустой: intents: [])
    2. Слоты должны быть в нижнем регистре (как и userCommand)
    3. Включите режим dev для просмотра процесса поиска команд

    Подробнее о конфигурации (IAppConfig, IAppParam), приоритете токенов и содержимом .env — в разделе Конфигурация: IAppConfig и IAppParam.