Commit 9c26c145 authored by Gregor Anzelj's avatar Gregor Anzelj Committed by Robert Lyon

Bug 845263: Password policy

Improve the password policy enforcement and configuration in Mahara.
Have a pre-defined password policy of a minimum of 8 characters with
type "alphanumeric mixed case + symbols".

Also allow site administrators to set the desired password policy in
Site Options > Security Settings. In all locations where password
is set, the password input should also include a password strength
indicator.

Change-Id: I020af58a6cf1635fe295f5434783ce5b6f6daacb
parent f3d614cb
......@@ -25,6 +25,7 @@ $authobj = AuthFactory::create($USER->authinstance);
// @todo auth preference for a password change screen for all auth methods other than internal
if (method_exists($authobj, 'change_password')) {
$elements = array(
'changepassworddesc' => array(
'value' => '<tr><td colspan="2"><h3>' . get_string('changepassworddesc', 'account') . '</h3></td></tr>'
......@@ -38,7 +39,8 @@ if (method_exists($authobj, 'change_password')) {
'class' => 'hidden',
'value' => 'decoypassword',
),
'oldpassword' => array( 'type' => 'password',
'oldpassword' => array(
'type' => 'password',
'title' => get_string('oldpassword'),
'help' => true,
'autocomplete' => 'off',
......@@ -46,6 +48,8 @@ if (method_exists($authobj, 'change_password')) {
'password1' => array(
'type' => 'password',
'title' => get_string('newpassword'),
'description' => get_password_policy_description(),
'showstrength' => true
),
'password2' => array(
'type' => 'password',
......
......@@ -410,6 +410,16 @@ $siteoptionform = array(
'collapsed' => true,
'legend' => get_string('securitysettingslegend', 'admin'),
'elements' => array(
'passwordpolicy' => array(
'type' => 'passwordpolicy',
'minlength' => 8,
'maxlength' => 20,
'title' => get_string('passwordpolicy', 'admin'),
'description' => get_string('passwordpolicydesc', 'admin'),
'defaultvalue' => get_config('passwordpolicy'),
'disabled' => in_array('passwordpolicy', $OVERRIDDEN),
'class' => 'double'
),
'viruschecking' => array(
'type' => 'switchbox',
'title' => get_string('viruschecking', 'admin'),
......@@ -807,6 +817,7 @@ function siteoptions_fail(Pieform $form, $field) {
}
function siteoptions_submit(Pieform $form, $values) {
global $USER;
$fields = array(
'sitename','lang','theme',
'defaultaccountlifetime', 'defaultregistrationexpirylifetime', 'defaultaccountinactiveexpire', 'defaultaccountinactivewarn',
......@@ -815,7 +826,7 @@ function siteoptions_submit(Pieform $form, $values) {
'institutionstrictprivacy',
'showselfsearchsideblock', 'nousernames', 'searchplugin', 'showtagssideblock',
'tagssideblockmaxtags', 'country', 'userscanchooseviewthemes', 'internalnotificationexpire',
'remoteavatars', 'userscanhiderealnames', 'antispam', 'spamhaus', 'surbl', 'anonymouscomments',
'remoteavatars', 'userscanhiderealnames', 'antispam', 'spamhaus', 'surbl', 'anonymouscomments', 'passwordpolicy',
'recaptchaonregisterform', 'recaptchapublickey', 'recaptchaprivatekey', 'loggedinprofileviewaccess', 'disableexternalresources',
'proxyaddress', 'proxyauthmodel', 'proxyauthcredentials', 'smtphosts', 'smtpport', 'smtpuser', 'smtppass', 'smtpsecure',
'noreplyaddress', 'homepageinfo', 'showprogressbar', 'showonlineuserssideblock', 'onlineuserssideblockmaxusers',
......@@ -885,6 +896,21 @@ function siteoptions_submit(Pieform $form, $values) {
if (!empty($values['eventlogenhancedsearch']) && $values['searchplugin'] != 'elasticsearch') {
$values['eventlogenhancedsearch'] = false;
}
// If password policy is changed, force reset password for all users with internal authentication.
if ($values['passwordpolicy'] != get_password_policy()) {
db_begin();
execute_sql("
UPDATE {usr} SET passwordchange = 1
WHERE authinstance IN (
SELECT ai.id
FROM {auth_instance} ai
WHERE ai.authname = 'internal'
)
AND id NOT IN (0, ?)
", array($USER->get('id'))); // Ignore the root and current admin user
db_commit();
}
$oldsearchplugin = get_config('searchplugin');
$oldlanguage = get_config('lang');
$oldtheme = get_config('theme');
......
......@@ -84,6 +84,8 @@ $elements = array(
'type' => 'password',
'title' => get_string('password'),
'rules' => array('required' => true),
'description' => get_password_policy_description(),
'showstrength' => true,
),
'staff' => array(
'type' => 'switchbox',
......@@ -144,7 +146,7 @@ unset($prefs);
$form = pieform(array(
'name' => 'adduser',
'class' => 'panel panel-default panel-body',
'class' => 'panel panel-default panel-body',
'autofocus' => false,
'template' => 'adduser.php',
'templatedir' => pieform_template_dir('adduser.php'),
......@@ -206,7 +208,13 @@ function adduser_validate(Pieform $form, $values) {
}
if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) {
$form->set_error('password', get_string('passwordinvalidform', 'auth.' . $authobj->type));
if ($authobj->type == 'internal') {
$form->set_error('password', get_password_policy_description('error'));
}
else {
// Allow auth type to return their own error message - Currently not used
$form->set_error('password', get_string('passwordinvalidform' . $authobj->type, 'auth.' . $authobj->type));
}
}
if (param_exists('createmethod') && param_variable('createmethod') == 'leap2a') {
......
......@@ -60,12 +60,13 @@ if (method_exists($authobj, 'change_username')) {
);
}
// Only show the password options if the plugin allows for the functionality
if (method_exists($authobj, 'change_password')) {
// Only show the password options if the plugin allows for the functionality
$elements['password'] = array(
'type' => 'password',
'title' => get_string('resetpassword','admin'),
'description' => get_string('resetpassworddescription','admin'),
'description' => get_string('resetpassworddescription', 'admin') . ' ' . get_password_policy_description(),
'showstrength' => true
);
$elements['passwordchange'] = array(
......@@ -288,17 +289,15 @@ function edituser_site_validate(Pieform $form, $values) {
$userobj = new User();
$userobj = $userobj->find_by_id($user->id);
if (isset($values['username']) && !empty($values['username']) && $values['username'] != $userobj->username) {
if (!isset($values['authinstance'])) {
$authobj = AuthFactory::create($userobj->authinstance);
}
else {
$authobj = AuthFactory::create($values['authinstance']);
}
if (!isset($values['authinstance'])) {
$authobj = AuthFactory::create($userobj->authinstance);
}
else {
$authobj = AuthFactory::create($values['authinstance']);
}
if (isset($values['username']) && !empty($values['username']) && $values['username'] != $userobj->username) {
if (method_exists($authobj, 'change_username')) {
if (method_exists($authobj, 'is_username_valid_admin')) {
if (!$authobj->is_username_valid_admin($values['username'])) {
$form->set_error('username', get_string('usernameinvalidadminform', 'auth.internal'));
......@@ -318,7 +317,17 @@ function edituser_site_validate(Pieform $form, $values) {
$form->set_error('username', get_string('usernamechangenotallowed', 'admin'));
}
}
if (isset($values['password']) && !empty($values['password'])) {
if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($values['password'])) {
if ($authobj->type == 'internal') {
$form->set_error('password', get_password_policy_description('error'));
}
else {
// Allow auth type to return their own error message - Currently not used
$form->set_error('password', get_string('passwordinvalidform' . $authobj->type, 'auth.' . $authobj->type));
}
}
}
// Check that the external username isn't already in use by someone else
if (isset($values['authinstance']) && isset($values['remoteusername'])) {
// there are 4 cases for changes on the page
......
......@@ -281,7 +281,7 @@ function uploadcsv_validate(Pieform $form, $values) {
// like whether the password is too easy. The user is going to have to
// change their password on first login anyway.
if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) {
$csverrors->add($i, get_string('uploadcsverrorinvalidpassword', 'admin', $i));
$csverrors->add($i, get_string('uploadcsverrorinvalidpassword1', 'admin', $i, get_password_policy_description()));
}
}
......@@ -391,7 +391,7 @@ function uploadcsv_validate(Pieform $form, $values) {
else {
// New user, check the password
if (method_exists($authobj, 'is_password_valid') && !$authobj->is_password_valid($password)) {
$csverrors->add($line, get_string('uploadcsverrorinvalidpassword', 'admin', $line));
$csverrors->add($line, get_string('uploadcsverrorinvalidpassword1', 'admin', $line, get_password_policy_description()));
}
}
......
......@@ -19,10 +19,7 @@ $string['completeregistration'] = 'Complete registration';
$string['emailalreadytaken'] = 'This email address has already been registered here.';
$string['emailalreadytakenbyothers'] = 'This email address has been taken by another user.';
$string['iagreetothetermsandconditions'] = 'I agree to the Terms and Conditions.';
$string['passwordformdescription'] = 'Your password must be at least six characters long. Passwords are case sensitive and must be different from your username.<br/>
For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.';
$string['passwordinvalidform'] = 'Your password must be at least six characters long. Passwords are case sensitive and must be different from your username.<br/>
For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.';
$string['passwordinvalidform1'] = 'Your password must be at least %s characters long. Passwords are case sensitive and must be different from your username. Your password must contain %s.';
$string['recaptcharegistertitle'] = 'reCAPTCHA challenge';
$string['recaptcharegisterdesc1'] = 'Please tick the "I\'m not a robot" box. Doing so helps prevent automated programs from abusing this service.';
$string['registeredemailsubject'] = 'You have registered at %s';
......
......@@ -72,17 +72,34 @@ class AuthInternal extends Auth {
/**
* For internal authentication, passwords can contain a range of letters,
* numbers and symbols. There is a minimum limit of six characters allowed
* numbers and symbols. There is a minimum limit of eight characters allowed
* for the password, and no upper limit
*
* @param string $password The password to check
* @return bool Whether the password is valid
*/
public function is_password_valid($password) {
if (!preg_match('/^[a-zA-Z0-9 ~!@#\$%\^&\*\(\)_\-=\+\,\.<>\/\?;:"\[\]\{\}\\\|`\']{6,}$/', $password)) {
list($minlength, $format) = get_password_policy(true);
if (!preg_match('/^[a-zA-Z0-9 ~!@#\$%\^&\*\(\)_\-=\+\,\.<>\/\?;:"\[\]\{\}\\\|`\']{' . $minlength . ',}$/', $password)) {
return false;
}
return true;
$containsLetter = preg_match('/\pL/', $password); // '/[a-zA-Z]/'
$containsNumber = preg_match('/\pN/', $password); // '/\d/'
$containsSymbol = preg_match('/[^\pL\pN]/', $password); // '/[^a-zA-Z\d]/'
if ($format == 'ul') {
return $containsLetter;
}
if ($format == 'uln') {
return ($containsLetter && $containsNumber);
}
if ($format == 'ulns') {
return ($containsLetter && $containsNumber && $containsSymbol);
}
return false;
}
/**
......
......@@ -912,7 +912,8 @@ function auth_check_required_fields() {
$elements['password1'] = array(
'type' => 'password',
'title' => get_string('newpassword') . ':',
'description' => get_string('yournewpassword'),
'description' => get_password_policy_description('user'),
'showstrength' => true,
'rules' => array(
'required' => true
)
......@@ -2227,7 +2228,7 @@ function password_validate(Pieform $form, $values, $user) {
$authobj = AuthFactory::create($user->authinstance);
if (!$form->get_error('password1') && !$authobj->is_password_valid($values['password1'])) {
$form->set_error('password1', get_string('passwordinvalidform', "auth.$authobj->type"), false);
$form->set_error('password1', get_password_policy_description('error'));
}
$suckypasswords = array(
......
......@@ -20,8 +20,7 @@ $string['webserviceconnectionsconfigdesc'] = 'Set up the connection objects that
$string['completeregistration'] = 'Complete registration';
$string['emailalreadytaken'] = 'This email address has already registered here';
$string['iagreetothetermsandconditions'] = 'I agree to the Terms and Conditions.';
$string['passwordformdescription'] = 'Your password must be at least six characters long and contain at least one digit and two letters.';
$string['passwordinvalidform'] = 'Your password must be at least six characters long and contain at least one digit and two letters.';
$string['passwordinvalidform1'] = 'Your password must be at least %s characters long. Passwords are case sensitive and must be different from your username. Your password must contain %s.';
$string['registeredemailsubject'] = 'You have registered at %s';
$string['registeredemailmessagetext'] = 'Hello %s,
......
......@@ -48,7 +48,8 @@ if ($SESSION->get('forgotpasskey')) {
'password1' => array(
'type' => 'password',
'title' => get_string('password'),
'description' => get_string('yournewpassword'),
'description' => get_password_policy_description('user'),
'showstrength' => true,
'rules' => array(
'required' => true
)
......
Copyright (c) 2012-2016 Dan Wheeler and Dropbox, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
zxcvbn
======
Website: https://github.com/dropbox/zxcvbn
Version: 4.4.2
zxcvbn is a password strength estimator inspired by password crackers. Through pattern matching and conservative estimation, it recognizes and weighs 30k common passwords, common names and surnames according to US census data, popular English words from Wikipedia and US television and movies, and other common patterns like dates, repeats (aaa), sequences (abcd), keyboard patterns (qwertyuiop), and l33t speak.
Changes:
* None
This diff is collapsed.
......@@ -372,6 +372,10 @@ $string['defaultaccountlifetimeupdatedescription'] = 'If default account lifetim
$string['defaultaccountlifetimeupdatenone'] = 'Only for newly created users';
$string['defaultaccountlifetimeupdatesome'] = 'For new users and users without an account lifetime already set (excluding site administrators)';
$string['defaultaccountlifetimeupdateall'] = 'For all user accounts (excluding site administrators)';
$string['passwordpolicy'] = 'Password policy';
$string['passwordpolicydesc'] = 'Password policy for people whose account is set to use the built-in internal authentication method. Select the number of minimum characters and the complexity of the password.';
$string['passwordpolicylength'] = 'Minimum password length';
$string['passwordpolicytype'] = 'Password complexity';
$string['deprecatedmobileapp'] = "Sorry, this mobile application has been superseded. You need to use Mahara mobile application instead. Download for android devices https://play.google.com/store/apps/details?id=org.mahara.mobile or for apple devices https://itunes.apple.com/us/app/mahara-mobile/id1172638950";
$string['embeddedcontent'] = 'Embedded content';
$string['embeddedcontentdescription'] = 'If you would like users to be able to embed videos or other outside content into their portfolios, you can choose which sites to trust below.';
......@@ -633,8 +637,7 @@ $string['uploadcsverrorunspecifiedproblem1'] = 'The records in your CSV file cou
$string['uploadcsverrorwrongnumberoffields'] = 'Error on line %s of your file: Incorrect number of fields.';
$string['uploadcsverrorinvalidemail'] = 'Error on line %s of your file: The email address for this user is not in the correct format.';
$string['uploadcsverrorincorrectnumberoffields'] = 'Error on line %s of your file: This line does not have the correct number of fields.';
$string['uploadcsverrorinvalidpassword'] = 'Error on line %s of your file: Passwords must be at least six characters long. Passwords are case-sensitive and must be different from your username.<br/>
For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.';
$string['uploadcsverrorinvalidpassword1'] = 'Error on line %s of your file: %s';
$string['uploadcsverrorinvalidusername'] = 'Error on line %s of your file: The username for this user is not in the correct format.';
$string['uploadcsverrormandatoryfieldnotspecified'] = 'Line %s of the file does not have the required "%s" field.';
$string['uploadcsverroruseralreadyexists'] = 'Line %s of the file specifies the username "%s" that already exists.';
......
......@@ -2,5 +2,5 @@
<!-- @copyright For copyright information on Mahara, please see the README file distributed with this software. -->
<h3>Passwords</h3>
<p>To change your login password, first enter your current password here, then enter your preferred new password in both the other boxes.</p>
<p>Your password must be at least six characters long. Passwords are case sensitive and must be different from your username.</p>
<p>Your new password must match the password policy.</p>
<p>For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.</p>
<!-- @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later -->
<!-- @copyright For copyright information on Mahara, please see the README file distributed with this software. -->
<h3>Passwords</h3>
<p>To change your login password, first enter your current password here, then enter your preferred new password in both the other boxes.</p>
<p>Your password must be at least six characters long. Passwords are case sensitive and must be different from your username.</p>
<p>For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.</p>
<!-- @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later -->
<!-- @copyright For copyright information on Mahara, please see the README file distributed with this software. -->
<h3>Password</h3>
<p>Your password must be at least six characters long. Passwords are case sensitive, and must be different from your username.</p>
<p><strong>Warning:</strong> For security reasons, please do not disclose your password to any user, including the site administrator.</p>
<p>For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.</p>
<!-- @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later -->
<!-- @copyright For copyright information on Mahara, please see the README file distributed with this software. -->
<h3>Passwords</h3>
<p>To change your login password, first enter your current password here, then enter your preferred new password in both the other boxes.</p>
<p>Your password must be at least six characters long. Passwords are case sensitive, and must be different from your username.</p>
<p>For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.</p>
\ No newline at end of file
......@@ -441,7 +441,15 @@ $string['newpassword'] = 'New password';
$string['nosessionreload'] = 'Reload the page to log in';
$string['oldpassword'] = 'Current password';
$string['password'] = 'Password';
$string['passworddescription'] = ' ';
$string['passwordstrength1'] = 'Very weak';
$string['passwordstrength2'] = 'Weak';
$string['passwordstrength3'] = 'Strong';
$string['passwordstrength4'] = 'Very strong';
$string['passworddescription'] = '';
$string['passworddescriptionbase'] = 'The mininum length of the password is %s characters.';
$string['passworddescription.ul'] = 'It must contain upper and lowercase letters.';
$string['passworddescription.uln'] = 'It must contain upper and lowercase letters and numbers.';
$string['passworddescription.ulns'] = 'It must contain upper and lowercase letters, numbers and symbols.';
$string['passwordhelp'] = 'The password you use to access the system';
$string['passwordnotchanged'] = 'You did not change your password. Please choose a new password.';
$string['passwordsaved'] = 'Your new password has been saved';
......@@ -457,7 +465,7 @@ $string['preferredname'] = 'Display name';
$string['usernamedescription'] = ' ';
$string['usernamehelp'] = 'The username you have been given to access this system.';
$string['youaremasqueradingas'] = 'You are masquerading as %s.';
$string['yournewpassword'] = 'Your new password. Passwords must be at least six characters long. Passwords are case-sensitive and must be different from your username.<br/>
$string['yournewpassword1'] = 'Your new password. Password must be at least %s characters long. Passwords are case sensitive and must be different from your username. %s<br/>
For good security, consider using a passphrase. A passphrase is a sentence rather than a single word. Consider using a favourite quote or listing two (or more!) of your favourite things separated by spaces.';
$string['yournewpasswordagain'] = 'Your new password again';
$string['invalidsesskey'] = 'Invalid session key';
......
......@@ -46,6 +46,10 @@ $string['element.expiry.noenddate'] = 'No end date';
$string['element.files.addattachment'] = 'Add attachment';
$string['element.passwordpolicy.ul'] = 'Upper and lowercase letters';
$string['element.passwordpolicy.uln'] = 'Upper and lowercase letters, numbers';
$string['element.passwordpolicy.ulns'] = 'Upper and lowercase letters, numbers, symbols';
$string['element.select.other'] = 'Other';
$string['element.select.remove'] = 'Remove "%s"';
......@@ -78,4 +82,4 @@ $string['switchbox.off'] = 'Off';
$string['switchbox.yes'] = 'Yes';
$string['switchbox.no'] = 'No';
$string['requiredfields'] = "Fields marked by '%s' are required.";
\ No newline at end of file
$string['requiredfields'] = "Fields marked by '%s' are required.";
......@@ -5265,7 +5265,6 @@ function create_elasticsearch_triggers() {
}
}
/**
* Return a list of available institution(s) to associate to a group.
*
......@@ -5302,3 +5301,37 @@ function get_institutions_to_associate() {
return $institutions;
}
/**
* Get the password policy for this site
*
* @param bool $parts When true we return an array of the policy parts and when false return the policy string
*/
function get_password_policy($parts = false) {
$policy = !empty(get_config('passwordpolicy')) ? get_config('passwordpolicy') : '8_ulns';
if ($parts) {
return explode('_', $policy);
}
return $policy;
}
/**
* Get the password policy description based on password policy values
*
* @param bool $type When 'error' we return an error description rather than form field description
* When 'user' we use message to user rather than generic message
*/
function get_password_policy_description($type = 'generic') {
list($numbervalue, $formatvalue) = get_password_policy(true);
if ($type == 'error') {
$formatdesc = strtolower(get_string('element.passwordpolicy.' . $formatvalue, 'pieforms'));
$description = get_string('passwordinvalidform1', 'auth.internal', $numbervalue, $formatdesc);
}
else if ($type == 'user') {
$description = get_string('yournewpassword1', 'mahara', $numbervalue, get_string('passworddescription.' . $formatvalue, 'mahara'));
}
else {
$description = get_string('passworddescriptionbase', 'mahara', $numbervalue) . ' ' . get_string('passworddescription.' . $formatvalue, 'mahara');
}
return $description;
}
......@@ -32,11 +32,65 @@
* @return string The HTML for the element
*/
function pieform_element_password(Pieform $form, $element) {/*{{{*/
return '<input type="password"'
$result = '<input type="password"'
. $form->element_attributes($element)
. ' value="' . Pieform::hsc($form->get_value($element)) . '">';
if (isset($element['showstrength']) && $element['showstrength']) {
$id = $form->get_name() . '_' . $element['id'];
$msg1 = get_string('passwordstrength1');
$msg2 = get_string('passwordstrength2');
$msg3 = get_string('passwordstrength3');
$msg4 = get_string('passwordstrength4');
$result .= '<label for="strengthBar"></label>'
. '<div class="form-control progress password-progress">'
. ' <div id="strengthBar" class="progress-bar" role="progressbar" style="width: 0;"></div>'
. '</div>';
$result .= <<<EOJS
<script type="application/javascript">
jQuery('#{$id}').keyup(function() {
var result = zxcvbn(jQuery('#{$id}').val());
var score = result.score;
var bar = jQuery('#strengthBar');
switch (score) {
case 0:
bar.attr('class', 'progress-bar progress-bar-danger').css('width', '1%');
bar.text('');
break;
case 1:
bar.attr('class', 'progress-bar progress-bar-danger').css('width', '25%');
bar.text('{$msg1}');
break;
case 2:
bar.attr('class', 'progress-bar progress-bar-danger').css('width', '50%');
bar.text('{$msg2}');
break;
case 3:
bar.attr('class', 'progress-bar progress-bar-warning').css('width', '75%');
bar.text('{$msg3}');
break;
case 4:
bar.attr('class', 'progress-bar progress-bar-success').css('width', '100%');
bar.text('{$msg4}');
break;
}
});
</script>
EOJS;
}
return $result;
}/*}}}*/
function pieform_element_password_get_headdata() {
$libjs = get_config('wwwroot') . 'js/zxcvbn/zxcvbn.js';
$result = array(
'<script type="application/javascript" src="' . append_version_number($libjs) . '"></script>',
);
return $result;
}
function pieform_element_password_get_value(Pieform $form, $element) {/*{{{*/
if (isset($element['value'])) {
return $element['value'];
......
<?php
/**
*
* @package pieforms
* @subpackage element
* @author Gregor Anzelj <gregor.anzelj@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
/**
* Provides a password policy chooser, in the form of a minimum length dropdown box
* and password type (uppercase, lowercase, numerals, special symbols) dropdown box.
*
* @param Pieform $form The form to render the element for
* @param array $element The element to render
* @return string The HTML for the element
*/
function pieform_element_passwordpolicy(Pieform $form, $element) {/*{{{*/
$name = Pieform::hsc($element['name']);
$min = (isset($element['minlength'])) && intval($element['minlength']) >= 8 ? intval($element['minlength']) : 8;
$max = (isset($element['maxlength'])) && intval($element['maxlength']) > intval($element['minlength']) ? intval($element['maxlength']) : 20;
$global = ($form->get_property('method') == 'get') ? $_GET : $_POST;
// Get the value of the element for rendering.
if (isset($element['value'])) {
$value = $element['value'];
}
else if ($form->is_submitted() && isset($global[$name . '_number']) && isset($global[$name . '_format'])) {
$value = $global[$name . '_number'] . '_' . $global[$name . '_format'];
}
else if (isset($element['defaultvalue'])) {
$value = $element['defaultvalue'];
}
else {
$value = '8_ulns'; // 8 characters - upper and lowercase letters, numbers, symbols
}
list($numbervalue, $formatvalue) = explode('_', $value);
// Number dropdown
$label = get_string('passwordpolicylength', 'admin');
$number = '<label for="' . $name . '_number" class="accessible-hidden sr-only">' . $label . '</label>';
$number .= '<span class="picker"><select class="form-control select" ';
$number .= 'name="' . $name . '_number" id="' . $name . '_number"' . ' tabindex="' . Pieform::hsc($element['tabindex']) . '"';
if (isset($element['description'])) {
$number .= ' aria-describedby="' . $form->element_descriptors($element) . '"';
}
$number .= ">\n";
for ($i = $min; $i <= $max; $i++) {
$number .= "\t<option value=\"$i\"" . (($numbervalue == $i) ? ' selected="selected"' : '') . '>' . $i . "</option>\n";
}
$number .= "</select></span>\n";
// Format dropdown
$label = get_string('passwordpolicytype', 'admin');
$format = '<label for="' . $name . '_format" class="accessible-hidden sr-only">' . $label . '</label>';
$format .= '<span class="picker"><select class="form-control select" ';
$format .= 'name="' . $name . '_format" id="' . $name . '_format"' . ' tabindex="' . Pieform::hsc($element['tabindex']) . '"';
if (isset($element['description'])) {
$format .= ' aria-describedby="' . $form->element_descriptors($element) . '"';
}
$format .= ">\n";
foreach (pieform_element_passwordpolicy_get_formats() as $f) {
$format .= "\t<option value=\"$f\"" . (($formatvalue == $f) ? ' selected="selected"' : '') . '>'
. $form->i18n('element', 'passwordpolicy', $f, $element) . "</option>\n";
}
$format .= "</select></span>\n";
return $number . $format;
}/*}}}*/
/**