diff --git a/env_example b/env_example index cb9a19b..94e03ba 100644 --- a/env_example +++ b/env_example @@ -2,11 +2,11 @@ TG_APP_ID= TG_APP_HASH= # Адрес своего Bot API сервера для Django. Пусто - api.telegram.org -TELEGRAM_API_URL=http://localhost:8081 +TELEGRAM_API_URL=http://127.0.0.1:8081 # Файлы, присланные ботам документами (сервис telegram-files): свой Bot API сервер не отдает их по HTTP -TELEGRAM_FILES_URL=http://localhost:8083 +TELEGRAM_FILES_URL=http://127.0.0.1:8083 # Адрес сайта для webhook ботов, как его видит Bot API сервер (он в сети хоста, network_mode: host) -TELEGRAM_WEBHOOK_URL=http://localhost:8000 +TELEGRAM_WEBHOOK_URL=http://127.0.0.1:8000 # Хосты сайта через запятую, в том числе хост из TELEGRAM_WEBHOOK_URL ALLOWED_HOSTS=127.0.0.1,localhost diff --git a/src/Telegram/README.md b/src/Telegram/README.md index 0d3cd25..af309f4 100644 --- a/src/Telegram/README.md +++ b/src/Telegram/README.md @@ -71,7 +71,7 @@ class Shop(Interface): 3. Отдельный процесс не нужен: обновления принимает сайт. Смена интерфейса применяется без перезапуска. `TELEGRAM_API_URL` направляет бота на свой Bot API сервер (сервис `telegram` в `docker-compose.yaml`). -`TELEGRAM_FILES_URL` - раздача файлов своего Bot API сервера (сервис `telegram-files`). В `--local` режиме сервер не отдает файлы по HTTP, а пишет их в свою папку (`api.WORK_DIR`) с правами 0600 от uid 101. Рядом с ним работает nginx, воркеры которого тоже от uid 101: он отдает только `documents/` и слушает только локальный адрес. +`TELEGRAM_FILES_URL` - раздача файлов своего Bot API сервера (сервис `telegram-files`). В `--local` режиме сервер не отдает файлы по HTTP, а пишет их в свою папку (`api.WORK_DIR`) с правами 0600 от uid 101. Рядом с ним работает nginx, воркеры которого тоже от uid 101: он отдает только `documents/` и слушает только локальный адрес. При заданном `TELEGRAM_API_URL` переменная обязательна: без нее сайт не запустится (`ImproperlyConfigured`). `TELEGRAM_WEBHOOK_URL` - адрес сайта, как его видит Bot API сервер, к нему дописывается путь webhook. Сервер в docker запущен с `--local` (`TELEGRAM_LOCAL`), поэтому webhook может быть на http и на любом порту. Хост из этого адреса нужно добавить в `ALLOWED_HOSTS`. diff --git a/src/Telegram/api.py b/src/Telegram/api.py index 253df8e..479ca1b 100644 --- a/src/Telegram/api.py +++ b/src/Telegram/api.py @@ -1,8 +1,13 @@ +import logging + import requests import telebot from django.conf import settings +from django.core.exceptions import ImproperlyConfigured from telebot import apihelper +logger = logging.getLogger(__name__) + def configure_api_server(): """Направляет pyTelegramBotAPI на свой инстанс Bot API сервера, если он задан в TELEGRAM_API_URL.""" @@ -10,7 +15,10 @@ def configure_api_server(): url = settings.TELEGRAM_API_URL.rstrip('/') apihelper.API_URL = url + '/bot{0}/{1}' # в --local режиме сервер файлы не отдает, их раздает TELEGRAM_FILES_URL по пути внутри WORK_DIR - apihelper.FILE_URL = getattr(settings, 'TELEGRAM_FILES_URL', '').rstrip('/') + '{1}' + files_url = getattr(settings, 'TELEGRAM_FILES_URL', '') + if not files_url: + raise ImproperlyConfigured('TELEGRAM_API_URL is set, so TELEGRAM_FILES_URL is required') + apihelper.FILE_URL = files_url.rstrip('/') + '{1}' CLOUD_API_URL = 'https://api.telegram.org' @@ -62,7 +70,9 @@ def download_file(api: telebot.TeleBot, file_id: str, max_size: int) -> bytes: except ApiError: raise except Exception as error: - raise ApiError(f'download: {error}') from error + # путь к файлу и URL содержат токен бота: текст ошибки уходит в чат, поэтому подробности только в лог + logger.exception('Failed to download file %s', file_id) + raise ApiError(f'download: {type(error).__name__}') from error if len(content) > max_size: raise FileTooLarge(f'file is larger than {max_size} bytes') return content diff --git a/src/Telegram/tests.py b/src/Telegram/tests.py index 8c0e9d2..c6679e0 100644 --- a/src/Telegram/tests.py +++ b/src/Telegram/tests.py @@ -194,6 +194,24 @@ class DocumentTests(TestCase): 'http://127.0.0.1:8083/1:t/documents/file_0.zip', ) + @override_settings(TELEGRAM_API_URL='http://127.0.0.1:8081', TELEGRAM_FILES_URL='') + def test_own_server_requires_file_url(self): + from django.core.exceptions import ImproperlyConfigured + from telebot import apihelper + + with mock.patch.object(apihelper, 'API_URL', None), mock.patch.object(apihelper, 'FILE_URL', None): + with self.assertRaises(ImproperlyConfigured): + bot_api.configure_api_server() + + @override_settings(TELEGRAM_API_URL='http://127.0.0.1:8081') + def test_download_error_hides_token(self): + api = mock.Mock() + api.get_file.return_value = SimpleNamespace(file_path=f'{bot_api.WORK_DIR}/1:secret/documents/a.zip', file_size=1) + api.download_file.side_effect = ValueError('No connection adapters were found for /1:secret/documents/a.zip') + with self.assertLogs('Telegram.api', 'ERROR'), self.assertRaises(bot_api.ApiError) as raised: + bot_api.download_file(api, 'id', 10) + self.assertNotIn('secret', str(raised.exception)) + @override_settings(TELEGRAM_WEBHOOK_URL='http://localhost:8000/') class PublishTests(TestCase):