diff --git a/backend/bot/app/web/admin_settings_manifest.py b/backend/bot/app/web/admin_settings_manifest.py index a4c4c57..60fa062 100644 --- a/backend/bot/app/web/admin_settings_manifest.py +++ b/backend/bot/app/web/admin_settings_manifest.py @@ -692,6 +692,120 @@ SETTINGS_MANIFEST: List[SettingField] = [ SettingField("USER_TRAFFIC_LIMIT_GB", "float", "devices", "Лимит трафика пользователя (ГБ)"), SettingField("USER_TRAFFIC_STRATEGY", "string", "devices", "Стратегия сброса трафика"), # ─── System ──────────────────────────────────────────────────── + SettingField( + "TELEGRAM_DROP_NON_PRIVATE_UPDATES", + "bool", + "system", + "Drop non-private Telegram updates", + "Drops group/channel messages and callbacks before DB-backed middleware runs.", + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_ENABLED", + "bool", + "system", + "Telegram anti-flood enabled", + "Enables soft per-user limits for extreme Telegram update floods.", + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_WINDOW_SECONDS", + "int", + "system", + "Anti-flood window", + "Rolling window, in seconds, used by all Telegram anti-flood buckets.", + min=1, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_MAX_UPDATES_PER_WINDOW", + "int", + "system", + "All updates limit", + "Maximum total Telegram updates from one actor during the window. 0 disables this bucket.", + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_MESSAGE_MAX_PER_WINDOW", + "int", + "system", + "Messages limit", + "Maximum message updates from one actor during the window. 0 disables this bucket.", + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_CALLBACK_MAX_PER_WINDOW", + "int", + "system", + "Button callbacks limit", + "Maximum callback-query updates from one actor during the window. 0 disables this bucket.", + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_INLINE_MAX_PER_WINDOW", + "int", + "system", + "Inline queries limit", + "Maximum inline-query updates from one actor during the window. 0 disables this bucket.", + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_START_MAX_PER_WINDOW", + "int", + "system", + "/start limit", + "Maximum /start messages from one actor during the window. 0 disables this bucket.", + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ANTIFLOOD_EXPENSIVE_CALLBACK_MAX_PER_WINDOW", + "int", + "system", + "Expensive callbacks limit", + ( + "Maximum payment, trial, promo and account-changing callbacks from one actor " + "during the window. 0 disables this bucket." + ), + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_ACTION_COOLDOWN_ENABLED", + "bool", + "system", + "Action cooldowns enabled", + "Deduplicates repeated payment and trial button presses from the same user.", + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_PAYMENT_CALLBACK_COOLDOWN_SECONDS", + "int", + "system", + "Payment callback cooldown", + ( + "Seconds to suppress an exact repeated payment callback from the same user. " + "0 disables this cooldown." + ), + min=0, + subsection="telegram_antiflood", + ), + SettingField( + "TELEGRAM_TRIAL_CALLBACK_COOLDOWN_SECONDS", + "int", + "system", + "Trial callback cooldown", + ( + "Seconds to suppress an exact repeated trial activation callback from the same user. " + "0 disables this cooldown." + ), + min=0, + subsection="telegram_antiflood", + ), SettingField( "TELEMETRY_ENABLED", "bool", diff --git a/docs/configuration/env-vars.md b/docs/configuration/env-vars.md index b2e43f2..f94d224 100644 --- a/docs/configuration/env-vars.md +++ b/docs/configuration/env-vars.md @@ -71,6 +71,18 @@ | `PANEL_SYNC_LIFETIME_TRAFFIC_MIN_DELTA_BYTES` | Дельта lifetime-трафика для более ранней записи. | | `WEBAPP_RATE_LIMIT_TTL_SECONDS` | Окно Web App rate limit. | | `WEBAPP_RATE_LIMIT_MAX_REQUESTS` | Количество запросов в окне rate limit. | +| `TELEGRAM_DROP_NON_PRIVATE_UPDATES` | Отбрасывать group/channel Telegram-апдейты до DB-backed middleware. По умолчанию `True`. | +| `TELEGRAM_ANTIFLOOD_ENABLED` | Включает мягкие per-user/per-chat лимиты для экстремального Telegram-флуда. По умолчанию `True`. | +| `TELEGRAM_ANTIFLOOD_WINDOW_SECONDS` | Окно лимитов Telegram антифлуда. По умолчанию `60`. | +| `TELEGRAM_ANTIFLOOD_MAX_UPDATES_PER_WINDOW` | Глобальный лимит Telegram-апдейтов на источник за окно. По умолчанию `180`; `0` отключает лимит. | +| `TELEGRAM_ANTIFLOOD_MESSAGE_MAX_PER_WINDOW` | Лимит Telegram messages на источник за окно. По умолчанию `120`; `0` отключает лимит. | +| `TELEGRAM_ANTIFLOOD_CALLBACK_MAX_PER_WINDOW` | Лимит callback query на источник за окно. По умолчанию `240`; `0` отключает лимит. | +| `TELEGRAM_ANTIFLOOD_INLINE_MAX_PER_WINDOW` | Лимит inline query на источник за окно. По умолчанию `60`; `0` отключает лимит. | +| `TELEGRAM_ANTIFLOOD_START_MAX_PER_WINDOW` | Лимит `/start` на источник за окно. По умолчанию `30`; `0` отключает лимит. | +| `TELEGRAM_ANTIFLOOD_EXPENSIVE_CALLBACK_MAX_PER_WINDOW` | Лимит платежных, trial, promo и account-changing callback за окно. По умолчанию `60`; `0` отключает лимит. | +| `TELEGRAM_ACTION_COOLDOWN_ENABLED` | Дедуплицирует точные повторы платежных и trial callback от того же пользователя. По умолчанию `True`. | +| `TELEGRAM_PAYMENT_CALLBACK_COOLDOWN_SECONDS` | Cooldown точного повтора платежного callback. По умолчанию `20`; `0` отключает cooldown. | +| `TELEGRAM_TRIAL_CALLBACK_COOLDOWN_SECONDS` | Cooldown точного повтора trial callback. По умолчанию `30`; `0` отключает cooldown. | | `WEBHOOK_QUEUE_NAME` | Redis queue для тяжелой обработки webhook. | | `WEBHOOK_QUEUE_CONCURRENCY` | Количество worker consumers для webhook queue. | | `WORKER_PANEL_SYNC_INTERVAL_SECONDS` | Интервал фоновой синхронизации с панелью. | diff --git a/docs/configuration/security.md b/docs/configuration/security.md index 98d04c4..1fd0deb 100644 --- a/docs/configuration/security.md +++ b/docs/configuration/security.md @@ -15,6 +15,33 @@ openssl rand -hex 32 ``` +## Telegram антифлуд + +Апдейты Telegram-бота проходят через ранний anti-flood middleware до sync +профиля, проверки каналов и логирования действий, которые обращаются к базе. +Профиль по умолчанию специально мягкий: он не должен мешать быстрым обычным +нажатиям кнопок, но отбрасывает экстремальные всплески сообщений и callback от +одного источника до того, как они разгонят записи в БД, платежные обработчики +или Telegram FloodWait. + +Настройки доступны в **Админка -> Система -> Настройки -> Система -> Telegram +антифлуд**. Для обычного приватного продающего бота дефолтов достаточно, поэтому +они не добавлены в `.env.example`. Меняйте их только если реальный трафик +показывает, что пороги нужно расширить или сузить. + +- `TELEGRAM_DROP_NON_PRIVATE_UPDATES=True` отбрасывает апдейты из групп и + каналов до дорогих middleware. Оставляйте включенным, если бот не должен + работать вне приватных чатов. +- `TELEGRAM_ANTIFLOOD_ENABLED=True` включает per-user/per-chat лимиты. Значение + `0` у отдельного числового лимита отключает только этот лимит. +- `TELEGRAM_ANTIFLOOD_WINDOW_SECONDS=60` задает общее скользящее окно. Дефолты + рассчитаны на нормальные button-heavy флоу: `180` всех апдейтов, `120` + сообщений, `240` callback, `60` inline-запросов, `30` команд `/start` и `60` + тяжелых callback за окно. +- `TELEGRAM_ACTION_COOLDOWN_ENABLED=True` дедуплицирует точные повторные + платежные и trial callback от того же пользователя. Разные платежные payload + не объединяются, поэтому обычный checkout остается независимым. + ## Доступ администраторов - `ADMIN_IDS` задает Telegram ID администраторов. diff --git a/docs/features/admin-panel.md b/docs/features/admin-panel.md index 1bc7f36..8ceb670 100644 --- a/docs/features/admin-panel.md +++ b/docs/features/admin-panel.md @@ -53,7 +53,7 @@ - инструкции подключения: `SUBSCRIPTION_GUIDES_ENABLED`, `SUBSCRIPTION_GUIDES_BOT_MENU_ENABLED`, чтение конфига из Remnawave Panel, JSON-переопределение и резервный путь к файлу; - legacy-тарифы без JSON-каталога: периоды подписки, RUB/Stars цены, реферальные бонусы и пакеты трафика; - платежные провайдеры: включение методов, порядок кнопок, публичные параметры и секреты YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay, Heleket и Stars, а также текст и иконки кнопок оплаты; -- пробный период, приветственный реферальный бонус, уведомления, логирование, поддержка, раздел устройств, лимит устройств и legacy-лимиты трафика. +- пробный период, приветственный реферальный бонус, уведомления, логирование, Telegram антифлуд, поддержка, раздел устройств, лимит устройств и legacy-лимиты трафика. Секретные поля помечены как secret и не должны использоваться для произвольного просмотра старых значений. Настройки, которых нет в manifest, остаются только в `.env` или коде. diff --git a/frontend/src/lib/webapp/settingsManifest.generated.json b/frontend/src/lib/webapp/settingsManifest.generated.json index eb1ff71..e82900f 100644 --- a/frontend/src/lib/webapp/settingsManifest.generated.json +++ b/frontend/src/lib/webapp/settingsManifest.generated.json @@ -6030,6 +6030,243 @@ "id": "system", "order": 12, "fields": [ + { + "key": "TELEGRAM_DROP_NON_PRIVATE_UPDATES", + "type": "bool", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Drop non-private Telegram updates", + "description": "Drops group/channel messages and callbacks before DB-backed middleware runs.", + "i18n_label_key": "admin_settings_field_telegram_drop_non_private_updates_label", + "i18n_description_key": "admin_settings_field_telegram_drop_non_private_updates_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_ENABLED", + "type": "bool", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Telegram anti-flood enabled", + "description": "Enables soft per-user limits for extreme Telegram update floods.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_enabled_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_enabled_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_WINDOW_SECONDS", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Anti-flood window", + "description": "Rolling window, in seconds, used by all Telegram anti-flood buckets.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_window_seconds_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_window_seconds_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 1, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_MAX_UPDATES_PER_WINDOW", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "All updates limit", + "description": "Maximum total Telegram updates from one actor during the window. 0 disables this bucket.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_max_updates_per_window_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_max_updates_per_window_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_MESSAGE_MAX_PER_WINDOW", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Messages limit", + "description": "Maximum message updates from one actor during the window. 0 disables this bucket.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_message_max_per_window_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_message_max_per_window_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_CALLBACK_MAX_PER_WINDOW", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Button callbacks limit", + "description": "Maximum callback-query updates from one actor during the window. 0 disables this bucket.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_callback_max_per_window_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_callback_max_per_window_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_INLINE_MAX_PER_WINDOW", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Inline queries limit", + "description": "Maximum inline-query updates from one actor during the window. 0 disables this bucket.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_inline_max_per_window_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_inline_max_per_window_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_START_MAX_PER_WINDOW", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "/start limit", + "description": "Maximum /start messages from one actor during the window. 0 disables this bucket.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_start_max_per_window_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_start_max_per_window_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ANTIFLOOD_EXPENSIVE_CALLBACK_MAX_PER_WINDOW", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Expensive callbacks limit", + "description": "Maximum payment, trial, promo and account-changing callbacks from one actor during the window. 0 disables this bucket.", + "i18n_label_key": "admin_settings_field_telegram_antiflood_expensive_callback_max_per_window_label", + "i18n_description_key": "admin_settings_field_telegram_antiflood_expensive_callback_max_per_window_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_ACTION_COOLDOWN_ENABLED", + "type": "bool", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Action cooldowns enabled", + "description": "Deduplicates repeated payment and trial button presses from the same user.", + "i18n_label_key": "admin_settings_field_telegram_action_cooldown_enabled_label", + "i18n_description_key": "admin_settings_field_telegram_action_cooldown_enabled_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_PAYMENT_CALLBACK_COOLDOWN_SECONDS", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Payment callback cooldown", + "description": "Seconds to suppress an exact repeated payment callback from the same user. 0 disables this cooldown.", + "i18n_label_key": "admin_settings_field_telegram_payment_callback_cooldown_seconds_label", + "i18n_description_key": "admin_settings_field_telegram_payment_callback_cooldown_seconds_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, + { + "key": "TELEGRAM_TRIAL_CALLBACK_COOLDOWN_SECONDS", + "type": "int", + "section": "system", + "section_order": 12, + "subsection": "telegram_antiflood", + "label": "Trial callback cooldown", + "description": "Seconds to suppress an exact repeated trial activation callback from the same user. 0 disables this cooldown.", + "i18n_label_key": "admin_settings_field_telegram_trial_callback_cooldown_seconds_label", + "i18n_description_key": "admin_settings_field_telegram_trial_callback_cooldown_seconds_description", + "i18n_subsection_key": "admin_settings_subsection_telegram_antiflood", + "i18n_placeholder_key": null, + "placeholder": "", + "optional": true, + "secret": false, + "min": 0, + "value": "", + "overridden": false, + "updated_at": null + }, { "key": "TELEMETRY_ENABLED", "type": "bool", diff --git a/locales/en.json b/locales/en.json index f234711..890b4e7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1155,7 +1155,32 @@ "admin_settings_section_migrations": "Migrations", "admin_settings_field_telemetry_enabled_label": "Anonymous install analytics", "admin_settings_field_telemetry_enabled_description": "Sends one anonymous heartbeat per day (version, OS, locale, user-count range). No personal data, tokens or domains. Helps gauge how many installs are active and which versions are in use. Toggling this off takes effect without a restart.", + "admin_settings_field_telegram_drop_non_private_updates_label": "Drop non-private Telegram updates", + "admin_settings_field_telegram_drop_non_private_updates_description": "Drops group and channel messages/callbacks before database-backed middleware runs. Keep enabled for a private sales bot.", + "admin_settings_field_telegram_antiflood_enabled_label": "Telegram anti-flood enabled", + "admin_settings_field_telegram_antiflood_enabled_description": "Enables soft per-user limits that cut off only extreme Telegram update floods.", + "admin_settings_field_telegram_antiflood_window_seconds_label": "Anti-flood window", + "admin_settings_field_telegram_antiflood_window_seconds_description": "Rolling window in seconds used by all Telegram anti-flood buckets.", + "admin_settings_field_telegram_antiflood_max_updates_per_window_label": "All updates limit", + "admin_settings_field_telegram_antiflood_max_updates_per_window_description": "Maximum total Telegram updates from one user or chat during the window. 0 disables this bucket.", + "admin_settings_field_telegram_antiflood_message_max_per_window_label": "Messages limit", + "admin_settings_field_telegram_antiflood_message_max_per_window_description": "Maximum message updates from one user or chat during the window. 0 disables this bucket.", + "admin_settings_field_telegram_antiflood_callback_max_per_window_label": "Button callbacks limit", + "admin_settings_field_telegram_antiflood_callback_max_per_window_description": "Maximum callback-query updates from one user during the window. 0 disables this bucket.", + "admin_settings_field_telegram_antiflood_inline_max_per_window_label": "Inline queries limit", + "admin_settings_field_telegram_antiflood_inline_max_per_window_description": "Maximum inline-query updates from one user during the window. 0 disables this bucket.", + "admin_settings_field_telegram_antiflood_start_max_per_window_label": "/start limit", + "admin_settings_field_telegram_antiflood_start_max_per_window_description": "Maximum /start messages from one user during the window. 0 disables this bucket.", + "admin_settings_field_telegram_antiflood_expensive_callback_max_per_window_label": "Expensive callbacks limit", + "admin_settings_field_telegram_antiflood_expensive_callback_max_per_window_description": "Maximum payment, trial, promo and account-changing callbacks from one user during the window. 0 disables this bucket.", + "admin_settings_field_telegram_action_cooldown_enabled_label": "Action cooldowns enabled", + "admin_settings_field_telegram_action_cooldown_enabled_description": "Deduplicates exact repeated payment and trial button presses from the same user.", + "admin_settings_field_telegram_payment_callback_cooldown_seconds_label": "Payment callback cooldown", + "admin_settings_field_telegram_payment_callback_cooldown_seconds_description": "Seconds to suppress an exact repeated payment callback from the same user. 0 disables this cooldown.", + "admin_settings_field_telegram_trial_callback_cooldown_seconds_label": "Trial callback cooldown", + "admin_settings_field_telegram_trial_callback_cooldown_seconds_description": "Seconds to suppress an exact repeated trial activation callback from the same user. 0 disables this cooldown.", "admin_settings_subsection_common": "Common", + "admin_settings_subsection_telegram_antiflood": "Telegram anti-flood", "admin_settings_subsection_checkout": "Checkout", "admin_settings_subsection_trial": "Trial", "admin_settings_subsection_referral": "Referral program", diff --git a/locales/ru.json b/locales/ru.json index 6900916..d0845ce 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -1155,7 +1155,32 @@ "admin_settings_section_migrations": "Миграции", "admin_settings_field_telemetry_enabled_label": "Анонимная статистика установки", "admin_settings_field_telemetry_enabled_description": "Раз в сутки отправляет обезличенный сигнал: версия, ОС, локаль и число пользователей в виде диапазона. Без персональных данных, токенов и доменов. Помогает оценить число активных установок и используемые версии. Отключение применяется без перезапуска.", + "admin_settings_field_telegram_drop_non_private_updates_label": "Отбрасывать неприватные чаты", + "admin_settings_field_telegram_drop_non_private_updates_description": "Отбрасывает сообщения и нажатия кнопок из групп и каналов до middleware, которые ходят в базу. Для приватного продающего бота лучше держать включенным.", + "admin_settings_field_telegram_antiflood_enabled_label": "Антифлуд Telegram включен", + "admin_settings_field_telegram_antiflood_enabled_description": "Включает мягкие лимиты на пользователя, которые отсекают только экстремальный поток Telegram-апдейтов.", + "admin_settings_field_telegram_antiflood_window_seconds_label": "Окно антифлуда", + "admin_settings_field_telegram_antiflood_window_seconds_description": "Скользящее окно в секундах, по которому считаются все лимиты Telegram антифлуда.", + "admin_settings_field_telegram_antiflood_max_updates_per_window_label": "Лимит всех апдейтов", + "admin_settings_field_telegram_antiflood_max_updates_per_window_description": "Максимум всех Telegram-апдейтов от одного пользователя или чата за окно. 0 отключает этот лимит.", + "admin_settings_field_telegram_antiflood_message_max_per_window_label": "Лимит сообщений", + "admin_settings_field_telegram_antiflood_message_max_per_window_description": "Максимум сообщений от одного пользователя или чата за окно. 0 отключает этот лимит.", + "admin_settings_field_telegram_antiflood_callback_max_per_window_label": "Лимит нажатий кнопок", + "admin_settings_field_telegram_antiflood_callback_max_per_window_description": "Максимум callback query от одного пользователя за окно. 0 отключает этот лимит.", + "admin_settings_field_telegram_antiflood_inline_max_per_window_label": "Лимит inline-запросов", + "admin_settings_field_telegram_antiflood_inline_max_per_window_description": "Максимум inline query от одного пользователя за окно. 0 отключает этот лимит.", + "admin_settings_field_telegram_antiflood_start_max_per_window_label": "Лимит /start", + "admin_settings_field_telegram_antiflood_start_max_per_window_description": "Максимум сообщений /start от одного пользователя за окно. 0 отключает этот лимит.", + "admin_settings_field_telegram_antiflood_expensive_callback_max_per_window_label": "Лимит тяжелых кнопок", + "admin_settings_field_telegram_antiflood_expensive_callback_max_per_window_description": "Максимум платежных, trial, промокодных и меняющих аккаунт callback от одного пользователя за окно. 0 отключает этот лимит.", + "admin_settings_field_telegram_action_cooldown_enabled_label": "Cooldown действий включен", + "admin_settings_field_telegram_action_cooldown_enabled_description": "Дедуплицирует точные повторные нажатия платежных и trial-кнопок от одного пользователя.", + "admin_settings_field_telegram_payment_callback_cooldown_seconds_label": "Cooldown платежной кнопки", + "admin_settings_field_telegram_payment_callback_cooldown_seconds_description": "Сколько секунд подавлять точный повтор платежного callback от того же пользователя. 0 отключает этот cooldown.", + "admin_settings_field_telegram_trial_callback_cooldown_seconds_label": "Cooldown trial-кнопки", + "admin_settings_field_telegram_trial_callback_cooldown_seconds_description": "Сколько секунд подавлять точный повтор callback активации trial от того же пользователя. 0 отключает этот cooldown.", "admin_settings_subsection_common": "Общие", + "admin_settings_subsection_telegram_antiflood": "Telegram антифлуд", "admin_settings_subsection_checkout": "Оформление оплаты", "admin_settings_subsection_trial": "Пробный период", "admin_settings_subsection_referral": "Реферальная программа", diff --git a/tests/test_admin_settings_manifest_i18n.py b/tests/test_admin_settings_manifest_i18n.py index 1228bcd..095b1b8 100644 --- a/tests/test_admin_settings_manifest_i18n.py +++ b/tests/test_admin_settings_manifest_i18n.py @@ -44,6 +44,21 @@ BACKUP_SETTINGS = ( "BACKUP_COMPOSE_ENABLED", ) +TELEGRAM_ANTIFLOOD_SETTINGS = ( + "TELEGRAM_DROP_NON_PRIVATE_UPDATES", + "TELEGRAM_ANTIFLOOD_ENABLED", + "TELEGRAM_ANTIFLOOD_WINDOW_SECONDS", + "TELEGRAM_ANTIFLOOD_MAX_UPDATES_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_MESSAGE_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_CALLBACK_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_INLINE_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_START_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_EXPENSIVE_CALLBACK_MAX_PER_WINDOW", + "TELEGRAM_ACTION_COOLDOWN_ENABLED", + "TELEGRAM_PAYMENT_CALLBACK_COOLDOWN_SECONDS", + "TELEGRAM_TRIAL_CALLBACK_COOLDOWN_SECONDS", +) + REMNASHOP_MIGRATION_SETTINGS = ( "MIGRATION_REMNASHOP_REFERRAL_CODE_COMPAT_ENABLED", "MIGRATION_REMNASHOP_PROMO_CODE_COMPAT_ENABLED", @@ -224,6 +239,40 @@ def test_backup_settings_i18n_keys_exist(): assert field["i18n_description_key"] in messages +def test_telegram_antiflood_settings_i18n_keys_exist(): + manifest = _manifest_by_key() + + for setting_key in TELEGRAM_ANTIFLOOD_SETTINGS: + field = manifest[setting_key] + assert field["section"] == "system" + assert field["section_order"] == 12 + assert field["subsection"] == "telegram_antiflood" + assert field["i18n_subsection_key"] == "admin_settings_subsection_telegram_antiflood" + + assert manifest["TELEGRAM_ANTIFLOOD_WINDOW_SECONDS"]["min"] == 1 + for setting_key in ( + "TELEGRAM_ANTIFLOOD_MAX_UPDATES_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_MESSAGE_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_CALLBACK_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_INLINE_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_START_MAX_PER_WINDOW", + "TELEGRAM_ANTIFLOOD_EXPENSIVE_CALLBACK_MAX_PER_WINDOW", + "TELEGRAM_PAYMENT_CALLBACK_COOLDOWN_SECONDS", + "TELEGRAM_TRIAL_CALLBACK_COOLDOWN_SECONDS", + ): + assert manifest[setting_key]["min"] == 0 + + for language in ("ru", "en"): + messages = _locale(language) + + assert "admin_settings_section_system" in messages + assert "admin_settings_subsection_telegram_antiflood" in messages + for setting_key in TELEGRAM_ANTIFLOOD_SETTINGS: + field = manifest[setting_key] + assert field["i18n_label_key"] in messages + assert field["i18n_description_key"] in messages + + def test_remnashop_migration_settings_i18n_keys_exist(): manifest = _manifest_by_key()