Webhook. Allow requests only from Telegram servers. // Optional

This commit is contained in:
Alex Root Junior 2017-11-16 15:27:15 +02:00
parent 6d9bdce935
commit f050d08c75
2 changed files with 44 additions and 1 deletions

View file

@ -2,6 +2,7 @@ import asyncio
import asyncio.tasks
import datetime
import functools
import ipaddress
import typing
from typing import Dict, Optional, Union
@ -25,6 +26,21 @@ WEBHOOK = 'webhook'
WEBHOOK_CONNECTION = 'WEBHOOK_CONNECTION'
WEBHOOK_REQUEST = 'WEBHOOK_REQUEST'
TELEGRAM_IP_LOWER = ipaddress.IPv4Address('149.154.167.197')
TELEGRAM_IP_UPPER = ipaddress.IPv4Address('149.154.167.233')
LOCALHOST_IP = ipaddress.IPv4Address('127.0.0.1')
def _check_ip(ip: str) -> bool:
"""
Check IP in range
:param ip:
:return:
"""
address = ipaddress.IPv4Address(ip)
return TELEGRAM_IP_LOWER <= address <= TELEGRAM_IP_UPPER or address == LOCALHOST_IP
class WebhookRequestHandler(web.View):
"""
@ -78,6 +94,11 @@ class WebhookRequestHandler(web.View):
:return: :class:`aiohttp.web.Response`
"""
if self.request.app.get('_check_ip', False):
ip_address, accept = self.check_ip()
if not accept:
raise web.HTTPUnauthorized()
context.set_value('TELEGRAM_IP', ip_address)
context.update_state({'CALLER': WEBHOOK,
WEBHOOK_CONNECTION: True,
@ -164,6 +185,26 @@ class WebhookRequestHandler(web.View):
if isinstance(result, BaseResponse):
return result
def check_ip(self):
"""
Check client IP. Accept requests only from telegram servers.
:return:
"""
# For reverse proxy (nginx)
forwarded_for = self.request.headers.get('X-Forwarded-For', None)
if forwarded_for:
return forwarded_for, _check_ip(forwarded_for)
# For default method
peer_name = self.request.transport.get_extra_info('peername')
if peer_name is not None:
host, _ = peer_name
return host, _check_ip(host)
# Not allowed and can't get client IP
return None, False
def configure_app(dispatcher, app: web.Application, path=DEFAULT_WEB_PATH):
"""

View file

@ -61,7 +61,7 @@ def start_pooling(dispatcher, *, loop=None, skip_updates=False, on_startup=None,
def start_webhook(dispatcher, webhook_path, *, loop=None, skip_updates=None, on_startup=None, on_shutdown=None,
**kwargs):
check_ip=False, **kwargs):
log.warning('Start bot with webhook.')
if loop is None:
loop = dispatcher.loop
@ -72,8 +72,10 @@ def start_webhook(dispatcher, webhook_path, *, loop=None, skip_updates=None, on_
app['_startup_callback'] = on_startup
app['_shutdown_callback'] = on_shutdown
app['_skip_updates'] = skip_updates
app['_check_ip'] = check_ip
app.on_startup.append(_wh_startup)
app.on_shutdown.append(_wh_shutdown)
web.run_app(app, loop=loop, **kwargs)
return app