Загрузка...

[LAVA Business API & FastAPI] Webhook Signature verification

Thread in Python created by Toil Mar 17, 2023. 563 views

  1. Toil
    Toil Topic starter Mar 17, 2023 ������� ������ :coder: 3,500 Nov 18, 2018
    Уже, все, возможные, варианты перепробовал, и всё, никак, не могу понять, почему не совпадает сигнатура, которая приходит с ответом и генерируемая мной на сервере.

    Делаю всё по оф. докам, но в них не сильно понятно на счёт момента с генерацией подписи для проверки вебхука, понял, только, то, что используется та же функция, что и для подписи запроса, но, только, с помощью доп. ключа (в коде - LAVA_SECRET2), а не основного. Всё сделал - не работает. И самое странное, что, этот же, код (sign_hmac_sha256), отлично работает для подписи запроса на выставление счета на оплату и запрос проходит.

    Имеется, такой, код вебхука проверки оплаты (прикреплена упрощенная версия, где убран функционал, который идет, уже после проверки на сигнатуру):

    Python

    # /api/callback/lava
    @router.post('/lava', summary = 'Callback for lava payments')
    async def index(data: LavaRequest, signature = Header(default="", alias="Authorization")):
    """Callback for lava payments"""
    log.debug(locals())
    if signature and data:
    if data.status != 'success':
    log.debug('privilege not yet been paid')
    return JSONResponse(content = {'error': 'Privilege has not yet been paid'}, status_code = status.HTTP_402_PAYMENT_REQUIRED)

    secret2 = os.environ.get('LAVA_SECRET2')
    server_sign = sign_hmac_sha256(data.dict(), secret2) # сортировка словаря тоже не помогает

    log.debug(server_sign)
    if server_sign != signature:
    log.debug('wrong sign')
    return JSONResponse(content = {'error': 'Wrong sign'}, status_code = status.HTTP_403_FORBIDDEN)
    ...
    return JSONResponse(content = {'error': 'Request is wrong'}, status_code = status.HTTP_403_FORBIDDEN)


    Код класса LavaRequest (полностью совпадает с "request.json()", поэтому проблема явно не в нем):
    Python

    from pydantic import BaseModel


    class LavaRequest(BaseModel):
    invoice_id: str
    status: str
    pay_time: str
    amount: str
    order_id: str
    pay_service: str
    payer_details: str
    custom_fields: str
    type: int
    credited: str

    Код функции "sign_hmac_sha256" (при генерации ссылки на оплату всё нормально работает, поэтому, мне кажется, что дело, так же, не в этой функции):
    Python
    import hmac
    import json
    from hashlib import md5, sha1, sha256


    def sign_hmac_sha256(data: dict, secret: str):
    json_str = json.dumps(data).encode()
    return hmac.new(bytes(secret, 'UTF-8'), json_str, sha256).hexdigest()

    Входящие данные (тип: json; значения invoice_id, order_id, payer_details отредактированы, дабы не палить реальные данные запроса) :
    JS
    {
    'invoice_id': '11c57588-625f-4c37-bf09-71596539bb07',
    'status': 'success',
    'pay_time': '2023-03-16 23:50:40',
    'amount': '15.00',
    'order_id': '1s53g797e3211f73a7d11992b8cedd76',
    'pay_service': 'card',
    'payer_details': '111999******1199',
    'custom_fields': '11,15,idToil,#TESTTEXT',
    'type': 1,
    'credited': '14.62'
    }

    Может быть, кто-нибудь может помочь советом - что я делаю не так, или подсказать, где найти какой-нибудь пример вебхука для лавы с новым апи. Всё перерыл, но ничего не нашёл, кроме лава сдк для пхп, где по сути, код такой же (там, используется сортировка ключей словаря (ksort) - пробовал создавать сигнатуру, тоже, с сортировкой ключей, но, всё равно, получается не правильная сигнатура)

    Python
    def sort_dict(data: dict):
    sorted_tuple = sorted(data.items(), key=lambda x: x[0])
    return dict(sorted_tuple)
     
  2. Toil
    Toil Topic starter Mar 17, 2023 ������� ������ :coder: 3,500 Nov 18, 2018
    Нашёл, всё, таки, в чем была проблема. Проблема была в том, что json.dumps автоматически ставит пробелы и получается вот такая строка:
    Code
    {"amount": "15.00", "credited": "14.62", "custom_fields": ...}
    в то время, когда она должна быть такой (без пробелов):
    Code
    {"amount":"15.00","credited":"14.62","custom_fields":...}
    Как же я это решил? Добавил "separators=(',', ':')" в функцию json.dumps:
    Python
    def sign_hmac_sha256(data: dict, secret: str):
    json_str = json.dumps(data, separators=(',', ':')).encode()
    return hmac.new(bytes(secret, 'UTF-8'), json_str, sha256).hexdigest()
    Надеюсь этот ответ, кому-то в будущем поможет, кто так же столкнется с этим
    P.S:. так же, словарь должен быть отсортированным
     
Loading...