From f3bc29cbdc19066c14acdfa8b7a47f3dbcc9c73e Mon Sep 17 00:00:00 2001 From: shadrak gurupnor Date: Tue, 31 Aug 2021 12:14:12 +0530 Subject: [PATCH] feat: applied rate-limiting on web-forms to avoid bulk submission --- frappe/model/document.py | 2 +- frappe/rate_limiter.py | 10 ++++++++-- frappe/website/doctype/web_form/web_form.py | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index d0d66ac3de..37549e2001 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -469,7 +469,7 @@ class Document(BaseDocument): if not self.creation: self.creation = self.modified if not self.owner: - self.owner = self.flags.owner or self.modified_by + self.owner = self.modified_by for d in self.get_all_children(): d.modified = self.modified diff --git a/frappe/rate_limiter.py b/frappe/rate_limiter.py index 528e5d6b56..743ddcfe24 100644 --- a/frappe/rate_limiter.py +++ b/frappe/rate_limiter.py @@ -107,8 +107,14 @@ def rate_limit(key: str, limit: Union[int, Callable] = 5, seconds: int= 24*60*60 _limit = limit() if callable(limit) else limit - identity = frappe.form_dict[key] - cache_key = f"rl:{frappe.form_dict.cmd}:{identity}" + cmd = (frappe.form_dict.cmd).split('.')[-1] + user_key=frappe.form_dict[key] + ip = frappe.local.request_ip + + # cmd "accept" is used for web-forms only + ip_based_key = ":".join([ip, user_key]) if cmd == 'accept' else ip + + cache_key = f"rl:{frappe.form_dict.cmd}:{ip_based_key}" value = frappe.cache().get_value(cache_key, expires=True) or 0 if not value: diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index 32f7e030a6..948ce46283 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -13,7 +13,7 @@ from frappe.modules.utils import export_module_json, get_doc_module from frappe.utils import cstr from frappe.website.utils import get_comment_list from frappe.website.website_generator import WebsiteGenerator - +from frappe.rate_limiter import rate_limit class WebForm(WebsiteGenerator): website = frappe._dict( @@ -365,6 +365,7 @@ def get_context(context): @frappe.whitelist(allow_guest=True) +@rate_limit(key='web_form', limit=5, seconds=60, methods=['POST']) def accept(web_form, data, docname=None, for_payment=False): '''Save the web form''' data = frappe._dict(json.loads(data))