Commit cc09d3f9 authored by Nabin Hait's avatar Nabin Hait
Browse files

Merge branch 'hotfix'

parents 4d4fb723 b41bc5c1
Showing with 111 additions and 25 deletions
+111 -25
......@@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json
from .exceptions import *
from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template
__version__ = '9.2.23'
__version__ = '9.2.24'
__title__ = "Frappe Framework"
local = Local()
......
......@@ -769,6 +769,8 @@ def reset_password(user):
try:
user = frappe.get_doc("User", user)
if not user.enabled:
return 'disabled'
user.validate_reset_password()
user.reset_password(send_email=True)
......
......@@ -255,3 +255,36 @@ frappe.is_mobile = function() {
return $(document).width() < 768;
}
frappe.utils.xss_sanitise = function (string, options) {
// Reference - https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
let sanitised = string; // un-sanitised string.
const DEFAULT_OPTIONS = {
strategies: ['html', 'js'] // use all strategies.
}
const HTML_ESCAPE_MAP = {
'&': '&amp',
'<': '&lt',
'>': '&gt',
'"': '&quot',
"'": '&#x27',
'/': '&#x2F'
};
const REGEX_SCRIPT = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi; // used in jQuery 1.7.2 src/ajax.js Line 14
options = Object.assign({ }, DEFAULT_OPTIONS, options); // don't deep copy, immutable beauty.
// Rule 1
if ( options.strategies.includes('html') ) {
// By far, the best thing that has ever happened to JS - Object.keys
Object.keys(HTML_ESCAPE_MAP).map((char, escape) => {
const regex = new RegExp(char, "g");
sanitised = sanitised.replace(regex, escape);
});
}
// Rule 3 - TODO: Check event handlers?
if ( options.strategies.includes('js') ) {
sanitised = sanitised.replace(REGEX_SCRIPT, "");
}
return sanitised;
}
\ No newline at end of file
......@@ -17,8 +17,8 @@ login.bind_events = function() {
event.preventDefault();
var args = {};
args.cmd = "login";
args.usr = ($("#login_email").val() || "").trim();
args.pwd = $("#login_password").val();
args.usr = frappe.utils.xss_sanitise(($("#login_email").val() || "").trim());
args.pwd = frappe.utils.xss_sanitise($("#login_password").val());
args.device = "desktop";
if(!args.usr || !args.pwd) {
frappe.msgprint("{{ _("Both login and password required") }}");
......@@ -184,6 +184,8 @@ login.login_handlers = (function() {
login.set_indicator("{{ _("Not a valid user") }}", 'red');
} else if (data.message=='not allowed') {
login.set_indicator("{{ _("Not Allowed") }}", 'red');
} else if (data.message=='disabled') {
login.set_indicator("{{ _("Not Allowed: Disabled User") }}", 'red');
} else {
login.set_indicator("{{ _("Instructions Emailed") }}", 'green');
}
......
......@@ -10,8 +10,12 @@ from frappe.utils import cint, strip_html_tags
from frappe.model.base_document import get_controller
from six import text_type
def setup_global_search_table():
'''Creates __global_seach table'''
"""
Creates __global_seach table
:return:
"""
if not '__global_search' in frappe.db.get_tables():
frappe.db.sql('''create table __global_search(
doctype varchar(100),
......@@ -26,12 +30,21 @@ def setup_global_search_table():
ENGINE=MyISAM
CHARACTER SET=utf8mb4''')
def reset():
'''Deletes all data in __global_search'''
"""
Deletes all data in __global_search
:return:
"""
frappe.db.sql('delete from __global_search')
def get_doctypes_with_global_search(with_child_tables=True):
'''Return doctypes with global search fields'''
"""
Return doctypes with global search fields
:param with_child_tables:
:return:
"""
def _get():
global_search_doctypes = []
filters = {}
......@@ -43,17 +56,25 @@ def get_doctypes_with_global_search(with_child_tables=True):
global_search_doctypes.append(d)
installed_apps = frappe.get_installed_apps()
module_app = frappe.local.module_app
doctypes = [
d.name for d in global_search_doctypes
if module_app.get(frappe.scrub(d.module))
and module_app[frappe.scrub(d.module)] in installed_apps
]
doctypes = [d.name for d in global_search_doctypes
if frappe.local.module_app[frappe.scrub(d.module)] in installed_apps]
return doctypes
return frappe.cache().get_value('doctypes_with_global_search', _get)
def rebuild_for_doctype(doctype):
'''Rebuild entries of doctype's documents in __global_search on change of
searchable fields
:param doctype: Doctype '''
"""
Rebuild entries of doctype's documents in __global_search on change of
searchable fields
:param doctype: Doctype
"""
def _get_filters():
filters = frappe._dict({ "docstatus": ["!=", 2] })
......@@ -127,6 +148,7 @@ def rebuild_for_doctype(doctype):
if all_contents:
insert_values_for_multiple_docs(all_contents)
def delete_global_search_records_for_doctype(doctype):
frappe.db.sql('''
delete
......@@ -134,6 +156,7 @@ def delete_global_search_records_for_doctype(doctype):
where
doctype = %s''', doctype, as_dict=True)
def get_selected_fields(meta, global_search_fields):
fieldnames = [df.fieldname for df in global_search_fields]
if meta.istable==1:
......@@ -146,6 +169,7 @@ def get_selected_fields(meta, global_search_fields):
return fieldnames
def get_children_data(doctype, meta):
"""
Get all records from all the child tables of a doctype
......@@ -182,6 +206,7 @@ def get_children_data(doctype, meta):
return all_children, child_search_fields
def insert_values_for_multiple_docs(all_contents):
values = []
for content in all_contents:
......@@ -201,9 +226,11 @@ def insert_values_for_multiple_docs(all_contents):
def update_global_search(doc):
'''Add values marked with `in_global_search` to
`frappe.flags.update_global_search` from given doc
:param doc: Document to be added to global search'''
"""
Add values marked with `in_global_search` to
`frappe.flags.update_global_search` from given doc
:param doc: Document to be added to global search
"""
if doc.docstatus > 1 or (doc.meta.has_field("enabled") and not doc.get("enabled")) \
or doc.get("disabled"):
......@@ -235,6 +262,7 @@ def update_global_search(doc):
published=published, title=doc.get_title(), route=doc.get('route')))
enqueue_global_search()
def enqueue_global_search():
if frappe.flags.update_global_search:
try:
......@@ -246,21 +274,32 @@ def enqueue_global_search():
frappe.flags.update_global_search = []
def get_formatted_value(value, field):
'''Prepare field from raw data'''
"""
Prepare field from raw data
:param value:
:param field:
:return:
"""
from six.moves.html_parser import HTMLParser
if(getattr(field, 'fieldtype', None) in ["Text", "Text Editor"]):
if getattr(field, 'fieldtype', None) in ["Text", "Text Editor"]:
h = HTMLParser()
value = h.unescape(value)
value = (re.subn(r'<[\s]*(script|style).*?</\1>(?s)', '', text_type(value))[0])
value = ' '.join(value.split())
return field.label + " : " + strip_html_tags(text_type(value))
def sync_global_search(flags=None):
'''Add values from `flags` (frappe.flags.update_global_search) to __global_search.
This is called internally at the end of the request.'''
"""
Add values from `flags` (frappe.flags.update_global_search) to __global_search.
This is called internally at the end of the request.
:param flags:
:return:
"""
if not flags:
flags = frappe.flags.update_global_search
......@@ -278,10 +317,13 @@ def sync_global_search(flags=None):
frappe.flags.update_global_search = []
def delete_for_document(doc):
'''Delete the __global_search entry of a document that has
been deleted
:param doc: Deleted document'''
"""
Delete the __global_search entry of a document that has
been deleted
:param doc: Deleted document
"""
frappe.db.sql('''
delete
......@@ -290,13 +332,16 @@ def delete_for_document(doc):
doctype = %s and
name = %s''', (doc.doctype, doc.name), as_dict=True)
@frappe.whitelist()
def search(text, start=0, limit=20, doctype=""):
'''Search for given text in __global_search
"""
Search for given text in __global_search
:param text: phrase to be searched
:param start: start results at, default 0
:param limit: number of results to return, default 20
:return: Array of result objects'''
:return: Array of result objects
"""
text = "+" + text + "*"
if not doctype:
......@@ -328,13 +373,16 @@ def search(text, start=0, limit=20, doctype=""):
return results
@frappe.whitelist(allow_guest=True)
def web_search(text, start=0, limit=20):
'''Search for given text in __global_search where published = 1
"""
Search for given text in __global_search where published = 1
:param text: phrase to be searched
:param start: start results at, default 0
:param limit: number of results to return, default 20
:return: Array of result objects'''
:return: Array of result objects
"""
text = "+" + text + "*"
results = frappe.db.sql('''
......
......@@ -185,6 +185,7 @@ $.extend(frappe, {
if($.isArray(html)) {
html = html.join("<hr>")
}
return frappe.get_modal(title || "Message", html).modal("show");
},
send_message: function(opts, btn) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment