diff --git a/CHANGES/1173.feature.rst b/CHANGES/1173.feature.rst new file mode 100644 index 00000000..5a0f4d0c --- /dev/null +++ b/CHANGES/1173.feature.rst @@ -0,0 +1 @@ +Added X-Telegram-Bot-Api-Secret-Token header check diff --git a/aiogram/webhook/aiohttp_server.py b/aiogram/webhook/aiohttp_server.py index 4406f1ff..953f90fe 100644 --- a/aiogram/webhook/aiohttp_server.py +++ b/aiogram/webhook/aiohttp_server.py @@ -131,6 +131,10 @@ class BaseRequestHandler(ABC): """ pass + @abstractmethod + def verify_secret(self, telegram_secret_token: str, bot: Bot) -> bool: + pass + async def _background_feed_update(self, bot: Bot, update: Dict[str, Any]) -> None: result = await self.dispatcher.feed_raw_update(bot=bot, update=update, **self.data) if isinstance(result, TelegramMethod): @@ -185,6 +189,8 @@ class BaseRequestHandler(ABC): async def handle(self, request: web.Request) -> web.Response: bot = await self.resolve_bot(request) + if not self.verify_secret(request.headers.get("X-Telegram-Bot-Api-Secret-Token", ""), bot): + return web.Response(body="Unauthorized", status=401) if self.handle_in_background: return await self._handle_request_background(bot=bot, request=request) return await self._handle_request(bot=bot, request=request) @@ -198,7 +204,12 @@ class SimpleRequestHandler(BaseRequestHandler): """ def __init__( - self, dispatcher: Dispatcher, bot: Bot, handle_in_background: bool = True, **data: Any + self, + dispatcher: Dispatcher, + bot: Bot, + handle_in_background: bool = True, + secret_token: Optional[str] = None, + **data: Any, ) -> None: """ :param dispatcher: instance of :class:`aiogram.dispatcher.dispatcher.Dispatcher` @@ -208,6 +219,12 @@ class SimpleRequestHandler(BaseRequestHandler): """ super().__init__(dispatcher=dispatcher, handle_in_background=handle_in_background, **data) self.bot = bot + self.secret_token = secret_token + + def verify_secret(self, telegram_secret_token: str, bot: Bot) -> bool: + if self.secret_token: + return secrets.compare_digest(telegram_secret_token, self.secret_token) + return True async def close(self) -> None: """ @@ -244,6 +261,9 @@ class TokenBasedRequestHandler(BaseRequestHandler): self.bot_settings = bot_settings self.bots: Dict[str, Bot] = {} + def verify_secret(self, telegram_secret_token: str, bot: Bot) -> bool: + return True + async def close(self) -> None: for bot in self.bots.values(): await bot.session.close() diff --git a/tests/test_webhook/test_aiohtt_server.py b/tests/test_webhook/test_aiohtt_server.py index 5be8f43e..4e3f6658 100644 --- a/tests/test_webhook/test_aiohtt_server.py +++ b/tests/test_webhook/test_aiohtt_server.py @@ -189,8 +189,24 @@ class TestSimpleRequestHandler: result = await resp.json() assert not result + async def test_verify_secret(self, bot: MockedBot, aiohttp_client): + app = Application() + dp = Dispatcher() + handler = SimpleRequestHandler( + dispatcher=dp, bot=bot, handle_in_background=False, secret_token="vasya228" + ) + handler.register(app, path="/webhook") + client: TestClient = await aiohttp_client(app) + resp = await self.make_reqest(client=client) + assert resp.status == 401 + class TestTokenBasedRequestHandler: + async def test_verify_secret(self, bot: MockedBot): + dispatcher = Dispatcher() + handler = TokenBasedRequestHandler(dispatcher=dispatcher) + assert handler.verify_secret("petro328", bot) + async def test_register(self): dispatcher = Dispatcher() app = Application()