├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── bot ├── __init__.py ├── main.py ├── mwt.py └── utils.py ├── docker-compose.yml ├── hooks └── build ├── requirements.txt └── scripts ├── generate_ssl_cert.sh └── start.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | .python-version 4 | __pycache__ 5 | certs/ 6 | .git 7 | .gitignore 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | .python-version 4 | __pycache__ 5 | certs/ 6 | variables.env 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.4.6 2 | LABEL maintainer="Jeff Corcoran " 3 | ARG BUILD_DATE 4 | ARG VCS_REF 5 | 6 | ENV DOCKER_BUILD_DATE=$BUILD_DATE 7 | ENV DOCKER_VCS_REF=$VCS_REF 8 | 9 | LABEL org.label-schema.build-date=$BUILD_DATE \ 10 | org.label-schema.vcs-url="https://github.com/mimicmobile/flask-telegram-relay-bot.git" \ 11 | org.label-schema.vcs-ref=$VCS_REF 12 | 13 | RUN apt-get update; apt-get install -y openssl 14 | 15 | COPY requirements.txt /usr/src/app/ 16 | 17 | RUN cd /usr/src/app && pip install --no-cache-dir -r requirements.txt 18 | COPY . /usr/src/app 19 | 20 | WORKDIR /usr/src/app 21 | 22 | VOLUME /usr/src/app/certs 23 | 24 | CMD [ "scripts/start.sh" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jeff Corcoran 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram Relay Bot 2 | 3 | [![Docker Automated build](https://img.shields.io/docker/automated/mimicmobile/flask-telegram-relay-bot.svg)](https://hub.docker.com/r/mimicmobile/flask-telegram-relay-bot/) 4 | [![Docker Stars](https://img.shields.io/docker/stars/mimicmobile/flask-telegram-relay-bot.svg)](https://hub.docker.com/r/mimicmobile/flask-telegram-relay-bot/) 5 | [![Docker Pulls](https://img.shields.io/docker/pulls/mimicmobile/flask-telegram-relay-bot.svg)](https://hub.docker.com/r/mimicmobile/flask-telegram-relay-bot/) 6 | [![](https://images.microbadger.com/badges/image/mimicmobile/flask-telegram-relay-bot.svg)](https://microbadger.com/images/mimicmobile/flask-telegram-relay-bot "Get your own image badge on microbadger.com") 7 | [![](https://images.microbadger.com/badges/commit/mimicmobile/flask-telegram-relay-bot.svg)](https://microbadger.com/images/mimicmobile/flask-telegram-relay-bot "Get your own commit badge on microbadger.com") 8 | 9 | This bot acts as a relay between an existing service and Telegram. It listens for a unique `POST` `JSON` request from a service and relays (via Webhooks) that message to your Telegram chat(s) of choice. 10 | 11 | A bot token is **required** and can be obtained by messaging [@BotFather](https://telegram.me/BotFather). 12 | 13 | ## Configuration 14 | This bot uses environment variables to configure and run. At the minimum, `HOST`, `SOURCE_TOKEN` and `TOKEN` are required. 15 | 16 | ### Variables 17 | * HOST (**required**) - The FQDN/IP your bot is listening on 18 | * POST (default: 8443) 19 | * SOURCE_TOKEN (**required**) - A unique token of any length that **you** define 20 | * TOKEN (**required**) - Telegram bot token 21 | * PERMANENT_CHATS - A comma separated string of chat IDs you want your bot to always send messages to 22 | * OWNER_ID - Your (owner) telegram id (get ids for `PERMANENT_CHATS` and `OWNER_ID` by messaging [@RawDataBot](https://telegram.me/RawDataBot)) 23 | * ADMIN_LEVEL (default: 1) - Determines can control the bot. 24 | * 1=Channel admins + Owner 25 | * 2=Channel admins 26 | * 3=Owner only 27 | * DISABLE_SSL (default: undefined) - Set to 1 to skip cert creation and use regular ol' http (see **IMPORTANT** below) 28 | * DEBUG (default: 0) - If set to 1, will enable Flask debug logging 29 | 30 | ### Environment file 31 | The easiest method is to place the above variables you're using in a `variables.env` file. 32 | 33 | ## API spec 34 | This bot listens on `https://HOST:PORT/relay/SOURCE_TOKEN` for a `POST` request with a `JSON` string body. _HTML tags are supported_. 35 | At the moment the only field parsed from the JSON object is `message`. 36 | 37 | **IMPORTANT** 38 | 39 | Telegram requires Webhooks to be received over `HTTPS`! **This means we're optionally creating and using self-signed certs**. This is all taken care for you when the bot starts. Beware that you may need to grab the public cert from the `certs/` directory (locally or inside the docker container) depending on how you're sending your `POST request` from your service. 40 | 41 | If you're using a load balancer or some other method of handling and terminating your SSL before it reaches the bot, you may need to use `DISABLE_SSL`. As mentioned above, Telegram -will not- send non-https requests to your bot! 42 | 43 | ### curl example 44 | ```bash 45 | curl -k -X POST -d '{ "message": "Hello world!" }' https://HOST:PORT/relay/SOURCE_TOKEN 46 | ``` 47 | ### JSON body example with HTML 48 | ```json 49 | { "message": "Alice updated Client XDA Developers account permissions: ADDRESS" } 50 | ``` 51 | 52 | ## Connecting services 53 | Having your service deliver `HTTP POST requests` can be done many ways. If you're using Python or Django, one such way could be to use the [Python logging facility](https://docs.python.org/3/library/logging.html). 54 | 55 | Using this fork of the [Python Logging Loggly Handler](https://github.com/mimicmobile/loggly-python-handler), you can see how a logger would be configured in `Python` / `Django`. 56 | Regardless of how you're sending your requests, your URL is always https://`HOST`:`PORT`/relay/`SOURCE_TOKEN` 57 | 58 | ## Install 59 | _The recommended usage is through Docker._ To install locally clone and install the python requirements: 60 | ```bash 61 | git clone https://github.com/mimicmobile/flask-telegram-relay-bot 62 | pip install -r requirements.txt 63 | ``` 64 | 65 | ## Usage 66 | *Add necessary variables to `variables.env` file* 67 | ### Docker 68 | ```bash 69 | docker run --env-file variables.env --name telegram-bot -p 8443:8443 mimicmobile/flask-telegram-relay-bot 70 | ``` 71 | ### Locally 72 | ```bash 73 | ./scripts/start.sh 74 | ``` 75 | 76 | ## Bot commands 77 | The following commands are currently available: 78 | * `/register` - Registers channel/group to receive relay messages 79 | * `/unregister` - Unregister channel. Bot will leave 80 | * `/mute` - Mute output in _all_ channels 81 | * `/unmute` - Unmute output 82 | * `/about` - About this bot 83 | * `/uptime` - Time elapsed since the bot was started 84 | 85 | ## Thanks 86 | This bot was heavily influenced by [this gist](https://gist.github.com/leandrotoledo/4e9362acdc5db33ae16c) by [leandrotoledo](https://github.com/leandrotoledo) 87 | -------------------------------------------------------------------------------- /bot/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mimicmobile/flask-telegram-relay-bot/fb8279d8588e51e347fc7e6e119aed42c21064d4/bot/__init__.py -------------------------------------------------------------------------------- /bot/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import os 5 | import traceback 6 | 7 | import telegram 8 | from flask import Flask, request, current_app, logging 9 | 10 | from telegram.ext import Dispatcher, CommandHandler 11 | 12 | from utils import Utils 13 | 14 | TOKEN = os.getenv('TOKEN') 15 | SOURCE_TOKEN = os.getenv('SOURCE_TOKEN', "") 16 | HOST = os.getenv('HOST') # Same FQDN used when generating SSL Cert 17 | PORT = int(os.getenv('PORT', 8443)) 18 | CERT = os.getenv('CERT') 19 | CERT_KEY = os.getenv('CERT_KEY') 20 | DISABLE_SSL = os.getenv('DISABLE_SSL') 21 | PERMANENT_CHATS = os.getenv('PERMANENT_CHATS') # Comma separated ids wrapped in a string 22 | OWNER_ID = os.getenv('OWNER_ID') 23 | DEBUG = int(os.getenv('DEBUG', 0)) 24 | 25 | DEBUG_STATE = { 26 | 0: logging.ERROR, 27 | 1: logging.DEBUG 28 | } 29 | 30 | ADMIN_LEVEL = 1 # 1=Channel admins + Owner, 2=Channel admins, 3=Owner only 31 | 32 | telegram_bot = telegram.Bot(TOKEN) 33 | 34 | app = Flask(__name__) 35 | 36 | 37 | @app.route('/healthz') 38 | def healthz(): 39 | return "OK" 40 | 41 | 42 | @app.route('/relay/' + SOURCE_TOKEN, methods=['POST']) 43 | def relay(): 44 | with app.app_context(): 45 | muted = current_app.muted 46 | chats = current_app.chats 47 | if not muted: 48 | try: 49 | request_data = request.get_data().decode('latin-1') 50 | logger.debug("request data: {}".format(request_data)) 51 | parsed_json = json.loads(request_data, strict=False) 52 | except: 53 | traceback.print_exc() 54 | return "ERROR" 55 | for chat in chats: 56 | chat_id = telegram_bot.get_chat(chat).id 57 | utils.send_message(chat_id=chat_id, text=parsed_json['message']) 58 | return "OK" 59 | return "MUTED" 60 | 61 | 62 | @app.route('/relay/' + TOKEN, methods=['POST']) 63 | def webhook(): 64 | update = telegram.update.Update.de_json(request.get_json(force=True), telegram_bot) 65 | logger.debug("webhook update: {}".format(update)) 66 | 67 | utils.set_update(update) 68 | bot_dispatcher.process_update(update) 69 | return "OK" 70 | 71 | 72 | class BotDispatcher: 73 | def __init__(self): 74 | self.dispatcher = Dispatcher(telegram_bot, None, workers=0) 75 | self.dispatcher.add_handler(CommandHandler('register', register)) 76 | self.dispatcher.add_handler(CommandHandler('unregister', unregister)) 77 | self.dispatcher.add_handler(CommandHandler('mute', mute)) 78 | self.dispatcher.add_handler(CommandHandler('unmute', unmute)) 79 | self.dispatcher.add_handler(CommandHandler('about', about)) 80 | self.dispatcher.add_handler(CommandHandler('uptime', uptime)) 81 | 82 | def process_update(self, update): 83 | self.dispatcher.process_update(update) 84 | 85 | 86 | def get_uptime(): 87 | import datetime 88 | import psutil 89 | 90 | from dateutil.relativedelta import relativedelta 91 | 92 | p = psutil.Process(os.getpid()) 93 | created_time = datetime.datetime.fromtimestamp(p.create_time()) 94 | attrs = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'] 95 | human_readable = lambda delta: ['%d %s' % (getattr(delta, attr), 96 | getattr(delta, attr) > 1 and attr or attr[:-1]) 97 | for attr in attrs if getattr(delta, attr)] 98 | return ' '.join(human_readable(relativedelta(datetime.datetime.now(), 99 | created_time))) 100 | 101 | 102 | def about(bot, update): 103 | utils.send_message(chat_id=utils.get_chat().id, 104 | text="Running flask-telegram-relay-bot ({})\n" 105 | "| Built: {}\n" 106 | "| Uptime: {}" 107 | .format('https://github.com/mimicmobile/flask-telegram-relay-bot', 108 | os.getenv('DOCKER_VCS_REF'), 109 | os.getenv('DOCKER_BUILD_DATE'), 110 | get_uptime())) 111 | 112 | 113 | def uptime(bot, update): 114 | utils.send_message(chat_id=utils.get_chat().id, 115 | text="up {}".format(get_uptime())) 116 | 117 | 118 | def register(bot, update): 119 | if has_permission(): 120 | with app.app_context(): 121 | chats = current_app.chats 122 | 123 | chat = utils.get_message().chat 124 | if str(chat.id) not in chats: 125 | chats.append(str(chat.id)) 126 | 127 | with app.app_context(): 128 | current_app.chats = chats 129 | 130 | utils.send_message(chat_id=chat.id, 131 | text="Registered {} to receive updates".format(chat.title)) 132 | else: 133 | permission_denied() 134 | 135 | 136 | def unregister(bot, update): 137 | if has_permission(): 138 | with app.app_context(): 139 | chats = current_app.chats 140 | 141 | chat = utils.get_message().chat 142 | if str(chat.id) in chats: 143 | chats.remove(str(chat.id)) 144 | 145 | with app.app_context(): 146 | current_app.chats = chats 147 | 148 | utils.send_message(chat_id=utils.get_chat().id, 149 | text="Unregistered {}. Bye!".format(utils.get_chat().title)) 150 | 151 | chat.leave() 152 | 153 | else: 154 | permission_denied() 155 | 156 | 157 | def mute(bot, update): 158 | if utils.is_chat_private() or has_permission(): 159 | toggle_mute(True) 160 | else: 161 | permission_denied() 162 | 163 | 164 | def unmute(bot, update): 165 | if utils.is_chat_private() or has_permission(): 166 | toggle_mute(False) 167 | else: 168 | permission_denied() 169 | 170 | 171 | def toggle_mute(is_muted): 172 | with app.app_context(): 173 | current_app.muted = is_muted 174 | 175 | muted_str = "off" 176 | if is_muted: 177 | muted_str = "on" 178 | 179 | utils.send_message(chat_id=utils.get_chat().id, 180 | text="Turning mute {}".format(muted_str)) 181 | 182 | 183 | def has_permission(): 184 | if ADMIN_LEVEL == 1: 185 | return utils.is_user_admin() or utils.is_chat_all_admins() or utils.matches_user_id(OWNER_ID) 186 | elif ADMIN_LEVEL == 2: 187 | return utils.is_user_admin() or utils.is_chat_all_admins() 188 | elif ADMIN_LEVEL == 3: 189 | return utils.matches_user_id(OWNER_ID) 190 | 191 | 192 | def permission_denied(): 193 | utils.send_message(chat_id=utils.get_chat().id, 194 | reply_to_message_id=utils.get_message().message_id, 195 | text="You're not my mom!") 196 | 197 | 198 | def set_webhook(): 199 | if DISABLE_SSL: 200 | cert = None 201 | else: 202 | cert = open(CERT, 'rb') 203 | 204 | response = telegram_bot.set_webhook(url='https://%s:%s/relay/%s' % (HOST, PORT, TOKEN), 205 | certificate=cert, timeout=20) 206 | logger.debug("set_webhook response: {}".format(response)) 207 | 208 | 209 | def init(): 210 | set_webhook() 211 | 212 | if PERMANENT_CHATS: 213 | chats = PERMANENT_CHATS.split(',') 214 | 215 | with app.app_context(): 216 | current_app.muted = False 217 | try: 218 | current_app.chats = chats 219 | except AttributeError: 220 | current_app.chats = [] 221 | 222 | logger.debug("Added {} chats on start {}".format(len(chats), chats)) 223 | else: 224 | logger.debug("No chats added on start") 225 | 226 | if not SOURCE_TOKEN: 227 | logger.debug("SOURCE_TOKEN required to receive relays") 228 | exit() 229 | 230 | params = { 231 | 'host': '0.0.0.0', 232 | 'port': PORT 233 | } 234 | 235 | if CERT and CERT_KEY: 236 | params['ssl_context'] = (CERT, CERT_KEY) 237 | 238 | return params 239 | 240 | 241 | bot_dispatcher = BotDispatcher() 242 | utils = Utils(telegram_bot) 243 | 244 | logger = logging.getLogger() 245 | logger.handlers = logging.getLogger('gunicorn.error').handlers 246 | logger.setLevel(DEBUG_STATE[DEBUG]) 247 | 248 | app_params = init() 249 | 250 | 251 | if __name__ == '__main__': 252 | app.run(**app_params) 253 | -------------------------------------------------------------------------------- /bot/mwt.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | # http://code.activestate.com/recipes/325905-memoize-decorator-with-timeout/#c1 5 | class MWT(object): 6 | """Memoize With Timeout""" 7 | _caches = {} 8 | _timeouts = {} 9 | 10 | def __init__(self,timeout=2): 11 | self.timeout = timeout 12 | 13 | def collect(self): 14 | """Clear cache of results which have timed out""" 15 | for func in self._caches: 16 | cache = {} 17 | for key in self._caches[func]: 18 | if (time.time() - self._caches[func][key][1]) < self._timeouts[func]: 19 | cache[key] = self._caches[func][key] 20 | self._caches[func] = cache 21 | 22 | def __call__(self, f): 23 | self.cache = self._caches[f] = {} 24 | self._timeouts[f] = self.timeout 25 | 26 | def func(*args, **kwargs): 27 | kw = sorted(kwargs.items()) 28 | key = (args, tuple(kw)) 29 | try: 30 | v = self.cache[key] 31 | print("cache") 32 | if (time.time() - v[1]) > self.timeout: 33 | raise KeyError 34 | except KeyError: 35 | print("new") 36 | v = self.cache[key] = f(*args,**kwargs),time.time() 37 | return v[0] 38 | func.func_name = f.__name__ 39 | 40 | return func 41 | -------------------------------------------------------------------------------- /bot/utils.py: -------------------------------------------------------------------------------- 1 | from telegram import Chat, ParseMode 2 | 3 | from mwt import MWT 4 | 5 | 6 | class Utils: 7 | 8 | def __init__(self, bot): 9 | self.bot = bot 10 | self.update = None 11 | 12 | def set_update(self, update): 13 | print("set_update {}".format(update)) 14 | self.update = update 15 | 16 | def is_chat_private(self): 17 | return self.get_chat().type == Chat.PRIVATE 18 | 19 | def is_user_admin(self): 20 | return self.update.message.from_user.id in self.get_admin_ids() 21 | 22 | @MWT(timeout=60*15) 23 | def get_admin_ids(self): 24 | return [admin.user.id for admin in self.bot.get_chat_administrators(self.update.message.chat_id)] 25 | 26 | def is_chat_all_admins(self): 27 | return self.get_chat().all_members_are_administrators 28 | 29 | def get_chat(self): 30 | return self.update.effective_chat 31 | 32 | def get_chatroom(self): 33 | return self.update.message.chat 34 | 35 | def get_message(self): 36 | return self.update.message 37 | 38 | def get_user(self): 39 | return self.update.effective_user 40 | 41 | def send_message(self, *args, **kwargs): 42 | kwargs.update({'parse_mode': ParseMode.HTML, 'timeout': 20}) 43 | self.bot.send_message(*args, **kwargs) 44 | 45 | def matches_user_id(self, owner_id): 46 | return str(self.update.message.from_user.id) == owner_id 47 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | bot: 5 | build: 6 | context: . 7 | # There are a number of variables we need to define before we can launch this service 8 | # At a minimum you must provide: 9 | # HOST 10 | # (Your FQDN that Telegram connects to for webhook events) 11 | # TOKEN 12 | # (Your telegram generated token from BotFather) 13 | # SOURCE_TOKEN 14 | # (A token of your choosing that your source connects to to relay) 15 | # 16 | # The most convenient way is to create a variables.env file and store each variable there 17 | env_file: 18 | - variables.env 19 | ports: 20 | # Change this if you've specified a different port 21 | - 8443:8443 -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $IMAGE_NAME var is injected into the build so the tag is correct. 4 | 5 | echo "Build hook running" 6 | docker build --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \ 7 | --build-arg VCS_REF=`git rev-parse --short HEAD` \ 8 | -t $IMAGE_NAME . -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2018.8.24 2 | click==6.7 3 | Flask==0.12.3 4 | future==0.16.0 5 | gevent==1.2.2 6 | greenlet==0.4.12 7 | gunicorn==19.7.1 8 | python-telegram-bot==11.1.0 9 | dateutils==0.6.6 10 | psutil==5.4.6 11 | -------------------------------------------------------------------------------- /scripts/generate_ssl_cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(echo $PWD | sed 's/\/scripts//') # Strip off scripts/ dir if we're in there 4 | 5 | if [ ! -e "$DIR/certs/cert.pem" ] || [ ! -e "$DIR/certs/key.pem" ] 6 | then 7 | 8 | if [ -z "$HOST" ]; then 9 | echo "No \$HOST env var defined. Cannot generate SSL cert!!" 10 | exit 11 | fi 12 | 13 | [ -d $DIR/certs ] || mkdir $DIR/certs 14 | echo ">> generating self signed cert" 15 | openssl req -x509 -newkey rsa:4086 \ 16 | -subj "/C=XX/ST=XXXX/L=XXXX/O=XXXX/CN=${HOST}" \ 17 | -keyout "$DIR/certs/key.pem" \ 18 | -out "$DIR/certs/cert.pem" \ 19 | -days 3650 -nodes -sha256 20 | fi -------------------------------------------------------------------------------- /scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(echo $PWD | sed 's/\/scripts//') # Strip off scripts/ dir if we're in there 4 | cd $DIR 5 | 6 | if [ -e "./variables.env" ]; then 7 | set -a; . ./variables.env 8 | fi 9 | 10 | if [[ -z "$DOCKER_BUILD_DATE" && -x "$(command -v git)" ]]; then 11 | DOCKER_VCS_REF=$(git show -s --format=%h HEAD) 12 | DOCKER_BUILD_DATE=$(git show -s --format=%ci HEAD) 13 | fi 14 | 15 | if ! [ -z "$DOCKER_BUILD_DATE" ]; then 16 | echo "" 17 | echo "Build date ($DOCKER_BUILD_DATE) VCS ref ($DOCKER_VCS_REF)" 18 | fi 19 | 20 | if [ -z "$DISABLE_SSL" ]; then 21 | ./scripts/generate_ssl_cert.sh 22 | SSL_PARAMS="--keyfile ../certs/key.pem --certfile ../certs/cert.pem" 23 | fi 24 | 25 | 26 | # Setup default port 27 | if [ -z "$PORT" ]; then 28 | PORT=8443 29 | fi 30 | 31 | if [[ -z "$HOST" || -z "$TOKEN" || -z "$SOURCE_TOKEN" ]]; then 32 | echo "" 33 | echo "You MUST launch this docker container with at least the follow env variables:" 34 | echo "" 35 | echo " HOST (Your FQDN that Telegram connects to for webhook events)" 36 | echo " TOKEN (Your telegram generated token from BotFather)" 37 | echo " SOURCE_TOKEN (A token of your choosing that your source connects to to relay)" 38 | echo "" 39 | echo "i.e. HOST=example.com TOKEN=ASHFL:KU296_DSAFKLAH90 SOURCE_TOKEN=ABC1234" 40 | echo " Your source would send JSON payloads to https://example.com:8443/ABC1234" 41 | echo " Telegram would send webhook events to https://example.com:8443/ASHFL:KU296_DSAFKLAH90" 42 | echo "" 43 | exit 44 | fi 45 | 46 | echo "" 47 | echo "Send POST requests to:" 48 | echo "" 49 | echo " https://$HOST:$PORT/relay/$SOURCE_TOKEN" 50 | echo "" 51 | echo " Test using curl:" 52 | echo " $ curl -k -X POST -d '{\"message\": \"Hello world!\"}' https://$HOST:$PORT/relay/$SOURCE_TOKEN" 53 | echo "" 54 | 55 | cd bot && \ 56 | gunicorn \ 57 | -w 1 \ 58 | -k gevent \ 59 | $SSL_PARAMS \ 60 | -e SOURCE_TOKEN=$SOURCE_TOKEN \ 61 | -e DISABLE_SSL=$DISABLE_SSL \ 62 | -e HOST=$HOST \ 63 | -e CERT=../certs/cert.pem \ 64 | -e TOKEN=$TOKEN \ 65 | -e "DOCKER_BUILD_DATE=$DOCKER_BUILD_DATE" \ 66 | -e DOCKER_VCS_REF=$DOCKER_VCS_REF \ 67 | -b 0.0.0.0:$PORT \ 68 | main:app 69 | 70 | cd .. 71 | --------------------------------------------------------------------------------