Slack Interactive Messages: полезная нагрузка POST-запроса имеет неожиданный формат - PullRequest
0 голосов
/ 24 октября 2018

Я получаю POST-запрос в приложении Flask от Slack.Запрос отправляется, когда пользователь нажимает кнопку интерактивного сообщения.Согласно Slack docs я должен извлечь тело запроса для проверки подписи.Моя вычисленная подпись не совпадает с той, что прислал Slack.Фактически, тело запроса представляет собой некоторую закодированную строку.Строка на самом деле представляет собой закодированный словарь вместо параметров запроса str, как и ожидалось.

Вот начало моего представления:

@app.route('/register', methods=['POST'])
def register_visit():
    data = request.get_data()
    signature = request.headers.get('X-Slack-Signature', None)
    timestamp = request.headers.get('X-Slack-Request-Timestamp', None)
    signing_secret = b'aaaaaaaaaaaaaaaa'


    # old message, ignore
    if round(actual_time.time() - float(timestamp)) > 60 * 5:
        return
    concatenated = ("v0:%s:%s" % (timestamp, data)).encode('utf-8')
    computed_signature = 'v0=' + hmac.new(signing_secret, msg=concatenated, digestmod=hashlib.sha256).hexdigest()
    if hmac.compare_digest(computed_signature, signature):
        ...

Я попытался отформатировать полученные данные, чтобы сделатьэто выглядит так:

token=fdjkgjl&user_id=1234... но я не знаю всех необходимых параметров, которые должны присутствовать в данных.

Любые идеи высоко ценятся.

Тело сообщения следующее - после декодирования URL (обратите внимание, что я изменил, возможно, конфиденциальные данные):

b'payload = {"type": "interactive_message", "actions":[{ "имя": "yes_button", "тип": "кнопка", "значение": "236"}], "callback_id": "visit_button", "команда": { "ID": "FFFFF",»домен ":" FFFF "}," канал ": {" идентификатор ":" FFFF», "название": "directmessage"}, "пользователь": { "идентификатор": "FFFFFF", "название": "fffft"}, "action_ts": "1540403943,419120", "message_ts": "1541403949,000100", "attachment_id": "1", "маркер": "8LpjBuv13J7xAjhl2lEajoBU", "is_app_unfurl" ложь "original_message": { "текст":»Тест " "bot_id": "DDDDDDDDD", "вложения": [{ "callback_id":" visit_button», "Текст": "Регистрация", "идентификатор": 1, "цвет": "3AA3E3", "действия": [{ "ID": "1", "имя": "yes_button", "текст": "Да", "тип": "кнопка", "значение": "236", "стиль": ""}], "запасной вариант": "Регистрация"}], "типа": "сообщение", "подтип":" bot_message "," ts ":" 1540413949.000100 "}," response_url ":" https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":"464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

ОК, проблема не связана с тем, как Слэк отправляет мне сообщение.Речь шла о недопонимании того, какие данные поступают в виде байтов, а какие - в юникоде.Виновником было форматирование строк в моем случае - строка concatenated = ("v0:%s:%s" % (timestamp, data)).encode('utf-8') должна была быть concatenated = (b"v0:%b:%b" % (timestamp.encode("utf-8"), data)).Данные уже байты, временная метка пока что в юникоде.Не могу поверить, что я ударился об это часами -_-

@app.route('/register', methods=['POST'])
def register_visit():
    data = request.get_data()
    signature = request.headers.get('X-Slack-Signature', None)
    timestamp = request.headers.get('X-Slack-Request-Timestamp', None)
    signing_secret = b'aaaaaaaaaaaaaaaa'
    # old message, ignore
    if round(actual_time.time() - float(timestamp)) > 60 * 5:
        return
    concatenated = (b"v0:%b:%b" % (timestamp.encode("utf-8"), data))
    computed_signature = 'v0=' + hmac.new(signing_secret, msg=concatenated, 
    digestmod=hashlib.sha256).hexdigest()
    if hmac.compare_digest(computed_signature, signature):
        ...
0 голосов
/ 24 октября 2018

Причиной получения "искаженных" данных является то, что вы используете request.get_data().Этот метод возвращает необработанные данные запроса, но не выполняет никакого декодирования для вас.

Гораздо удобнее использовать request.form.get('payload'), который непосредственно даст вам строку JSON:объект запроса.Затем вы можете преобразовать это в объект dict с помощью json.loads() для дальнейшей обработки в вашем приложении.

Обратите внимание, что полученный вами формат является правильным форматом для интерактивных сообщений.Вы не получите строку запроса (например, «token = abc; user_id? Def ...»), как вы предлагали (например, для запросов команды слэша).Интерактивный запрос сообщения всегда будет содержать запрос в виде строки JSON в свойстве формы полезной нагрузки.См. здесь для справки.

Вот простой рабочий пример, который ответит на приветствие пользователю, который нажал кнопку.Он будет работать напрямую со Slack, но я рекомендую использовать Почтальон для его проверки.

#app.py

from flask import Flask, request #import main Flask class and request object
import json

app = Flask(__name__) #create the Flask app

@app.route('/register', methods=['POST'])
def register_visit():
    slack_req = json.loads(request.form.get('payload'))
    response = '{"text": "Hi, <@' + slack_req["user"]["id"] + '>"}'
    return response, 200, {'content-type': 'application/json'}

if __name__ == '__main__':
    app.run(debug=True, port=5000) #run app in debug mode on port 5000
...