次の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つの理由で403エラーが発生します。 ViberからのWebhookリクエストをシミュレートするには、_X-Viber-Content-Signature
_ヘッダーを送信する必要があります。また、この値は、APIのドキュメントの Callbacks で説明されているように、認証トークンとWebhookペイロードを使用して計算されたSHA256ハッシュである必要があります。
ここには2つの選択肢があると思います。コードがWebhookを正しく受信したことを確認するだけの場合は、verify_signature()
行を一時的にコメント化できます。 Webhookリクエストの検証はViber(または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()
関数を指摘していることに注意してください。これは、署名の計算方法を示しています。
更新されたため、編集されました。 _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')
は異なります。そのため、禁止メッセージが表示されます。