Why cannot I receive any POST request on my Telegram bot written with Flask (Python)?

a 夏天 提交于 2020-07-07 07:18:25

问题


I don't want to use getUpdates method to retrieve updates from Telegram, but a webhook instead.

Error from getWebhookInfo is:

has_custom_certificate: false,
pending_update_count: 20,
last_error_date: 1591888018,
last_error_message: "SSL error {error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}"

My code is:

from flask import Flask
from flask import request
from flask import Response

app = Flask(__name__)

@app.route('/', methods=['POST', 'GET']) 
def bot():
    if request.method == 'POST':
        return Response('Ok', status=200)
    else:
        return f'--- GET request ----'

if __name__ == "__main__":
    app.run(host='0.0.0.0', port='8443', debug=True, ssl_context=('./contract.crt', '.private.key'))

When I hit https://www.mydomain.ext:8443/ I can see GET requests coming but not POST ones when I write something on my telegram-bot chat Also that's how I set a webhook for telegram as follow:

https://api.telegram.org/botNUMBER:TELEGRAM_KEY/setWebhook?url=https://www.mydomain.ext:8443

result:

{
  ok: true,
  result: true,
  description: "Webhook was set"
}

Any suggestion or something wrong I've done?

https://core.telegram.org/bots/api#setwebhook

I'm wondering if the problem it's caused because I'm using 0.0.0.0, the reason it's that if I use 127.0.0.0 the url/www.mydomain.ext cannot be reached

Update

ca_certitificate = {'certificate': open('./folder/ca.ca-bundle', 'rb')}
r = requests.post(url, files=ca_certitificate)
print(r.text)

that print gives me:

{
  "ok": false,
  "error_code": 400,
  "description": "Bad Request: bad webhook: Failed to set custom certificate file"
 }

回答1:


I think the issue you're facing is with the certificate.

As you can see from the docs about setWebhook (under Notes section):

To use a self-signed certificate, you need to upload your public key certificate using certificate parameter. Please upload as InputFile, sending a String will not work.

You may run a script like the following once to setup the webhook with certificate:

import requests

BOT_TOKEN = 'BOT TOKEN'

cert =  'contracts.crt'

url = 'https://www.mydomain.ext:8443'

message = f"https://api.telegram.org/bot{BOT_TOKEN}/setWebhook?url={url}"
send = requests.post(message, files = {
    'certificate': open(cert, 'rb')
})

I hope this solves the issue.




回答2:


I deployed a Telegram chatbot without Flask a while ago. I remember that the POST and GET requests required /getUpdates and /sendMessage added to the bot url. Maybe it will help.




回答3:


Telegram bots only works with full chained certificates. And the error in your getWebHookInfo:

"last_error_message":"SSL error {337047686, error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}"

Is the Telegram saying that it needs the whole certificate chain (it's also called CA Bundle or full chained certificate). as answered on the question.

If you validate your certificate using the SSLlabs you will see that your domain have chain issues:

https://www.ssllabs.com/ssltest/analyze.html?d=www.vallotta-party-bot.com&hideResults=on

To solve this need you need to set set the CA Certificate. In this way you need to find the CA certificate file with your CA provider.

Also, the best option in production sites is use gunicorn instead of Flask.

If you are using gunicorn, you can do this with command line arguments:

$ gunicorn --certfile cert.pem --keyfile key.pem --ca_certs cert.ca-bundle -b 0.0.0.0:443 hello:app

Or create a gunicorn.py with following content:

import multiprocessing

bind = "0.0.0.0:443"

workers = multiprocessing.cpu_count() * 2 + 1

timeout = 120

certfile = "cert/certfile.crt"

keyfile = "cert/service-key.pem"

ca_certs = "cert/cert.ca-bundle"

loglevel = 'info'

and run as follows:

gunicorn --config=gunicorn.py hello:app

If you use nginx as a reverse proxy, then you can configure the certificate with nginx, and then nginx can "terminate" the encrypted connection, meaning that it will accept encrypted connections from the outside, but then use regular unencrypted connections to talk to your Flask backend. This is a very useful set up, as it frees your application from having to deal with certificates and encryption. The configuration items for nginx are as follows:

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    # ...
}

Another important item you need to consider is how are clients that connect through regular HTTP going to be handled. The best solution, in my opinion, is to respond to unencrypted requests with a redirect to the same URL but on HTTPS. For a Flask application, you can achieve that using the Flask-SSLify extension. With nginx, you can include another server block in your configuration:

server {
    listen 80;
    server_name example.com;
    location / {
        return 301 https://$host$request_uri;
    }
}

A good tutorial of how setup your application with https can be found here: Running Your Flask Application Over HTTPS



来源:https://stackoverflow.com/questions/62325866/why-cannot-i-receive-any-post-request-on-my-telegram-bot-written-with-flask-pyt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!