[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Noalyss-commit] [noalyss] 05/20: Task #2309 mot de passe fort
From: |
dwm |
Subject: |
[Noalyss-commit] [noalyss] 05/20: Task #2309 mot de passe fort |
Date: |
Sun, 10 Dec 2023 03:22:23 -0500 (EST) |
sparkyx pushed a commit to branch master
in repository noalyss.
commit a0d1c26eafe015d78bf35e2465f08430c4f50acf
Author: sparkyx <danydb@noalyss.eu>
AuthorDate: Sat Dec 2 18:01:53 2023 +0100
Task #2309 mot de passe fort
---
html/ajax_misc.php | 15 +++++
html/install.php | 14 +++-
html/js/noalyss_script.js | 54 ++++++++++++++-
include/ajax/ajax_preference.php | 29 +++++---
include/class/noalyss_user.class.php | 3 +-
include/lib/ac_common.php | 115 +++++++++++++++++++++++++++++++-
include/recover.php | 21 ++----
include/user.inc.php | 36 ++++++++--
include/user_detail.inc.php | 2 +
unit-test/include/lib/ac_commonTest.php | 42 ++++++++++++
10 files changed, 296 insertions(+), 35 deletions(-)
diff --git a/html/ajax_misc.php b/html/ajax_misc.php
index 3227b94aa..1ee537040 100644
--- a/html/ajax_misc.php
+++ b/html/ajax_misc.php
@@ -113,7 +113,22 @@ if ($op == "progressBar") {
return;
}
+//-------------------------------------------------------------------------------------------
+// check password
+//-------------------------------------------------------------------------------------------
+if ($op=='password_chk') {
+ $cnt = $http->request("pass");
+ $result=check_password_strength($cnt)['msg'];
+ if (count($result) == 0) {
+ echo json_response(["password" => "ok", "msg" => 0]);
+ } else {
+ $str="";
+ foreach ($result as $item) {$str.=sprintf("<li>%s</li>",$item);}
+ echo json_response(["password" => "nok", "msg" =>
'<ol>'.$str.'</ol>']);
+ }
+ return;
+}
$html = var_export($_REQUEST, true);
set_language();
if ( LOGINPUT)
diff --git a/html/install.php b/html/install.php
index f4c5a90e9..9ec75f0a9 100644
--- a/html/install.php
+++ b/html/install.php
@@ -233,7 +233,19 @@ if (isset($_POST['save_config'])) {
$err++;
}
-
+ // check strenght password admin
+ $passw_error=check_password_strength($cpassword_admin);
+ if ( count($passw_error['msg'])>0) {
+ echo '<h2 class="warning">';
+ echo _("Mot de passe trop faible");
+ echo '</h2>';
+ echo '<ol>';
+ foreach ($passw_error['msg'] as $error) {
+ echo "<li>",$error,"</li>";
+ }
+ echo '</ol>';
+ $err++;
+ }
// check password and admin not containing quote or double quote
//
if ( strpos($cpassword_admin,'"') !== false
diff --git a/html/js/noalyss_script.js b/html/js/noalyss_script.js
index 3e6301e22..e78c118f2 100644
--- a/html/js/noalyss_script.js
+++ b/html/js/noalyss_script.js
@@ -3786,9 +3786,13 @@ function updatePreference()
method: "post",
parameters: param,
onSuccess: function (req) {
- var style = req.responseText.evalJSON();
+ var answer = req.responseText.evalJSON();
// $('pagestyle').setAttribute('href', style.style);
- removeDiv('preference_div');
+ if ( answer['psw']=='NOK') {
+ smoke.alert(answer['msg']);
+ } else {
+ removeDiv('preference_div');
+ }
}
});
} catch (e)
@@ -4224,4 +4228,50 @@ function event_display_main(p_dossier) {
{
alert_box(e.message);
}
+}
+
+/**
+ * @brief check if password is strong or not, update a DIV element
+ * @param p_pass_domid DOM ID of the INPUT element with the password
+ * @param p_result_domid DOM ID of the element to update
+ */
+function check_password_strength(p_pass_domid,p_result_domid,details)
+{
+ try
+ {
+ if ( $(p_pass_domid).value=="") {
$(p_result_domid).update("");return;}
+ var queryString= {
+ 'op':"password_chk"
+ ,pass:$(p_pass_domid).value
+ };
+ var action = new Ajax.Request(
+ "ajax_misc.php" ,
+ {
+ method:'GET',
+ parameters:queryString,
+ onFailure:ajax_misc_failure,
+ onSuccess:function(req){
+ remove_waiting_box();
+ if (req.responseText == 'NOCONX') {
+ return;
+ }
+ var answer=req.responseJSON;
+ console.debug(answer);
+ if (answer['password']=='nok') {
+
+
$(p_pass_domid).setStyle("background-color:red");
+ if ( details) {
+ $(p_result_domid).update(answer['msg'])
+ }
+ return;
+ }
+ $(p_pass_domid).setStyle("background-color:
lightgreen");
+ $(p_result_domid).update("")
+ }
+ }
+ );
+ }catch( e)
+ {
+ alert_box(e.message);
+ }
}
\ No newline at end of file
diff --git a/include/ajax/ajax_preference.php b/include/ajax/ajax_preference.php
index 99a0bdf45..f66c6cb99 100644
--- a/include/ajax/ajax_preference.php
+++ b/include/ajax/ajax_preference.php
@@ -84,8 +84,9 @@ if ( $action == 'display_form' )
<tr><td>
Mot de passe :
</td>
- <td><input type="password" value="" class="input_text"
name="pass_1" nohistory>
+ <td><input type="password" value="" class="input_text"
name="pass_1" id="pass_1" nohistory
onkeyup=check_password_strength('pass_1','info_passid',1)>
<input type="password" value="" class="input_text"
name="pass_2" nohistory>
+ <span id="info_passid"></span>
</td>
</tr>
@@ -321,20 +322,32 @@ if ($action == 'save')
$csv_decimal=$http->post("csv_decimal","number");
$csv_encoding=$http->post("csv_encoding");
$firstday=$http->post("selFirstDay","number");
-
+ $password="OK";
+ $msg ="";
if (noalyss_strlentrim($pass_1) != 0 && noalyss_strlentrim($pass_2) != 0)
{
if ( $g_user->save_password($_POST['pass_1'],$pass_2) )
- { $g_user->password_to_session() ;
+ {
+ $g_user->password_to_session() ;
} else {
/**
* password not changed
- */
-
+ */
+ $password="NOK";
+ $msg="";
+ if ( $_POST['pass_1'] !== $pass_2) {
+ $msg = _("Mot de passe ne correspondent pas");
+ $msg .="<br/>";
+ }
+ $a_pass_error=check_password_strength($_POST['pass_1']);
+ if ( count($a_pass_error['msg']) != 0 ) {
+ foreach($a_pass_error['msg'] as $pass_error) {
+ $msg.=$pass_error."<br/>";
+ }
+ }
+
}
-
-
}
if ( $inside_dossier)
{
@@ -366,6 +379,6 @@ if ($action == 'save')
{
$style = "style-classic7.css";
}
- json_response(["style"=>$style]);
+ json_response(["style"=>$style,'psw'=>$password,'msg'=>$msg]);
}
diff --git a/include/class/noalyss_user.class.php
b/include/class/noalyss_user.class.php
index 890f7d886..b9b10e2df 100644
--- a/include/class/noalyss_user.class.php
+++ b/include/class/noalyss_user.class.php
@@ -1635,11 +1635,12 @@ class Noalyss_User
* @brief Save the password of the current user
* @param string $p_pass1 password (clear)
* @param string $p_pass2 for confirming password (clear)
+ * @see check_password_strength()
* @return true : password successfully changed otherwise false
*/
function save_password($p_pass1, $p_pass2)
{
- if ($p_pass1==$p_pass2)
+ if ($p_pass1==$p_pass2 &&
count(check_password_strength($p_pass1)['msg'])==0)
{
$repo=new Database();
$l_pass=md5($p_pass1);
diff --git a/include/lib/ac_common.php b/include/lib/ac_common.php
index dcab67a9f..82ea4dbac 100644
--- a/include/lib/ac_common.php
+++ b/include/lib/ac_common.php
@@ -1416,10 +1416,13 @@ function remove_divide_zero($p_formula)
* @brief Create randomly a string
* @param int $p_length length of the generate string
*/
-function generate_random_string($p_length)
+function generate_random_string($p_length,$special=1)
{
$string="";
- $chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789*/+-=";
+ if ($special == 1)
+
$chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789*/+-=";
+ if ($special == 0)
+ $chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789";
$microtime=microtime(true)*microtime(true)*100;
srand(0);
srand((int)$microtime);
@@ -1663,3 +1666,111 @@ function MaintenanceMode($p_file)
exit;
}
}
+
+/**
+ * @brief returns an double array with the error found and code , if the count
is 0 then the password is very string, 5 means it is
+ * empty ,4 weak, ... the array contains the errors, [msg]=>array message
[code] => array of code
+ * Codes are
+ * - 1 : too short
+ * - 2 : missing digit
+ * - 3 : missing lowercase letter
+ * - 4 : missing uppercase letter
+ * - 5 : too many time same letter or symbol..
+ * - 6 : missing special char
+ *
+ * If the password is strong returns an empty array
+ *
+ * @param $password string
+ * @code
+
+ $error = check_password_strength($password);
+ if ( count($error['msg']) > 0 ) {
+ echo "password to weak";
+ foreach ($error['msg'] as $item_error) {
+ echo "error $item_error";
+ }
+
+ } else {
+ echo "OK password strong";
+ }
+
+ * @endcode
+ */
+function check_password_strength($password) {
+ $errors=array();
+ $error_code=array();
+
+ $len=strlen($password??"");
+ if ( $len < 8) {
+ $errors[] = _("mot de passe de 8 lettres minimum");
+ $error_code[]=1;
+ }
+
+ if (!preg_match("#[0-9]+#", $password)) {
+ $errors[] = _("mot de passe doit inclure au moins un chiffre");
+ $error_code[]=2;
+ }
+
+ if (!preg_match("#[a-z]+#", $password)) {
+ $errors[] = _("mot de passe doit inclure au moins une minuscule");
+ $error_code[]=3;
+ }
+ if (!preg_match("#[A-Z]+#", $password)) {
+ $errors[] = _("mot de passe doit inclure au moins une majuscule");
+ $error_code[]=4;
+ }
+
+ if ( $len > 0 ) {
+ $cnt_diff=count(count_chars($password,1));
+ $ratio_diff=$len/$cnt_diff;
+
+ if ($ratio_diff > 2) {
+ $errors[] = _("Trop souvent le(s) même(s) symbole(s)");
+ $error_code[]=5;
+ }
+ $special_char=preg_replace('/[[:alnum:]]/','',$password);
+ if ( strlen($special_char??"")==0)
+ {
+ $errors[] = _("mot de passe doit inclure au moins un caractére
spécial '+-/*[...'");
+ $error_code[]=6;
+
+ }
+ }
+
+ return array( 'msg'=>$errors, 'code'=>$error_code);
+}
+/**
+ * @brief generate a strong random password
+ * @param $car int length of the password, minimum 8
+ *
+ */
+function generate_random_password($car):string
+{
+ $string="";
+ $car=($car < 8 )?8:$car;
+ $max_loop=20;$loop=0;
+ do
+ {
+ $loop++;
+ $string="";
+ $chaine="abcdefghijklmnpqrstuvwxy";
+ // srand( (int)microtime()*1020030);
+ for ($i=0; $i<$car; $i++)
+ {
+ $string .= $chaine[rand()%strlen($chaine)];
+ }
+ $chaine="ABCDEFGHIJKLMNPQRSTUVWXY";
+ for ($i=0;$i<2;$i++) {
+ $string[rand()%$car]=$chaine[rand()%strlen($chaine)];;
+ }
+ $chaine="0123456789";
+ for ($i=0;$i<2;$i++) {
+ $string[rand()%$car]=$chaine[rand()%strlen($chaine)];;
+ }
+ $special_set="+-/*;,.=:&()[]";
+ $special_car=$special_set[rand()%strlen($special_set)];
+ $string[rand()%$car]=$special_car;
+ // echo $string."\n";
+ }while ( count(check_password_strength($string)['msg'])> 0 &&
$loop<$max_loop);
+ return $string;
+}
\ No newline at end of file
diff --git a/include/recover.php b/include/recover.php
index 026863f65..ed8d7ad47 100644
--- a/include/recover.php
+++ b/include/recover.php
@@ -17,27 +17,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright (2014) Author Dany De Bontridder <dany@alchimerys.be>
+require_once NOALYSS_INCLUDE.'/lib/ac_common.php';
if (!defined('RECOVER'))
die('Appel direct ne sont pas permis');
define('SIZE_REQUEST', 70);
-/**
- * @brief generate a random string of char
- * @param $car int length of the string
- */
-function generate_random($car)
-{
- $string="";
- $chaine="abcdefghijklmnpqrstuvwxyABCDEFGHIJKLMNPQRSTUVWXY0123456789";
- srand((double) microtime()*1020030);
- for ($i=0; $i<$car; $i++)
- {
- $string .= $chaine[rand()%strlen($chaine)];
- }
- return $string;
-}
+
$http=new HttpInput();
/**
* @file
@@ -89,8 +76,8 @@ elseif ($action=="send_email") :
if ($valid==true):
- $request_id=generate_random(SIZE_REQUEST);
- $user_password=generate_random(10);
+ $request_id=generate_random_string(SIZE_REQUEST,special: 0);
+ $user_password=generate_random_password(10);
// exist a valid request for this user ?
$exist_request= $cn->get_array("select request , password from
recover_pass
where use_id=$1 and created_on > now() - interval '12
hours'",[$user_id]);
diff --git a/include/user.inc.php b/include/user.inc.php
index c714f83e5..dddccd752 100644
--- a/include/user.inc.php
+++ b/include/user.inc.php
@@ -35,6 +35,7 @@ echo '<div class="content" >';
if ( isset ($_POST["ADD"]) )
{
$cn=new Database();
+ $a_result =check_password_strength($_POST['PASS']);
$pass5=md5($_POST['PASS']);
$new_user=new Noalyss_user($cn,0);
$new_user->first_name=$http->post('FNAME');
@@ -45,11 +46,18 @@ if ( isset ($_POST["ADD"]) )
$login=str_replace(" ","",$login);
$login=strtolower($login);
$new_user->login=$login;
- $new_user->setPassword($pass5);
+
$new_user->email=$http->post('EMAIL',"string",'');
if ( trim($login)=="")
{
alert(_("Le login ne peut pas être vide"));
+ }elseif (count($a_result['msg']) > 0){
+ // password too weak
+ $msg='<span class="warning">'._("Mot de passe inchangé").'</span>';
+ foreach ($a_result['msg'] as $result ) {
+ $msg.="$result <br/>";
+ }
+ alert($msg);
}
else
{
@@ -101,8 +109,18 @@ if ($sbaction == "save")
}
if ( trim($_POST['password'])<>'')
{
- $UserChange->setPassword(md5($_POST['password']));
- $UserChange->save();
+ $a_result =check_password_strength($_POST['password']);
+ if (count($a_result['msg']) > 0){
+ // password too weak
+ $msg='<span class="warning">'._("Mot de passe
inchangé").'</span>';
+ foreach ($a_result['msg'] as $result ) {
+ $msg.="$result <br/>";
+ }
+ alert($msg);
+ } else {
+ $UserChange->setPassword(md5($_POST['password']));
+ $UserChange->save();
+ }
}
else
{
@@ -168,9 +186,19 @@ if ( isset($_REQUEST['det']) && $sbaction=="")
<TR><TD style="text-align: right"> <?php echo
_('login')?></TD><TD><INPUT id="input_login" class="input_text" TYPE="TEXT"
NAME="LOGIN"></TD></tr>
<TR><TD style="text-align: right"> <?php echo
_('Prénom')?></TD><TD><INPUT class="input_text" TYPE="TEXT"
NAME="FNAME"></TD></tr>
<TR><TD style="text-align: right"> <?php echo _('Nom')?></TD><TD><INPUT
class="input_text" TYPE="TEXT" NAME="LNAME"></TD></TR>
- <TR><TD style="text-align: right"> <?php echo _('Mot de
passe')?></TD><TD> <INPUT id="input_password" class="input_text" TYPE="TEXT"
NAME="PASS"></TD></TR>
+ <TR>
+ <TD style="text-align: right"> <?php echo _('Mot de passe')?>
+ <?=\Icon_Action::tips("Mot de passe : longueur minimale = 8 dont
au moins 1 majuscule, 1 minuscule,1 chiffre et 1 car.spécial")?>
+
+ </TD>
+ <TD> <INPUT id="input_password" class="input_text" TYPE="TEXT"
NAME="PASS"
+ onkeyup=check_password_strength('input_password','info_passid')
+ >
+ <span id="info_passid"></span>
+ </TD></TR>
<TR><TD style="text-align: right"> <?php echo _('Email')?></TD><TD>
<INPUT class="input_text" TYPE="TEXT" NAME="EMAIL"></TD></TR>
</TABLE>
+
<?php
echo HtmlInput::submit("ADD",_('Créer Utilisateur'),"",'button');
echo HtmlInput::button_action(_("Fermer"),
"$('create_user').style.display='none';");
diff --git a/include/user_detail.inc.php b/include/user_detail.inc.php
index 7f28466bd..c84f5602f 100644
--- a/include/user_detail.inc.php
+++ b/include/user_detail.inc.php
@@ -42,6 +42,7 @@ if ($UserChange->id == false)
$UserChange->load();
$it_pass=new IText('password');
+$it_pass->javascript='onkeyup="check_password_strength(\'password\',\'password_info\',1)"';
$it_pass->value="";
?>
<FORM id="user_detail_frm" METHOD="POST">
@@ -81,6 +82,7 @@ $it_pass->value="";
</td>
<td>
<?php echo $it_pass->input();?>
+ <span id="password_info" style="background-color:
yellow;color:red;position:absolute"></span>
</td>
</tr>
<tr>
diff --git a/unit-test/include/lib/ac_commonTest.php
b/unit-test/include/lib/ac_commonTest.php
index 10483089a..91f2ff39c 100644
--- a/unit-test/include/lib/ac_commonTest.php
+++ b/unit-test/include/lib/ac_commonTest.php
@@ -424,4 +424,46 @@ EOF;
$this->assertEquals(strtoupper($expect),strtoupper(preg_replace("/\s+/",'',faxTo('123'))),);
}
+
+ /**
+ * supply data for user password
+ * @return array[$password, $weakness] 0 means strong password
+ */
+ public function dataCheck_password_strength()
+ {
+ return array(
+ ["AAAAAAA",5]
+ ,["123456789",3]
+ ,["Az123456789",1]
+ ,["",4]
+ ,["+",4]
+ ,["AAAA121212abx",2]
+ ,["Az&123456789",0]
+ ,["l5F8Cny=",0]
+ );
+ }
+ /**
+ * @testDoc test the check_password_strength function
+ * @dataProvider dataCheck_password_strength()
+ */
+ public function testCheck_password_strength($p_password,$p_cnt)
+ {
+
+ $count=count(check_password_strength($p_password)['msg']);
+ $this->assertTrue($count ==$p_cnt,"error : $p_password weak password
$count" );
+
+ }
+
+ public function testGenerate_strong_password()
+ {
+
+ for ($i = 0; $i < 100; $i++)
+ {
+ $pass=generate_random_password(5);
+
+ $this->assertTrue( count(check_password_strength($pass)['msg'])==0
+ ,"error cannot generate strong password get $pass");
+ }
+ }
+
}
- [Noalyss-commit] [noalyss] branch master updated (4bf2ca815 -> 98390d4d4), dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 11/20: remove raise, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 05/20: Task #2309 mot de passe fort,
dwm <=
- [Noalyss-commit] [noalyss] 13/20: FIX : when taken from git NOALYSS_VERSION is undefined, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 02/20: Improve Manage_Table : search button if modify or delete is on the left, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 18/20: DatabaseCore : clear prepare stmt, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 19/20: Test disable xdebug, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 16/20: PRINTGL Main Ledger (GL) improve performance and code prepare the SQL , better filter for accounting, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 08/20: Improve documentation, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 01/20: PHP Compatibility 8.1, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 17/20: PRINTGL Main Ledger (GL), dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 20/20: Fix merge issue, dwm, 2023/12/10
- [Noalyss-commit] [noalyss] 06/20: ergo, dwm, 2023/12/10