Commit 47c7fcb5 authored by lindonb's avatar lindonb

[FIX] password validation: use iconsets; fix broken formatting; make...

 [FIX] password validation: use iconsets; fix broken formatting; make generated passwords better than just average strength; fix bugs in password matching/generation jQuery and place in a single file. TODO: allow jQuery validator to be applied to add new user admin form and change password form and centralize validator code.
parent 930e3d74
......@@ -5705,6 +5705,7 @@ templates/object_selector.tpl -text
templates/object_selector_multi.tpl -text
templates/pagehistory.tpl -text
templates/password_help.tpl -text
templates/password_jq.tpl -text
templates/permission_link.tpl -text
templates/plugins/index.php -text
templates/plugins/plugin-topfriends.tpl -text
......
......@@ -262,28 +262,36 @@ function setMenuCon(foo) {
}
function genPass(w1) {
var vo = "aeiouAEU", co, s, l, p, i, letter;
co = "bcdfgjklmnprstvwxzBCDFGHJKMNPQRSTVWXYZ0123456789_$%#";
s = Math.round(Math.random());
var lower, upper, num, other, l, p, pstr, i, letter, j, temp;
lower = 'abcdefghijklmnopqrstuvwxyz';
upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
num = '0123456789';
other = '_$%#[email protected]*+';
l = 8;
p = '';
p = [];
//ensure at least 2 upper case letters, 2 numbers, and 2 other characters
for (i = 0; i < l; i++) {
if (s) {
letter = vo.charAt(Math.round(Math.random() * (vo.length - 1)));
s = 0;
if (i < 2) {
letter = lower.charAt(Math.round(Math.random() * (lower.length - 1)));
} else if (i < 4) {
letter = upper.charAt(Math.round(Math.random() * (upper.length - 1)));
} else if (i < 6) {
letter = num.charAt(Math.round(Math.random() * (num.length - 1)));
} else {
letter = co.charAt(Math.round(Math.random() * (co.length - 1)));
s = 1;
letter = other.charAt(Math.round(Math.random() * (other.length - 1)));
}
p = p + letter;
p[i] = letter;
}
document.getElementById(w1).value = p;
//shuffle the characters since they are blocks of 2 per above
for (i = p.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
//implode into a string
pstr = p.join('');
document.getElementById(w1).value = pstr;
}
function setUserModule(foo1) {
......@@ -1722,70 +1730,88 @@ function checkPassword(strPassword)
//Runs password through check and then updates GUI
function runPassword(strPassword, strFieldID)
{
// Check password
var nScore = checkPassword(strPassword);
// Get controls
var ctlBar = document.getElementById(strFieldID + "_bar");
var ctlText = document.getElementById(strFieldID + "_text");
if (!ctlBar || !ctlText) {
var ctlTextInner = document.getElementById(strFieldID + "_text_inner");
if (!ctlBar || !ctlText || !ctlTextInner) {
return;
}
// Set new width
ctlBar.style.width = nScore + "%";
if (strPassword.length > 0) {
// Check password
var nScore = checkPassword(strPassword);
// Color and text
// -- Very Secure
if (nScore >= 90)
{
var strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Very Secure' />";
var strText = tr("Very Secure");
var strColor = "#0ca908";
}
// -- Secure
else if (nScore >= 80)
{
strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Secure' />";
strText = tr("Secure");
strColor = "#0ca908";
}
// -- Very Strong
else if (nScore >= 70)
{
strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Very Strong' />";
strText = tr("Very Strong");
strColor = "#0ca908";
}
// -- Strong
else if (nScore >= 60)
{
strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Strong' />";
strText = tr("Strong");
strColor = "#0ca908";
}
// -- Average
else if (nScore >= 40)
{
strIcon = " ";
strText = tr("Average");
strColor = "#e3cb00";
}
// -- Weak
else if (nScore >= 25)
{
strIcon = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Weak' />";
strText = tr("Weak");
strColor = "#ff0000";
}
// -- Very Weak
else
{
strIcon = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Very weak' />";
strText = tr("Very Weak");
strColor = "#ff0000";
// Set new width
ctlBar.style.width = nScore + "%";
// Color and text
var icon, strText, strColor;
// -- Very Secure
if (nScore >= 90)
{
icon = 'ok';
strText = tr("Very Secure");
strColor = "#0ca908";
}
// -- Secure
else if (nScore >= 80)
{
icon = 'ok';
strText = tr("Secure");
strColor = "#0ca908";
}
// -- Very Strong
else if (nScore >= 70)
{
icon = 'ok';
strText = tr("Very Strong");
strColor = "#0ca908";
}
// -- Strong
else if (nScore >= 60)
{
icon = 'ok';
strText = tr("Strong");
strColor = "#0ca908";
}
// -- Average
else if (nScore >= 40)
{
icon = 'none';
strText = tr("Average");
strColor = "#e3cb00";
}
// -- Weak
else if (nScore >= 25)
{
icon = 'error';
strText = tr("Weak");
strColor = "#ff0000";
}
// -- Very Weak
else
{
icon = 'error';
strText = tr("Very Weak");
strColor = "#ff0000";
}
ctlBar.style.backgroundColor = strColor;
$(ctlBar).show();
if (icon === 'none') {
$(ctlText).children('span.icon').hide();
} else if (icon === 'ok') {
$(ctlText).children('span.icon-ok').css('color', strColor).show();
$(ctlText).children('span.icon-error').hide();
} else if (icon === 'error') {
$(ctlText).children('span.icon-ok').hide();
$(ctlText).children('span.icon-error').css('color', strColor).show();
}
$(ctlTextInner).text(tr('Strength') + ': ' + strText).show();
} else {
$(ctlText).children().hide();
$(ctlTextInner).hide();
$(ctlBar).hide();
}
ctlBar.style.backgroundColor = strColor;
ctlText.innerHTML = "<span>" + strIcon + " " + tr("Strength") + ": " + strText + "</span>";
}
//Checks a string for a list of characters
......@@ -1806,12 +1832,18 @@ function countContain(strPassword, strCheck)
}
function checkPasswordsMatch(in1, in2, el) {
if ($(in1).val().length && $(in1).val() == $(in2).val()) {
$(el).html("<img src='img/icons/accept.png' style='vertical-align:middle' alt='Secure' /><em>" + tr("Passwords match") + "</em>");
return true;
if ($(in1).val().length) {
if ($(in1).val() == $(in2).val()) {
$(el).children('#match').show();
$(el).children('#nomatch').hide();
return true;
} else {
$(el).children('#match').hide();
$(el).children('#nomatch').show();
return false;
}
} else {
$(el).html("");
return false;
$(el).children().hide();
}
}
......
{* $Id$ *}
{jq notonready=true}
{* Test for caps lock - used below *}
var divRegCapson = $('#divRegCapson');
function regCapsLock(e){
kc = e.keyCode?e.keyCode:e.which;
sk = e.shiftKey?e.shiftKey:((kc == 16)?true:false);
if(((kc >= 65 && kc <= 90) && !sk)||((kc >= 97 && kc <= 122) && sk)) {
divRegCapson.show();
} else {
divRegCapson.hide();
}
}
{/jq}
{*
The below assumes:
(1) first password input id='pass1',
(1.1) divs underneath the first password input as follows (to show password strength icon, text and bar):
<div id="mypassword_text">{icon name='ok' istyle='display:none'}{icon name='error' istyle='display:none' } <span id="mypassword_text_inner"></span></div>
<div id="mypassword_bar" style="font-size: 5px; height: 2px; width: 0px;"></div>
(2) repeat password input id='pass2',
(2.1) divs underneath the repeat password input as follows to show whether passord matches:
<div id="mypassword2_text">
<div id="match" style="display:none">
{icon name='ok' istyle='color:#0ca908'} {tr}Passwords match{/tr}
</div>
<div id="nomatch" style="display:none">
{icon name='error' istyle='color:#ff0000'} {tr}Passwords do not match{/tr}
</div>
</div>
This password match will only be run if jquery validator is not on
*}
{jq}
{* Give warning if caps lock is on when user starts typing in characters for a password *}
$('#pass1, #pass2').on('keypress', function () {
regCapsLock(event);
});
{* Show strength of the password as it is being typed *}
$('#pass1').on('keyup', function () {
runPassword(this.value, 'mypassword');
});
{/jq}
{if (isset($ignorejq) && $ignorejq === 'y') || $prefs.feature_jquery_validation neq 'y'}
{jq}
{* Indicate whether repeat password matches as user types it in *}
$('#pass1, #pass2').on('keyup', function () {
checkPasswordsMatch('#pass2', '#pass1', '#mypassword2_text')
});
{/jq}
{/if}
{if $prefs.generate_password eq 'y'}
{jq}
{* Generate password and insert into an input element that will be shown and selected *}
$('#genPass').click(function () {
genPass('genepass');
$('#genepass').show().select();
return false;
});
{/jq}
{/if}
......@@ -7,22 +7,26 @@
<div class="form-group">
<label class="col-md-4 col-sm-3 control-label" for="pass1">{tr}Password{/tr}</label>
<div class="col-md-4 col-sm-6">
<input class="form-control" id='pass1' type="password" name="pass" onkeypress="regCapsLock(event)" value="{if !empty($smarty.post.pass)}{$smarty.post.pass}{/if}"
onkeyup="runPassword(this.value, 'mypassword');{if $prefs.feature_jquery_validation neq 'y' && !$userTrackerData}checkPasswordsMatch('#pass2', '#pass1', '#mypassword2_text');{/if}">
<input
class="form-control"
id='pass1'
type="password"
name="pass"
value="{if !empty($smarty.post.pass)}{$smarty.post.pass}{/if}"
>
<div style="margin-left:5px;">
<div id="mypassword_text"></div>
<div id="mypassword_text">{icon name='ok' istyle='display:none'}{icon name='error' istyle='display:none' } <span id="mypassword_text_inner"></span></div>
<div id="mypassword_bar" style="font-size: 5px; height: 2px; width: 0px;"></div>
</div>
{if $prefs.feature_jquery_validation neq 'y'}
{include file='password_help.tpl'}
<div style="margin-top:5px">
{include file='password_help.tpl'}
</div>
{/if}
</div>
<div class="col-sm-1">
{if $trackerEditFormId}<span class='text-danger tips' title=":{tr}This field is manadatory{/tr}">*</span>{/if}
</div>
<div class="col-sm-2">
<input class="form-control" id='genepass' name="genepass" type="text" tabindex="0" size="10" style="display: none; width:160px">
</div>
</div>
{/if}
{/if}
......@@ -7,28 +7,37 @@
<div class="form-group">
<label class="col-md-4 col-sm-3 control-label" for="pass2">{tr}Repeat password{/tr}</label>
<div class="col-md-4 col-sm-6">
<input class="form-control" id='pass2' type="password" name="passAgain" onkeypress="regCapsLock(event)" value="{if !empty($smarty.post.passAgain)}{$smarty.post.passAgain}{/if}"
onkeyup="{if $prefs.feature_jquery_validation neq 'y' && !$userTrackerData}checkPasswordsMatch('#pass2', '#pass1', '#mypassword2_text');{/if}">
<div style="float:right;margin-left:5px;">
<div id="mypassword2_text"></div>
<input
class="form-control"
id='pass2'
type="password"
name="passAgain"
value="{if !empty($smarty.post.passAgain)}{$smarty.post.passAgain}{/if}"
>
<div id="mypassword2_text">
<div id="match" style="display:none">
{icon name='ok' istyle='color:#0ca908'} {tr}Passwords match{/tr}
</div>
<div id="nomatch" style="display:none">
{icon name='error' istyle='color:#ff0000'} {tr}Passwords do not match{/tr}
</div>
</div>
{if $prefs.feature_jquery_validation neq 'y' && !$userTrackerData}<span id="checkpass"></span>{/if}
</div>
<div class="col-md-1 col-sm-1">
{if $trackerEditFormId}<span class='text-danger tips' title=":{tr}This field is manadatory{/tr}">*</span>{/if}
</div>
{if $prefs.generate_password eq 'y'}
{*if !$reg_in_module}<td>&nbsp;</td>{/if*}
<div class="col-md-3 col-sm-2{*if $reg_in_module} inmodule{/if*}">
<span id="genPass">
{if 0 and $prefs.feature_ajax eq 'y'}
{button href="#" _onclick="check_pass();" _text="{tr}Generate a password{/tr}"}
{else}
{button href="#" _onclick="" _text="{tr}Generate a password{/tr}"}
{/if}
</span>
</div>
{/if}
</div>
{if $prefs.generate_password eq 'y'}
{*if !$reg_in_module}<td>&nbsp;</td>{/if*}
<div class="form-group">
<div class="col-sm-3 col-sm-offset-3 col-md-2 col-md-offset-4">
<span id="genPass">{button href="#" _text="{tr}Generate a password{/tr}"}</span>
</div>
<div class="col-sm-3 col-md-2">
<input id='genepass' class="form-control" name="genepass" type="text" tabindex="0" style="display:none">
</div>
</div>
{/if}
{/if}
{/if}
......@@ -478,49 +478,43 @@
</div>
</div>
{else}
{include file='password_jq.tpl' ignorejq='y'}
<div class="form-group">
<label class="col-sm-3 col-md-2 control-label" for="pass1">{tr}New Password{/tr}</label>
<div class="col-sm-7 col-md-6">
<input type="password" class="form-control" placeholder="New Password" name="pass" id="pass1"
onkeypress="regCapsLock(event)" onkeyup="runPassword(this.value, 'mypassword');{if 0 and $prefs.feature_ajax eq 'y'}check_pass();{/if}">
</div>
<div class="col-md-4">
<div id="mypassword_text"></div>
<div id="mypassword_bar" style="font-size: 5px; height: 2px; width: 0px;"></div>
<input type="password" class="form-control" placeholder="New Password" name="pass" id="pass1">
<div style="margin-left:5px;">
<div id="mypassword_text">{icon name='ok' istyle='display:none'}{icon name='error' istyle='display:none' } <span id="mypassword_text_inner"></span></div>
<div id="mypassword_bar" style="font-size: 5px; height: 2px; width: 0px;"></div>
</div>
<div style="margin-top:5px">
{include file='password_help.tpl'}
</div>
</div>
<div class="col-md-4 col-sm-10 help-block">{include file='password_help.tpl'}</div>
</div>
<div class="form-group">
<label class="col-sm-3 col-md-2 control-label" for="pass2">{tr}Repeat Password{/tr}</label>
<div class="col-sm-7 col-md-6">
<input type="password" class="form-control" name="pass2" id="pass2" placeholder="Repeat Password">
<input type="password" class="form-control" name="passAgain" id="pass2" placeholder="Repeat Password">
<div id="mypassword2_text">
<div id="match" style="display:none">
{icon name='ok' istyle='color:#0ca908'} {tr}Passwords match{/tr}
</div>
<div id="nomatch" style="display:none">
{icon name='error' istyle='color:#ff0000'} {tr}Passwords do not match{/tr}
</div>
</div>
</div>
</div>
{if ! ( $prefs.auth_method eq 'ldap' and ( $prefs.ldap_create_user_tiki eq 'n' or $prefs.ldap_skip_admin eq 'y' ) and $prefs.ldap_create_user_ldap eq 'n' )}
<div class="form-group">
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<span id="genPass">{button href="#" _onclick="genPass('genepass');runPassword(document.RegForm.genepass.value, 'mypassword');checkPasswordsMatch('#pass2', '#pass1', '#mypassword2_text');return false;" _text="{tr}Generate a password{/tr}"}</span>
<div class="col-sm-3 col-sm-offset-3 col-md-2 col-md-offset-2">
<span id="genPass">{button href="#" _text="{tr}Generate a password{/tr}"}</span>
</div>
</div>
<div id="genepass_div" class="form-group" style="display: none">
<label class="col-sm-3 col-md-2 control-label" for="pass2">{tr}Generated Password{/tr}</label>
<div class="col-sm-7 col-md-6">
<input id='genepass' class="form-control" name="genepass" type="text" tabindex="0">
<div class="col-sm-3 col-md-2">
<input id='genepass' class="form-control" name="genepass" type="text" tabindex="0" style="display:none">
</div>
</div>
{jq}
$("#genPass").click(function () {
$('#pass1, #pass2').val('');
$('#mypassword_text, #mypassword2_text').hide();
$("#genepass_div").show();
});
$("#pass1, #pass2").change(function () {
$('#mypassword_text, #mypassword2_text').show();
document.RegForm.genepass.value='';
$("#genepass_div").hide();
});
{/jq}
{/if}
{if $userinfo.login neq 'admin' && $prefs.change_password neq 'n'}
<div class="form-group">
......
{* test for caps lock*}
{jq notonready=true}
{literal}
function regCapsLock(e){
var kc = e.keyCode?e.keyCode:e.which;
var sk = e.shiftKey?e.shiftKey:((kc == 16)?true:false);
if(((kc >= 65 && kc <= 90) && !sk)||((kc >= 97 && kc <= 122) && sk))
document.getElementById('divRegCapson').style.visibility = 'visible';
else
document.getElementById('divRegCapson').style.visibility = 'hidden';
}
var submit_counter = 0;
function match_pass() {
submit_counter += 1;
var ret_msg = document.getElementById('validate');
var pass0 = document.getElementById('oldpass') ? document.getElementById('oldpass').value : "dummy";
var pass1 = document.getElementById('pass1').value;
var pass2 = document.getElementById('pass2').value;
if (submit_counter > 10) {
ret_msg.innerHTML = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Overflow'> {tr}Too many tries{/tr}";
return false;
} else if ((pass0 == '') || (pass1 == '') || (pass2 == '')) {
ret_msg.innerHTML = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Missing'> {tr}Passwords missing{/tr}";
return false;
} else if ( pass1 != pass2 ) {
ret_msg.innerHTML = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Do not match'> {tr}Passwords don\'t match{/tr}";
return false;
}
return true;
}
{/literal}
{/jq}
{* $Id$ *}
{if isset($new_user_validation) && $new_user_validation eq 'y'}
{title}{tr}Your account has been validated.{/tr} {tr}You have to choose a password to use this account.{/tr}{/title}
{else}
......@@ -70,22 +37,40 @@
</div>
</div>
{/if}
{include file='password_jq.tpl'}
<div class="form-group">
<label class="col-sm-3 col-md-2 control-label" for="pass1">{tr}New Password{/tr}</label>
<div class="col-sm-7 col-md-6">
<input type="password" class="form-control" placeholder="New Password" name="pass" id="pass1"
onkeypress="regCapsLock(event)" onkeyup="runPassword(this.value, 'mypassword');{if 0 and $prefs.feature_ajax eq 'y'}check_pass();{/if}">
</div>
<div class="col-md-4">
<div id="mypassword_text"></div>
<div id="mypassword_bar" style="font-size: 5px; height: 2px; width: 0px;"></div>
<input type="password" class="form-control" placeholder="New Password" name="pass" id="pass1">
<div style="margin-left:5px;">
<div id="mypassword_text">{icon name='ok' istyle='display:none'}{icon name='error' istyle='display:none' } <span id="mypassword_text_inner"></span></div>
<div id="mypassword_bar" style="font-size: 5px; height: 2px; width: 0px;"></div>
</div>
<div style="margin-top:5px">
{include file='password_help.tpl'}
</div>
</div>
<div class="col-md-4 col-sm-10 help-block">{include file='password_help.tpl'}</div>
</div>
<div class="form-group">
<label class="col-sm-3 col-md-2 control-label" for="pass2">{tr}Repeat Password{/tr}</label>
<div class="col-sm-7 col-md-6">
<input type="password" class="form-control" name="pass2" id="pass2" placeholder="Repeat Password">
<input type="password" class="form-control" name="passAgain" id="pass2" placeholder="Repeat Password">
<div id="mypassword2_text">
<div id="match" style="display:none">
{icon name='ok' istyle='color:#0ca908'} {tr}Passwords match{/tr}
</div>
<div id="nomatch" style="display:none">
{icon name='error' istyle='color:#ff0000'} {tr}Passwords do not match{/tr}
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-3 col-sm-offset-3 col-md-2 col-md-offset-2">
<span id="genPass">{button href="#" _text="{tr}Generate a password{/tr}"}</span>
</div>
<div class="col-sm-3 col-md-2">
<input id='genepass' class="form-control" name="genepass" type="text" tabindex="0" style="display:none">
</div>
</div>
{if empty($email)}
......
{* $Id:$ *}
{if empty($user)}
{jq notonready=true} {* test for caps lock*}
var divRegCapson = $('#divRegCapson');
function regCapsLock(e){
kc = e.keyCode?e.keyCode:e.which;
sk = e.shiftKey?e.shiftKey:((kc == 16)?true:false);
if(((kc >= 65 && kc <= 90) && !sk)||((kc >= 97 && kc <= 122) && sk)) {
divRegCapson.show();
} else {
divRegCapson.hide();
}
}
{/jq}
{if $prefs.generate_password eq 'y'}
{jq}
$("#genPass").click(function () {
genPass('genepass');
$('#mypassword_text, #mypassword2_text, #mypassword_bar').hide();
$('#genepass').show();
return false;
});
$("#pass1, #pass2").change(function () {
$('#mypassword_text, #mypassword2_text, #mypassword_bar').show();
$("#genepass").val('');
$("#genepass").hide();
return false;
});
{/jq}
{/if}
{include file='password_jq.tpl'}
{if $openid_associate neq 'n'}
<h1>{tr}Your OpenID identity is valid{/tr}</h1>
<p>{tr}However, no account is associated to the OpenID identifier.{/tr}</p>
......@@ -52,7 +22,7 @@
</form>
{/if}
</div>
<div class="row">
<div class="col-sm-9 col-sm-offset-2">
{remarksbox type="note" title="{tr}Note{/tr}"}
{if $prefs.feature_wiki_protect_email eq 'y'}
{assign var=sender_email value=$prefs.sender_email|default:"this domain"|escape:'hexentity'}
......
......@@ -265,7 +265,7 @@ if (isset($_REQUEST['batch']) && is_uploaded_file($_FILES['csvlist']['tmp_name']
);
$AddUser=false;
}
if ($_REQUEST['pass'] != $_REQUEST['pass2']) {
if ($_REQUEST['pass'] != $_REQUEST['passAgain']) {
$errors[] = array(
'num' => 1,
'mes' => tra('The passwords do not match')
......
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