Browse Source

Security: Integrate Settings and necessary functions to enforce password complexity requirements.
Theme: Add basic password strength indicator bar.
Default Settings: Also verify correct Type (name) on Upgrade > App Defaults.
User: Show Nickname in Contact select if no Given or Family name.
Password Reset: Integrate hide and convert password fields method to prevent browser prompt.

reliberate 9 năm trước cách đây
mục cha
commit
d7e2183026

+ 33 - 5
core/default_settings/app_defaults.php

@@ -59,14 +59,42 @@ if ($domains_processed == 1) {
 		$x++;
 		$array[$x]['default_setting_category'] = 'security';
 		$array[$x]['default_setting_subcategory'] = 'password_length';
-		$array[$x]['default_setting_name'] = 'var';
+		$array[$x]['default_setting_name'] = 'numeric';
 		$array[$x]['default_setting_value'] = '10';
 		$array[$x]['default_setting_enabled'] = 'true';
-		$array[$x]['default_setting_description'] = 'Sets the default length for system generated passwords.';
+		$array[$x]['default_setting_description'] = 'Set the required/default length for user/system generated passwords.';
+		$x++;
+		$array[$x]['default_setting_category'] = 'security';
+		$array[$x]['default_setting_subcategory'] = 'password_number';
+		$array[$x]['default_setting_name'] = 'boolean';
+		$array[$x]['default_setting_value'] = 'true';
+		$array[$x]['default_setting_enabled'] = 'false';
+		$array[$x]['default_setting_description'] = 'Set whether to require at least one number in user passwords.';
+		$x++;
+		$array[$x]['default_setting_category'] = 'security';
+		$array[$x]['default_setting_subcategory'] = 'password_lowercase';
+		$array[$x]['default_setting_name'] = 'boolean';
+		$array[$x]['default_setting_value'] = 'true';
+		$array[$x]['default_setting_enabled'] = 'true';
+		$array[$x]['default_setting_description'] = 'Set whether to require at least one lowecase letter in user passwords.';
+		$x++;
+		$array[$x]['default_setting_category'] = 'security';
+		$array[$x]['default_setting_subcategory'] = 'password_uppercase';
+		$array[$x]['default_setting_name'] = 'boolean';
+		$array[$x]['default_setting_value'] = 'true';
+		$array[$x]['default_setting_enabled'] = 'false';
+		$array[$x]['default_setting_description'] = 'Set whether to require at least one uppercase letter in user passwords.';
+		$x++;
+		$array[$x]['default_setting_category'] = 'security';
+		$array[$x]['default_setting_subcategory'] = 'password_special';
+		$array[$x]['default_setting_name'] = 'boolean';
+		$array[$x]['default_setting_value'] = 'true';
+		$array[$x]['default_setting_enabled'] = 'false';
+		$array[$x]['default_setting_description'] = 'Set whether to require at least one special character in user passwords.';
 		$x++;
 		$array[$x]['default_setting_category'] = 'security';
 		$array[$x]['default_setting_subcategory'] = 'password_strength';
-		$array[$x]['default_setting_name'] = 'var';
+		$array[$x]['default_setting_name'] = 'numeric';
 		$array[$x]['default_setting_value'] = '4';
 		$array[$x]['default_setting_enabled'] = 'true';
 		$array[$x]['default_setting_description'] = 'Set the default strength for system generated passwords.  Valid Options: 1 - Numeric Only, 2 - Include Lower Apha, 3 - Include Upper Alpha, 4 - Include Special Characters.';
@@ -315,7 +343,7 @@ if ($domains_processed == 1) {
 			$found = false;
 			$missing[$x] = $setting;
 			foreach ($default_settings as $row) {
-				if (trim($row['default_setting_subcategory']) == trim($setting['default_setting_subcategory'])) {
+				if (trim($row['default_setting_subcategory']) == trim($setting['default_setting_subcategory']) && trim($row['default_setting_name']) == trim($setting['default_setting_name'])) {
 					$found = true;
 					//remove items from the array that were found
 					unset($missing[$x]);
@@ -351,7 +379,7 @@ if ($domains_processed == 1) {
 				$sql .= "'".check_str($row['default_setting_enabled'])."', ";
 				$sql .= "'".check_str($row['default_setting_description'])."' ";
 				$sql .= ")";
-				if ($missing_count != $i) { 
+				if ($missing_count != $i) {
 					$sql .= ",\n";
 				}
 				$i++;

+ 103 - 0
core/user_settings/app_languages.php

@@ -126,6 +126,39 @@ $text['message-password_reset']['ro'] = "Resetare parolă";
 $text['message-password_reset']['fa'] = "";
 $text['message-password_reset']['ar-eg'] = "اعادة تعيين كلمة السر";
 
+$text['message-password_requirements']['en-us'] = "Password Requirements";
+$text['message-password_requirements']['es-cl'] = "Requisitos de Contraseña";
+$text['message-password_requirements']['pt-pt'] = "Requisitos Senha";
+$text['message-password_requirements']['fr-fr'] = "Mot de passe requis";
+$text['message-password_requirements']['pl'] = "Wymagania Hasło";
+$text['message-password_requirements']['uk'] = "вимоги до паролю";
+$text['message-password_requirements']['sv-se'] = "lösenordskrav ";
+$text['message-password_requirements']['ro'] = "Cerințe privind parola";
+$text['message-password_requirements']['de-at'] = "Kennwortanforderungen ";
+$text['message-password_requirements']['he'] = "דרישות סיסמא";
+
+$text['message-password_mismatch']['en-us'] = "Password Mismatch";
+$text['message-password_mismatch']['es-cl'] = "Contraseñas no coinciden";
+$text['message-password_mismatch']['pt-pt'] = "As passwords não correspondem.";
+$text['message-password_mismatch']['fr-fr'] = "Les mots de passe ne correspondent pas";
+$text['message-password_mismatch']['pl'] = "Wprowadzone hasła nie są takie same";
+$text['message-password_mismatch']['uk'] = "Паролі не співпадають";
+$text['message-password_mismatch']['sv-se'] = "Lösenordet Stämmer Inte";
+$text['message-password_mismatch']['ro'] = "";
+$text['message-password_mismatch']['de-at'] = "Passwörter stimmen nicht überein.";
+$text['message-password_mismatch']['he'] = "הסיסמא לא נכונה";
+
+$text['message-password_blank']['en-us'] = "Invalid Password";
+$text['message-password_blank']['es-cl'] = "Contraseña No Válida";
+$text['message-password_blank']['pt-pt'] = "Senha Inválida";
+$text['message-password_blank']['fr-fr'] = "Mot de Passe Incorrect";
+$text['message-password_blank']['pl'] = "Nieprawidłowe hasło";
+$text['message-password_blank']['uk'] = "Неправильний пароль";
+$text['message-password_blank']['sv-se'] = "Ogiltigt Lösenord";
+$text['message-password_blank']['ro'] = "";
+$text['message-password_blank']['de-at'] = "Falsches Passwort";
+$text['message-password_blank']['he'] = "סיסמא לא קיימת";
+
 $text['message-invalid_username_mismatch_passwords']['en-us'] = "Invalid Username and/or Mismatched Passwords";
 $text['message-invalid_username_mismatch_passwords']['es-cl'] = "Nombre de usuario válido y/o contraseñas no coincidentes";
 $text['message-invalid_username_mismatch_passwords']['pt-pt'] = "Nome de usuário inválido e/ou palavras-passe não correspondentes";
@@ -281,6 +314,20 @@ $text['label-used']['ro'] = "Folosit";
 $text['label-used']['fa'] = "";
 $text['label-used']['ar-eg'] = "مستعمل";
 
+$text['label-uppercase_letters']['en-us'] = "Uppercase Letters";
+$text['label-uppercase_letters']['es-cl'] = "Letras mayúsculas";
+$text['label-uppercase_letters']['pt-pt'] = "Letras maiúsculas";
+$text['label-uppercase_letters']['fr-fr'] = "Lettres capitales";
+$text['label-uppercase_letters']['pt-br'] = "Letras maiúsculas";
+$text['label-uppercase_letters']['pl'] = "Wielkie litery";
+$text['label-uppercase_letters']['he'] = "אותיות רישיות";
+$text['label-uppercase_letters']['uk'] = "Великі літери";
+$text['label-uppercase_letters']['sv-se'] = "Versala bokstäver";
+$text['label-uppercase_letters']['de-at'] = "Großbuchstaben";
+$text['label-uppercase_letters']['ro'] = "Litere mari";
+$text['label-uppercase_letters']['fa'] = "";
+$text['label-uppercase_letters']['ar-eg'] = "الأحرف الكبيرة";
+
 $text['label-total_extensions']['en-us'] = "Total Extensions";
 $text['label-total_extensions']['es-cl'] = "Las extensiones totales";
 $text['label-total_extensions']['pt-pt'] = "total de extensões";
@@ -410,6 +457,20 @@ $text['label-status']['ro'] = "Stare";
 $text['label-status']['fa'] = "";
 $text['label-status']['ar-eg'] = "الحالة";
 
+$text['label-special_characters']['en-us'] = "Special Characters";
+$text['label-special_characters']['es-cl'] = "Caracteres especiales";
+$text['label-special_characters']['pt-pt'] = "Caracteres especiais";
+$text['label-special_characters']['fr-fr'] = "Caractères spéciaux";
+$text['label-special_characters']['pt-br'] = "Caracteres especiais";
+$text['label-special_characters']['pl'] = "Znaki specjalne";
+$text['label-special_characters']['he'] = "תווים מיוחדים";
+$text['label-special_characters']['uk'] = "спеціальні символи";
+$text['label-special_characters']['sv-se'] = "Speciella karaktärer";
+$text['label-special_characters']['de-at'] = "Spezielle Charaktere";
+$text['label-special_characters']['ro'] = "caractere speciale";
+$text['label-special_characters']['fa'] = "";
+$text['label-special_characters']['ar-eg'] = "أحرف خاصة";
+
 $text['label-ring_groups']['en-us'] = "Ring Groups";
 $text['label-ring_groups']['es-cl'] = "Grupo de llamado";
 $text['label-ring_groups']['fr-fr'] = "Groupes de Sonnerie";
@@ -523,6 +584,20 @@ $text['label-outbound']['uk'] = "";
 $text['label-outbound']['de-at'] = "Ausgehend";
 $text['label-outbound']['he'] = "";
 
+$text['label-numbers']['en-us'] = "Numbers";
+$text['label-numbers']['es-cl'] = "Números";
+$text['label-numbers']['pt-pt'] = "Números";
+$text['label-numbers']['fr-fr'] = "Nombres";
+$text['label-numbers']['pt-br'] = "Números";
+$text['label-numbers']['pl'] = "Liczby";
+$text['label-numbers']['he'] = "מספרים";
+$text['label-numbers']['uk'] = "чисел";
+$text['label-numbers']['sv-se'] = "Tal";
+$text['label-numbers']['de-at'] = "Nummern";
+$text['label-numbers']['ro'] = "numere";
+$text['label-numbers']['fa'] = "";
+$text['label-numbers']['ar-eg'] = "أرقام";
+
 $text['label-no_voicemail_assigned']['en-us'] = "No Voicemail Assigned";
 $text['label-no_voicemail_assigned']['es-cl'] = "No Asignado correo de voz";
 $text['label-no_voicemail_assigned']['pt-pt'] = "Sem Voicemail Assigned";
@@ -625,6 +700,20 @@ $text['label-memory_usage']['ro'] = "Folosirea memoriei";
 $text['label-memory_usage']['fa'] = "";
 $text['label-memory_usage']['ar-eg'] = "استخدام الذاكرة";
 
+$text['label-lowercase_letters']['en-us'] = "Lowercase Letters";
+$text['label-lowercase_letters']['es-cl'] = "Letras minusculas";
+$text['label-lowercase_letters']['pt-pt'] = "Letras minúsculas";
+$text['label-lowercase_letters']['fr-fr'] = "Minuscules";
+$text['label-lowercase_letters']['pt-br'] = "Letras minúsculas";
+$text['label-lowercase_letters']['pl'] = "Małe litery";
+$text['label-lowercase_letters']['he'] = "אותיות קטנות";
+$text['label-lowercase_letters']['uk'] = "Букви нижнього регістру";
+$text['label-lowercase_letters']['sv-se'] = "Gemener";
+$text['label-lowercase_letters']['de-at'] = "Kleinbuchstaben";
+$text['label-lowercase_letters']['ro'] = "Litere mici";
+$text['label-lowercase_letters']['fa'] = "";
+$text['label-lowercase_letters']['ar-eg'] = "أحرف صغيرة";
+
 $text['label-local']['en-us'] = "Local";
 $text['label-local']['es-cl'] = "Local";
 $text['label-local']['pt-pt'] = "Local";
@@ -943,6 +1032,20 @@ $text['label-cid_name']['uk'] = "Назва";
 $text['label-cid_name']['de-at'] = "Name";
 $text['label-cid_name']['he'] = "שם";
 
+$text['label-characters']['en-us'] = "Characters";
+$text['label-characters']['es-cl'] = "Caracteres";
+$text['label-characters']['pt-pt'] = "Personagens";
+$text['label-characters']['fr-fr'] = "Personnages";
+$text['label-characters']['pt-br'] = "Personagens";
+$text['label-characters']['pl'] = "Postacie";
+$text['label-characters']['he'] = "דמויות";
+$text['label-characters']['uk'] = "персонажі";
+$text['label-characters']['sv-se'] = "tecken";
+$text['label-characters']['de-at'] = "Figuren";
+$text['label-characters']['ro'] = "caractere";
+$text['label-characters']['fa'] = "";
+$text['label-characters']['ar-eg'] = "الشخصيات";
+
 $text['label-channels']['en-us'] = "Channels";
 $text['label-channels']['es-cl'] = "Canales";
 $text['label-channels']['pt-pt'] = "Canais";

+ 107 - 77
core/user_settings/user_edit.php

@@ -78,30 +78,26 @@ if (count($_POST)>0 && $_POST["persistform"] != "1") {
 
 	//get the HTTP values and set as variables
 		$password = check_str($_POST["password"]);
-		$confirm_password = check_str($_POST["confirm_password"]);
+		$password_confirm = check_str($_POST["password_confirm"]);
 		$user_status = check_str($_POST["user_status"]);
 		$user_template_name = check_str($_POST["user_template_name"]);
 		$user_language = check_str($_POST["user_language"]);
 		$user_time_zone = check_str($_POST["user_time_zone"]);
 		$group_member = check_str($_POST["group_member"]);
 
-	//set the required values
-		$msg = '';
-		//if (strlen($password) == 0) { $msg .= "Password cannot be blank.<br>\n"; }
-		if ($password != $confirm_password) { $msg .= "".$text['confirm-password']."<br>\n"; }
-		//if (strlen($user_time_zone) == 0) { $msg .= "Please provide an time zone.<br>\n"; }
-		if (strlen($msg) > 0) {
-			require_once "resources/header.php";
-			echo "<div align='center'>";
-			echo "<table><tr><td>";
-			echo $msg;
-			echo "</td></tr></table>";
-			echo "<br />\n";
-			require_once "resources/persist_form.php";
-			echo persistform($_POST);
-			echo "</div>";
-			require_once "resources/footer.php";
-			return;
+	//check required values
+		if ($password != $password_confirm) { $msg_error = $text['message-password_mismatch']; }
+
+		if ($msg_error != '') {
+			$_SESSION["message"] = $msg_error;
+			$_SESSION["message_mood"] = 'negative';
+			header("Location: user_edit.php");
+			exit;
+		}
+
+		if (!check_password_strength($password, $text)) {
+			header("Location: user_edit.php");
+			exit;
 		}
 
 	//check to see if user language is set
@@ -216,15 +212,9 @@ if (count($_POST)>0 && $_POST["persistform"] != "1") {
 			}
 		}
 
-	//if the template has not been assigned by the superadmin
-		//if (strlen($_SESSION['domain']['template']['name']) == 0) {
-			//set the session theme for the active user
-			//	$_SESSION['domain']['template']['name'] = $user_template_name;
-		//}
-
 	//sql update
 		$sql  = "update v_users set ";
-		if (strlen($password) > 0 && $confirm_password == $password) {
+		if (strlen($password) > 0 && $password_confirm == $password) {
 			//salt used with the password to create a one way hash
 				$salt = generate_password('20', '4');
 			//set the password
@@ -250,9 +240,6 @@ if (count($_POST)>0 && $_POST["persistform"] != "1") {
 				$response = event_socket_request($fp, $cmd);
 		}
 
-	//clear the template so it will rebuild in case the template was changed
-		//$_SESSION["template_content"] = '';
-
 	//redirect the browser
 		$_SESSION["message"] = $text['confirm-update'];
 		header("Location: ".PROJECT_PATH."/core/user_settings/user_edit.php");
@@ -282,6 +269,81 @@ else {
 
 //show the content
 	$table_width ='width="100%"';
+
+	echo "<script>\n";
+	echo "	function compare_passwords() {\n";
+	echo "		if (document.getElementById('password') === document.activeElement || document.getElementById('password_confirm') === document.activeElement) {\n";
+	echo "			if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
+	echo "				if ($('#password').val() != $('#password_confirm').val()) {\n";
+	echo "					$('#password').removeClass('formfld_highlight_good');\n";
+	echo "					$('#password_confirm').removeClass('formfld_highlight_good');\n";
+	echo "					$('#password').addClass('formfld_highlight_bad');\n";
+	echo "					$('#password_confirm').addClass('formfld_highlight_bad');\n";
+	echo "				}\n";
+	echo "				else {\n";
+	echo "					$('#password').removeClass('formfld_highlight_bad');\n";
+	echo "					$('#password_confirm').removeClass('formfld_highlight_bad');\n";
+	echo "					$('#password').addClass('formfld_highlight_good');\n";
+	echo "					$('#password_confirm').addClass('formfld_highlight_good');\n";
+	echo "				}\n";
+	echo "			}\n";
+	echo "		}\n";
+	echo "		else {\n";
+	echo "			$('#password').removeClass('formfld_highlight_bad');\n";
+	echo "			$('#password_confirm').removeClass('formfld_highlight_bad');\n";
+	echo "			$('#password').removeClass('formfld_highlight_good');\n";
+	echo "			$('#password_confirm').removeClass('formfld_highlight_good');\n";
+	echo "		}\n";
+	echo "	}\n";
+
+	$req['length'] = $_SESSION['security']['password_length']['numeric'];
+	$req['number'] = ($_SESSION['security']['password_number']['boolean'] == 'true') ? true : false;
+	$req['lowercase'] = ($_SESSION['security']['password_lowercase']['boolean'] == 'true') ? true : false;
+	$req['uppercase'] = ($_SESSION['security']['password_uppercase']['boolean'] == 'true') ? true : false;
+	$req['special'] = ($_SESSION['security']['password_special']['boolean'] == 'true') ? true : false;
+
+	echo "	function check_password_strength(pwd) {\n";
+	echo "		if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
+	echo "			var msg_errors = [];\n";
+	if (is_numeric($req['length']) && $req['length'] != 0) {
+		echo "		var re = /.{".$req['length'].",}/;\n"; //length
+		echo "		if (!re.test(pwd)) { msg_errors.push('".$req['length']."+ ".$text['label-characters']."'); }\n";
+	}
+	if ($req['number']) {
+		echo "		var re = /(?=.*[\d])/;\n";  //number
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-numbers']."'); }\n";
+	}
+	if ($req['lowercase']) {
+		echo "		var re = /(?=.*[a-z])/;\n";  //lowercase
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-lowercase_letters']."'); }\n";
+	}
+	if ($req['uppercase']) {
+		echo "		var re = /(?=.*[A-Z])/;\n";  //uppercase
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-uppercase_letters']."'); }\n";
+	}
+	if ($req['special']) {
+		echo "		var re = /(?=.*[\W])/;\n";  //special
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-special_characters']."'); }\n";
+	}
+	echo "			if (msg_errors.length > 0) {\n";
+	echo "				var msg = '".$text['message-password_requirements'].": ' + msg_errors.join(', ');\n";
+	echo "				display_message(msg, 'negative', '6000');\n";
+	echo "				return false;\n";
+	echo "			}\n";
+	echo "			else {\n";
+	echo "				return true;\n";
+	echo "			}\n";
+	echo "		}\n";
+	echo "		else {\n";
+	echo "			return true;\n";
+	echo "		}\n";
+	echo "	}\n";
+
+	echo "	function show_strenth_meter() {\n";
+	echo "		$('#pwstrength_progress').slideDown();\n";
+	echo "	}\n";
+	echo "</script>\n";
+
 	echo "<form name='frm' id='frm' method='post' action=''>";
 
 	echo "<table $table_width cellpadding='0' cellspacing='0' border='0'>";
@@ -308,17 +370,24 @@ else {
 	echo "</tr>\n";
 
 	echo "	<tr>";
-	echo "		<td width='30%' class='vncellreq' align='left' valign='top'>".$text['label-username']."</td>";
-	echo "		<td width='70%' class='vtable' align='left'>$username</td>";
+	echo "		<td width='30%' class='vncellreq' valign='top'>".$text['label-username']."</td>";
+	echo "		<td width='70%' class='vtable'>";
+	echo "			".$username."<input type='hidden' id='username' value='".$username."'>\n";
+	echo "		</td>";
 	echo "	</tr>";
 
 	echo "	<tr>";
-	echo "		<td class='vncell' align='left' valign='top'>".$text['label-password']."</td>";
-	echo "		<td class='vtable' align='left'><input type='password' autocomplete='off' class='formfld' name='password' value=\"\"></td>";
+	echo "		<td class='vncell' valign='top'>".$text['label-password']."</td>";
+	echo "		<td class='vtable'>";
+	echo "			<input type='password' autocomplete='off' class='formfld' name='password' id='password' value='' onkeypress='show_strenth_meter();' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'>";
+	echo "			<div id='pwstrength_progress' class='pwstrength_progress'></div>";
+	echo "		</td>";
 	echo "	</tr>";
 	echo "	<tr>";
-	echo "		<td class='vncell' align='left' valign='top'>".$text['label-confirm-password']."</td>";
-	echo "		<td class='vtable' align='left'><input type='password' autocomplete='off' class='formfld' name='confirm_password' value=\"\"></td>";
+	echo "		<td class='vncell' valign='top'>".$text['label-confirm-password']."</td>";
+	echo "		<td class='vtable'>";
+	echo "			<input type='password' autocomplete='off' class='formfld' name='password_confirm' id='password_confirm' value='' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'>";
+	echo "		</td>";
 	echo "	</tr>";
 
 	echo "		</td>";
@@ -380,40 +449,6 @@ else {
 		echo "	</tr>\n";
 	}
 
-	//if the template has not been assigned by the superadmin
-		/*
-		if (strlen($_SESSION['domain']['template']['name']) == 0) {
-			echo "	<tr>\n";
-			echo "	<td width='20%' class=\"vncell\">\n";
-			echo "		Template: \n";
-			echo "	</td>\n";
-			echo "	<td class=\"vtable\">\n";
-			echo "		<select id='user_template_name' name='user_template_name' class='formfld' style=''>\n";
-			echo "		<option value=''></option>\n";
-			$theme_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/themes';
-			if ($handle = opendir($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/themes')) {
-				while (false !== ($dir_name = readdir($handle))) {
-					if ($dir_name != "." && $dir_name != ".." && $dir_name != ".svn" && is_dir($theme_dir.'/'.$dir_name)) {
-						$dir_label = str_replace('_', ' ', $dir_name);
-						$dir_label = str_replace('-', ' ', $dir_label);
-						if ($dir_name == $user_settings['domain']['template']['name']) {
-							echo "		<option value='$dir_name' selected='selected'>$dir_label</option>\n";
-						}
-						else {
-							echo "		<option value='$dir_name'>$dir_label</option>\n";
-						}
-					}
-				}
-				closedir($handle);
-			}
-			echo "	</select>\n";
-			echo "	<br />\n";
-			echo "	Select a template to set as the default and then press save.<br />\n";
-			echo "	</td>\n";
-			echo "	</tr>\n";
-		}
-		*/
-
 	echo "	<tr>\n";
 	echo "	<td width='20%' class=\"vncell\" valign='top'>\n";
 	echo "		".$text['label-user_language']."\n";
@@ -475,15 +510,10 @@ else {
 	echo "	</td>\n";
 	echo "	</tr>\n";
 	echo "</table>";
-	echo "<br>";
+	echo "<br />";
 
-	echo "<table $table_width>";
-	echo "	<tr>";
-	echo "		<td align='right'>";
-	echo "			<input type='button' class='btn' value='".$text['button-save']."' onclick='submit_form();'>";
-	echo "		</td>";
-	echo "	</tr>";
-	echo "</table>";
+	echo "<div align='right'><input type='button' class='btn' value='".$text['button-save']."' onclick=\"if (check_password_strength(document.getElementById('password').value)) { submit_form(); }\"></div>";
+	echo "<br />";
 
 	echo "</form>";
 
@@ -492,7 +522,7 @@ else {
 	echo "	$(window).keypress(function(event){\n";
 	echo "		if (event.which == 13) { submit_form(); }\n";
 	echo "	});\n";
-// convert password fields to
+// convert password fields to text
 	echo "	function submit_form() {\n";
 	echo "		$('input:password').css('visibility','hidden');\n";
 	echo "		$('input:password').attr({type:'text'});\n";

+ 81 - 0
core/users/app_languages.php

@@ -219,6 +219,17 @@ $text['message-password_blank']['ro'] = "";
 $text['message-password_blank']['de-at'] = "Falsches Passwort";
 $text['message-password_blank']['he'] = "סיסמא לא קיימת";
 
+$text['message-password_requirements']['en-us'] = "Password Requirements";
+$text['message-password_requirements']['es-cl'] = "Requisitos de Contraseña";
+$text['message-password_requirements']['pt-pt'] = "Requisitos Senha";
+$text['message-password_requirements']['fr-fr'] = "Mot de passe requis";
+$text['message-password_requirements']['pl'] = "Wymagania Hasło";
+$text['message-password_requirements']['uk'] = "вимоги до паролю";
+$text['message-password_requirements']['sv-se'] = "lösenordskrav ";
+$text['message-password_requirements']['ro'] = "Cerințe privind parola";
+$text['message-password_requirements']['de-at'] = "Kennwortanforderungen ";
+$text['message-password_requirements']['he'] = "דרישות סיסמא";
+
 $text['message-new_group_name']['en-us'] = "Enter a Name for the new Group...";
 $text['message-new_group_name']['es-cl'] = "Introduzca un Nombre para el nuevo Grupo...";
 $text['message-new_group_name']['pt-pt'] = "Digite um Nome para o novo Grupo...";
@@ -343,6 +354,20 @@ $text['label-user_info']['ro'] = "";
 $text['label-user_info']['de-at'] = "Benutzer Information";
 $text['label-user_info']['he'] = "פרטי משתמש";
 
+$text['label-uppercase_letters']['en-us'] = "Uppercase Letters";
+$text['label-uppercase_letters']['es-cl'] = "Letras mayúsculas";
+$text['label-uppercase_letters']['pt-pt'] = "Letras maiúsculas";
+$text['label-uppercase_letters']['fr-fr'] = "Lettres capitales";
+$text['label-uppercase_letters']['pt-br'] = "Letras maiúsculas";
+$text['label-uppercase_letters']['pl'] = "Wielkie litery";
+$text['label-uppercase_letters']['he'] = "אותיות רישיות";
+$text['label-uppercase_letters']['uk'] = "Великі літери";
+$text['label-uppercase_letters']['sv-se'] = "Versala bokstäver";
+$text['label-uppercase_letters']['de-at'] = "Großbuchstaben";
+$text['label-uppercase_letters']['ro'] = "Litere mari";
+$text['label-uppercase_letters']['fa'] = "";
+$text['label-uppercase_letters']['ar-eg'] = "الأحرف الكبيرة";
+
 $text['label-top']['en-us'] = "Top";
 $text['label-top']['es-cl'] = "encima";
 $text['label-top']['pt-pt'] = "Topo";
@@ -407,6 +432,20 @@ $text['label-static']['ro'] = "Static";
 $text['label-static']['fa'] = "";
 $text['label-static']['ar-eg'] = "ساكن";
 
+$text['label-special_characters']['en-us'] = "Special Characters";
+$text['label-special_characters']['es-cl'] = "Caracteres especiales";
+$text['label-special_characters']['pt-pt'] = "Caracteres especiais";
+$text['label-special_characters']['fr-fr'] = "Caractères spéciaux";
+$text['label-special_characters']['pt-br'] = "Caracteres especiais";
+$text['label-special_characters']['pl'] = "Znaki specjalne";
+$text['label-special_characters']['he'] = "תווים מיוחדים";
+$text['label-special_characters']['uk'] = "спеціальні символи";
+$text['label-special_characters']['sv-se'] = "Speciella karaktärer";
+$text['label-special_characters']['de-at'] = "Spezielle Charaktere";
+$text['label-special_characters']['ro'] = "caractere speciale";
+$text['label-special_characters']['fa'] = "";
+$text['label-special_characters']['ar-eg'] = "أحرف خاصة";
+
 $text['label-right']['en-us'] = "Right";
 $text['label-right']['es-cl'] = "Derecha";
 $text['label-right']['pt-pt'] = "Certo";
@@ -479,6 +518,20 @@ $text['label-other']['sv-se'] = "Annat";
 $text['label-other']['de-at'] = "Andere";
 $text['label-other']['he'] = "אחר";
 
+$text['label-numbers']['en-us'] = "Numbers";
+$text['label-numbers']['es-cl'] = "Números";
+$text['label-numbers']['pt-pt'] = "Números";
+$text['label-numbers']['fr-fr'] = "Nombres";
+$text['label-numbers']['pt-br'] = "Números";
+$text['label-numbers']['pl'] = "Liczby";
+$text['label-numbers']['he'] = "מספרים";
+$text['label-numbers']['uk'] = "чисел";
+$text['label-numbers']['sv-se'] = "Tal";
+$text['label-numbers']['de-at'] = "Nummern";
+$text['label-numbers']['ro'] = "numere";
+$text['label-numbers']['fa'] = "";
+$text['label-numbers']['ar-eg'] = "أرقام";
+
 $text['label-none']['en-us'] = "None";
 $text['label-none']['es-cl'] = "Ninguna";
 $text['label-none']['pt-pt'] = "Nenhum";
@@ -493,6 +546,20 @@ $text['label-none']['ro'] = "Nici unul";
 $text['label-none']['fa'] = "";
 $text['label-none']['ar-eg'] = "لا شيء";
 
+$text['label-lowercase_letters']['en-us'] = "Lowercase Letters";
+$text['label-lowercase_letters']['es-cl'] = "Letras minusculas";
+$text['label-lowercase_letters']['pt-pt'] = "Letras minúsculas";
+$text['label-lowercase_letters']['fr-fr'] = "Minuscules";
+$text['label-lowercase_letters']['pt-br'] = "Letras minúsculas";
+$text['label-lowercase_letters']['pl'] = "Małe litery";
+$text['label-lowercase_letters']['he'] = "אותיות קטנות";
+$text['label-lowercase_letters']['uk'] = "Букви нижнього регістру";
+$text['label-lowercase_letters']['sv-se'] = "Gemener";
+$text['label-lowercase_letters']['de-at'] = "Kleinbuchstaben";
+$text['label-lowercase_letters']['ro'] = "Litere mici";
+$text['label-lowercase_letters']['fa'] = "";
+$text['label-lowercase_letters']['ar-eg'] = "أحرف صغيرة";
+
 $text['label-left']['en-us'] = "Left";
 $text['label-left']['es-cl'] = "Izquierda";
 $text['label-left']['pt-pt'] = "Esquerda";
@@ -725,6 +792,20 @@ $text['label-company_name']['ro'] = "";
 $text['label-company_name']['de-at'] = "Firmenname";
 $text['label-company_name']['he'] = "שם חברה";
 
+$text['label-characters']['en-us'] = "Characters";
+$text['label-characters']['es-cl'] = "Caracteres";
+$text['label-characters']['pt-pt'] = "Personagens";
+$text['label-characters']['fr-fr'] = "Personnages";
+$text['label-characters']['pt-br'] = "Personagens";
+$text['label-characters']['pl'] = "Postacie";
+$text['label-characters']['he'] = "דמויות";
+$text['label-characters']['uk'] = "персонажі";
+$text['label-characters']['sv-se'] = "tecken";
+$text['label-characters']['de-at'] = "Figuren";
+$text['label-characters']['ro'] = "caractere";
+$text['label-characters']['fa'] = "";
+$text['label-characters']['ar-eg'] = "الشخصيات";
+
 $text['label-center']['en-us'] = "Center";
 $text['label-center']['es-cl'] = "Centrar";
 $text['label-center']['pt-pt'] = "Centro";

+ 110 - 66
core/users/usersupdate.php

@@ -101,7 +101,7 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 		$username_old = check_str($_POST["username_old"]);
 		$username = check_str($_POST["username"]);
 		$password = check_str($_POST["password"]);
-		$confirm_password = check_str($_POST["confirm_password"]);
+		$password_confirm = check_str($_POST["password_confirm"]);
 		$user_status = check_str($_POST["user_status"]);
 		$user_language = check_str($_POST["user_language"]);
 		$user_time_zone = check_str($_POST["user_time_zone"]);
@@ -124,15 +124,20 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 			unset($sql);
 		}
 
-		if ($password != $confirm_password) { $msg_error = $text['message-password_mismatch']; }
+		if ($password != $password_confirm) { $msg_error = $text['message-password_mismatch']; }
 
-		if ($msg_error) {
+		if ($msg_error != '') {
 			$_SESSION["message"] = $msg_error;
 			$_SESSION["message_mood"] = 'negative';
 			header("Location: usersupdate.php?id=".$user_uuid);
 			exit;
 		}
 
+		if (!check_password_strength($password, $text)) {
+			header("Location: usersupdate.php?id=".$user_uuid);
+			exit;
+		}
+
 	//check to see if user language is set
 		$sql = "select count(*) as num_rows from v_user_settings ";
 		$sql .= "where user_setting_category = 'domain' ";
@@ -311,7 +316,7 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 		if (strlen($username) > 0 && $username != $username_old) {
 			$sql .= "username = '".$username."', ";
 		}
-		if (strlen($password) > 0 && $confirm_password == $password) {
+		if (strlen($password) > 0 && $password_confirm == $password) {
 			//salt used with the password to create a one way hash
 				$salt = uuid();
 			//set the password
@@ -406,34 +411,79 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 //show the content
 	$table_width ='width="100%"';
 
-	echo "<script>";
-	echo "	function compare_passwords() {";
-	echo "		if (document.getElementById('password') === document.activeElement || document.getElementById('confirmpassword') === document.activeElement) {";
-	echo "			if (document.getElementById('password').value != '' || document.getElementById('confirmpassword').value != '') {";
-	echo "				if (document.getElementById('password').value != document.getElementById('confirmpassword').value) {";
-	echo "					$('#password').removeClass('formfld_highlight_good');";
-	echo "					$('#confirmpassword').removeClass('formfld_highlight_good');";
-	echo "					$('#password').addClass('formfld_highlight_bad');";
-	echo "					$('#confirmpassword').addClass('formfld_highlight_bad');";
-	echo "				}";
-	echo "				else {";
-	echo "					$('#password').removeClass('formfld_highlight_bad');";
-	echo "					$('#confirmpassword').removeClass('formfld_highlight_bad');";
-	echo "					$('#password').addClass('formfld_highlight_good');";
-	echo "					$('#confirmpassword').addClass('formfld_highlight_good');";
-	echo "				}";
-	echo "			}";
-	echo "		}";
-	echo "		else {";
-	echo "			if (document.getElementById('password').value == document.getElementById('confirmpassword').value) {";
-	echo "				$('#password').removeClass('formfld_highlight_bad');";
-	echo "				$('#confirmpassword').removeClass('formfld_highlight_bad');";
-	echo "				$('#password').removeClass('formfld_highlight_good');";
-	echo "				$('#confirmpassword').removeClass('formfld_highlight_good');";
-	echo "			}";
-	echo "		}";
-	echo "	}";
-	echo "</script>";
+	echo "<script>\n";
+	echo "	function compare_passwords() {\n";
+	echo "		if (document.getElementById('password') === document.activeElement || document.getElementById('password_confirm') === document.activeElement) {\n";
+	echo "			if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
+	echo "				if ($('#password').val() != $('#password_confirm').val()) {\n";
+	echo "					$('#password').removeClass('formfld_highlight_good');\n";
+	echo "					$('#password_confirm').removeClass('formfld_highlight_good');\n";
+	echo "					$('#password').addClass('formfld_highlight_bad');\n";
+	echo "					$('#password_confirm').addClass('formfld_highlight_bad');\n";
+	echo "				}\n";
+	echo "				else {\n";
+	echo "					$('#password').removeClass('formfld_highlight_bad');\n";
+	echo "					$('#password_confirm').removeClass('formfld_highlight_bad');\n";
+	echo "					$('#password').addClass('formfld_highlight_good');\n";
+	echo "					$('#password_confirm').addClass('formfld_highlight_good');\n";
+	echo "				}\n";
+	echo "			}\n";
+	echo "		}\n";
+	echo "		else {\n";
+	echo "			$('#password').removeClass('formfld_highlight_bad');\n";
+	echo "			$('#password_confirm').removeClass('formfld_highlight_bad');\n";
+	echo "			$('#password').removeClass('formfld_highlight_good');\n";
+	echo "			$('#password_confirm').removeClass('formfld_highlight_good');\n";
+	echo "		}\n";
+	echo "	}\n";
+
+	$req['length'] = $_SESSION['security']['password_length']['numeric'];
+	$req['number'] = ($_SESSION['security']['password_number']['boolean'] == 'true') ? true : false;
+	$req['lowercase'] = ($_SESSION['security']['password_lowercase']['boolean'] == 'true') ? true : false;
+	$req['uppercase'] = ($_SESSION['security']['password_uppercase']['boolean'] == 'true') ? true : false;
+	$req['special'] = ($_SESSION['security']['password_special']['boolean'] == 'true') ? true : false;
+
+	echo "	function check_password_strength(pwd) {\n";
+	echo "		if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
+	echo "			var msg_errors = [];\n";
+	if (is_numeric($req['length']) && $req['length'] != 0) {
+		echo "		var re = /.{".$req['length'].",}/;\n"; //length
+		echo "		if (!re.test(pwd)) { msg_errors.push('".$req['length']."+ ".$text['label-characters']."'); }\n";
+	}
+	if ($req['number']) {
+		echo "		var re = /(?=.*[\d])/;\n";  //number
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-numbers']."'); }\n";
+	}
+	if ($req['lowercase']) {
+		echo "		var re = /(?=.*[a-z])/;\n";  //lowercase
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-lowercase_letters']."'); }\n";
+	}
+	if ($req['uppercase']) {
+		echo "		var re = /(?=.*[A-Z])/;\n";  //uppercase
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-uppercase_letters']."'); }\n";
+	}
+	if ($req['special']) {
+		echo "		var re = /(?=.*[\W])/;\n";  //special
+		echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-special_characters']."'); }\n";
+	}
+	echo "			if (msg_errors.length > 0) {\n";
+	echo "				var msg = '".$text['message-password_requirements'].": ' + msg_errors.join(', ');\n";
+	echo "				display_message(msg, 'negative', '6000');\n";
+	echo "				return false;\n";
+	echo "			}\n";
+	echo "			else {\n";
+	echo "				return true;\n";
+	echo "			}\n";
+	echo "		}\n";
+	echo "		else {\n";
+	echo "			return true;\n";
+	echo "		}\n";
+	echo "	}\n";
+
+	echo "	function show_strenth_meter() {\n";
+	echo "		$('#pwstrength_progress').slideDown();\n";
+	echo "	}\n";
+	echo "</script>\n";
 
 	echo "<form name='frm' id='frm' method='post' action=''>\n";
 	echo "<input type='hidden' name='action' id='action' value=''>\n";
@@ -462,7 +512,7 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 	echo "		<td width='30%' class='vncellreq' valign='top'>".$text['label-username']."</td>";
 	echo "		<td width='70%' class='vtable'>";
 	if (if_group("admin") || if_group("superadmin")) {
-		echo "		<input type='text' class='formfld' name='username' value='".$username."' required='required'>";
+		echo "		<input type='text' class='formfld' name='username' id='username' value='".$username."' required='required'>";
 	}
 	else {
 		echo "		".$username;
@@ -472,11 +522,17 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 
 	echo "	<tr>";
 	echo "		<td class='vncell' valign='top'>".$text['label-password']."</td>";
-	echo "		<td class='vtable'><input style='display:none;' type='password' name='autocomplete'><input type='password' autocomplete='off' class='formfld' name='password' id='password' value='' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'></td>";
+	echo "		<td class='vtable'>";
+	echo "			<input style='display: none;' type='password'>";
+	echo "			<input type='password' autocomplete='off' class='formfld' name='password' id='password' value='' onkeypress='show_strenth_meter();' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'>";
+	echo "			<div id='pwstrength_progress' class='pwstrength_progress'></div>";
+	echo "		</td>";
 	echo "	</tr>";
 	echo "	<tr>";
 	echo "		<td class='vncell' valign='top'>".$text['label-confirm_password']."</td>";
-	echo "		<td class='vtable'><input type='password' autocomplete='off' class='formfld' name='confirm_password' id='confirmpassword' value='' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'></td>";
+	echo "		<td class='vtable'>";
+	echo "			<input type='password' autocomplete='off' class='formfld' name='password_confirm' id='password_confirm' value='' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'>";
+	echo "		</td>";
 	echo "	</tr>";
 
 	if (permission_exists('user_domain')) {
@@ -589,9 +645,9 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 	echo "	<tr>";
 	echo "		<td width='30%' class='vncell' valign='top'>".$text['label-contact']."</td>";
 	echo "		<td width='70%' class='vtable'>\n";
-	$sql = " select contact_uuid, contact_organization, contact_name_given, contact_name_family from v_contacts ";
+	$sql = " select contact_uuid, contact_organization, contact_name_given, contact_name_family, contact_nickname from v_contacts ";
 	$sql .= " where domain_uuid = '".$domain_uuid."' ";
-	$sql .= " order by contact_organization desc, contact_name_family asc, contact_name_given asc ";
+	$sql .= " order by contact_organization desc, contact_name_family asc, contact_name_given asc, contact_nickname asc ";
 	$prep_statement = $db->prepare(check_sql($sql));
 	$prep_statement->execute();
 	$result = $prep_statement->fetchAll(PDO::FETCH_NAMED);
@@ -599,24 +655,12 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 	echo "<select name=\"contact_uuid\" id=\"contact_uuid\" class=\"formfld\">\n";
 	echo "<option value=\"\"></option>\n";
 	foreach($result as $row) {
-			$contact_name = '';
-			if (strlen($row['contact_organization']) > 0) {
-					$contact_name = $row['contact_organization'];
-			}
-			if (strlen($row['contact_name_family']) > 0) {
-					if (strlen($contact_name) > 0) { $contact_name .= ", "; }
-					$contact_name .= $row['contact_name_family'];
-			}
-			if (strlen($row['contact_name_given']) > 0) {
-					if (strlen($contact_name) > 0) { $contact_name .= ", "; }
-					$contact_name .= $row['contact_name_given'];
-			}
-			if ($row['contact_uuid'] == $contact_uuid) {
-					echo "<option value=\"".$row['contact_uuid']."\" selected=\"selected\">".$contact_name."</option>\n";
-			}
-			else {
-					echo "<option value=\"".$row['contact_uuid']."\">".$contact_name."</option>\n";
-			}
+			$contact_name = array();
+			if ($row['contact_organization'] != '') { $contact_name[] = $row['contact_organization']; }
+			if ($row['contact_name_family'] != '') { $contact_name[] = $row['contact_name_family']; }
+			if ($row['contact_name_given'] != '') { $contact_name[] = $row['contact_name_given']; }
+			if ($row['contact_name_family'] == '' && $row['contact_name_family'] == '' && $row['contact_nickname'] != '') { $contact_name[] = $row['contact_nickname']; }
+			echo "<option value='".$row['contact_uuid']."' ".(($row['contact_uuid'] == $contact_uuid) ? "selected='selected'" : null).">".implode(', ', $contact_name)."</option>\n";
 	}
 	unset($sql, $result, $row_count);
 	echo "</select>\n";
@@ -745,7 +789,7 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 	echo "			<input type='hidden' name='id' value=\"$user_uuid\">";
 	echo "			<input type='hidden' name='username_old' value=\"$username\">";
 	echo "			<br>";
-	echo "			<input type='button' class='btn' value='".$text['button-save']."' onclick=\"document.getElementById('action').value = '".$text['button-save']."'; submit_form();\">";
+	echo "			<input type='button' class='btn' value='".$text['button-save']."' onclick=\"document.getElementById('action').value = '".$text['button-save']."'; if (check_password_strength(document.getElementById('password').value)) { submit_form(); }\">";
 	echo "		</td>";
 	echo "	</tr>";
 	echo "</table>";
@@ -753,16 +797,16 @@ if (count($_POST) > 0 && $_POST["persistform"] != "1") {
 	echo "</form>";
 
 	echo "<script>\n";
-//capture enter key to submit form
-	echo "	$(window).keypress(function(event){\n";
-	echo "		if (event.which == 13) { submit_form(); }\n";
-	echo "	});\n";
-// convert password fields to
-	echo "	function submit_form() {\n";
-	echo "		$('input:password').css('visibility','hidden');\n";
-	echo "		$('input:password').attr({type:'text'});\n";
-	echo "		$('form#frm').submit();\n";
-	echo "	}\n";
+	//capture enter key to submit form
+		echo "	$(window).keypress(function(event){\n";
+		echo "		if (event.which == 13) { submit_form(); }\n";
+		echo "	});\n";
+	// convert password fields to text
+		echo "	function submit_form() {\n";
+		echo "		$('input:password').css('visibility','hidden');\n";
+		echo "		$('input:password').attr({type:'text'});\n";
+		echo "		$('form#frm').submit();\n";
+		echo "	}\n";
 	echo "</script>\n";
 
 	if (permission_exists('user_setting_view')) {

+ 38 - 3
resources/functions.php

@@ -988,8 +988,8 @@ function format_string ($format, $data) {
 		$password = '';
 		$charset = '';
 		if ($length === 0 && $strength === 0) { //set length and strenth if specified in default settings and strength isn't numeric-only
-			$length = (is_numeric($_SESSION["security"]["password_length"]["var"])) ? $_SESSION["security"]["password_length"]["var"] : 10;
-			$strength = (is_numeric($_SESSION["security"]["password_strength"]["var"])) ? $_SESSION["security"]["password_strength"]["var"] : 4;
+			$length = (is_numeric($_SESSION["security"]["password_length"]["numeric"])) ? $_SESSION["security"]["password_length"]["numeric"] : 10;
+			$strength = (is_numeric($_SESSION["security"]["password_strength"]["numeric"])) ? $_SESSION["security"]["password_strength"]["numeric"] : 4;
 		}
 		if ($strength >= 1) { $charset .= "0123456789"; }
 		if ($strength >= 2) { $charset .= "abcdefghijkmnopqrstuvwxyz";	}
@@ -1002,7 +1002,42 @@ function format_string ($format, $data) {
 		}
 		return $password;
 	}
-	//echo generate_password(4, 4);
+
+//check password strength against requirements (if any)
+	function check_password_strength($password, $text) {
+		if ($password != '') {
+			$req['length'] = $_SESSION['security']['password_length']['numeric'];
+			$req['number'] = ($_SESSION['security']['password_number']['boolean'] == 'true') ? true : false;
+			$req['lowercase'] = ($_SESSION['security']['password_lowercase']['boolean'] == 'true') ? true : false;
+			$req['uppercase'] = ($_SESSION['security']['password_uppercase']['boolean'] == 'true') ? true : false;
+			$req['special'] = ($_SESSION['security']['password_special']['boolean'] == 'true') ? true : false;
+			if (is_numeric($req['length']) && $req['length'] != 0 && !preg_match_all('$\S*(?=\S{'.$req['length'].',})\S*$', $password)) { // length
+				$msg_errors[] = $req['length'].'+ '.$text['label-characters'];
+			}
+			if ($req['number'] && !preg_match_all('$\S*(?=\S*[\d])\S*$', $password)) { //number
+				$msg_errors[] = '1+ '.$text['label-numbers'];
+			}
+			if ($req['lowercase'] && !preg_match_all('$\S*(?=\S*[a-z])\S*$', $password)) { //lowercase
+				$msg_errors[] = '1+ '.$text['label-lowercase_letters'];
+			}
+			if ($req['uppercase'] && !preg_match_all('$\S*(?=\S*[A-Z])\S*$', $password)) { //uppercase
+				$msg_errors[] = '1+ '.$text['label-uppercase_letters'];
+			}
+			if ($req['special'] && !preg_match_all('$\S*(?=\S*[\W])\S*$', $password)) { //special
+				$msg_errors[] = '1+ '.$text['label-special_characters'];
+			}
+			if (is_array($msg_errors) && sizeof($msg_errors) > 0) {
+				$_SESSION["message"] = $text['message-password_requirements'].': '.implode(', ', $msg_errors);
+				$_SESSION['message_mood'] = 'negative';
+				$_SESSION['message_delay'] = '6000';
+				return false;
+			}
+			else {
+				return true;
+			}
+		}
+		return true;
+	}
 
 //based on Wez Furlong do_post_request
 	if (!function_exists('send_http_request')) {

+ 104 - 15
resources/login.php

@@ -116,16 +116,22 @@
 			$password_repeat != '' &&
 			$password_new == $password_repeat
 			) {
-			$salt = generate_password('20', '4');
-			$sql  = "update v_users set ";
-			$sql .= "password = '".md5($salt.$password_new)."', ";
-			$sql .= "salt = '".$salt."' ";
-			$sql .= "where domain_uuid = '".$_SESSION['domain_uuid']."' ";
-			$sql .= "and username = '".$username."' ";
-			$db->exec(check_sql($sql));
-
-			$_SESSION["message"] = $text['message-password_reset'];
-			$password_reset = false;
+
+			if (!check_password_strength($password_new, $text)) {
+				$password_reset = true;
+			}
+			else {
+				$salt = generate_password('20', '4');
+				$sql  = "update v_users set ";
+				$sql .= "password = '".md5($salt.$password_new)."', ";
+				$sql .= "salt = '".$salt."' ";
+				$sql .= "where domain_uuid = '".$_SESSION['domain_uuid']."' ";
+				$sql .= "and username = '".$username."' ";
+				$db->exec(check_sql($sql));
+
+				$_SESSION["message"] = $text['message-password_reset'];
+				$password_reset = false;
+			}
 		}
 		else {
 			//not found
@@ -253,17 +259,100 @@
 	}
 	else {
 
+		echo "<script>\n";
+		echo "	function compare_passwords() {\n";
+		echo "		if (document.getElementById('password') === document.activeElement || document.getElementById('password_confirm') === document.activeElement) {\n";
+		echo "			if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
+		echo "				if ($('#password').val() != $('#password_confirm').val()) {\n";
+		echo "					$('#password').removeClass('formfld_highlight_good');\n";
+		echo "					$('#password_confirm').removeClass('formfld_highlight_good');\n";
+		echo "					$('#password').addClass('formfld_highlight_bad');\n";
+		echo "					$('#password_confirm').addClass('formfld_highlight_bad');\n";
+		echo "				}\n";
+		echo "				else {\n";
+		echo "					$('#password').removeClass('formfld_highlight_bad');\n";
+		echo "					$('#password_confirm').removeClass('formfld_highlight_bad');\n";
+		echo "					$('#password').addClass('formfld_highlight_good');\n";
+		echo "					$('#password_confirm').addClass('formfld_highlight_good');\n";
+		echo "				}\n";
+		echo "			}\n";
+		echo "		}\n";
+		echo "		else {\n";
+		echo "			$('#password').removeClass('formfld_highlight_bad');\n";
+		echo "			$('#password_confirm').removeClass('formfld_highlight_bad');\n";
+		echo "			$('#password').removeClass('formfld_highlight_good');\n";
+		echo "			$('#password_confirm').removeClass('formfld_highlight_good');\n";
+		echo "		}\n";
+		echo "	}\n";
+
+		$req['length'] = $_SESSION['security']['password_length']['numeric'];
+		$req['number'] = ($_SESSION['security']['password_number']['boolean'] == 'true') ? true : false;
+		$req['lowercase'] = ($_SESSION['security']['password_lowercase']['boolean'] == 'true') ? true : false;
+		$req['uppercase'] = ($_SESSION['security']['password_uppercase']['boolean'] == 'true') ? true : false;
+		$req['special'] = ($_SESSION['security']['password_special']['boolean'] == 'true') ? true : false;
+
+		echo "	function check_password_strength(pwd) {\n";
+		echo "		if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
+		echo "			var msg_errors = [];\n";
+		if (is_numeric($req['length']) && $req['length'] != 0) {
+			echo "		var re = /.{".$req['length'].",}/;\n"; //length
+			echo "		if (!re.test(pwd)) { msg_errors.push('".$req['length']."+ ".$text['label-characters']."'); }\n";
+		}
+		if ($req['number']) {
+			echo "		var re = /(?=.*[\d])/;\n";  //number
+			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-numbers']."'); }\n";
+		}
+		if ($req['lowercase']) {
+			echo "		var re = /(?=.*[a-z])/;\n";  //lowercase
+			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-lowercase_letters']."'); }\n";
+		}
+		if ($req['uppercase']) {
+			echo "		var re = /(?=.*[A-Z])/;\n";  //uppercase
+			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-uppercase_letters']."'); }\n";
+		}
+		if ($req['special']) {
+			echo "		var re = /(?=.*[\W])/;\n";  //special
+			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-special_characters']."'); }\n";
+		}
+		echo "			if (msg_errors.length > 0) {\n";
+		echo "				var msg = '".$text['message-password_requirements'].": ' + msg_errors.join(', ');\n";
+		echo "				display_message(msg, 'negative', '6000');\n";
+		echo "				return false;\n";
+		echo "			}\n";
+		echo "			else {\n";
+		echo "				return true;\n";
+		echo "			}\n";
+		echo "		}\n";
+		echo "		else {\n";
+		echo "			return true;\n";
+		echo "		}\n";
+		echo "	}\n";
+
+		echo "	function show_strenth_meter() {\n";
+		echo "		$('#pwstrength_progress').slideDown();\n";
+		echo "	}\n";
+		echo "</script>\n";
+
 		echo "<span id='reset_form'>\n";
-		echo "<form name='reset' method='post' action=''>\n";
+		echo "<form name='reset' id='frm' method='post' action=''>\n";
 		echo "<input type='hidden' name='action' value='reset'>\n";
 		echo "<input type='hidden' name='au' value='".md5($_SESSION['login']['password_reset_key']['text'].$username)."'>\n";
 		echo "<input type='text' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 8px;' name='username' id='username' placeholder=\"".$text['label-username']."\"><br />\n";
-		echo "<input type='password' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 8px;' name='password_new' autocomplete='off' placeholder=\"".$text['label-new_password']."\"><br />\n";
-		echo "<input type='password' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 8px;' name='password_repeat' autocomplete='off' placeholder=\"".$text['label-repeat_password']."\"><br />\n";
-		echo "<input type='submit' class='btn' style='width: 100px; margin-top: 15px;' value='".$text['button-save']."'>\n";
+		echo "<input type='password' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 4px;' name='password_new' id='password' autocomplete='off' placeholder=\"".$text['label-new_password']."\" onkeypress='show_strenth_meter();' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'><br />\n";
+		echo "<div id='pwstrength_progress' class='pwstrength_progress pwstrength_progress_password_reset'></div>";
+		echo "<input type='password' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-top: 4px; margin-bottom: 8px;' name='password_repeat' id='password_confirm' autocomplete='off' placeholder=\"".$text['label-repeat_password']."\" onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'><br />\n";
+		echo "<input type='button' class='btn' style='width: 100px; margin-top: 15px;' value='".$text['button-save']."' onclick=\"if (check_password_strength(document.getElementById('password').value)) { submit_form(); }\">\n";
 		echo "<br><br><a class='login_link' onclick=\"document.location.href='login.php';\">".$text['label-cancel']."</a>";
 		echo "</form>";
-		echo "<script>document.getElementById('username').focus();</script>";
+		echo "<script>\n";
+		echo "	document.getElementById('username').focus();\n";
+		// convert password fields to text
+			echo "	function submit_form() {\n";
+			echo "		$('input:password').css('visibility','hidden');\n";
+			echo "		$('input:password').attr({type:'text'});\n";
+			echo "		$('form#frm').submit();\n";
+			echo "	}\n";
+		echo "</script>\n";
 		echo "</span>";
 
 	}

+ 35 - 2
themes/default/css.php

@@ -356,6 +356,7 @@ $default_login = ($_REQUEST['login'] == 'default') ? true : false;
 	.dropdown-menu > li > a:active {
 		color: <?php echo ($_SESSION['theme']['menu_sub_text_color_hover']['text'] != '') ? $_SESSION['theme']['menu_sub_text_color_hover']['text'] : '#fd9c03'; ?>;
 		background: <?php echo ($_SESSION['theme']['menu_sub_background_color_hover']['text'] != '') ? $_SESSION['theme']['menu_sub_background_color_hover']['text'] : '#141414'; ?>;
+		outline: none;
 		}
 
 	.dropdown-menu > li > a > span.glyphicon {
@@ -975,14 +976,20 @@ $default_login = ($_REQUEST['login'] == 'default') ? true : false;
 	input.login:-ms-input-placeholder { color: <?php echo $placeholder_color; ?> } /* ie 10+ */
 	input.login::placeholder { color: <?php echo $placeholder_color; ?> } /* official standard */
 
-	.formfld_highlight_bad {
+	input[type=password].formfld_highlight_bad,
+	input[type=password].formfld_highlight_bad:hover,
+	input[type=password].formfld_highlight_bad:active,
+	input[type=password].formfld_highlight_bad:focus {
 		border-color: #aa2525;
 		-webkit-box-shadow: 0 0 3px #aa2525 inset;
 		-moz-box-shadow: 0 0 3px #aa2525 inset;
 		box-shadow: 0 0 3px #aa2525 inset;
 		}
 
-	.formfld_highlight_good {
+	input[type=password].formfld_highlight_good,
+	input[type=password].formfld_highlight_good:hover,
+	input[type=password].formfld_highlight_good:active,
+	input[type=password].formfld_highlight_good:focus {
 		border-color: #2fb22f;
 		-webkit-box-shadow: 0 0 3px #2fb22f inset;
 		-moz-box-shadow: 0 0 3px #2fb22f inset;
@@ -1026,6 +1033,32 @@ $default_login = ($_REQUEST['login'] == 'default') ? true : false;
 		display: block;
 		}
 
+	div.pwstrength_progress {
+		display: none;
+		}
+
+	div.pwstrength_progress > div.progress {
+		max-width: 200px;
+		height: 6px;
+		margin: 1px 0 0 1px;
+		background: <?php echo ($_SESSION['theme']['input_background_color']['text'] != '') ? $_SESSION['theme']['input_background_color']['text'] : 'rgb(245, 245, 245)'; ?>;
+		<?php $br = format_border_radius($_SESSION['theme']['input_border_radius']['text'], '3px'); ?>
+		-moz-border-radius: <?php echo $br['tl']['n'].$br['tl']['u']; ?> <?php echo $br['tr']['n'].$br['tr']['u']; ?> <?php echo $br['br']['n'].$br['br']['u']; ?> <?php echo $br['bl']['n'].$br['bl']['u']; ?>;
+		-webkit-border-radius: <?php echo $br['tl']['n'].$br['tl']['u']; ?> <?php echo $br['tr']['n'].$br['tr']['u']; ?> <?php echo $br['br']['n'].$br['br']['u']; ?> <?php echo $br['bl']['n'].$br['bl']['u']; ?>;
+		-khtml-border-radius: <?php echo $br['tl']['n'].$br['tl']['u']; ?> <?php echo $br['tr']['n'].$br['tr']['u']; ?> <?php echo $br['br']['n'].$br['br']['u']; ?> <?php echo $br['bl']['n'].$br['bl']['u']; ?>;
+		border-radius: <?php echo $br['tl']['n'].$br['tl']['u']; ?> <?php echo $br['tr']['n'].$br['tr']['u']; ?> <?php echo $br['br']['n'].$br['br']['u']; ?> <?php echo $br['bl']['n'].$br['bl']['u']; ?>;
+		<?php unset($br); ?>
+		}
+
+	div.pwstrength_progress_password_reset > div.progress {
+		margin: 0 auto 4px auto;
+		width: 200px;
+		max-width: 200px;
+		background: <?php echo ($_SESSION['theme']['login_input_background_color']['text'] != '') ? $_SESSION['theme']['login_input_background_color']['text'] : (($_SESSION['theme']['input_background_color']['text'] != '') ? $_SESSION['theme']['input_background_color']['text'] : '#ffffff'); ?>;
+		border-width: <?php echo ($_SESSION['theme']['login_input_border_size']['text'] != '') ? $_SESSION['theme']['login_input_border_size']['text'] : (($_SESSION['theme']['input_border_size']['text'] != '') ? $_SESSION['theme']['input_border_size']['text'] : '1px'); ?>;
+		border-color: <?php echo ($_SESSION['theme']['login_input_border_color']['text'] != '') ? $_SESSION['theme']['login_input_border_color']['text'] : (($_SESSION['theme']['input_border_color']['text'] != '') ? $_SESSION['theme']['input_border_color']['text'] : '#c0c0c0'); ?>;
+		}
+
 /* TABLES *****************************************************************/
 
 	table {

+ 19 - 0
themes/default/template.php

@@ -51,6 +51,7 @@
 <script language="JavaScript" type="text/javascript" src="<!--{project_path}-->/resources/bootstrap/js/bootstrap.min.js"></script>
 <script language="JavaScript" type="text/javascript" src="<!--{project_path}-->/resources/bootstrap/js/bootstrap-datetimepicker.min.js"></script>
 <script language="JavaScript" type="text/javascript" src="<!--{project_path}-->/resources/bootstrap/js/bootstrap-colorpicker.js"></script>
+<script language="JavaScript" type="text/javascript" src="<!--{project_path}-->/resources/bootstrap/js/bootstrap-pwstrength.min.js"></script>
 <?php
 //web font loader
 	if ($_SESSION['theme']['font_loader']['text'] == 'true') {
@@ -195,6 +196,24 @@
 				});
 			});
 
+		//apply password strength plugin
+			$('#password').pwstrength({
+				common: {
+					minChar: 8,
+					usernameField: '#username',
+				},
+				/* rules: { },  */
+				ui: {
+					//				very weak weak		normal	   medium	  strong	 very strong
+					colorClasses: ["danger", "warning", "warning", "warning", "success", "success"],
+					progressBarMinPercentage: 15,
+					showVerdicts: false,
+					viewports: {
+						progress: "#pwstrength_progress"
+					}
+				}
+			});
+
 		<?php if ($_SESSION['theme']['menu_brand_image']['text'] != '' && $_SESSION['theme']['menu_brand_image_hover']['text'] != '') { ?>
 			//crossfade menu brand images (if hover version set)
 				$(function(){