From 01afd95177e4ffabfd9203d63c7c938ae7ff5a9f Mon Sep 17 00:00:00 2001 From: Marius Robert Macamete Date: Fri, 19 Dec 2025 15:18:54 +0200 Subject: [PATCH] something --- UI_V2/flask_server.py | 58 +++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/UI_V2/flask_server.py b/UI_V2/flask_server.py index 74bae65..dd83a3d 100644 --- a/UI_V2/flask_server.py +++ b/UI_V2/flask_server.py @@ -50,33 +50,53 @@ def healthz(): # app.logger.exception("IPN verification failed: %s", e) # return jsonify({"errorCode": 0}), 200 + @app.post("/api/payments/ipn") def ipn(): - # 1. Get the signature from the 'Verification-Token' header - token = request.headers.get('Verification-Token') - - if token: - # This ignores the signature completely just so we can see what's inside - raw_data = jwt.decode(token, options={"verify_signature": False}) - app.logger.info(f"UNVERIFIED JWT CONTENT: {raw_data}") + token = request.headers.get('Verification-Token') or request.headers.get('X-Netopia-Signature') - # 2. If it exists, inject it into the location the SDK expects - if token: - request.headers.environ['HTTP_X_NETOPIA_SIGNATURE'] = token - app.logger.info("Mapped Verification-Token to X-Netopia-Signature") + if not token: + app.logger.error("No token found") + return jsonify({"errorCode": 1, "error": "No token"}), 400 try: - # Now the SDK will find the signature in X-Netopia-Signature - data = verify_ipn(request) + # Get the clean key from your env/settings + from helpers.netopia import NetopiaSettings + settings = NetopiaSettings.from_env() + # Ensure newlines are correct + public_key = settings.public_key_str.replace('\\n', '\n').strip() + if not public_key.startswith("-----BEGIN"): + public_key = f"-----BEGIN PUBLIC KEY-----\n{public_key}\n-----END PUBLIC KEY-----" + + # MANUAL VERIFICATION + # We allow 30 seconds of 'leeway' for the clock + # We specify RS512 because that's what Netopia uses + decoded_data = jwt.decode( + token, + public_key, + algorithms=["RS256", "RS512"], + audience=settings.pos_signature, + leeway=30 + ) - # NOTE: Your log shows "status: 12" and "Invalid card number" - # The verification should now pass, even if the payment failed. - app.logger.info("IPN Verification Result: %s", data) + app.logger.info(f"VERIFIED DATA: {decoded_data}") + + # If we got here, the signature is VALID! + # Now we just need to get the order status from the body + json_body = request.get_json() + order_id = json_body.get('order', {}).get('orderID') + status = json_body.get('payment', {}).get('status') + + app.logger.info(f"Order {order_id} has status {status}") return jsonify({"errorCode": 0}), 200 - except Exception as e: - app.logger.exception("IPN verification failed: %s", e) - return jsonify({"ok": False, "error": str(e)}), 400 + + except jwt.ExpiredSignatureError: + app.logger.error("Token expired") + return jsonify({"errorCode": 1, "error": "Expired"}), 400 + except jwt.InvalidTokenError as e: + app.logger.error(f"Invalid Token: {e}") + return jsonify({"errorCode": 1, "error": str(e)}), 400 @app.get("/api/payments/status")