From 0e2cf29f1636568c98fa4c66f041e2658286571e Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 5 Oct 2018 17:16:28 +0530 Subject: [PATCH] [fix] add validations on payment notification callback --- .../paypal_settings/paypal_settings.py | 55 +++++++++++++----- .../razorpay_settings/razorpay_settings.py | 57 ++++++++++++++----- 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py index 80aadfd..9fa3164 100644 --- a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py +++ b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py @@ -68,10 +68,10 @@ import frappe import json from frappe import _ from datetime import datetime -from frappe.utils import get_url, call_hook_method, cint, get_timestamp, cstr, now, date_diff, get_datetime from six.moves.urllib.parse import urlencode from frappe.model.document import Document from frappe.integrations.utils import create_request_log, make_post_request, create_payment_gateway +from frappe.utils import get_url, call_hook_method, cint, get_timestamp, cstr, now, date_diff, get_datetime api_path = '/api/method/frappe.integrations.doctype.paypal_settings.paypal_settings' @@ -363,27 +363,56 @@ def manage_recurring_payment_profile_status(profile_id, action, args, url): }) response = make_post_request(url, data=args) - if response.get("ACK")[0] != "Success": frappe.throw(_("Failed while amending subscription")) @frappe.whitelist(allow_guest=True) def ipn_handler(): - data = frappe.local.form_dict - data.update({ - "payment_gateway": "PayPal" + try: + data = frappe.local.form_dict + + validate_ipn_request(data) + + data.update({ + "payment_gateway": "PayPal" + }) + + doc = frappe.get_doc({ + "data": json.dumps(frappe.local.form_dict), + "doctype": "Integration Request", + "status": "Subscription Notification" + }).insert(ignore_permissions=True) + frappe.db.commit() + + frappe.enqueue(method='frappe.integrations.doctype.paypal_settings.paypal_settings.handle_subscription_notification', + queue='long', timeout=600, is_async=True, **{"doctype": "Integration Request", "docname": doc.name}) + + except frappe.InvalidStatusError: + pass + except Exception as e: + frappe.log(frappe.log_error(title=e)) + +def validate_ipn_request(data): + def _throw(): + frappe.throw(_("In Valid Request"), exc=frappe.InvalidStatusError) + + if not data.get("recurring_payment_id"): + _throw() + + doc = frappe.get_doc("PayPal Settings") + params, url = doc.get_paypal_params_and_url() + + params.update({ + "METHOD": "GetRecurringPaymentsProfileDetails", + "PROFILEID": data.get("recurring_payment_id") }) - doc = frappe.get_doc({ - "data": frappe.local.form_dict, - "doctype": "Integration Request", - "status": "Subscription Notification" - }).insert(ignore_permissions=True) - frappe.db.commit() + params = urlencode(params) + res = make_post_request(url=url, data=params.encode("utf-8")) - frappe.enqueue(method='frappe.integrations.doctype.paypal_settings.paypal_settings.handle_subscription_notification', - queue='long', timeout=600, is_async=True, **{"doctype": "Integration Request", "docname": doc.name}) + if res['ACK'][0] != 'Success': + _throw() def handle_subscription_notification(doctype, docname): call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname) diff --git a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py index a1029aa..0eb41e5 100644 --- a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py +++ b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py @@ -331,23 +331,50 @@ def convert_rupee_to_paisa(**kwargs): frappe.conf.converted_rupee_to_paisa = True - @frappe.whitelist(allow_guest=True) def razorpay_subscription_callback(): - data = frappe.local.form_dict - data.update({ - "payment_gateway": "Razorpay" - }) - - doc = frappe.get_doc({ - "data": json.dumps(frappe.local.form_dict), - "doctype": "Integration Request", - "status": "Subscription Notification" - }).insert(ignore_permissions=True) - frappe.db.commit() - - frappe.enqueue(method='frappe.integrations.doctype.razorpay_settings.razorpay_settings.handle_subscription_notification', - queue='long', timeout=600, is_async=True, **{"doctype": "Integration Request", "docname": doc.name}) + try: + data = frappe.local.form_dict + + validate_payment_callback() + + data.update({ + "payment_gateway": "Razorpay" + }) + + doc = frappe.get_doc({ + "data": json.dumps(frappe.local.form_dict), + "doctype": "Integration Request", + "status": "Subscription Notification" + }).insert(ignore_permissions=True) + frappe.db.commit() + + frappe.enqueue(method='frappe.integrations.doctype.razorpay_settings.razorpay_settings.handle_subscription_notification', + queue='long', timeout=600, is_async=True, **{"doctype": "Integration Request", "docname": doc.name}) + + except frappe.InvalidStatusError: + pass + except Exception as e: + frappe.log(frappe.log_error(title=e)) + +def validate_payment_callback(data): + def _throw(): + frappe.throw(_("Invalid Subscription"), exc=frappe.InvalidStatusError) + + subscription_id = data.get('payload').get("subscription").get("entity").get("id") + + if not(subscription_id): + _throw() + + controller = frappe.get_doc("Razorpay Settings") + + settings = controller.get_settings(data) + + resp = make_get_request("https://api.razorpay.com/v1/subscriptions/{0}".format(subscription_id), + auth=(settings.api_key, settings.api_secret)) + + if resp.get("status") != "active": + _throw() def handle_subscription_notification(doctype, docname): call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname) \ No newline at end of file