Index: install.php =================================================================== RCS file: /cvs/drupal/drupal/install.php,v retrieving revision 1.53 diff -u -p -r1.53 install.php --- install.php 22 May 2007 07:42:36 -0000 1.53 +++ install.php 23 May 2007 11:20:24 -0000 @@ -818,6 +818,8 @@ function install_configure_form() { // This is necessary to add the task to the $_GET args so the install // system will know that it is done and we've taken over. + _user_password_strength_prepare(); + $form['intro'] = array( '#value' => st('To configure your web site, please provide the following information.'), '#weight' => -10, Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.196 diff -u -p -r1.196 form.inc --- includes/form.inc 16 May 2007 07:56:19 -0000 1.196 +++ includes/form.inc 23 May 2007 11:20:24 -0000 @@ -1198,6 +1198,7 @@ function expand_password_confirm($elemen '#type' => 'password', '#title' => t('Password'), '#value' => empty($element['#value']) ? NULL : $element['#value']['pass1'], + '#attributes' => array('class' => 'password-field'), ); $element['pass2'] = array( '#type' => 'password', Index: modules/system/system.css =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.css,v retrieving revision 1.27 diff -u -p -r1.27 system.css --- modules/system/system.css 20 May 2007 16:38:19 -0000 1.27 +++ modules/system/system.css 23 May 2007 11:20:24 -0000 @@ -446,3 +446,27 @@ thead div.sticky-header { html.js .js-hide { display: none; } + +/* +** Password strength indicator +*/ +.password-strength { + padding: 2px; + margin: 0 2px 0 15px; + padding-top: 0; + float: left; + display: none; + width: 285px; +} +.password-title { + font-weight: bold; +} +.password-sibling { + float: left; + margin-top: 0; + padding-top: 0; + clear: left; +} +.password-clear { + clear: left; +} Index: modules/user/user.js =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.js,v retrieving revision 1.1 diff -u -p -r1.1 user.js --- modules/user/user.js 20 May 2007 16:38:19 -0000 1.1 +++ modules/user/user.js 23 May 2007 11:20:24 -0000 @@ -1,6 +1,89 @@ /* $Id: user.js,v 1.1 2007/05/20 16:38:19 dries Exp $ */ /** + * Attach handlers to evaluate the strength of any password fields. + */ +Drupal.passwordStrengthAttach = function(context) { + var context = context || $(document); + $("input.password-field", context).each(function() { + // Add the password strength layers. + $(this).parent().after("
"+ Drupal.settings.password.title +"
"); + var password = $(this).parent().next(".password-strength"); + + // Fix CSS so the indicator displays to the right of the password field. + $(this).parent().addClass("password-sibling"); + $(this).parent().next().next().addClass("password-clear"); + + // Monitor keyup event. + $(this).keyup(function() { + if (!$(this).val()) { + // Password is empty so hide the password strength UI. + password.hide(); + } + else { + password.show(); + } + var result = Drupal.evaluatePasswordStrength($(this).val()); + $("span.password-result", password).html(result.strength == "" ? "" : Drupal.settings.password[result.strength +"Strength"]); + $("div.description", password).html(result.message); + // Map the password strength to the relevant drupal CSS class. + var cssClass = { low: "error", medium: "warning", high: "ok" }; + var newClass = cssClass[result.strength]; + // Remove the previous styling if one exists and the class changed. + if (this.oldStrength && newClass != this.oldStrength) { + password.removeClass(cssClass[this.oldStrength]); + } + // Add the new CSS class if it changed. + if (!this.oldStrength || newClass != this.oldStrength) { + password.addClass(newClass); + } + // Save the strength for the next iteration. + this.oldStrength = result.strength; + }); + }); +} + +/** + * Evaluate the strength of a user's password. + * + * Returns the estimated strength and the relevant output message. + */ +Drupal.evaluatePasswordStrength = function(value) { + var strength = "", msg = ""; + + // Check if the password is blank. + if (!value.length) { + strength = ""; + msg = ""; + } + // Check if length is less than 6 characters. + else if (value.length < 6) { + strength = "low"; + msg = Drupal.settings.password.tooShort; + } + // Check if password is the same as the username (convert both to lowercase). + else if (value.toLowerCase() == Drupal.settings.password.username.toLowerCase()) { + strength = "low"; + msg = Drupal.settings.password.sameAsUsername; + } + // Check if it only contains letters. + else if (value.match(/^[a-zA-Z]*$/)) { + strength = "medium"; + msg = Drupal.settings.password.onlyLetters; + } + // Check if it contains punctuation or other special characters. + else if (value.match(/^[a-zA-Z0-9]*$/)) { + strength = "medium"; + msg = Drupal.settings.password.addPunctuation; + } + else { + strength = "high"; + msg = Drupal.settings.password.goodPassword; + } + return { strength: strength, message: msg }; +} + +/** * On the admin/user/settings page, conditionally show all of the * picture-related form elements depending on the current value of the * "Picture support" radio buttons. @@ -10,5 +93,6 @@ if (Drupal.jsEnabled) { $('div.user-admin-picture-radios input[@type=radio]').click(function () { $('div.user-admin-picture-settings')[['hide', 'show'][this.value]](); }); + Drupal.passwordStrengthAttach(); }); } Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.785 diff -u -p -r1.785 user.module --- modules/user/user.module 22 May 2007 05:52:17 -0000 1.785 +++ modules/user/user.module 23 May 2007 11:20:25 -0000 @@ -1424,6 +1424,7 @@ function user_register_submit($form_valu } function user_edit_form($uid, $edit, $register = FALSE) { + _user_password_strength_prepare(); $admin = user_access('administer users'); // Account information: @@ -3161,3 +3162,33 @@ function _user_mail_notify($op, $account } return $result; } + +/** + * Add javascript and string translations for password strength evaluation. + * + * This is an internal function that makes it easier to manage the translation + * strings that need to be passed to the javascript code. + */ +function _user_password_strength_prepare() { + static $complete = FALSE; + global $user; + // Only need to do once per page. + if (!$complete) { + drupal_add_js(drupal_get_path('module', 'user') .'/user.js', 'module'); + + drupal_add_js(array( + 'password' => array( + 'title' => t('Password strength:'), + 'lowStrength' => t('Low'), + 'mediumStrength' => t('Medium'), + 'highStrength' => t('High'), + 'tooShort' => t('Your password should be at least six characters in length for a minimum level of security.'), + 'onlyLetters' => t('Your password currently only contains leters. Please add numbers and punctuation to it.'), + 'addPunctuation' => t('To increase the strength of your password please add punctuation characters.'), + 'sameAsUsername' => t('Your password should not be the same as your username.'), + 'goodPassword' => t('Your password is complex enough to be reasonably secure.'), + 'username' => (isset($user->name) ? $user->name : ''))), + 'setting'); + $complete = TRUE; + } +}