From 4c1393417d1602af31b9ca3333acfba1c368fa9a Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Sun, 19 Feb 2017 12:14:03 +0100 Subject: [PATCH 1/4] Updated database to use sha512 (128 char. long) + machine creation with unlock_code/token to NULL + [TODO] machine unlock management --- autoloader.php | 21 +++ build/api/core/Checker.php | 2 +- build/api/module/authentificationDefault.php | 5 +- build/api/module/machineDefault.php | 35 ++++- build/database/repo/machine.php | 46 ++++++- build/manager/sessionManager.php | 133 ------------------- build/orm/core/Rows.php | 2 +- config/modules.json | 4 +- config/repositories.json | 4 +- public_html/index.php | 6 +- 10 files changed, 100 insertions(+), 158 deletions(-) delete mode 100755 build/manager/sessionManager.php diff --git a/autoloader.php b/autoloader.php index 21dfb38..0211473 100755 --- a/autoloader.php +++ b/autoloader.php @@ -44,6 +44,27 @@ } + /*************************/ + /* SECURE SHA1 ALGORITHM */ + /*************************/ + function secure_hash($data, $salt='">\[..|{@#))', $depth=1){ + /* (1) On hash @depth fois + ---------------------------------------------------------*/ + $hash = $data; + $c = 0; + + for( $h = 0 ; $h < $depth ; $h++ ){ + $hash = hash('sha512', $salt.hash('sha512', $hash.'_)Q@#((%*_$%(@#') ); + $c++; + } + + + /* (2) On renvoie le résultat + ---------------------------------------------------------*/ + return $hash; + } + + diff --git a/build/api/core/Checker.php b/build/api/core/Checker.php index 6ee96d9..94b152b 100644 --- a/build/api/core/Checker.php +++ b/build/api/core/Checker.php @@ -92,7 +92,7 @@ // Hash sha1/md5 case 'hash': - return $checker && is_string($value) && preg_match('/^[\da-f]+$/i', $value) && (strlen($value) == 40 || strlen($value) == 64); + return $checker && is_string($value) && preg_match('/^[\da-f]+$/i', $value) && (strlen($value) == 64 || strlen($value) == 128); break; case 'alphanumeric': diff --git a/build/api/module/authentificationDefault.php b/build/api/module/authentificationDefault.php index 5416997..01276b5 100755 --- a/build/api/module/authentificationDefault.php +++ b/build/api/module/authentificationDefault.php @@ -2,7 +2,6 @@ namespace api\module; use \database\core\DatabaseDriver; - use \manager\sessionManager; use \api\core\Authentification; use \database\core\Repo; use \manager\repo\cluster as clusterRepo; @@ -47,7 +46,7 @@ /* [2] On vérifie le mot de passe =========================================================*/ - $hash_password = sessionManager::secure_hash($password); + $hash_password = secure_hash($password, $name); // Si mot de passe faux, on retourne le status FALSE if( $nameFetched[0]['password'] != $hash_password ) @@ -101,7 +100,7 @@ /* [2] On vérifie le mot de passe =========================================================*/ - $hash_password = sessionManager::secure_hash($password); + $hash_password = secure_hash($password, $username); // Si mot de passe faux, on retourne le status FALSE if( $usernameFetched['password'] != $hash_password ) diff --git a/build/api/module/machineDefault.php b/build/api/module/machineDefault.php index ac9f301..33b0471 100755 --- a/build/api/module/machineDefault.php +++ b/build/api/module/machineDefault.php @@ -33,7 +33,7 @@ // Si une erreur est retournee, on retourne une erreur if( $id_machine === false ) - return ['error' => new Error(Err::error)]; + return ['error' => new Error(Err::ModuleError)]; @@ -324,19 +324,38 @@ /* ENVOI DES DONNEES D'INITIALISATION DU SYSTEME DES MACHINES * - * @return data Données d'initialisation du système + * @return id_machine UID de la machine + * @return token Nouveau token d'identification (hashage cyclique) + * @return unlock Code de déblocage de la machine * */ public function init($params){ extract($params); - /* [1] On récupére la liste des actions + + /* [1] On essaie de débloquer la machine + =========================================================*/ + /* (1) On rédige la requête */ + $unlockReq = new Repo('machine/unlock', [ + $_SESSION['WAREHOUSE']['id'], + $id_machine, + $unlock, + $token + ]); + + /* (2) On gère l'erreur */ + if( $unlockReq->error->get() != Err::Success || !$unlockReq->answer() ) + return [ 'error' => new Error(Err::TokenError) ]; + + + /* [2] On récupére la liste des actions =========================================================*/ $actionsReq = new Repo('action/getAll'); $actions = ($actionsReq->error->get()==Err::Success) ? $actionsReq->answer() : []; // var_dump($actionsReq->answer()); - /* [2] On regroupe les actions par TIMEOUT + + /* [3] On regroupe les actions par TIMEOUT =========================================================*/ $sorted_actions = []; @@ -354,12 +373,14 @@ ]; } - /* [3] On récupère la liste des états + + /* [4] On récupère la liste des états =========================================================*/ $globalStatesReq = new Repo('global_state/getAll'); $globalStates = ($globalStatesReq->error->get()==Err::Success) ? $globalStatesReq->answer() : []; - /* [4] On récupère la liste des MODULES (puces) + + /* [5] On récupère la liste des MODULES (puces) =========================================================*/ $chipsReq = new Repo('chip/getAll', [$_SESSION['WAREHOUSE']['id']]); $chips = ($chipsReq->error->get()==Err::Success) ? $chipsReq->answer() : []; @@ -394,7 +415,7 @@ } - /* [7] On récupère les utilisateurs + accès sur la machine + /* [6] On récupère les utilisateurs + accès sur la machine =========================================================*/ /* (1) On récupère les utilisateurs et leurs permissions */ $permissionsReq = new Repo('action_merge/getAccess', [ diff --git a/build/database/repo/machine.php b/build/database/repo/machine.php index 5a91aa2..ceb5a7f 100755 --- a/build/database/repo/machine.php +++ b/build/database/repo/machine.php @@ -2,7 +2,6 @@ namespace database\repo; use \database\core\DatabaseDriver; - use \manager\sessionManager; use \orm\core\Table; use \orm\core\Rows; use \api\core\Checker; @@ -28,7 +27,8 @@ 'id_machine' => Rows::INSERT_DEFAULT, 'id_warehouse' => $id_warehouse, 'name' => $name, - 'token' => sessionManager::secure_hash( uniqid() ) + 'token' => Rows::INSERT_DEFAULT, + 'unlock_code' => Rows::INSERT_DEFAULT ]); // Si erreur (car name doit être unique) @@ -66,7 +66,8 @@ ->whereIdWarehouse($id_warehouse) ->whereName(["%$keyword%", Rows::COND_LIKE]) ->select('id_machine') - ->select('name'); + ->select('name') + ->orderby('name', Rows::ORDER_ASC); return $search->fetch(); } @@ -89,6 +90,7 @@ =========================================================*/ $cluster = Table::get('machine_cluster') ->whereIdWarehouse($id_warehouse) + ->orderby('name', Rows::ORDER_ASC) ->select('*'); $cluster_merge = Table::get('machine_cluster_merge') ->whereIdMachine($id_machine) @@ -182,6 +184,7 @@ ->whereIdWarehouse($id_warehouse) ->select('id_machine') ->select('name') + ->orderby('id_machine', Rows::ORDER_ASC) ->unique(); return $machine->fetch(); @@ -211,7 +214,8 @@ ->whereName($name) ->whereIdWarehouse($id_warehouse) ->select('id_machine') - ->selcet('name') + ->select('name') + ->orderby('name', Rows::ORDER_ASC) ->unique(); return $machine->fetch(); @@ -242,6 +246,7 @@ ->whereIdWarehouse($id_warehouse) ->select('id_machine') ->select('name') + ->orderby('name', Rows::ORDER_ASC) ->unique(); return $machine->fetch(); @@ -268,6 +273,7 @@ $machine = Table::get('machine') ->whereIdWarehouse($id_warehouse) ->select('id_machine') + ->orderby('name', Rows::ORDER_ASC) ->select('name'); return $machine->fetch(); @@ -275,13 +281,39 @@ + /* DEBLOQUE UNE MACHINE (PREMIER TOKEN) AVEC UN CODE DE DEBLOCAGE + * + * @id_warehouse UID de l'entrepot + * @id_machine UID de la machine + * @unlock_code Code de déblocage + * @first_token Premier token de hashage cyclique + * + * @return unlocked TRUE si débloqué, sinon FALSE + * + */ + public static function unlock($id_warehouse, $id_machine, $unlock_code, $first_token){ + /* [1] On vérifie le code déblocage + =========================================================*/ + /* (1) On effectue la requête */ + $machine = Table::get('machine') + ->whereId($id_machine) + ->whereIdWarehouse($id_warehouse) + ->whereUnlockCode($unlock_code) + ->fetch(); + + var_dump($machine); + + /* (2) On vérifie si on a bien le bon code */ + if( $machine === false ) + return false; + } /* VERIFIE MET A JOUR LE TOKEN DE SYNCHRONISATION * * @id_warehouse UID de l'entrepot - * @token Token de synchronisation + * @token Token de synchronisation * @newToken Nouveau token de synchronisation (optionnel, uniquement quand on arrive à la fin du cycle de la hashChain) * * @return status VRAI si le token est correct, sinon FALSE @@ -290,12 +322,12 @@ public static function checkToken($id_warehouse, $token, $newToken=null){ /* [1] On vérifie le token =========================================================*/ - $hash = sessionManager::secure_hash($token); + $hash = secure_hash($token); $byToken = self::getByToken($id_warehouse, $hash); // Si aucun résultat, erreur - if( count($byToken) < 1 ) + if( $byToken == false ) return false; diff --git a/build/manager/sessionManager.php b/build/manager/sessionManager.php deleted file mode 100755 index 7f208d8..0000000 --- a/build/manager/sessionManager.php +++ /dev/null @@ -1,133 +0,0 @@ -\[..|{@#))'.hash('sha256', $hash.'_)Q@#((%*_$%(@#') ); - $c++; - } - - - /* [2] On renvoie le résultat - =========================================================*/ - return $hash; - } - - - /*****************************/ - /* INITIALISATION DE SESSION */ - /*****************************/ - private static function reset_session($session_id=null){ - // On ferme la session - session_destroy(); - - // On definit l'id session si donne en argument - if( $session_id != null ) - session_id( $session_id ); - - // Precaution: on met a jour le cookie - setcookie('PHPSESSID', session_id(), time()+60*30 ); - - // On redemarre la session avec le bon id session - \session_start(); - - // On met a jour le token - self::update_token(); - - - header('Refresh: 0'); - } - - /*******************/ - /* GENERE UN TOKEN */ - /*******************/ - private static function update_token(){ - $token = self::$prefix.self::secure_sha1(uniqid()); - - // On definit le token en session - $_SESSION['session_token'] = $token; - - // On definit le token en cookie - $_COOKIE['session_token'] = $_SESSION['session_token']; - setcookie('session_token', $_COOKIE['session_token'], time()+60*30 ); - } - - /************/ - /* AMORCEUR */ - /************/ - public static function session_start(){ - - \session_start(); - return; - - - - /* [1] Génération et Gestion des donnees a utiliser - ==============================================================*/ - // On genere le hash a partir des donnees personnelles - self::$prefix = self::secure_sha1( $_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'] ); - - // On cree un id session associe a ces donnees personnelles - $sessid = substr(self::$prefix,0,5) . substr(self::secure_sha1(uniqid()),0,24); - - // On genere un token pour l'execution suivante - $token = self::$prefix.self::secure_sha1(uniqid()); - - // On definit/recupere le token - $session_token = (isset($_COOKIE['session_token'])) ? $_COOKIE['session_token'] : null; - - - - /* [2] Verification de l'id session - ==============================================================*/ - \session_start(); - - // On verifie l'id session (5 premiers chars du hash des donnees perso) - $valid_sessid = strpos( session_id(), substr(self::$prefix,0,5) ) === 0; - - // Si id session incorrect ou pas de token - if( !$valid_sessid ) - self::reset_session( $sessid ); // On initialise la session (bon id session) - - - // si id session invalide - - - /* [3] Verification du token - ==============================================================*/ - // On verifie que le token est valide - $valid_token = $session_token != null; // verification de l'existence du cookie - $valid_token = $valid_token && strpos($session_token, self::$prefix) === 0; // verification des donnes personnelles - $valid_token = $valid_token && isset($_SESSION['session_token']); // verification que la variable session associee existe - $valid_token = $valid_token && $_SESSION['session_token'] == $_COOKIE['session_token']; // verification que la session est coherente - - /* [4] Si token inexistant - ==============================================================*/ - if( !$valid_token ) - self::reset_session($sessid); // On initialise la session - else - self::update_token(); // Dans tous les cas, on cree un nouveau token - - - } - - - } - - -?> diff --git a/build/orm/core/Rows.php b/build/orm/core/Rows.php index ec66941..f0de40a 100755 --- a/build/orm/core/Rows.php +++ b/build/orm/core/Rows.php @@ -169,7 +169,7 @@ /* FILTRAGE DYNAMIQUES * - * @method Nom de la méthode + * @method Nom de la méthode * @parameter Valeur du paramètre * @parameter Valeur du paramètre + type de vérification (tableau) * diff --git a/config/modules.json b/config/modules.json index cde01cd..2986900 100755 --- a/config/modules.json +++ b/config/modules.json @@ -238,7 +238,9 @@ "description": "Données d'initialisation d'une machine.", "permissions": ["warehouse"], "parameters": { - "id_machine": { "description": "UID de la machine.", "type": "id" } + "id_machine": { "description": "UID de la machine.", "type": "id" }, + "token": { "description": "Initialisation du code d'accès évolutif", "type": "hash" }, + "unlock": { "description": "Code d'initialisation", "type": "hash" } }, "output": { "data": { "description": "Données d'initialisation.", "type": "array" } diff --git a/config/repositories.json b/config/repositories.json index 57929d9..149fdf3 100755 --- a/config/repositories.json +++ b/config/repositories.json @@ -41,7 +41,9 @@ "search", - "getClusters" + "getClusters", + + "unlock" ], diff --git a/public_html/index.php b/public_html/index.php index db00ca4..83f9c48 100755 --- a/public_html/index.php +++ b/public_html/index.php @@ -9,7 +9,6 @@ use \api\core\AuthSystemDefault; - /*******************************************/ /* DEBUGGER */ /*******************************************/ @@ -18,14 +17,13 @@ /* DEBUGGER */ /*******************************************/ - - /* [1] Gestion des authentifications et des droits =========================================================*/ /* (1) On met à jour l'authentification et les permissions */ + Request::setAuthSystem(new AuthSystemDefault); + $auth = AuthSystemDefault::auth(); - Request::setAuthSystem(new AuthSystemDefault); /* (2) On définit la page d'accueil */ From 63ddeca3aaadde12df8d1ad148865cf4ac1c3a68 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Sun, 19 Feb 2017 12:33:19 +0100 Subject: [PATCH 2/4] [Done] init|sync works --- build/database/repo/machine.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/build/database/repo/machine.php b/build/database/repo/machine.php index ceb5a7f..74765a1 100755 --- a/build/database/repo/machine.php +++ b/build/database/repo/machine.php @@ -301,11 +301,25 @@ ->whereUnlockCode($unlock_code) ->fetch(); - var_dump($machine); - /* (2) On vérifie si on a bien le bon code */ if( $machine === false ) return false; + + + /* [2] Si le code est bon, on le supprime et on met le token + =========================================================*/ + /* (1) Update (edit) machine */ + $updated = Table::get('machine') + ->whereId($id_machine) + ->whereIdWarehouse($id_warehouse) + ->edit([ + 'unlock_code' => null, + 'token' => $first_token + ]); + + /* (2) Manage edition error */ + return $updated; + } @@ -322,7 +336,7 @@ public static function checkToken($id_warehouse, $token, $newToken=null){ /* [1] On vérifie le token =========================================================*/ - $hash = secure_hash($token); + $hash = secure_hash($token, ''); $byToken = self::getByToken($id_warehouse, $hash); From 6b67e414e6446da829739e39f05777b275128b36 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Sun, 19 Feb 2017 12:43:37 +0100 Subject: [PATCH 3/4] [Fixed] Logout urls --- public_html/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public_html/index.php b/public_html/index.php index 83f9c48..e3aa103 100755 --- a/public_html/index.php +++ b/public_html/index.php @@ -84,7 +84,7 @@ // logout from admin $R->get('logout/?', function(){ $_SERVER['REQUEST_METHOD'] = 'POST'; - $req = new Request('authentificationDefault/admin', ['username' => ' ', 'password' => '']); + $req = new Request('authentificationDefault/admin', ['username' => '-', 'password' => '']); $res = $req->dispatch(); header('Location: /'); }); @@ -108,7 +108,7 @@ // warehouse logout $R->get('logout/?', function(){ $_SERVER['REQUEST_METHOD'] = 'POST'; - (new Request('authentificationDefault/warehouse', ['name' => ' ', 'password' => '']))->dispatch(); + (new Request('authentificationDefault/warehouse', ['name' => '---', 'password' => '']))->dispatch(); header('Location: /'); }); From 055cc62fa79d7bcea17fbdde25c227a736427138 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Sun, 19 Feb 2017 15:46:52 +0100 Subject: [PATCH 4/4] [Fixed] machineDefault/init & machineDefault/sync ok --- build/api/module/machineDefault.php | 2 +- build/database/repo/machine.php | 14 ++++++++------ build/orm/core/Rows.php | 15 ++++++++++++--- build/orm/core/SQLBuilder.php | 15 +++++++++++++++ 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/build/api/module/machineDefault.php b/build/api/module/machineDefault.php index 33b0471..601b9b7 100755 --- a/build/api/module/machineDefault.php +++ b/build/api/module/machineDefault.php @@ -498,7 +498,7 @@ $checkToken = new Repo('machine/checkToken', [ $_SESSION['WAREHOUSE']['id'], $token, $renew ]); // Si token incorrect, on envoie une erreur - if( $checkToken->answer() !== true ) + if( !$checkToken->answer() ) return [ 'error' => new Error(Err::TokenError) ]; diff --git a/build/database/repo/machine.php b/build/database/repo/machine.php index 74765a1..c9f002c 100755 --- a/build/database/repo/machine.php +++ b/build/database/repo/machine.php @@ -27,8 +27,8 @@ 'id_machine' => Rows::INSERT_DEFAULT, 'id_warehouse' => $id_warehouse, 'name' => $name, - 'token' => Rows::INSERT_DEFAULT, - 'unlock_code' => Rows::INSERT_DEFAULT + 'token' => Rows::NULL, + 'unlock_code' => Rows::NULL ]); // Si erreur (car name doit être unique) @@ -296,13 +296,15 @@ =========================================================*/ /* (1) On effectue la requête */ $machine = Table::get('machine') + ->select('id_machine') + ->select('name') ->whereId($id_machine) ->whereIdWarehouse($id_warehouse) ->whereUnlockCode($unlock_code) ->fetch(); /* (2) On vérifie si on a bien le bon code */ - if( $machine === false ) + if( count($machine) < 1 ) return false; @@ -336,7 +338,7 @@ public static function checkToken($id_warehouse, $token, $newToken=null){ /* [1] On vérifie le token =========================================================*/ - $hash = secure_hash($token, ''); + $hash = hash('sha512', $token); $byToken = self::getByToken($id_warehouse, $hash); @@ -348,10 +350,10 @@ /* [2] On met à jour le token =========================================================*/ $updated = Table::get('machine') - ->whereId($id_machine) + ->whereId($byToken['id_machine']) ->edit([ 'token' => Checker::run('hash', $newToken) ? $newToken : $token, - 'id_machine' => $byToken[0]['id_machine'] + 'id_machine' => $byToken['id_machine'] ]); diff --git a/build/orm/core/Rows.php b/build/orm/core/Rows.php index f0de40a..75ec804 100755 --- a/build/orm/core/Rows.php +++ b/build/orm/core/Rows.php @@ -37,6 +37,7 @@ // {3} Constantes d'insertion // const INSERT_DEFAULT = '__DEFAULT__'; // Valeur DEFAULT (pour insertion) + const NULL = '__NULL__'; // Valeur DEFAULT (pour insertion) /* Attributs */ private $driver; // Database driver label @@ -266,9 +267,13 @@ /* (2) On vérifie le type de chaque valeur */ $type = $this->schema['columns'][$field]['type']; - if( $type == 'int' && !is_numeric($args[0][0]) ) return $this; - if( $type == 'float' && !is_numeric($args[0][0]) ) return $this; - if( in_array($type, ['text', 'varchar']) && !is_string($args[0][0]) ) return $this; + if( !is_null($args[0][0]) ){ + + if( $type == 'int' && !is_numeric($args[0][0]) ) return $this; + if( $type == 'float' && !is_numeric($args[0][0]) ) return $this; + if( in_array($type, ['text', 'varchar']) && !is_string($args[0][0]) ) return $this; + + } } @@ -511,6 +516,10 @@ /* (3) On vérifie les types des champs */ foreach($cleared as $field=>$value){ + // let null values + if( is_null($value) ) + continue; + $type = $this->schema['columns'][$field]['type']; // {1} Si de type INT/FLOAT et pas numérique, on retire le champ // diff --git a/build/orm/core/SQLBuilder.php b/build/orm/core/SQLBuilder.php index 99bc59f..24a907e 100755 --- a/build/orm/core/SQLBuilder.php +++ b/build/orm/core/SQLBuilder.php @@ -138,6 +138,13 @@ $sql .= substr($value[1], 2, -2).' '; /* (3) Variable */ + // {1} Si NULL // + if( is_null($value[0]) ){ + $sql .= 'NULL'; + return $sql; + } + + // {2} Si not NULL // $sql .= ':'.$field[0].'_x_'.$field[1].'_'.$offset; $bound[':'.$field[0].'_x_'.$field[1].'_'.$offset] = $value[0]; @@ -166,6 +173,14 @@ $sql[$c] = $field.' = '; /* (2) Variable */ + // {1} Si NULL // + if( is_null($value) ){ + $sql[$c] .= 'NULL'; + $c++; + continue; + } + + // {2} Si not NULL // $sql[$c] .= ':update_'.$field; $bound[':update_'.$field] = $value;