diff --git a/frappe/integrations/doctype/webhook/webhook.js b/frappe/integrations/doctype/webhook/webhook.js index 90b5b12dc6..09c296113a 100644 --- a/frappe/integrations/doctype/webhook/webhook.js +++ b/frappe/integrations/doctype/webhook/webhook.js @@ -66,6 +66,10 @@ frappe.ui.form.on('Webhook', { webhook_doctype: (frm) => { frappe.webhook.set_fieldname_select(frm); + }, + + enable_security: (frm) => { + frm.toggle_reqd('webhook_secret', frm.doc.enable_security); } }); diff --git a/frappe/integrations/doctype/webhook/webhook.json b/frappe/integrations/doctype/webhook/webhook.json index 8aa96e6859..9f979099c9 100644 --- a/frappe/integrations/doctype/webhook/webhook.json +++ b/frappe/integrations/doctype/webhook/webhook.json @@ -19,6 +19,9 @@ "request_url", "cb_webhook", "request_structure", + "sb_security", + "enable_security", + "webhook_secret", "sb_webhook_headers", "webhook_headers", "sb_webhook_data", @@ -127,10 +130,27 @@ "fieldtype": "Select", "label": "Naming Series", "options": "\nHOOK-.####" + }, + { + "fieldname": "sb_security", + "fieldtype": "Section Break", + "label": "Webhook Security" + }, + { + "default": "0", + "fieldname": "enable_security", + "fieldtype": "Check", + "label": "Enable Security" + }, + { + "depends_on": "eval:doc.enable_security == 1", + "fieldname": "webhook_secret", + "fieldtype": "Password", + "label": "Webhook Secret" } ], "links": [], - "modified": "2020-01-06 02:51:07.997566", + "modified": "2020-01-13 01:53:04.459968", "modified_by": "Administrator", "module": "Integrations", "name": "Webhook", diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 0a97022f66..5cbe7c0a02 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -4,7 +4,10 @@ from __future__ import unicode_literals +import base64 import datetime +import hashlib +import hmac import json from time import sleep @@ -16,6 +19,8 @@ from frappe import _ from frappe.model.document import Document from frappe.utils.jinja import validate_template +WEBHOOK_SECRET_HEADER = "X-Frappe-Webhook-Signature" + class Webhook(Document): def validate(self): @@ -94,10 +99,23 @@ def enqueue_webhook(doc, webhook): def get_webhook_headers(doc, webhook): headers = {} + + if webhook.enable_security: + data = get_webhook_data(doc, webhook) + signature = base64.b64encode( + hmac.new( + webhook.get_password("webhook_secret").encode("utf8"), + json.dumps(data).encode("utf8"), + hashlib.sha256 + ).digest() + ) + headers[WEBHOOK_SECRET_HEADER] = signature + if webhook.webhook_headers: for h in webhook.webhook_headers: if h.get("key") and h.get("value"): headers[h.get("key")] = h.get("value") + return headers