from flask import Flask, request, abort
import json
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.exceptions import InvalidSignature
app = Flask(__name__)
# Replace with your actual public key provided by Ripio
RIPIO_PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----"""
def verify_signature(payload_bytes: bytes, signature_header: str, public_key_pem: str) -> bool:
"""Verifies the ECDSA signature of the raw payload."""
try:
public_key = ec.from_pem_public_key(public_key_pem.encode("utf-8"))
signature = base64.b64decode(signature_header)
public_key.verify(signature, payload_bytes, ec.ECDSA(hashes.SHA256()))
return True
except (InvalidSignature, TypeError, ValueError):
return False
@app.route('/ripio-webhook-handler', methods=['POST'])
def ripio_webhook_handler():
received_signature = request.headers.get('X-Signature-Ecdsa-Sha256')
# Get raw body bytes for signature verification
raw_payload_bytes = request.get_data()
if not received_signature:
print("Error: Missing X-Signature-Ecdsa-Sha256 header")
abort(400, 'Missing signature header')
if not raw_payload_bytes:
print("Error: Missing payload")
abort(400, 'Missing payload')
if not verify_signature(raw_payload_bytes, received_signature, RIPIO_PUBLIC_KEY):
print(f"Error: Invalid signature. Received: {received_signature}")
abort(403, 'Invalid signature')
# If signature is valid, parse the JSON payload for processing
try:
payload_json = json.loads(raw_payload_bytes.decode('utf-8'))
except json.JSONDecodeError:
print("Error: Could not decode JSON payload")
abort(400, 'Invalid JSON payload')
print("Webhook received and signature validated!")
print("Event Type:", payload_json.get("eventType"))
print("Payload:", payload_json)
# TODO: Add your asynchronous business logic here
# (e.g., add to a queue for processing)
return "Webhook processed successfully", 200
if __name__ == '__main__':
# For development only. Use a proper WSGI server in production.
app.run(port=5000, debug=True)