From 323255ce972ce28fb2867de0b273d1e06c3ff72c Mon Sep 17 00:00:00 2001 From: Marco Gil Date: Thu, 8 Jan 2026 09:38:10 +0100 Subject: [PATCH] PTHMINT-96: Webhook validation for payloads with Unicode characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update Webhook.validate to use ensure_ascii=False during JSON reconstruction. - Add unit test for Unicode support in webhook validation (e.g., 'ñ', '€'). (Fix) --- src/multisafepay/util/webhook.py | 1 + .../unit/util/test_unit_webhook.py | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/multisafepay/util/webhook.py b/src/multisafepay/util/webhook.py index 333d631..c311f4d 100644 --- a/src/multisafepay/util/webhook.py +++ b/src/multisafepay/util/webhook.py @@ -57,6 +57,7 @@ def validate( transaction_compact_json = json.dumps( transaction_json, separators=(",", ":"), + ensure_ascii=False, ) except json.JSONDecodeError as e: raise InvalidArgumentException( diff --git a/tests/multisafepay/unit/util/test_unit_webhook.py b/tests/multisafepay/unit/util/test_unit_webhook.py index 95e4eaa..7bbd18e 100644 --- a/tests/multisafepay/unit/util/test_unit_webhook.py +++ b/tests/multisafepay/unit/util/test_unit_webhook.py @@ -10,6 +10,10 @@ import pytest import json +import base64 +import hashlib +import hmac +import time from multisafepay.exception.invalid_argument import InvalidArgumentException from multisafepay.util.webhook import Webhook @@ -157,3 +161,43 @@ def test_verify_with_empty_spaces_in_api_key(): " your-MultiSafepay-API-key ", 0, ) + + +def test_validate_with_unicode_characters(): + """Test Webhook validation with unicode characters in the payload.""" + api_key = "test-api-key" + timestamp = str(int(time.time())) + + # Payload with unicode characters + data = { + "city": "München", + "price": "€100", + "description": "Descripción con ñ", + } + json_request = json.dumps(data) + + # Manually calculate expected signature using ensure_ascii=False + transaction_compact_json = json.dumps( + data, + separators=(",", ":"), + ensure_ascii=False, + ) + payload = f"{timestamp}:{transaction_compact_json}" + + signature = hmac.new( + api_key.encode(), + payload.encode(), + hashlib.sha512, + ).hexdigest() + + auth_header = base64.b64encode( + f"{timestamp}:{signature}".encode(), + ).decode() + + # Validation should pass + assert Webhook.validate( + json_request, + auth_header, + api_key, + validation_time_in_seconds=600, + )