function Password(arg_password, arg_spc_chars){
var actPassword = arg_password;
var spc_chars = arg_spc_chars;
this.lcase_count = 0;
this.ucase_count = 0;
this.num_count = 0;
this.schar_count = 0;
this.length = 0;
this.strength = 0;
this.runs_score = 0;
this.verdict = '';
// These numbers are just guesses on my part (and not
// all that educated, either ;) Adjust accordingly.
var verdict_conv = {'veryweak':2, 'weak':5, 'medium':53, 'strong':150, 'verystrong':250};
// These are weighting factors. I figure that including
// numbers is a little better than including uppercase
// because numbers probably are not vulnerable to
// dictionary searches, and including special chars is
// even better. These factors provide yet another
// dimension. Again, there are only guesses.
var flc = 1.0; // lowercase factor
var fuc = 1.0; // uppercase factor
var fnm = 1.3; // number factor
var fsc = 1.5; // special char factor
this.getPwStrength = function(){
if ((this.run_score = this.detectPwRuns()) <= 1){
this.strength = 1;
}else{
var regex_sc = new RegExp('['+spc_chars+']', 'g');
this.lcase_count = actPassword.match(/[a-z]/g);
this.lcase_count = (this.lcase_count) ? this.lcase_count.length : 0;
this.ucase_count = actPassword.match(/[A-Z]/g);
this.ucase_count = (this.ucase_count) ? this.ucase_count.length : 0;
this.num_count = actPassword.match(/[0-9]/g);
this.num_count = (this.num_count) ? this.num_count.length : 0;
this.schar_count = actPassword.match(regex_sc);
this.schar_count = (this.schar_count) ? this.schar_count.length : 0;
this.length = actPassword.length;
var avg = this.length / 4;
// I'm dividing by (avg + 1) to linearize the strength a bit.
// To get a result that ranges from 0 to 1, divide
// by Math.pow(avg + 1, 4)
this.strength = ((this.lcase_count * flc + 1) *
(this.ucase_count * fuc + 1) *
(this.num_count * fnm + 1) *
(this.schar_count * fsc + 1)) / (avg + 1);
}
if (this.strength > verdict_conv.verystrong){
this.verdict = 'Very Strong ';
}else if (this.strength > verdict_conv.strong){
this.verdict = 'Strong ';
}else if (this.strength > verdict_conv.medium){
this.verdict = 'Medium ';
}else if (this.strength > verdict_conv.weak){
this.verdict = 'Weak';
}else if (this.strength > verdict_conv.veryweak){
this.verdict = 'Very Weak';
}else{
this.verdict = "Forget it!";
}
this.strength = this.strength > verdict_conv.verystrong ? verdict_conv.verystrong : this.strength;
var percent = this.getPwPercent();
percent < 0 ? 0 : percent;
this.verdict = this.verdict + " " + percent + "%";
document.getElementById('strength').style.backgroundPosition = "-" + parseInt(Math.round( (400 / verdict_conv.verystrong) * this.strength )) + "px";
return this.verdict;
};
this.getPwPercent = function(){
return this.strength <= 2 ? 0 : Math.floor( (this.strength/verdict_conv.verystrong) * 100 ) - 1;
};
// This is basically an edge detector with a 'rectified' (or
// absolute zero) result. The difference of adjacent equivalent
// char values is zero. The greater the difference, the higher
// the result. 'aaaaa' sums to 0. 'abcde' sums to 1. 'acegi'
// sums to 2, etc. 'aaazz', which has a sharp edge, sums to
// 6.25. Any thing 1 or below is a run, and should be considered
// weak.
this.detectPwRuns = function(){
var pwParts = actPassword.split('');
var ords = new Array();
for (i in pwParts)
{
ords[i] = pwParts[i].charCodeAt(0);
}
var accum = 0;
var lasti = ords.length-1;
for (var i=0; i < lasti; ++i){
accum += Math.abs(ords[i] - ords[i+1]);
}
return accum/lasti;
};
}
function checkPassword(){
var special_chars = "+-=¦|~!@#$%&*_";
var pw = new Password(document.getElementById('pw').value, special_chars);
var verdict = pw.getPwStrength();
var strength = document.getElementById("strength");
strength.style.display = "block";
strength.innerHTML = verdict;
return pw.getPwPercent();
}