includes/clientside/static/pwstrength.js
changeset 1227 bdac73ed481e
parent 586 234ddd896555
--- a/includes/clientside/static/pwstrength.js	Sun Mar 28 21:49:26 2010 -0400
+++ b/includes/clientside/static/pwstrength.js	Sun Mar 28 23:10:46 2010 -0400
@@ -12,281 +12,281 @@
 
 function password_score_len(password)
 {
-  if ( typeof(password) != "string" )
-  {
-    return -10;
-  }
-  var len = password.length;
-  var score = len - 7;
-  return score;
+	if ( typeof(password) != "string" )
+	{
+		return -10;
+	}
+	var len = password.length;
+	var score = len - 7;
+	return score;
 }
 
 function password_score(password)
 {
-  if ( typeof(password) != "string" )
-  {
-    return -10;
-  }
-  var score = 0;
-  var debug = [];
-  // length check
-  var lenscore = password_score_len(password);
-  
-  debug.push(''+lenscore+' points for length');
-  
-  score += lenscore;
-    
-  var has_upper_lower = false;
-  var has_symbols     = false;
-  var has_numbers     = false;
-  
-  // contains uppercase and lowercase
-  if ( password.match(/[A-z]+/) && password.toLowerCase() != password )
-  {
-    score += 1;
-    has_upper_lower = true;
-    debug.push('1 point for having uppercase and lowercase');
-  }
-  
-  // contains symbols
-  if ( password.match(/[^A-z0-9]+/) )
-  {
-    score += 1;
-    has_symbols = true;
-    debug.push('1 point for having nonalphanumeric characters (matching /[^A-z0-9]+/)');
-  }
-  
-  // contains numbers
-  if ( password.match(/[0-9]+/) )
-  {
-    score += 1;
-    has_numbers = true;
-    debug.push('1 point for having numbers');
-  }
-  
-  if ( has_upper_lower && has_symbols && has_numbers && password.length >= 9 )
-  {
-    // if it has uppercase and lowercase letters, symbols, and numbers, and is of considerable length, add some serious points
-    score += 4;
-    debug.push('4 points for having uppercase and lowercase, numbers, and nonalphanumeric and being more than 8 characters');
-  }
-  else if ( has_upper_lower && has_symbols && has_numbers && password.length >= 6 )
-  {
-    // still give some points for passing complexity check
-    score += 2;
-    debug.push('2 points for having uppercase and lowercase, numbers, and nonalphanumeric');
-  }
-  else if(( ( has_upper_lower && has_symbols ) ||
-            ( has_upper_lower && has_numbers ) ||
-            ( has_symbols && has_numbers ) ) && password.length >= 6 )
-  {
-    // if 2 of the three main complexity checks passed, add a point
-    score += 1;
-    debug.push('1 point for having 2 of 3 complexity checks');
-  }
-  else if ( ( !has_upper_lower && !has_numbers && has_symbols ) ||
-            ( !has_upper_lower && !has_symbols && has_numbers ) ||
-            ( !has_numbers && !has_symbols && has_upper_lower ) )
-  {
-    score += -2;
-    debug.push('-2 points for only meeting 1 complexity check');
-  }
-  else if ( password.match(/^[0-9]*?([a-z]+)[0-9]?$/) )
-  {
-    // password is something like magnum1 which will be cracked in seconds
-    score += -4;
-    debug.push('-4 points for being of the form [number][word][number], which is easily cracked');
-  }
-  else if ( !has_upper_lower && !has_numbers && !has_symbols )
-  {
-    // this is if somehow the user inputs a password that doesn't match the rule above, but still doesn't contain upper and lowercase, numbers, or symbols
-    debug.push('-3 points for not meeting any complexity checks');
-    score += -3;
-  }
-  
-  //
-  // Repetition
-  // Example: foobar12345 should be deducted points, where f1o2o3b4a5r should be given points
-  // None of the positive ones kick in unless the length is at least 8
-  //
-  
-  if ( password.match(/([A-Z][A-Z][A-Z][A-Z]|[a-z][a-z][a-z][a-z])/) )
-  {
-    debug.push('-2 points for having more than 4 letters of the same case in a row');
-    score += -2;
-  }
-  else if ( password.match(/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/) )
-  {
-    debug.push('-1 points for having more than 3 letters of the same case in a row');
-    score += -1;
-  }
-  else if ( password.match(/[A-z]/) && !password.match(/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/) && password.length >= 8 )
-  {
-    debug.push('1 point for never having more than 2 letters of the same case in a row');
-    score += 1;
-  }
-  
-  if ( password.match(/[0-9][0-9][0-9][0-9]/) )
-  {
-    debug.push('-2 points for having 4 or more numbers in a row');
-    score += -2;
-  }
-  else if ( password.match(/[0-9][0-9][0-9]/) )
-  {
-    debug.push('-1 points for having 3 or more numbers in a row');
-    score += -1;
-  }
-  else if ( has_numbers && !password.match(/[0-9][0-9][0-9]/) && password.length >= 8 )
-  {
-    debug.push('1 point for never more than 2 numbers in a row');
-    score += -1;
-  }
-  
-  // make passwords like fooooooooooooooooooooooooooooooooooooo totally die by subtracting a point for each character repeated at least 3 times in a row
-  var prev_char = '';
-  var warn = false;
-  var loss = 0;
-  for ( var i = 0; i < password.length; i++ )
-  {
-    var chr = password.substr(i, 1);
-    if ( chr == prev_char && warn )
-    {
-      loss += -1;
-    }
-    else if ( chr == prev_char && !warn )
-    {
-      warn = true;
-    }
-    else if ( chr != prev_char && warn )
-    {
-      warn = false;
-    }
-    prev_char = chr;
-  }
-  if ( loss < 0 )
-  {
-    debug.push(''+loss+' points for immediate character repetition');
-    score += loss;
-    // this can bring the score below -10 sometimes
-    if ( score < -10 )
-    {
-      debug.push('Score set to -10 because it went below that floor');
-      score = -10;
-    }
-  }
-  
-  var debug_txt = "<b>How this score was calculated</b>\nYour score was tallied up based on an extensive algorithm which outputted\nthe following scores based on traits of your password. Above you can see the\ncomposite score; your individual scores based on certain tests are below.\n\nThe scale is open-ended, with a minimum score of -10. 10 is very strong, 4\nis strong, 1 is good and -3 is fair. Below -3 scores \"Weak.\"\n\n";
-  for ( var i = 0; i < debug.length; i++ )
-  {
-    debug_txt += debug[i] + "\n";
-  }
-  
-  // For users that really want to know why their password sucks.
-  // Not localized because the feature is really only used for debugging the algorithm.
-  if ( document.getElementById('passdebug') )
-    document.getElementById('passdebug').innerHTML = debug_txt;
-  
-  return score;
+	if ( typeof(password) != "string" )
+	{
+		return -10;
+	}
+	var score = 0;
+	var debug = [];
+	// length check
+	var lenscore = password_score_len(password);
+	
+	debug.push(''+lenscore+' points for length');
+	
+	score += lenscore;
+		
+	var has_upper_lower = false;
+	var has_symbols     = false;
+	var has_numbers     = false;
+	
+	// contains uppercase and lowercase
+	if ( password.match(/[A-z]+/) && password.toLowerCase() != password )
+	{
+		score += 1;
+		has_upper_lower = true;
+		debug.push('1 point for having uppercase and lowercase');
+	}
+	
+	// contains symbols
+	if ( password.match(/[^A-z0-9]+/) )
+	{
+		score += 1;
+		has_symbols = true;
+		debug.push('1 point for having nonalphanumeric characters (matching /[^A-z0-9]+/)');
+	}
+	
+	// contains numbers
+	if ( password.match(/[0-9]+/) )
+	{
+		score += 1;
+		has_numbers = true;
+		debug.push('1 point for having numbers');
+	}
+	
+	if ( has_upper_lower && has_symbols && has_numbers && password.length >= 9 )
+	{
+		// if it has uppercase and lowercase letters, symbols, and numbers, and is of considerable length, add some serious points
+		score += 4;
+		debug.push('4 points for having uppercase and lowercase, numbers, and nonalphanumeric and being more than 8 characters');
+	}
+	else if ( has_upper_lower && has_symbols && has_numbers && password.length >= 6 )
+	{
+		// still give some points for passing complexity check
+		score += 2;
+		debug.push('2 points for having uppercase and lowercase, numbers, and nonalphanumeric');
+	}
+	else if(( ( has_upper_lower && has_symbols ) ||
+						( has_upper_lower && has_numbers ) ||
+						( has_symbols && has_numbers ) ) && password.length >= 6 )
+	{
+		// if 2 of the three main complexity checks passed, add a point
+		score += 1;
+		debug.push('1 point for having 2 of 3 complexity checks');
+	}
+	else if ( ( !has_upper_lower && !has_numbers && has_symbols ) ||
+						( !has_upper_lower && !has_symbols && has_numbers ) ||
+						( !has_numbers && !has_symbols && has_upper_lower ) )
+	{
+		score += -2;
+		debug.push('-2 points for only meeting 1 complexity check');
+	}
+	else if ( password.match(/^[0-9]*?([a-z]+)[0-9]?$/) )
+	{
+		// password is something like magnum1 which will be cracked in seconds
+		score += -4;
+		debug.push('-4 points for being of the form [number][word][number], which is easily cracked');
+	}
+	else if ( !has_upper_lower && !has_numbers && !has_symbols )
+	{
+		// this is if somehow the user inputs a password that doesn't match the rule above, but still doesn't contain upper and lowercase, numbers, or symbols
+		debug.push('-3 points for not meeting any complexity checks');
+		score += -3;
+	}
+	
+	//
+	// Repetition
+	// Example: foobar12345 should be deducted points, where f1o2o3b4a5r should be given points
+	// None of the positive ones kick in unless the length is at least 8
+	//
+	
+	if ( password.match(/([A-Z][A-Z][A-Z][A-Z]|[a-z][a-z][a-z][a-z])/) )
+	{
+		debug.push('-2 points for having more than 4 letters of the same case in a row');
+		score += -2;
+	}
+	else if ( password.match(/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/) )
+	{
+		debug.push('-1 points for having more than 3 letters of the same case in a row');
+		score += -1;
+	}
+	else if ( password.match(/[A-z]/) && !password.match(/([A-Z][A-Z][A-Z]|[a-z][a-z][a-z])/) && password.length >= 8 )
+	{
+		debug.push('1 point for never having more than 2 letters of the same case in a row');
+		score += 1;
+	}
+	
+	if ( password.match(/[0-9][0-9][0-9][0-9]/) )
+	{
+		debug.push('-2 points for having 4 or more numbers in a row');
+		score += -2;
+	}
+	else if ( password.match(/[0-9][0-9][0-9]/) )
+	{
+		debug.push('-1 points for having 3 or more numbers in a row');
+		score += -1;
+	}
+	else if ( has_numbers && !password.match(/[0-9][0-9][0-9]/) && password.length >= 8 )
+	{
+		debug.push('1 point for never more than 2 numbers in a row');
+		score += -1;
+	}
+	
+	// make passwords like fooooooooooooooooooooooooooooooooooooo totally die by subtracting a point for each character repeated at least 3 times in a row
+	var prev_char = '';
+	var warn = false;
+	var loss = 0;
+	for ( var i = 0; i < password.length; i++ )
+	{
+		var chr = password.substr(i, 1);
+		if ( chr == prev_char && warn )
+		{
+			loss += -1;
+		}
+		else if ( chr == prev_char && !warn )
+		{
+			warn = true;
+		}
+		else if ( chr != prev_char && warn )
+		{
+			warn = false;
+		}
+		prev_char = chr;
+	}
+	if ( loss < 0 )
+	{
+		debug.push(''+loss+' points for immediate character repetition');
+		score += loss;
+		// this can bring the score below -10 sometimes
+		if ( score < -10 )
+		{
+			debug.push('Score set to -10 because it went below that floor');
+			score = -10;
+		}
+	}
+	
+	var debug_txt = "<b>How this score was calculated</b>\nYour score was tallied up based on an extensive algorithm which outputted\nthe following scores based on traits of your password. Above you can see the\ncomposite score; your individual scores based on certain tests are below.\n\nThe scale is open-ended, with a minimum score of -10. 10 is very strong, 4\nis strong, 1 is good and -3 is fair. Below -3 scores \"Weak.\"\n\n";
+	for ( var i = 0; i < debug.length; i++ )
+	{
+		debug_txt += debug[i] + "\n";
+	}
+	
+	// For users that really want to know why their password sucks.
+	// Not localized because the feature is really only used for debugging the algorithm.
+	if ( document.getElementById('passdebug') )
+		document.getElementById('passdebug').innerHTML = debug_txt;
+	
+	return score;
 }
 
 function password_score_draw(score)
 {
-  if ( !$lang )
-  {
-    // $lang isn't initted yet, this happens sometimes on the usercp/emailpassword form.
-    // Try to init it if we have ENANO_LANG_ID and enano_lang; if not, report an error.
-    load_component('l10n');
-    if ( typeof(enano_lang) == 'object' && typeof(ENANO_LANG_ID) == 'number' )
-    {
-      language_onload();
-    }
-    else
-    {      
-      return {
-        'color' : '#000000',
-        'fgcolor' : '#666666',
-        'str' : 'Language init failed'
-      };
-    }
-  }
-  // some colors are from the Gmail sign-up form
-  if ( score >= 10 )
-  {
-    var color = '#010101';
-    var fgcolor = '#666666';
-    var str = $lang.get('usercp_pwstrength_score_verystrong', { score: score });
-  }
-  else if ( score > 3 )
-  {
-    var color = '#008000';
-    var fgcolor = '#004000';
-    var str = $lang.get('usercp_pwstrength_score_strong', { score: score });
-  }
-  else if ( score >= 1 )
-  {
-    var color = '#6699cc';
-    var fgcolor = '#4477aa';
-    var str = $lang.get('usercp_pwstrength_score_good', { score: score });
-  }
-  else if ( score >= -3 )
-  {
-    var color = '#f5ac00';
-    var fgcolor = '#ffcc33';
-    var str = $lang.get('usercp_pwstrength_score_fair', { score: score });
-  }
-  else
-  {
-    var color = '#aa0033';
-    var fgcolor = '#FF6060';
-    var str = $lang.get('usercp_pwstrength_score_weak', { score: score });
-  }
-  var ret = {
-    color: color,
-    fgcolor: fgcolor,
-    str: str
-  };
-  return ret;
+	if ( !$lang )
+	{
+		// $lang isn't initted yet, this happens sometimes on the usercp/emailpassword form.
+		// Try to init it if we have ENANO_LANG_ID and enano_lang; if not, report an error.
+		load_component('l10n');
+		if ( typeof(enano_lang) == 'object' && typeof(ENANO_LANG_ID) == 'number' )
+		{
+			language_onload();
+		}
+		else
+		{      
+			return {
+				'color' : '#000000',
+				'fgcolor' : '#666666',
+				'str' : 'Language init failed'
+			};
+		}
+	}
+	// some colors are from the Gmail sign-up form
+	if ( score >= 10 )
+	{
+		var color = '#010101';
+		var fgcolor = '#666666';
+		var str = $lang.get('usercp_pwstrength_score_verystrong', { score: score });
+	}
+	else if ( score > 3 )
+	{
+		var color = '#008000';
+		var fgcolor = '#004000';
+		var str = $lang.get('usercp_pwstrength_score_strong', { score: score });
+	}
+	else if ( score >= 1 )
+	{
+		var color = '#6699cc';
+		var fgcolor = '#4477aa';
+		var str = $lang.get('usercp_pwstrength_score_good', { score: score });
+	}
+	else if ( score >= -3 )
+	{
+		var color = '#f5ac00';
+		var fgcolor = '#ffcc33';
+		var str = $lang.get('usercp_pwstrength_score_fair', { score: score });
+	}
+	else
+	{
+		var color = '#aa0033';
+		var fgcolor = '#FF6060';
+		var str = $lang.get('usercp_pwstrength_score_weak', { score: score });
+	}
+	var ret = {
+		color: color,
+		fgcolor: fgcolor,
+		str: str
+	};
+	return ret;
 }
 
 function password_score_field(field)
 {
-  var indicator = false;
-  if ( field.nextSibling )
-  {
-    if ( field.nextSibling.className == 'password-checker' )
-    {
-      indicator = field.nextSibling;
-    }
-  }
-  if ( !indicator )
-  {
-    var indicator = document.createElement('span');
-    indicator.className = 'password-checker';
-    if ( field.nextSibling )
-    {
-      field.parentNode.insertBefore(indicator, field.nextSibling);
-    }
-    else
-    {
-      field.parentNode.appendChild(indicator);
-    }
-  }
-  var score = password_score(field.value);
-  var data = password_score_draw(score);
-  indicator.style.color = data.color;
-  indicator.style.fontWeight = 'bold';
-  indicator.innerHTML = ' ' + data.str;
-  
-  if ( document.getElementById('pwmeter') )
-  {
-    var div = document.getElementById('pwmeter');
-    div.style.width = '250px';
-    score += 10;
-    if ( score > 25 )
-      score = 25;
-    div.style.backgroundColor = data.color;
-    var width = Math.round( score * (250 / 25) );
-    div.innerHTML = '<div style="width: '+width+'px; background-color: '+data.fgcolor+'; height: 8px;"></div>';
-  }
+	var indicator = false;
+	if ( field.nextSibling )
+	{
+		if ( field.nextSibling.className == 'password-checker' )
+		{
+			indicator = field.nextSibling;
+		}
+	}
+	if ( !indicator )
+	{
+		var indicator = document.createElement('span');
+		indicator.className = 'password-checker';
+		if ( field.nextSibling )
+		{
+			field.parentNode.insertBefore(indicator, field.nextSibling);
+		}
+		else
+		{
+			field.parentNode.appendChild(indicator);
+		}
+	}
+	var score = password_score(field.value);
+	var data = password_score_draw(score);
+	indicator.style.color = data.color;
+	indicator.style.fontWeight = 'bold';
+	indicator.innerHTML = ' ' + data.str;
+	
+	if ( document.getElementById('pwmeter') )
+	{
+		var div = document.getElementById('pwmeter');
+		div.style.width = '250px';
+		score += 10;
+		if ( score > 25 )
+			score = 25;
+		div.style.backgroundColor = data.color;
+		var width = Math.round( score * (250 / 25) );
+		div.innerHTML = '<div style="width: '+width+'px; background-color: '+data.fgcolor+'; height: 8px;"></div>';
+	}
 }