Ver Fonte

Maj Profil et Ajout Google Authenticator

stany.ferer há 2 anos atrás
pai
commit
d30e33e9ea

+ 167 - 0
core/class/googleAuthenticator.class.php

@@ -0,0 +1,167 @@
+<?php
+
+class googleAuthenticator
+{
+    static protected $_codeLength = 6;
+
+    static public function createSecret($secretLength = 16)
+    {
+        $validChars = self::_getBase32LookupTable();
+
+        // Valid secret lengths are 80 to 640 bits
+        if ($secretLength < 16 || $secretLength > 128) {
+            throw new Exception('Bad secret length');
+        }
+        $secret = '';
+        $rnd = false;
+        if (function_exists('random_bytes')) {
+            $rnd = random_bytes($secretLength);
+        } elseif (function_exists('openssl_random_pseudo_bytes')) {
+            $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
+            if (!$cryptoStrong) {
+                $rnd = false;
+            }
+        }
+        if ($rnd !== false) {
+            for ($i = 0; $i < $secretLength; ++$i) {
+                $secret .= $validChars[ord($rnd[$i]) & 31];
+            }
+        } else {
+            throw new Exception('No source of secure random');
+        }
+
+        return $secret;
+    }
+
+    static public function getCode($secret, $timeSlice = null)
+    {
+        if ($timeSlice === null) {
+            $timeSlice = floor(time() / 30);
+        }
+
+        $secretkey = self::_base32Decode($secret);
+
+        // Pack time into binary string
+        $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
+        // Hash it with users secret key
+        $hm = hash_hmac('SHA1', $time, $secretkey, true);
+        // Use last nipple of result as index/offset
+        $offset = ord(substr($hm, -1)) & 0x0F;
+        // grab 4 bytes of the result
+        $hashpart = substr($hm, $offset, 4);
+
+        // Unpak binary value
+        $value = unpack('N', $hashpart);
+        $value = $value[1];
+        // Only 32 bits
+        $value = $value & 0x7FFFFFFF;
+
+        $modulo = pow(10, self::$_codeLength);
+
+        return str_pad($value % $modulo, self::$_codeLength, '0', STR_PAD_LEFT);
+    }
+
+    static public function getGoogleUrl($name, $secret)
+    {
+        $urlencoded = 'otpauth://totp/'.$name.'?secret='.$secret;
+        return $urlencoded;
+    }
+
+    static public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
+    {
+        if ($currentTimeSlice === null) {
+            $currentTimeSlice = floor(time() / 30);
+        }
+
+        if (strlen($code) != 6) {
+            return false;
+        }
+
+        for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
+            $calculatedCode = self::getCode($secret, $currentTimeSlice + $i);
+            if (self::timingSafeEquals($calculatedCode, $code)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    static public function setCodeLength($length)
+    {
+        return self::$_codeLength = $length;
+    }
+
+    static protected function _base32Decode($secret)
+    {
+        if (empty($secret)) {
+            return '';
+        }
+
+        $base32chars = self::_getBase32LookupTable();
+        $base32charsFlipped = array_flip($base32chars);
+
+        $paddingCharCount = substr_count($secret, $base32chars[32]);
+        $allowedValues = array(6, 4, 3, 1, 0);
+        if (!in_array($paddingCharCount, $allowedValues)) {
+            return false;
+        }
+        for ($i = 0; $i < 4; ++$i) {
+            if ($paddingCharCount == $allowedValues[$i] &&
+                substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
+                return false;
+            }
+        }
+        $secret = str_replace('=', '', $secret);
+        $secret = str_split($secret);
+        $binaryString = '';
+        for ($i = 0; $i < count($secret); $i = $i + 8) {
+            $x = '';
+            if (!in_array($secret[$i], $base32chars)) {
+                return false;
+            }
+            for ($j = 0; $j < 8; ++$j) {
+                $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
+            }
+            $eightBits = str_split($x, 8);
+            for ($z = 0; $z < count($eightBits); ++$z) {
+                $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
+            }
+        }
+
+        return $binaryString;
+    }
+
+    static protected function _getBase32LookupTable()
+    {
+        return array(
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', //  7
+            'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
+            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
+            'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
+            '=',  // padding char
+        );
+    }
+
+    static private function timingSafeEquals($safeString, $userString)
+    {
+        if (function_exists('hash_equals')) {
+            return hash_equals($safeString, $userString);
+        }
+        $safeLen = strlen($safeString);
+        $userLen = strlen($userString);
+
+        if ($userLen != $safeLen) {
+            return false;
+        }
+
+        $result = 0;
+
+        for ($i = 0; $i < $userLen; ++$i) {
+            $result |= (ord($safeString[$i]) ^ ord($userString[$i]));
+        }
+
+        // They are only identical strings if $result is exactly 0...
+        return $result === 0;
+    }
+}

+ 4 - 0
core/class/myQrcode.class.php

@@ -6,5 +6,9 @@ class myQrcode {
         include_once(DIR_PHP_LIBS . "phpqrcode/qrlib.php");
         QRcode::png($_lien, NULL ,QR_ECLEVEL_L, 10);
     }
+
+    public static function printQRCode(string $_data){
+        echo '<img src="./qrcode.php?q='.base64_encode($_data).'" />';
+    }
     
 }

+ 23 - 2
core/class/user.class.php

@@ -14,6 +14,7 @@ class user {
                 . "" . DB_T_USER . ".nom, "
                 . "" . DB_T_USER . ".cree, "
                 . "" . DB_T_USER . ".last_connect, "
+                . "" . DB_T_USER . ".googleAuthenticator, "
                 . "" . DB_T_USER . ".actif, "
                 . "" . DB_T_USER . ".id_type, "
                 . "" . DB_T_USER_TYPE . ".type "
@@ -33,6 +34,7 @@ class user {
                 . "" . DB_T_USER . ".nom, "
                 . "" . DB_T_USER . ".cree, "
                 . "" . DB_T_USER . ".last_connect, "
+                . "" . DB_T_USER . ".googleAuthenticator, "
                 . "" . DB_T_USER . ".actif, "
                 . "" . DB_T_USER . ".id_type, "
                 . "" . DB_T_USER_TYPE . ".type "
@@ -41,13 +43,28 @@ class user {
         return db::resultset();
     }
 
+    public static function getMyGoogleAuthenticator(int $_id){
+        db::query("SELECT "
+                . "" . DB_T_USER . ".googleAuthenticatorSecret "
+                . "FROM " . DB_T_USER . " "
+                . "WHERE " . DB_T_USER . ".id = :id");
+        db::bind(':id', $_id);
+        return db::single()["googleAuthenticatorSecret"];
+    }
+
     public static function connect(array $_input) {
         $return = NULL;
         if (isset($_input["email"]) AND isset($_input["password"])) {
-            db::query("SELECT id, email, password, prenom, nom, id_type, actif FROM " . DB_T_USER . " WHERE email = :email");
+            db::query("SELECT id, email, password, prenom, nom, id_type, googleAuthenticator, googleAuthenticatorSecret, actif FROM " . DB_T_USER . " WHERE email = :email");
             db::bind(':email', $_input["email"]);
             $row = db::single();
 
+            if($row["googleAuthenticator"] == 1){
+                if(googleAuthenticator::verifyCode($row["googleAuthenticatorSecret"], $_input["authenticator"], 1) == FALSE){
+                    $row["id"] = NULL;
+                }
+            }
+
             if (isset($row["id"])) {
                 if ($row["actif"] == 0) {
                     alert::recError("Votre compte est désactivé");
@@ -57,6 +74,7 @@ class user {
                         "id" => $row["id"],
                         "prenom" => $row["prenom"],
                         "nom" => $row["nom"],
+                        "googleAuthenticator" => $row["googleAuthenticator"],
                         "idType" => $row["id_type"],
                         "email" => $row["email"],
                         "actif" => $row["actif"]
@@ -84,6 +102,7 @@ class user {
     }
     
     public static function add_user(array $_input){
+
         db::query("INSERT INTO " . DB_T_USER . " "
                 . "(email, password, prenom, nom, id_type, actif) "
                 . "VALUES (:email, :password, :prenom, :nom, :id_type, :actif)");
@@ -91,6 +110,7 @@ class user {
         db::bind(':password', md5($_input["password"]));
         db::bind(':prenom', $_input["prenom"]);
         db::bind(':nom', $_input["nom"]);
+        db::bind(':googleAuthenticatorSecret', googleAuthenticator::createSecret());
         db::bind(':id_type', $_input["id_type"]);
         db::bind(':actif', $_input["actif"]);
         
@@ -123,10 +143,11 @@ class user {
             }
         }
         
-        db::query("UPDATE " . DB_T_USER . " SET email = :email, prenom = :prenom, nom = :nom, id_type = :id_type, actif = :actif WHERE id = :id");
+        db::query("UPDATE " . DB_T_USER . " SET email = :email, prenom = :prenom, nom = :nom, id_type = :id_type, googleAuthenticator = :googleAuthenticator, actif = :actif WHERE id = :id");
         db::bind(':email', $_input["email"]);
         db::bind(':prenom', $_input["prenom"]);
         db::bind(':nom', $_input["nom"]);
+        db::bind(':googleAuthenticator', $_input["googleAuthenticator"]);
         db::bind(':id_type', $_input["id_type"]);
         db::bind(':actif', $_input["actif"]);
         db::bind(':id', $_input["id"]);

+ 5 - 1
core/submit/cms.user.php

@@ -9,7 +9,11 @@ if (core::ifPost("from") AND core::getPost("from") == "user") {
         
     } else {
         user::maj_user(core::getPost());
-        header("Location: /user-" . core::getPost("id") . ".html");
+        if(core::getPost("id") == session::getId()){
+            header("Location: /user.html");
+        } else {
+            header("Location: /user-" . core::getPost("id") . ".html");
+        }
         exit();
     }
     

+ 1 - 0
core/views/pages/cms.login.php

@@ -35,6 +35,7 @@
                     <input type="hidden" name="from" value="login">
                     <input type="text" class="fadeIn second" name="email" placeholder="email">
                     <input type="password" class="fadeIn third" name="password" placeholder="mot de passe">
+                    <input type="text" class="fadeIn third" name="authenticator" maxlength="6" placeholder="Code Google Authenticator">
                     <input type="submit" class="fadeIn fourth" value="Se connecter">
                 </form>
                 

+ 46 - 7
core/views/pages/cms.user.php

@@ -7,14 +7,16 @@ if(core::ifGet("add")) {
     
     $databaseUser = new user();
     
-    if(core::ifGet("id")){
+    if(core::ifGet("id") and session::getId() != core::ifGet("id")){
         $user = $databaseUser->getUserById(core::getGet("id"));
         $submit = "Modifier ce profil";
         $titre = "Fiche de " . $user["prenom"] . " " . $user["nom"];
+        $protect = 0;
     } else {
         $user = $databaseUser->getUserById(session::getId());
         $submit = "Modifier votre profil";
         $titre = "Votre fiche de profil";
+        $protect = 1;
     }
     
     $id_form = '<input type="hidden" name="id" value="' . $user["id"] . '">';
@@ -48,11 +50,21 @@ if(core::ifGet("add")) {
     
     <div class="form-group">
         <label>Type de compte</label>
-        <select name="id_type" class="form-select">
-            <option value="2"<?php if(isset($user["id_type"]) AND $user["id_type"] == 2){ echo " selected"; } ?>>Contrôleur QRCode (émargement)</option>
-            <option value="3"<?php if(isset($user["id_type"]) AND $user["id_type"] == 3){ echo " selected"; } ?>>Assitance sociale</option>
-            <option value="1"<?php if(isset($user["id_type"]) AND $user["id_type"] == 1){ echo " selected"; } ?>>Administrateur</option>
-        </select>
+        <?php if($protect == 0): ?>
+            <select name="id_type" class="form-select">
+                <option value="2"<?php if(isset($user["id_type"]) AND $user["id_type"] == 2){ echo " selected"; } ?>>Contrôleur QRCode (émargement)</option>
+                <option value="3"<?php if(isset($user["id_type"]) AND $user["id_type"] == 3){ echo " selected"; } ?>>Assitance sociale</option>
+                <option value="1"<?php if(isset($user["id_type"]) AND $user["id_type"] == 1){ echo " selected"; } ?>>Administrateur</option>
+            </select>
+        <?php endif; ?>
+        <?php if($protect == 1): ?>
+            <input type="text" class="form-control" value="<?php 
+                if($user["id_type"] == 1){ echo "Administrateur"; } 
+                elseif($user["id_type"] == 2){ echo "Contrôleur QRCode (émargement)"; } 
+                elseif($user["id_type"] == 3){ echo "Assitance sociale"; } 
+                ?>" readonly="readonly" />
+            <input type="hidden" name="id_type" value="<?php echo $user["id_type"] ?>">
+        <?php endif; ?>
     </div>
     <br />
 
@@ -97,7 +109,30 @@ if(core::ifGet("add")) {
         <input type="password" class="form-control" value="" name="password2" placeholder="" <?php if(core::ifGet("add")){ echo "required"; } ?>>
     </div>
     <br />
-    
+
+    <div class="form-group">
+        <label>Google Authenticator</label>
+        <select name="googleAuthenticator" class="form-select">
+            <option value="0"<?php if(isset($user["googleAuthenticator"]) AND $user["googleAuthenticator"] == 0){ echo " selected"; } ?>>Désactivée</option>
+            <option value="1"<?php if(isset($user["googleAuthenticator"]) AND $user["googleAuthenticator"] == 1){ echo " selected"; } ?>>Activée</option>
+        </select>
+    </div>
+    <br />
+
+    <?php if(isset($user["googleAuthenticator"]) AND $user["googleAuthenticator"] == 1) { ?>
+        <div class="card text-center" style="width: 18rem;">
+                <?php
+                    $qrCodeUrl = googleAuthenticator::getGoogleUrl("CSE Invent: " . ENVIRONNEMENT,  user::getMyGoogleAuthenticator(session::getId()));
+                    myQrcode::printQRCode($qrCodeUrl);
+                ?>
+            <div class="card-footer text-body-secondary">
+                QRCode à scanner dans votre application Google Authenticator
+            </div>
+        </div>  
+        <br />
+    <?php } ?>
+
+    <?php if($protect == 0): ?>
     <div class="form-group">
         <label>Etat du compte</label>
         <select name="actif" class="form-select">
@@ -106,6 +141,10 @@ if(core::ifGet("add")) {
         </select>
     </div>
     <br />
+    <?php endif; ?>
+        <?php if($protect == 1): ?>
+            <input type="hidden" name="actif" value="<?php echo $user["actif"] ?>">
+        <?php endif; ?>
     
     <input class="btn btn-primary btn-lg" style="width: 100%" type="submit" value="<?php echo $submit ?>">