fix: файлы своего Bot API сервера без TELEGRAM_FILES_URL и токен в ошибке

Без TELEGRAM_FILES_URL адрес скачивания был голым путем, а текст ошибки с путем
(в нем токен бота) уходил в чат. Теперь сайт не стартует без TELEGRAM_FILES_URL
при заданном TELEGRAM_API_URL, а в ошибке скачивания только тип исключения.
env_example: 127.0.0.1 вместо localhost, чтобы не пробовать ::1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
protokeyandClaude Opus 5.5 committed 2026-10-01 09:22:05 +04:00
1 parent a90c265ff3
commit 803a6bf9f2
4 files changed
+34 -6

No files matched your search

+3 -3
View File
@@ -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
+1 -1
View File
@@ -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`.
+12 -2
View File
@@ -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
+18
View File
@@ -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):