feat: verify signature on webhook (#21872)

This commit is contained in:
Shivam Mishra 2020-06-02 13:48:22 +00:00 committed by GitHub
parent 7a05662e9f
commit 789df32683
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 6 deletions

View File

@ -64,9 +64,21 @@ def get_member_based_on_subscription(subscription_id, email):
}, order_by="creation desc") }, order_by="creation desc")
return frappe.get_doc("Member", members[0]['name']) return frappe.get_doc("Member", members[0]['name'])
def verify_signature(data):
signature = frappe.request.headers.get('X-Razorpay-Signature')
settings = frappe.get_doc("Membership Settings")
key = settings.get_webhook_secret()
controller = frappe.get_doc("Razorpay Settings")
controller.verify_signature(data, signature, key)
@frappe.whitelist(allow_guest=True) @frappe.whitelist(allow_guest=True)
def trigger_razorpay_subscription(*args, **kwargs): def trigger_razorpay_subscription(*args, **kwargs):
data = frappe.request.get_data() data = frappe.request.get_data()
verify_signature(data):
if isinstance(data, six.string_types): if isinstance(data, six.string_types):
data = json.loads(data) data = json.loads(data)
@ -113,7 +125,6 @@ def trigger_razorpay_subscription(*args, **kwargs):
return True return True
def notify_failure(log): def notify_failure(log):
try: try:
content = """Dear System Manager, content = """Dear System Manager,

View File

@ -1,8 +1,30 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Membership Settings', { frappe.ui.form.on("Membership Settings", {
refresh: function(frm) { refresh: function(frm) {
if (frm.doc.webhook_secret) {
frm.add_custom_button(__("Revoke <Key></Key>"), () => {
frm.call("revoke_key").then(() => {
frm.refresh();
})
});
}
frm.trigger("add_generate_button");
},
} add_generate_button: function(frm) {
let label;
if (frm.doc.webhook_secret) {
label = __("Regenerate Webhook Secret");
} else {
label = __("Generate Webhook Secret");
}
frm.add_custom_button(label, () => {
frm.call("generate_webhook_key").then(() => {
frm.refresh();
});
});
},
}); });

View File

@ -8,7 +8,8 @@
"enable_razorpay", "enable_razorpay",
"razorpay_settings_section", "razorpay_settings_section",
"billing_cycle", "billing_cycle",
"billing_frequency" "billing_frequency",
"webhook_secret"
], ],
"fields": [ "fields": [
{ {
@ -34,11 +35,17 @@
"fieldname": "billing_frequency", "fieldname": "billing_frequency",
"fieldtype": "Int", "fieldtype": "Int",
"label": "Billing Frequency" "label": "Billing Frequency"
},
{
"fieldname": "webhook_secret",
"fieldtype": "Password",
"label": "Webhook Secret",
"read_only": 1
} }
], ],
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2020-04-07 18:42:51.496807", "modified": "2020-05-22 12:38:27.103759",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Non Profit", "module": "Non Profit",
"name": "Membership Settings", "name": "Membership Settings",

View File

@ -4,11 +4,27 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.integrations.utils import get_payment_gateway_controller from frappe.integrations.utils import get_payment_gateway_controller
from frappe.model.document import Document from frappe.model.document import Document
class MembershipSettings(Document): class MembershipSettings(Document):
pass def generate_webhook_key(self):
key = frappe.generate_hash(length=20)
self.webhook_secret = key
self.save()
frappe.msgprint(
_("Here is your webhook secret, this will be shown to you only once.") + "<br><br>" + key,
_("Webhook Secret")
);
def revoke_key(self):
self.webhook_secret = None;
self.save()
def get_webhook_secret(self):
return self.get_password(fieldname="webhook_secret", raise_exception=False)
@frappe.whitelist() @frappe.whitelist()
def get_plans_for_membership(*args, **kwargs): def get_plans_for_membership(*args, **kwargs):