如何使用 Python 向 Viber 机器人发送消息?

Posted

技术标签:

【中文标题】如何使用 Python 向 Viber 机器人发送消息?【英文标题】:How to send message to Viber bot with Python? 【发布时间】:2019-07-26 15:02:31 【问题描述】:

我有以下 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)

【问题讨论】:

请确认您的 webhook 发送代码仅用于测试目的。如果是这样,我会尽快提供答案。 我只想向 Viber 机器人发送“Hello World”消息,仅用于真正的第一步。然后我会尝试做一些更复杂的事情 【参考方案1】:

您收到 403 错误有两个原因。要模拟来自 Viber 的 webhook 请求,您必须发送 X-Viber-Content-Signature 标头。此外,此值必须是使用身份验证令牌和 webhook 有效负载计算的 SHA256 哈希,如其 API 文档中所述,Callbacks。

我相信您在这里有 2 个选择。如果您只想验证您的代码是否正确接收了 webhook,您可以暂时注释掉 verify_signature() 行。 Viber(或任何 webhook 源)不需要验证 webhook 请求。通常,开发人员会假设像 Viber 提供的库这样的库可以正确测试他们的代码,因此通常不需要再次测试他们的功能。您也可以考虑模拟该函数,因为在这种情况下这非常简单。

如果你真的想测试 Viber 的签名验证,那么你需要实现我首先提到的 2 个原因。这基本上是您在测试 webhook 发送代码中需要做的事情。请注意,我只在下面包含了您需要的新代码,请合并到您的其他测试代码中。

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 指出了 viber-bot-python 存储库中的 _calculate_message_signature() 函数,该函数显示了签名的计算方式。

【讨论】:

【参考方案2】:

已编辑由于更新。您在 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) 的结果

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

我会检查您在self._bot_configuration.auth_token.encode('ascii') 中使用的auth_token。它是否包括非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') 这是不同的,这就是你收到禁止消息的原因。

【讨论】:

这个403来自:如果不是viber.verify_signature(request.get_data(), request.headers.get('X-Viber-Content-Signature')): return Response(status=403) @DmitrijKultasev 所以你有错误的签名不是吗? 是的,因为我不知道如何发送正确的请求。 @DmitrijKultasev 我明白了。由于您的更新问题,我已经更新了答案。请看看是否有帮助

以上是关于如何使用 Python 向 Viber 机器人发送消息?的主要内容,如果未能解决你的问题,请参考以下文章

从 Viber bot 向 botbuilder-viber 发送消息时出现错误 ERR_INVALID_ARG_TYPE

Viber REST API,如何找到唯一的 Viber 用户 ID?

如何从 Youtube 向 discord bot python 发送视频

如何主动向团队频道发送消息

如何让 Discord.py 机器人向服务器所有者发送消息?

从Viber bot发送消息给订阅用户