diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index c87bb34de8..2e3144c3ce 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -406,16 +406,11 @@ def get_perm_info(arg=None):
@frappe.whitelist(allow_guest=True)
def update_password(new_password, key=None, old_password=None):
- # verify old password
- if key:
- user = frappe.db.get_value("User", {"reset_password_key":key})
- if not user:
- return _("Cannot Update: Incorrect / Expired Link.")
-
- elif old_password:
- # verify old password
- frappe.local.login_manager.check_password(frappe.session.user, old_password)
- user = frappe.session.user
+ res = _get_user_for_update_password(key, old_password)
+ if res.get('message'):
+ return res['message']
+ else:
+ user = res['user']
_update_password(user, new_password)
@@ -428,6 +423,44 @@ def update_password(new_password, key=None, old_password=None):
else:
return redirect_url if redirect_url else "/"
+@frappe.whitelist(allow_guest=True)
+def test_password_strength(new_password, key=None, old_password=None):
+ from frappe.utils.password_strength import test_password_strength as _test_password_strength
+
+ res = _get_user_for_update_password(key, old_password)
+ if not res:
+ return
+ elif res.get('message'):
+ return res['message']
+ else:
+ user = res['user']
+
+ user_data = frappe.db.get_value('User', user, ['first_name', 'middle_name', 'last_name', 'email', 'birth_date'])
+
+ if new_password:
+ return _test_password_strength(new_password, user_inputs=user_data)
+
+def _get_user_for_update_password(key, old_password):
+ # verify old password
+ if key:
+ user = frappe.db.get_value("User", {"reset_password_key": key})
+ if not user:
+ return {
+ 'message': _("Cannot Update: Incorrect / Expired Link.")
+ }
+
+ elif old_password:
+ # verify old password
+ frappe.local.login_manager.check_password(frappe.session.user, old_password)
+ user = frappe.session.user
+
+ else:
+ return
+
+ return {
+ 'user': user
+ }
+
def reset_user_data(user):
user_doc = frappe.get_doc("User", user)
redirect_url = user_doc.redirect_url
diff --git a/frappe/templates/pages/update-password.html b/frappe/templates/pages/update-password.html
index 9960b82a9d..fb02197871 100644
--- a/frappe/templates/pages/update-password.html
+++ b/frappe/templates/pages/update-password.html
@@ -15,7 +15,9 @@
+
+
@@ -31,9 +33,9 @@ frappe.ready(function() {
$("#old_password").parent().toggle(false);
}
- $("#reset-password").on("submit", function() {
- return false;
- });
+ $("#reset-password").on("submit", function() {
+ return false;
+ });
$("#new_password").on("keypress", function(e) {
if(e.which===13) $("#update").click();
@@ -76,7 +78,99 @@ frappe.ready(function() {
return false;
});
+
+ window.strength_indicator = $('.password-strength-indicator');
+ window.strength_message = $('.password-strength-message');
+
+ $('#new_password').on('keyup', function() {
+ window.clear_timeout();
+ window.timout_password_strength = setTimeout(window.test_password_strength, 200);
+ });
+
+ window.test_password_strength = function() {
+ window.timout_password_strength = null;
+
+ var args = {
+ key: get_url_arg("key") || "",
+ old_password: $("#old_password").val(),
+ new_password: $("#new_password").val()
+ }
+
+ if (!args.new_password) {
+ set_strength_indicator('grey', {'warning': __('Please enter the password') });
+ return;
+ }
+
+ return frappe.call({
+ type: 'GET',
+ method: 'frappe.core.doctype.user.user.test_password_strength',
+ args: args,
+ callback: function(r) {
+ if (r.message && r.message.entropy) {
+ var score = r.message.score,
+ feedback = r.message.feedback;
+
+ feedback.crack_time_display = r.message.crack_time_display;
+ feedback.score = score;
+
+ if (score < 2) {
+ set_strength_indicator('red', feedback);
+ } else if (score < 4) {
+ set_strength_indicator('yellow', feedback);
+ } else {
+ set_strength_indicator('green', feedback);
+ }
+ }
+ // console.log(r.message);
+ }
+ });
+ };
+
+ window.set_strength_indicator = function(color, feedback) {
+ var message = [];
+ if (feedback) {
+ if (feedback.suggestions && feedback.suggestions.length) {
+ message = message.concat(feedback.suggestions);
+ } else if (feedback.warning) {
+ message.push(feedback.warning);
+ }
+
+ if (!message.length && feedback.crack_time_display) {
+ message.push(__('This password will take {0} to crack', [feedback.crack_time_display]));
+ if (feedback.score > 3) {
+ message.push('👍');
+ }
+ }
+ }
+
+ strength_indicator.removeClass().addClass('password-strength-indicator indicator ' + color);
+ strength_message.text(message.join(' ') || '').removeClass('hidden');
+ // strength_indicator.attr('title', message.join(' ') || '');
+ }
+
+ window.clear_timeout = function() {
+ if (window.timout_password_strength) {
+ clearTimeout(window.timout_password_strength);
+ window.timout_password_strength = null;
+ }
+ };
});
+
+{% endblock %}
+
+{% block style %}
+
{% endblock %}
diff --git a/frappe/utils/password_strength.py b/frappe/utils/password_strength.py
index adf60f6e16..bc0b6ad8c3 100644
--- a/frappe/utils/password_strength.py
+++ b/frappe/utils/password_strength.py
@@ -50,7 +50,7 @@ def get_feedback (score, sequence):
feedback = {
"warning": "",
"suggestions":[
- _("Add another word or two. Uncommon words are better.")
+ _("Better add a few more letters or another word")
],
}
return feedback
@@ -68,40 +68,39 @@ def get_match_feedback(match, is_sole_match):
def fun_spatial():
if match["turns"] == 1:
feedback ={
- "warning": _('Straight rows of keys are easy to guess.'),
+ "warning": _('Straight rows of keys are easy to guess'),
"suggestions":[
- _("Use a longer keyboard pattern with more turns.")
+ _("Try to use a longer keyboard pattern with more turns")
],
}
else:
feedback ={
- "warning": _('Short keyboard patterns are easy to guess.'),
+ "warning": _('Short keyboard patterns are easy to guess'),
"suggestions":[
- _("Use a longer keyboard pattern with more turns.")
+ _("Make use of longer keyboard patterns")
],
}
return feedback
def fun_repeat():
if len(match["repeated_char"]) == 1:
feedback ={
- "warning": _('Repeats like "aaa" are easy to guess.'),
+ "warning": _('Repeats like "aaa" are easy to guess'),
"suggestions":[
- _("Avoid repeated words and characters.")
+ _("Let's avoid repeated words and characters")
],
}
else:
feedback ={
"warning": _('Repeats like "abcabcabc" are only slightly harder to guess than "abc"'),
"suggestions":[
- _("Avoid repeated words and characters.")
+ _("Try to avoid repeated words and characters")
],
}
return feedback
def fun_sequence():
return {
- "warning": _("Sequences like abc or 6543 are easy to guess."),
"suggestions":[
- _("Avoid sequences.")
+ _("Avoid sequences like abc or 6543 as they are easy to guess")
],
}
def fun_regex():