refactor: Format and sanitise user inputs to search queries. (#22922)
* refactor: Sanitize whitelisted method inputs
Co-authored-by: Prssanna Desai <prssud@gmail.com>
Co-authored-by: Shivam Mishra <scmmishra@users.noreply.github.com>
* refactor: Format and sanitize tax_account_query inputs
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
Co-authored-by: Prssanna Desai <prssud@gmail.com>
Co-authored-by: Shivam Mishra <scmmishra@users.noreply.github.com>
* refactor: Validate and sanitize search inputs via decorator
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
Co-authored-by: Prssanna Desai <prssud@gmail.com>
Co-authored-by: Shivam Mishra <scmmishra@users.noreply.github.com>
* style: Minor formatting fix
* refactor: Validate and sanitize search inputs using decorator
* fix: Typo
* fix: Remove unwanted import statement
* refactor: Repalce validate_and_sanitize_search_inputs() with validate_and_sanitize_search_inputs
Co-authored-by: Prssanna Desai <prssud@gmail.com>
Co-authored-by: Shivam Mishra <scmmishra@users.noreply.github.com>
Co-authored-by: Prssanna Desai <prssud@gmail.com>
Co-authored-by: Shivam Mishra <scmmishra@users.noreply.github.com>
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index b402204..babc5bd 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -12,6 +12,7 @@
# searches for active employees
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def employee_query(doctype, txt, searchfield, start, page_len, filters):
conditions = []
fields = get_fields("Employee", ["name", "employee_name"])
@@ -42,6 +43,7 @@
# searches for leads which are not converted
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def lead_query(doctype, txt, searchfield, start, page_len, filters):
fields = get_fields("Lead", ["name", "lead_name", "company_name"])
@@ -72,6 +74,7 @@
# searches for customer
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def customer_query(doctype, txt, searchfield, start, page_len, filters):
conditions = []
cust_master_name = frappe.defaults.get_user_default("cust_master_name")
@@ -110,8 +113,10 @@
# searches for supplier
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def supplier_query(doctype, txt, searchfield, start, page_len, filters):
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
+
if supp_master_name == "Supplier Name":
fields = ["name", "supplier_group"]
else:
@@ -142,32 +147,49 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
company_currency = erpnext.get_company_currency(filters.get('company'))
- tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount
- where tabAccount.docstatus!=2
- and account_type in (%s)
- and is_group = 0
- and company = %s
- and account_currency = %s
- and `%s` LIKE %s
- order by idx desc, name
- limit %s, %s""" %
- (", ".join(['%s']*len(filters.get("account_type"))), "%s", "%s", searchfield, "%s", "%s", "%s"),
- tuple(filters.get("account_type") + [filters.get("company"), company_currency, "%%%s%%" % txt,
- start, page_len]))
+ def get_accounts(with_account_type_filter):
+ account_type_condition = ''
+ if with_account_type_filter:
+ account_type_condition = "AND account_type in %(account_types)s"
+
+ accounts = frappe.db.sql("""
+ SELECT name, parent_account
+ FROM `tabAccount`
+ WHERE `tabAccount`.docstatus!=2
+ {account_type_condition}
+ AND is_group = 0
+ AND company = %(company)s
+ AND account_currency = %(currency)s
+ AND `{searchfield}` LIKE %(txt)s
+ ORDER BY idx DESC, name
+ LIMIT %(offset)s, %(limit)s
+ """.format(account_type_condition=account_type_condition, searchfield=searchfield),
+ dict(
+ account_types=filters.get("account_type"),
+ company=filters.get("company"),
+ currency=company_currency,
+ txt="%{}%".format(txt),
+ offset=start,
+ limit=page_len
+ )
+ )
+
+ return accounts
+
+ tax_accounts = get_accounts(True)
+
if not tax_accounts:
- tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount
- where tabAccount.docstatus!=2 and is_group = 0
- and company = %s and account_currency = %s and `%s` LIKE %s limit %s, %s""" #nosec
- % ("%s", "%s", searchfield, "%s", "%s", "%s"),
- (filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len))
+ tax_accounts = get_accounts(False)
return tax_accounts
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = []
@@ -215,7 +237,6 @@
idx desc,
name, item_name
limit %(start)s, %(page_len)s """.format(
- key=searchfield,
columns=columns,
scond=searchfields,
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
@@ -231,6 +252,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def bom(doctype, txt, searchfield, start, page_len, filters):
conditions = []
fields = get_fields("BOM", ["name", "item"])
@@ -258,6 +280,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_project_name(doctype, txt, searchfield, start, page_len, filters):
cond = ''
if filters.get('customer'):
@@ -285,6 +308,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters, as_dict):
fields = get_fields("Delivery Note", ["name", "customer", "posting_date"])
@@ -315,6 +339,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
cond = ""
if filters.get("posting_date"):
@@ -373,6 +398,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_account_list(doctype, txt, searchfield, start, page_len, filters):
filter_list = []
@@ -396,6 +422,7 @@
limit_start=start, limit_page_length=page_len, as_list=True)
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
@@ -412,6 +439,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_income_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
@@ -438,6 +466,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
@@ -462,6 +491,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def warehouse_query(doctype, txt, searchfield, start, page_len, filters):
# Should be used when item code is passed in filters.
conditions, bin_conditions = [], []
@@ -505,6 +535,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters):
query = """select batch_id from `tabBatch`
where disabled = 0
@@ -518,6 +549,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters):
item_filters = [
['manufacturer', 'like', '%' + txt + '%'],
@@ -536,6 +568,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
query = """
select pr.name
@@ -550,6 +583,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
query = """
select pi.name
@@ -564,6 +598,7 @@
@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
item_doc = frappe.get_cached_doc('Item', filters.get('item_code'))