"""Server-side HMAC v2 example. Running this file only prints a synthetic fixture.""" import hashlib import hmac import json import time import uuid from typing import Any def canonical(value: Any) -> str: return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, allow_nan=False) def sign_request(client_id: str, client_secret: str, path: str, body: dict[str, Any], idempotency_key: str, timestamp: int | None = None, nonce: str | None = None) -> dict[str, Any]: serialized = canonical(body) timestamp = int(time.time()) if timestamp is None else timestamp nonce = str(uuid.uuid4()) if nonce is None else nonce text = "\n".join(["v2", str(timestamp), nonce, "POST", path, idempotency_key, serialized]) return {"body": serialized, "headers": { "Authorization": f"ApiKey {client_id}:{client_secret}", "Content-Type": "application/json", "X-Signature-Version": "2", "X-Request-Timestamp": str(timestamp), "X-Request-Nonce": nonce, "Idempotency-Key": idempotency_key, "hmac": hmac.new(client_secret.encode(), text.encode(), hashlib.sha512).hexdigest(), }} def verify_webhook(secret: str, timestamp: str, raw_body: bytes, signature: str, now: int | None = None) -> bool: if not timestamp.isascii() or not timestamp.isdecimal(): return False if abs((int(time.time()) if now is None else now) - int(timestamp)) > 300: return False expected = "sha256=" + hmac.new(secret.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature) if __name__ == "__main__": signed = sign_request("cli_example", "example-secret", "/api/external/pix/cash-in", {"external_id": "demo-1", "amount": 100, "description": "Ação / Pix", "nested": {"z": None, "a": [True, "á"]}}, "example-order-1", 1700000000, "example-nonce-123456") print(json.dumps({"canonical": signed["body"], "hmac": signed["headers"]["hmac"]}, ensure_ascii=False))