J'ai le serveur HTTPS suivant:
from flask import Flask, request, Response
from viberbot import Api
from viberbot.api.bot_configuration import BotConfiguration
from viberbot.api.messages import VideoMessage
from viberbot.api.messages.text_message import TextMessage
import logging
from viberbot.api.viber_requests import ViberConversationStartedRequest
from viberbot.api.viber_requests import ViberFailedRequest
from viberbot.api.viber_requests import ViberMessageRequest
from viberbot.api.viber_requests import ViberSubscribedRequest
from viberbot.api.viber_requests import ViberUnsubscribedRequest
logger = logging.getLogger(__name__)
app = Flask(__name__)
viber = Api(BotConfiguration(
name='PythonSampleBot',
avatar='http://www.clker.com/cliparts/3/m/v/Y/E/V/small-red-Apple-hi.png',
auth_token='xxx-xxx-xxx'
))
@app.route('/', methods=['POST'])
def incoming():
logger.debug("received request. post data: {0}".format(request.get_data()))
# every viber message is signed, you can verify the signature using this method
if not viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')):
return Response(status=403)
# this library supplies a simple way to receive a request object
viber_request = viber.parse_request(request.get_data())
if isinstance(viber_request, ViberMessageRequest):
message = viber_request.message
# lets echo back
viber.send_messages(viber_request.sender.id, [
message
])
Elif isinstance(viber_request, ViberSubscribedRequest):
viber.send_messages(viber_request.get_user.id, [
TextMessage(text="thanks for subscribing!")
])
Elif isinstance(viber_request, ViberFailedRequest):
logger.warn(
"client failed receiving message. failure: {0}".format(viber_request))
return Response(status=200)
def set_webhook(viber_bot):
viber_bot.set_webhook('https://xxx.xxx.xxx.xxx:4443')
logging.info("Web hook has been set")
if __name__ == "__main__":
context = ('certificate.pem', 'key.pem')
app.run(Host='0.0.0.0', port=4443, debug=True, ssl_context=context)
et essayer d'envoyer un message:
import json
import requests
webhook_url = 'https://xxx.xxx.xxx.xxx:4443'
data = {
"receiver": "xxx-xxx-xxx",
"type": "text",
"text": "Hello world!"
}
response = requests.post(
webhook_url, data=json.dumps(data),
headers={'Content-Type': 'application/json'},
verify='E:\\Docs\\learn_py\\viberbot\\certificate.pem'
)
if response.status_code != 200:
raise ValueError(
'Request returned an error %s, the response is:\n%s'
% (response.status_code, response.text)
)
Je reçois une erreur 403
ValueError: la demande a renvoyé une erreur 403, la réponse est:
METTRE À JOUR:
Le 403 provient de:
if not viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')):
return Response(status=403)
Vous obtenez l'erreur 403 pour 2 raisons. Pour simuler une demande de webhook de Viber, vous devez envoyer l'en-tête X-Viber-Content-Signature
. Cette valeur doit également être un hachage SHA256 calculé à l'aide du jeton d'authentification et de la charge utile du webhook comme décrit dans leurs documents API sous Callbacks .
Je crois que vous avez 2 choix ici. Si vous souhaitez simplement vérifier que votre code reçoit correctement le webhook, vous pouvez simplement commenter temporairement les lignes verify_signature()
. La validation des demandes de webhook n'est pas requise par Viber (ou toute autre source de webhook). En règle générale, un développeur suppose qu'une bibliothèque comme celle fournie par Viber teste correctement son code, il n'est donc généralement pas nécessaire de tester à nouveau ses fonctionnalités. Vous pouvez également envisager de vous moquer de la fonction, car c'est très simple dans ce cas.
Si vous voulez vraiment tester la validation de signature de Viber, alors vous devrez implémenter les 2 raisons que j'ai mentionnées en premier. Voici essentiellement ce que vous devez faire dans votre code d'envoi de webhook de test. Notez que je n'ai inclus que le nouveau code dont vous avez besoin ci-dessous, veuillez fusionner dans votre autre code de test.
import json
import hmac
import hashlib
# Compute SHA256 hex digest signature using auth token and payload.
auth_token = 'xxx-xxx-xxx'
signature = hmac.new(
key=auth_token.encode('ascii'),
msg=data.encode('ascii'),
digestmod=hashlib.sha256
).hexdigest()
# Send test webhook request with computed signature in header.
response = requests.post(
webhook_url,
data=json.dumps(data),
headers={
'X-Viber-Content-Signature': signature,
'Content-Type': 'application/json'
},
verify='E:\\Docs\\learn_py\\viberbot\\certificate.pem'
)
Notez que @tukan a souligné la fonction _calculate_message_signature()
dans le repo viber-bot-python , qui montre comment la signature est calculée.
Modifié en raison de la mise à jour. Vous obtenez une erreur sur verify_signature
.
La définition de verify_signature
:
def verify_signature(self, request_data, signature):
return signature == self._calculate_message_signature(request_data)
Vous y envoyez une request.headers.get('X-Viber-Content-Signature')
en tant que `signature. La solution pour vous est donc de vérifier le résultat de __calculate_message_signature (request_data)
requiest_data = request.get_data () dans votre cas.
La définition de _calculate_message_signature
Est:
def _calculate_message_signature(self, message):
return hmac.new(
bytes(self._bot_configuration.auth_token.encode('ascii')),
msg=message,
digestmod=hashlib.sha256)\
.hexdigest()
Je vérifierais votre auth_token
Qui est utilisé dans self._bot_configuration.auth_token.encode('ascii')
. Comprend-il des caractères non ascii? Si oui, alors vous avez la raison. (comme exemple)
Essayez de comparer le résultat de:
hmac.new(bytes(self._bot_configuration.auth_token.encode('ascii')),
msg=request.get_data(),
digestmod=hashlib.sha256).hexdigest()
à:
request.headers.get('X-Viber-Content-Signature')
qui est différent et c'est pourquoi vous recevez un message interdit.