noalyss-commit
[Top][All Lists]
Advanced

[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");
+        }
+    }
+
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]