Как отправить сообщение боту Viber с Python? - PullRequest
0 голосов
/ 05 марта 2019

У меня следующий HTTPS-сервер:

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)

и я пытаюсь отправить сообщение:

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)
    )

Я получаю 403 ошибку

ValueError:Запрос вернул ошибку 403, ответ:

ОБНОВЛЕНИЕ:

403 исходит от:

if not viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')):
        return Response(status=403)

Ответы [ 2 ]

0 голосов
/ 07 марта 2019

Вы получаете ошибку 403 по 2 причинам.Чтобы смоделировать запрос webhook от Viber, вы должны отправить заголовок X-Viber-Content-Signature.Также это значение должно быть хешем SHA256, вычисленным с использованием токена аутентификации и полезной нагрузки webhook, как описано в их документах по API в разделе Обратные вызовы .

. Я полагаю, у вас есть 2 варианта здесь.Если вы хотите просто проверить, правильно ли ваш код получает веб-крючок, вы можете временно закомментировать строки verify_signature().Viber (или любой другой источник webhook) не требует проверки запросов webhook.Обычно разработчик полагает, что библиотека, подобная той, что предоставляется Viber, правильно тестирует свой код, поэтому обычно нет необходимости снова тестировать их функциональность.Вы также можете подумать о создании этой функции, поскольку в этом случае это очень просто.

Если вы действительно хотите проверить проверку подписи Viber, вам нужно будет реализовать две причины, которые я упомянул в первую очередь.Вот в основном то, что вам нужно сделать в своем тестовом отправляющем коде.Обратите внимание, что я включил только новый код, который вам нужен ниже, пожалуйста, объедините его с другим вашим тестовым кодом.

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'
)

Обратите внимание, что @tukan указал на функцию _calculate_message_signature() в viber-bot-python репо, который показывает, как вычисляется подпись.

0 голосов
/ 07 марта 2019

Отредактировано из-за обновления.Вы получаете сообщение об ошибке verify_signature.

Определение verify_signature:

def verify_signature(self, request_data, signature):
    return signature == self._calculate_message_signature(request_data)

Вы отправляете туда request.headers.get('X-Viber-Content-Signature') в качестве "подписи",Поэтому решение для вас состоит в том, чтобы проверить результат __calculate_message_signature (request_data)

requireiest_data = request.get_data () в вашем случае.

Определение _calculate_message_signature:

    def _calculate_message_signature(self, message):
        return hmac.new(
            bytes(self._bot_configuration.auth_token.encode('ascii')),
            msg=message,
            digestmod=hashlib.sha256)\
.hexdigest()

Я бы проверил ваш auth_token, который используется в self._bot_configuration.auth_token.encode('ascii').Включает ли он символы не ascii?Если да, то у вас есть причина.(как пример)

Попробуйте сравнить результат:

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'), который отличается, и поэтому вы получаете запрещенное сообщение.

...