0 load the user , = 0 (or < -1 ) means an empty user * \param $repository ( \Database default null) database * to repository, if null is given the database will be defined in config.inc.php */ function __construct($p_cn, $p_id=-1,$repository=null) { $this->db=$p_cn; if ( $repository == null ) { $this->repository=new Database(0); } else { $this->repository=$repository; } // if p_id is not set then check the connected user if ($p_id==-1) { $this->connect_user(); $this->set_session_var(); } else // if p_id is set get data of another user { $this->id=$p_id; $this->load(); } } /** * @brief get the repository * @return Database */ public function get_repository():\Database { return $this->repository; } /** * @brief set the repository * @return Database */ public function set_repository(Database $repository) { $this->repository = $repository; return $this; } /** * @brief put user_login into Postgres config (session), it can be used for tracking users activities * @return void */ public function set_session_var() { $this->db->exec_sql(sprintf("select set_config('noalyss.user_login','%s',false)", Database::escape_string($_SESSION[SESSION_KEY.'g_user']))); $this->repository->exec_sql(sprintf("select set_config('noalyss.user_login','%s',false)", Database::escape_string($_SESSION[SESSION_KEY.'g_user']))); } public function __toString(): string { return "User ".print_r($this,true); } /** * @brief check the password and user */ function can_connect() { $can_connect=$this->repository->get_value("select count(*) from ac_users where use_active=1 and use_login=$1 and use_pass=$2", [$this->login,$this->password]); return $can_connect; } /** * @brief connect the user and set the $_SESSION variables if not set thanks the $_REQUEST */ private function connect_user() { if (!isset($_SESSION[SESSION_KEY.'g_user'])) { $http=new \HttpInput(); $user_login=$http->request("p_user", "string", ""); $user_password=$http->request("p_pass", "string", ""); if ($user_login!=""&&$user_password!="") { $_SESSION[SESSION_KEY."g_user"]=$user_login; $_SESSION[SESSION_KEY."g_pass"]=md5($user_password); } else { echo '

'._('Session expirée
Utilisateur déconnecté').'

'; redirect('index.php', 1); exit(); } if (strpos($user_login, '@mobile')!=false) { $this->access_mode='MOBILE'; $this->login=str_ireplace("@mobile", "", $user_login); } else { $this->access_mode='PC'; $this->login=strtolower($user_login); } $_SESSION[SESSION_KEY."access_mode"]=$this->access_mode; $_SESSION[SESSION_KEY.'g_user']=$this->login; } $this->login=$_SESSION[SESSION_KEY."g_user"]; $this->password=$_SESSION[SESSION_KEY.'g_pass']; $this->id=-1; $this->lang=(isset($_SESSION[SESSION_KEY.'g_lang']))?$_SESSION[SESSION_KEY.'g_lang']:'fr_FR.utf8'; $this->access_mode=$_SESSION[SESSION_KEY."access_mode"]; // share user login with the repository $this->repository->exec_sql(sprintf("select set_config('noalyss.user_login','%s',false)", Database::escape_string($_SESSION[SESSION_KEY.'g_user']))); if ($this->can_connect() == 0 || $this->load()==-1 ) { echo '

'._('Utilisateur ou mot de passe incorrect').'

'; $sql="insert into audit_connect (ac_user,ac_ip,ac_module,ac_url,ac_state) values ($1,$2,$3,$4,$5)"; $server_remote=$_SERVER['REMOTE_ADDR']?? "cmd-line"; $request_uri=$_SERVER['REQUEST_URI']??"REQUEST-URI"; $this->repository->exec_sql($sql, array($_SESSION[SESSION_KEY.'g_user'],$server_remote, "DISCON", $request_uri , 'FAIL')); $this->clean_session(); redirect('logout.php', 1); exit(); } $this->load_global_pref(); $_SESSION[SESSION_KEY.'g_lang']=$this->lang; $this->valid=(isset($_SESSION[SESSION_KEY.'isValid']))?1:0; if (isset($_SESSION[SESSION_KEY.'g_theme'])) { $this->theme=$_SESSION[SESSION_KEY.'g_theme']; } $_SESSION[SESSION_KEY.'use_admin']=$this->admin; $_SESSION[SESSION_KEY.'use_name']=$this->name; $_SESSION[SESSION_KEY.'use_first_name']=$this->first_name; } /** * @brief access_mode tells what mode must be used : pc or mobile */ public function get_access_mode() { return $this->access_mode; } /** * @brief access_mode tells what mode must be used : pc or mobile */ public function set_access_mode($access_mode): object { $this->access_mode=$access_mode; return $this; } /** * @return int|mixed */ public function getId(): int { return $this->id; } /** * @param int|mixed $id */ public function setId(int $id): void { $this->id=$id; } /** * @return mixed */ public function getDb() { return $this->db; } /** * @param mixed $db */ public function setDb($db): void { $this->db=$db; } /** * @return default|int|mixed|string|string[]|null */ public function getAdmin() { return $this->admin; } /** * @param default|int|mixed|string|string[]|null $admin */ public function setAdmin($admin): void { $this->admin=$admin; } /** * @return int */ public function getValid(): int { return $this->valid; } /** * @param int $valid */ public function setValid(int $valid): void { $this->valid=$valid; } /** * @return default|mixed|string|string[]|null */ public function getFirstName() { return $this->first_name; } /** * @param default|mixed|string|string[]|null $first_name */ public function setFirstName($first_name): void { $this->first_name=$first_name; } /** * @return default|mixed|string|string[]|null */ public function getName() { return $this->name; } /** * @param default|mixed|string|string[]|null $name */ public function setName($name): void { $this->name=$name; } /** * @return mixed */ public function getActive() { return $this->active; } /** * @param mixed $active */ public function setActive($active): void { $this->active=$active; } /** * @return string */ public function getLogin(): string { return $this->login; } /** * @param string $login */ public function setLogin(string $login): void { $this->login=$login; } /** * @return mixed */ public function getPassword() { return $this->password; } /** * @param mixed $password */ public function setPassword($password): void { $this->password=$password; } /** * @return mixed */ public function getEmail() { return $this->email; } /** * @param mixed $email */ public function setEmail($email): void { $this->email=$email; } /* * \brief load data from database. * if this->id == -1, it is unknown so we have to retrieve it from the database by the login * return -1 if nothing is found or the use_id */ function load():int { /* if this->id == -1, it is unknown so we have to retrieve it from the database thanks it login */ if ($this->id<0) { $sql_cond=" where lower(use_login)=lower($1)"; $sql_array=array($this->login); } else { $sql_cond=" where use_id=$1"; $sql_array=array($this->id); } /** * mono version */ if ( $this->repository->exist_table("repo_version")) { $repo_version = $this->repository->get_value("select val from repo_version"); } else { $repo_version = $this->repository->get_value("select val from version"); } /** * when upgrading , ACCOUNT_REPOSITORY is not yet upgraded */ if ( $repo_version < 21) { $sql="select use_id, use_first_name, use_name, use_login, use_active, use_admin, use_pass, use_email from ac_users "; $row=array(); $row['use_auth_method']=$row['use_otp_secret']=""; } else { $sql="select use_id, use_first_name, use_name, use_login, use_active, use_admin, use_pass, use_email, use_auth_method, use_otp_secret from ac_users "; } $Res=$this->repository->exec_sql($sql.$sql_cond, $sql_array); if (($Max=Database::num_row($Res))==0) return -1; $row=Database::fetch_array($Res, 0); $this->id=$row['use_id']; $this->first_name=$row['use_first_name']; $this->last_name=$row['use_name']; $this->name=$row['use_name']; $this->active=$row['use_active']; $this->login=strtolower($row['use_login']); $this->admin=$row['use_admin']; $this->password=$row['use_pass']; $this->email=$row['use_email']; $this->authent_method=$row['use_auth_method']; $this->otp_secret=$row['use_otp_secret']; return $this->id; } function save() { if ( $this->authent_method != 0 && $this->otp_secret == null) { $this->generate_otp(); } $Sql="update ac_users set use_first_name=$1, use_name=$2 ,use_active=$3,use_admin=$4,use_pass=$5 ,use_email = $7 , use_auth_method=$8,use_otp_secret=$9 where use_id=$6"; $Res=$this->repository->exec_sql($Sql, array($this->first_name //1 , $this->last_name // 2 , $this->active //3 , $this->admin //4 , $this->password //5 , $this->id //6 , $this->email //7 , $this->authent_method //8 , $this->otp_secret //9 )); } function insert() { $Sql="INSERT INTO ac_users( use_first_name, use_name, use_login, use_active, use_admin, use_pass, use_email) VALUES ($1, $2, $3, $4, $5, $6, $7) returning use_id"; $this->id=$this->repository->get_value($Sql, array($this->first_name, $this->last_name, $this->login, 1, $this->admin, $this->password, $this->email)); } /** * \brief Check if user is active and exists in therepository * Automatically redirect, it doesn't check if a user can access a folder * \param $silent false, echo an error message and exit, true : exit without warning * default is false * ++ */ function Check($silent=false, $from='') { $res=0; $pass5=$this->password; $sql="select ac_users.use_login,ac_users.use_active, ac_users.use_pass, use_admin,use_first_name,use_name from ac_users where ac_users.use_id=$1 and ac_users.use_active=1 and ac_users.use_pass=$2"; $ret=$this->repository->exec_sql($sql, array($this->id, $pass5)); $res=Database::num_row($ret); if ($res>0) { $r=Database::fetch_array($ret, 0); $_SESSION[SESSION_KEY.'use_admin']=$r['use_admin']; $_SESSION[SESSION_KEY.'use_name']=$r['use_name']; $_SESSION[SESSION_KEY.'use_first_name']=$r['use_first_name']; $_SESSION[SESSION_KEY.'isValid']=1; $this->admin=$_SESSION[SESSION_KEY.'use_admin']; $this->name=$_SESSION[SESSION_KEY.'use_name']; $this->first_name=$_SESSION[SESSION_KEY.'use_first_name']; $this->load_global_pref(); } $sql="insert into audit_connect (ac_user,ac_ip,ac_module,ac_url,ac_state) values ($1,$2,$3,$4,$5)"; if ($res==0 || $this->can_connect() == 0) { $this->repository->exec_sql($sql, array($_SESSION[SESSION_KEY.'g_user'], $_SERVER["REMOTE_ADDR"], $from, $_SERVER['REQUEST_URI'], 'FAIL')); if (!$silent) { echo ''; redirect('index.html'); } $this->valid=0; session_unset(); exit-1; } else { if ($from=='LOGIN' || $from=='PORTAL') { $this->repository->exec_sql($sql, array($_SESSION[SESSION_KEY.'g_user'], $_SERVER["REMOTE_ADDR"], $from, $_SERVER['REQUEST_URI'], 'SUCCESS')); } $this->valid=1; } return $ret; } /** * \brief return the access to a folder, * \param $p_dossier id if it is == 0 then we take the value from $_SESSION * \return the priv_priv * - X no access * - R has access (normal user) * */ function get_folder_access($p_dossier=0) { if ($p_dossier==0) $p_dossier=dossier::id(); if ($this->admin==1) return 'R'; $sql="select 'R' from jnt_use_dos where use_id=$1 and dos_id=$2"; $res=$this->repository->get_value($sql, array($this->id, $p_dossier)); if ($this->repository->get_affected()==0) return 'X'; return $res; } /** * \brief save the access of a folder * \param $db_id the dossier id * \param $priv boolean, true then it is granted, false it is removed */ function set_folder_access($db_id, $priv) { if ($priv) { // the access is granted $jnt=$this->repository->get_value("select jnt_id from jnt_use_dos where dos_id=$1 and use_id=$2", array($db_id, $this->id)); if ($this->repository->size()==0) { $Res=$this->repository->exec_sql("insert into jnt_use_dos(dos_id,use_id) values($1,$2)", array($db_id, $this->id)); } } else { // Access is revoked $this->repository->exec_sql('delete from jnt_use_dos where use_id = $1 and dos_id = $2 ', array($this->id, $db_id)); } } /** * \brief check that a user is valid and the access to the folder * \param $p_ledger the ledger to check * \return the priv_priv * - O only predefined operation * - W write * - R read only * - X no access * * */ function get_ledger_access($p_ledger) { if ($this->admin==1|| $this->is_local_admin(dossier::id())==1||$this->get_status_security_ledger()==0) return 'W'; $sql="select uj_priv from user_sec_jrn where uj_login=$1 and uj_jrn_id=$2"; $res=$this->db->get_value($sql, array($this->login, $p_ledger)); if ($res=='') $res='X'; return $res; } /** * \brief get all the available ledgers for the current user * \param $p_type = ALL or the type of the ledger (ACH,VEN,FIN,ODS) * \param $p_access =3 for Read or WRITE, 2 write, 1 for readonly * \param (boolean) $all if true show also inactive * \return a double array of available ledgers @verbatim [0] => [jrn_def_id] [jrn_def_type] [jrn_def_name] [jrn_def_class_deb] [jrn_def_class_cred] [jrn_type_id] [jrn_desc] [uj_priv] @endverbatim */ function get_ledger($p_type='ALL', $p_access=3, $all=TRUE) { $p_type=strtoupper($p_type); if (!in_array($p_type, ["FIN", "ALL", "ODS", "VEN", 'ACH'])) { record_log(sprintf("UGL1, p_type %s", $p_type)); throw new Exception("UGL1"._("Type incorrecte")); } if ($all==TRUE) { $sql_enable=""; } else { $sql_enable="and jrn_enable=1"; } if ($this->admin!=1&&$this->is_local_admin()!=1&&$this->get_status_security_ledger()==1) { $sql_type=($p_type=='ALL')?'':"and jrn_def_type=upper('".sql_string($p_type)."')"; switch ($p_access) { case 3: $sql_access=" and uj_priv!= 'X' "; break; case 2: $sql_access=" and uj_priv = 'W' and jrn_enable=1 "; break; case 1: $sql_access=" and ( uj_priv = 'R' or uj_priv='W') "; break; } $sql="select jrn_def_id,jrn_def_type,jrn_def_code, jrn_def_name,jrn_def_class_deb,jrn_def_class_cred,jrn_type_id,jrn_desc,uj_priv, jrn_deb_max_line,jrn_cred_max_line,jrn_def_description,jrn_enable from jrn_def join jrn_type on jrn_def_type=jrn_type_id join user_sec_jrn on uj_jrn_id=jrn_def_id where uj_login='".$this->login."'". $sql_type.$sql_access.$sql_enable. " order by jrn_Def_name"; } else { $sql_type=($p_type=='ALL')?' '.$sql_enable:"where jrn_def_type=upper('".sql_string($p_type)."') ".$sql_enable; $sql="select jrn_def_id,jrn_def_type,jrn_def_code,jrn_def_name,jrn_def_class_deb,jrn_def_class_cred,jrn_deb_max_line,jrn_cred_max_line, jrn_type_id,jrn_desc,'W' as uj_priv,jrn_def_description,jrn_enable from jrn_def join jrn_type on jrn_def_type=jrn_type_id $sql_type order by jrn_Def_name"; } $res=$this->db->exec_sql($sql); if (Database::num_row($res)==0) return null; $array=Database::fetch_all($res); return $array; } /** * \brief return an sql condition for filtering the permitted ledger * \param $p_type = ALL or the type of the ledger (ACH,VEN,FIN,ODS) * \param $p_access =3 for READ or WRITE, 2 READ and write, 1 for readonly * * \return sql condition like = jrn_def_id in (...) */ function get_ledger_sql($p_type='ALL', $p_access=3) { $aLedger=$this->get_ledger($p_type, $p_access); if (empty($aLedger)) return ' jrn_def_id < 0 '; $sql=" jrn_def_id in ("; foreach ($aLedger as $row) { $sql.=$row['jrn_def_id'].','; } $sql.='-1)'; return $sql; } /** * @brief synomym for isAdmin, * @deprecated */ function Admin():int { return $this->isAdmin(); } /** * @brief Check if an user is an admin and check also his password * * @return 1 for yes 0 for no */ function isAdmin():int { $this->admin=0; $pass5=$this->password; $sql="select count(*) from ac_users where use_login=$1 and use_active=1 and use_admin=1 and use_pass=$2 "; $this->admin=$this->repository->get_value($sql, array($this->login,$pass5)); return $this->admin; } /** * \brief Set the selected periode in the user's preferences * * \param $p_periode periode * \param - $p_user * */ function set_periode($p_periode) { $sql="update user_local_pref set parameter_value=$1 where user_id=$2 and parameter_type='PERIODE'"; $Res=$this->db->exec_sql($sql, [$p_periode, $this->id]); } private function set_default_periode() { /* get the first periode */ $sql='select min(p_id) as pid ' .' from parm_periode ' .' where p_closed = false and p_start = (select min(p_start) from parm_periode)'; $Res=$this->db->exec_sql($sql); $pid=Database::fetch_result($Res, 0, 0); /* if all the periode are closed, then we use the last closed period */ if ($pid==null) { $sql='select min(p_id) as pid ' .'from parm_periode ' .'where p_start = (select max(p_start) from parm_periode)'; $Res2=$this->db->exec_sql($sql); $pid=Database::fetch_result($Res2, 0, 0); if ($pid==null) { throw new Exception(_("Aucune période trouvéee !!!")); } $pid=Database::fetch_result($Res2, 0, 0); } $sql=sprintf("insert into user_local_pref (user_id,parameter_value,parameter_type) values ('%s','%d','PERIODE')", $this->id, $pid); $Res=$this->db->exec_sql($sql); } /** * \brief Get the default periode from the user's preferences * * \return the default periode * * */ function get_periode() { $array=$this->get_preference(); if (!isset($array['PERIODE'])) { $this->set_default_periode(); $array=$this->get_preference(); } return $array['PERIODE']; } /** * @brief Save the preference , the scope is global, the settings are saved * into account_repository * @param $key THEME, LANG , PAGESIZE * @param $value value of the key */ function save_global_preference($key, $value) { $count=$this->repository->get_value("select count(*) from user_global_pref where parameter_type=$1 and user_id=$2", array($key, $this->login)); if ($count==1) { $this->repository->exec_sql("update user_global_pref set parameter_value=$1 where parameter_type=$2 and user_id=$3", array($value, $key, $this->login)); } elseif ($count==0) { $this->repository->exec_sql("insert into user_global_pref(user_id,parameter_type,parameter_value) values($1,$2,$3)", array($this->login, $key, $value)); } } /** * \brief Get the default user's preferences * \return array of (parameter_type => parameter_value) */ function get_preference() { $sql="select parameter_type,parameter_value from user_local_pref where user_id=$1"; $Res=$this->db->exec_sql($sql, array($this->id)); $l_array=array(); for ($i=0; $irepository->get_array("select parameter_type,parameter_value from user_global_pref where upper(user_id) = upper($1)", [$this->login]); $nb_global=count($a_global_pref); for ($i=0; $i<$nb_global; $i++) { $idx=$a_global_pref[$i]['parameter_type']; $value=$a_global_pref[$i]['parameter_value']; $l_array[$idx]=$value; } return $l_array; } /** * @brief Check if an user can access a module, return 1 if yes, otherwise 0 * record in audit log * This function works only if user is connected to a Folder * @param string $p_module menu_ref.me_code * @returns 0 for FORBIDDEN, 1 for GRANTED */ function check_module($p_module) { if ( $this->access_mode == "PC") { $acc=$this->db->get_value("select count(*) from v_all_menu where p_id = $1 and me_code=$2", array($this->get_profile(), $p_module)); } elseif ($this->access_mode=="MOBILE") { $acc=$this->db->get_value("select count(*) from profile_mobile where p_id=$1 and me_code=$2", array($this->get_profile(), $p_module)); } else { throw new Exception("USER:823:ACCESS_MODE INCONNU"); } if ($acc==0) { $this->audit("FAIL", $p_module); return 0; } $this->audit("SUCCESS", $p_module); return 1; } /** * \brief Check if an user is allowed to do an action * \param p_action_id * \return * - 0 no priv * - 1 priv granted * @see constant.security.php */ function check_action($p_action_id) { /* save it into the log */ global $audit; if ($this->Admin()==1) return 1; if ($this->is_local_admin(dossier::id())==1) return 1; if ($this->get_status_security_action()==0) return 1; $Res=$this->db->exec_sql( "select * from user_sec_act where ua_login=$1 and ua_act_id=$2", array($this->login, $p_action_id)); $Count=Database::num_row($Res); if ($Count==0) { if (isset($audit)&&$audit==true) { $sql="insert into audit_connect (ac_user,ac_ip,ac_module,ac_url,ac_state) values ($1,$2,$3,$4,$5)"; $this->repository->exec_sql($sql, array($_SESSION[SESSION_KEY.'g_user'], $_SERVER["REMOTE_ADDR"], $p_action_id, $_SERVER['REQUEST_URI'], 'FAIL')); } return 0; } if ($Count==1) return 1; echo_error(_("Action invalide")); record_log("User:check_action".sprintf("login %s ua_act_id %s", $this->login, $p_action_id)); exit(); } /** * \brief Get the global preferences from user_global_pref * in the account_repository db * * \note set $SESSION[g_variable] */ function load_global_pref() { // Load everything in an array $Res=$this->repository->exec_sql("select parameter_type,parameter_value from user_global_pref where user_id=$1", [$this->login]); $Max=Database::num_row($Res); if ($Max==0) { $this->insert_default_global_pref(); $this->load_global_pref(); return; } // Load value into array $line=array(); for ($i=0; $i<$Max; $i++) { $row=Database::fetch_array($Res, $i); $type=$row['parameter_type']; $line[$type]=$row['parameter_value']; } // save array into g_ variable $array_pref=array('g_theme'=>'THEME', 'g_pagesize'=>'PAGESIZE', 'g_topmenu'=>'TOPMENU', 'g_lang'=>'LANG', 'csv_fieldsep'=>'csv_fieldsep', 'csv_decimal'=>'csv_decimal', 'csv_encoding'=>'csv_encoding', 'first_week_day'=>'first_week_day'); foreach ($array_pref as $name=> $parameter) { if (!isset($line[$parameter])) { $this->insert_default_global_pref($parameter); $this->load_global_pref(); return; } $_SESSION[SESSION_KEY.$name]=$line[$parameter]; } } /** * \brief insert default pref * if no parameter are given insert all the existing * parameter otherwise only the requested * \param $p_type parameter's type or nothing * \param $p_value parameter value * */ function insert_default_global_pref($p_type="", $p_value="") { $default_parameter=array("THEME"=>"classic", "PAGESIZE"=>"50", 'TOPMENU'=>'TEXT', 'LANG'=>'fr_FR.utf8', 'csv_fieldsep'=>'0', 'csv_decimal'=>'0', 'csv_encoding'=>'utf8', 'first_week_day'=>1 ); $sql="insert into user_global_pref(user_id,parameter_type,parameter_value) values ($1,$2,$3)"; if ($p_type=="") { foreach ($default_parameter as $name=> $value) { $this->repository->exec_sql($sql, array($this->login, $name, $value)); } } else { $value=($p_value=="")?$default_parameter[$p_type]:$p_value; if ( $this->repository->get_value("select count(*) from user_global_pref where user_id=$1 and parameter_type=$2", array($this->login,$p_type)) == 1) { $this->repository->exec_sql("update user_global_pref set parameter_value=$1 where user_id=$2 and parameter_type=$3", array($value,$this->login,$p_type)); } else { $this->repository->exec_sql($sql, array($this->login, $p_type, $value)); } } } /** * \brief update default pref * if value is not given then use the default value * * \param $p_type parameter's type * \param $p_value parameter's value value of the type */ function update_global_pref($p_type, $p_value="") { $default_parameter=array("THEME"=>"classic", "PAGESIZE"=>"50", "LANG"=>'fr_FR.utf8', 'TOPMENU'=>'SELECT', 'csv_fieldsep'=>'0', 'csv_decimal'=>'0', 'csv_encoding'=>'utf8', 'first_week_day'=>1 ); $Sql="update user_global_pref set parameter_value=$1 where parameter_type=$2 and user_id=$3"; $value=($p_value=="")?$default_parameter[$p_type]:$p_value; $this->repository->exec_sql($Sql, array($value, $p_type, $this->login)); } //end function /** * \brief Return the year of current Periode * it is the parm_periode.p_exercice col * if an error occurs return 0 */ function get_exercice() { $sql="select p_exercice from parm_periode where p_id=$1"; $Ret=$this->db->exec_sql($sql,[$this->get_periode()]); if (Database::num_row($Ret)==1) { $r=Database::fetch_array($Ret, 0); return $r['p_exercice']; } else return 0; } /** * \brief Check if the user can access * otherwise warn and exit * \param $p_action requested action * \param $p_js = 1 javascript, or 0 just a text or 2 to log it silently * \return nothing the program exits automatically */ function can_request($p_action, $p_js=0) { if ($this->check_action($p_action)==0) { $this->audit('FAIL'); if ($p_js==1) { echo create_script("alert_box(content[59])"); } elseif ($p_js==2) { record_log(_("Access invalid").$p_action); } else { echo '

', htmlspecialchars(_("Cette action ne vous est pas autorisée Contactez votre responsable")), '

'; echo ''; } exit(-1); } } /** * @brief Check if the user can print (in menu_ref p_type_display=p) * otherwise warn and exit * @param $p_action requested action * @return nothing the program exits automatically */ function check_print($p_action) { global $audit; $this->audit('AUDIT', $p_action); if ($this->Admin()==1) return 1; $res=$this->db->get_value("select count(*) from profile_menu join profile_user using (p_id) where user_name=$1 and me_code=$2 ", array($this->login, $p_action)); return $res; } /** * \brief Check if the user can print (in menu_ref p_type_display=p) * otherwise warn and exit * \param $p_action requested action * \return nothing the program exits automatically */ function can_print($p_action, $p_js=0) { if ($this->check_print($p_action)==0) { $this->audit('FAIL'); if ($p_js==1) { echo create_script("alert_box(content[59])"); } else { echo '
'; echo '

', htmlspecialchars(_("Cette action ne vous est pas autorisée Contactez votre responsable")), '

'; echo '
'; } exit(-1); } } /** * \brief Check if an user is an local administrator * @deprecated since version 6.7 * * * \param $p_dossier : dossier_id * * \return * - 0 if no * - 1 if yes * */ function is_local_admin($p_dossier=-1) { return 0; } /** * @brief return array of available repository * * @param $p_access R for read W for write * @return an array */ function get_available_repository($p_access='R') { $profile=$this->get_profile(); $r=array(); if ($p_access=='R') { $r=$this->db->get_array("select distinct u.r_id,r_name from profile_sec_repository as u join stock_repository as s on(u.r_id=s.r_id) where p_id =$1 and ur_right='W' order by 2 ", array($profile)); } if ($p_access=='W') { $r=$this->db->get_array("select distinct u.r_id,r_name from profile_sec_repository as u join stock_repository as s on(u.r_id=s.r_id) where p_id =$1 order by 2 ", array($profile)); } return $r; } /** * \brief return an array with all the active users who can access * $p_dossier including the global admin. The list concerns the user * in the repository of the "domain" defined in config.inc.php * * The user must be activated * * \param $p_dossier dossier * \return an array of user's object * array indices * - use_id (id ) * - use_login (login of the user) * - use_name * - use_first_name * \param $db_repository ( \Database default null) database * to repository, if null is given the database will be defined in config.inc.php * \exception throw an exception if nobody can access */ static function get_list($p_dossier, $db_repository = null ) { $sql="select distinct use_id,use_login,use_first_name,use_name from ac_users left outer join jnt_use_dos using (use_id) where (dos_id=$1 and use_active=1) or (use_active=1 and use_admin=1) order by use_login,use_name"; // connect to the repository if ( $db_repository == null ) { $repo_cnx=new Database(0); } else { $repo_cnx=$db_repository; } $array=$repo_cnx->get_array($sql, array($p_dossier)); if ($repo_cnx->size()==0) { throw new \Exception('noalyss_user.get_list error inaccessible folders',1186); } return $array; } /** * \brief check the access of an user on a ledger * * \param $p_jrn the ledger id * \return * - O only predefined operation * - W write * - R read only * - X no access * */ function check_jrn($p_jrn) { return $this->get_ledger_access($p_jrn); } /** * \brief check if an user can access a folder, if he cannot display a dialog box * and exit * \param the folder if * \param $silent false, echo an error message and exit, true : exit without warning * default is false * \return * - L for administrator (local and global) * - X no access * - R regular user */ function check_dossier($p_dossier_id, $silent=false) { $this->Admin(); if ($this->admin==1||$this->is_local_admin($p_dossier_id)==1) return 'L'; $dossier=$this->repository->get_value("select 'R' from jnt_use_dos where dos_id=$1 and use_id=$2", array($p_dossier_id, $this->id)); $dossier=($dossier=='')?'X':$dossier; if ($dossier=='X') { $this->audit('FAIL', "Access folder "); if (!$silent) { alert(_('Dossier non accessible')); exit(); } } return $dossier; } /** * @brief return the first date and the last date of the current exercice for the current user * @return and array ([0] => start_date,[1] => end_date) */ function get_limit_current_exercice() { $current_exercice=$this->get_exercice(); $periode=new Periode($this->db); list($per_start, $per_end)=$periode->get_limit($current_exercice); $start=$per_start->first_day(); $end=$per_end->last_day(); return array($start, $end); } /** * \brief Show all the available folder for the users * at the login page. For the special case 'E' * go directly to extension and bypasse the dashboard * \param $p_filtre user * * \return table in HTML * */ function show_dossier($p_filtre="") { $p_array=$this->get_available_folder($p_filtre); $result=""; $result.=""; $result.=""; $result.=""; $result.=""; $result.=""; $result.=""; if ($p_array==0) { $result.=""; $result.=''; $result.=""; return $result; } for ($i=0; $i"; $result.=td($id, ' class="num" '); $result.=""; $desc=($desc=="")?"Aucune description":h($desc); $desc="$desc"; $result.=""; $result.=""; } $result.="
"; $result.=_("Id"); $result.=""; $result.=_("Nom"); $result.=""; $result.=_("Description"); $result.="
'; $result.=_("Aucun dossier disponible"); $result.='
"; $result.=""; $result.=" ".h($name).""; $result.=""; $result.="".$desc; $result.="
"; return $result; } /** * \brief Get all the available folders * for the users, checked with the security * * \param $p_filter * \return array containing * - ac_dossier.dos_id * - ac_dossier.dos_name * - ac_dossier.dos_description * */ function get_available_folder($p_filter="") { $cn=$this->repository; $filter=""; if ($this->admin==0) { // show only available folders // if user is not an admin $Res=$this->repository->exec_sql("select distinct dos_id,dos_name,dos_description from ac_users natural join jnt_use_dos natural join ac_dossier where use_login= $1 and use_active = 1 and ( dos_name ilike '%' || $2 || '%' or dos_description ilike '%' || $2 || '%' ) order by dos_name", array($this->login, $p_filter)); } else { $Res=$this->repository->exec_sql("select distinct dos_id,dos_name,dos_description from ac_dossier where dos_name ilike '%' || $1|| '%' or dos_description ilike '%' || $1 || '%' order by dos_name", array($p_filter)); } $max=Database::num_row($Res); if ($max==0) return 0; for ($i=0; $i<$max; $i++) { $array[]=Database::fetch_array($Res, $i); } return $array; } /** * @brief Audit action from the administration menu. * Connect to the repository of the domain defined in config.inc.php * @param $p_module description of the action * @param $db_repository ( \Database default null) database * to repository, if null is given the database will be defined in config.inc.php */ static function audit_admin($p_module,$db_repository=null) { // connect to the repository if ( $db_repository == null ) { $repo_cnx=new Database(0); } else { $repo_cnx=$db_repository; } $sql="insert into audit_connect (ac_user,ac_ip,ac_module,ac_url,ac_state) values ($1,$2,$3,$4,$5)"; $repo_cnx->exec_sql($sql, array( $_SESSION[SESSION_KEY.'g_user'], $_SERVER["REMOTE_ADDR"], $p_module, $_SERVER['REQUEST_URI'], 'ADMIN')); } function audit($action='AUDIT', $p_module="") { global $audit; $http=new \HttpInput(); if ($audit) { if ($p_module==""&&isset($_REQUEST['ac'])) { $p_module=$_REQUEST['ac']; } $dossier=$http->request("gDossier","string",0); if ( $dossier != 0) $p_module.=" dossier : ".$dossier; $sql="insert into audit_connect (ac_user,ac_ip,ac_module,ac_url,ac_state) values ($1,$2,$3,$4,$5)"; $this->repository->exec_sql($sql, array( $_SESSION[SESSION_KEY.'g_user'], $_SERVER["REMOTE_ADDR"], $p_module, $_SERVER['REQUEST_URI'], $action)); if ( $action=="FAIL") { record_log("security alert see audit"); } } } function save_profile($p_id) { $count=$this->db->get_value("select count(*) from profile_user where user_name=$1", array($this->login)); if ($count==0) { $this->db->exec_sql("insert into profile_user(p_id,user_name) values ($1,$2)", array($p_id, $this->login)); } else { $this->db->exec_sql("update profile_user set p_id=$1 where user_name=$2", array($p_id, $this->login)); } } /** * @brief return the profile (p_id) * @return profile.p_id */ function get_profile() { $profile=$this->db->get_value("select p_id from profile_user where lower(user_name)=lower($1) ", array($this->login)); return $profile; } /** * @brief Compute the SQL string for the writable profile, * the subselect for p_id , example * p_id in $g_user->sql_writable_profile. * The administrator can access all the profiles * R = Read Only W = Write and delete O = write and not delete * @return SQL string with the subselect for p_id */ function sql_writable_profile() { if ($this->admin!=1) { $sql=" (select p_granted " ." from user_sec_action_profile " ." where ua_right in ('W','O') and p_id=".$this->get_profile().") "; } else { $sql="(select p_id p_granted from profile)"; } return $sql; } /** * @brief return array of writable action_profile * */ function get_writable_profile() { $value=$this->db->get_array("select p_granted from ".$this->sql_writable_profile()." as m") ; $aGranted=array_column($value,"p_granted"); return $aGranted; } /** * @brief return array of readable action_profile * */ function get_readable_profile() { $value=$this->db->get_array("select p_granted from ".$this->sql_readable_profile()." as m") ; $aGranted=array_column($value,"p_granted"); return $aGranted; } /** *@brief Compute the SQL string for the readable profile, * the subselect for p_id , example * p_id in $g_user->sql_readable_profile. * The administrator can read all the profiles * @return SQL string with the subselect for p_id */ function sql_readable_profile() { if ($this->admin!=1) { $sql=" (select p_granted " ." from user_sec_action_profile " ." where ua_right in ('W','R','O') and p_id=".$this->get_profile().") "; } else { $sql="(select p_id p_granted from profile)"; } return $sql; } /** * @brief Check if the current user can add an action in the profile given * in parameter * @param type $p_profile profile.p_id = action_gestion.ag_dest * @return boolean */ function can_add_action($p_profile) { $r=$this->db->get_value(' select count(*) from user_sec_action_profile where p_granted=$2 and p_id=$1', array($this->get_profile(), $p_profile)); if ($r==0) { return false; } return true; } /** * @brief Check if the profile of the user can write for this profile * @param $dtoc action_gestion.ag_id * @return true if he can write otherwise false */ function can_write_action($dtoc) { if ($this->Admin()==1) return TRUE; if ($this->get_status_security_action()==0) return TRUE; $profile=$this->get_profile(); $r=$this->db->get_value(" select count(*) from action_gestion where ag_id=$1 and ag_dest in (select p_granted from user_sec_action_profile where ua_right in ('W','O') and p_id=$2) ", array($dtoc, $profile)); if ($r==0) return FALSE; return true; } /** * @brief Check if the profile of the user can write AND delete for this profile * @param $dtoc action_gestion.ag_id * @return true if he can write otherwise false */ function can_delete_action($dtoc) { if ($this->Admin()==1) return TRUE; if ($this->get_status_security_action()==0) return TRUE; $profile=$this->get_profile(); $r=$this->db->get_value(" select count(*) from action_gestion where ag_id=$1 and ag_dest in (select p_granted from user_sec_action_profile where ua_right='W' and p_id=$2) ", array($dtoc, $profile)); if ($r==0) return FALSE; return true; } /** * @brief Check if the profile of the user can write for this profile * @param $dtoc action_gestion.ag_id * @return true if he can write otherwise false */ function can_read_action($dtoc) { if ($this->Admin()==1) return true; $profile=$this->get_profile(); $r=$this->db->get_value(" select count(*) from action_gestion where ag_id=$1 and (ag_dest in (select p_granted from user_sec_action_profile where p_id=$2) or ag_owner=$3)", array($dtoc, $profile, $this->login)); if ($r==0) return false; return true; } /** * @brief Check if the profile of the user can write for this repository * @param $p_repo stock_repository.r_id * @return true if he can write otherwise false */ function can_write_repo($p_repo) { if ($this->Admin()==1) return true; $profile=$this->get_profile(); $r=$this->db->get_value("select count(*) from profile_sec_repository where r_id=$1 and p_id =$2 and ur_right='W'", array($p_repo, $profile)); if ($r==0) return false; return true; } /** * @brief Check if the profile of the user can read for this repository * @param $p_repo stock_repository.r_id * @return true if he read write otherwise false */ function can_read_repo($p_repo) { if ($this->Admin()==1) return true; $profile=$this->get_profile(); $r=$this->db->get_value("select count(*) from profile_sec_repository where r_id=$1 and p_id =$2 ", array($p_repo, $profile)); if ($r==0) return false; return true; } /** * @brief store the password in session */ function password_to_session() { $_SESSION[SESSION_KEY.'g_pass']=$this->getPassword(); } /** * @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 && count(check_password_strength($p_pass1)['msg'])==0) { $l_pass=md5($p_pass1); $this->setPassword($l_pass); $this->repository->exec_sql("update ac_users set use_pass=$1 where use_login=$2", array($l_pass, $this->login)); return true; } else { return false; } } /** * @brief Save the password from PREFERENCE MODULE * @param type $p_email */ function save_email($p_email) { $this->repository->exec_sql("update ac_users set use_email=$1 where use_login=$2", array($p_email, $_SESSION[SESSION_KEY.'g_user'])); } /** *@brief Remove a user and all his privileges * So it cannot connect anymore and all his privileges are removed from * the dossier. * @param $p_login (String) login * @param $p_dossier (int) dossier id * @param $db_repository ( \Database default null) database * to repository, if null is given the database will be defined in config.inc.php * */ static function revoke_access($p_login, $p_dossier,$db_repository=null) { // connect to the repository if ( $db_repository == null ) { $repo_cnx=new Database(0); } else { $repo_cnx=$db_repository; } // Retrieve the user $user=$repo_cnx->get_array('select use_id,use_login from ac_users where use_login=$1', array($p_login)); if (!$user) return false; // remove him from jnt_use_dos $repo_cnx->exec_sql("delete from jnt_use_dos WHERE use_id=$1 and dos_id=$2", array($user[0]['use_id'], $p_dossier)); // Remove user from user's dossier $cn_dossier=new Database($p_dossier); $cn_dossier->exec_sql("delete from profile_user where user_name=$1", array($p_login)); $cn_dossier->exec_sql("delete from user_sec_act where ua_login=$1", array($p_login)); } /** * @brief Grant access to folder, grant administrator profile , all the ledgers and all the action * @param $p_login (String) login * @param $p_dossier (int) dossier id * @param $db_repository ( \Database default null) database * to repository, if null is given the database will be defined in config.inc.php */ static function grant_admin_access($p_login, $p_dossier,$db_repository=null) { // connect to the repository if ( $db_repository == null ) { $repo_cnx=new Database(0); } else { $repo_cnx=$db_repository; } $user=$repo_cnx->get_array("select use_id,use_login from ac_users where use_login=$1", array($p_login)); if (!$user) return false; $cn_dossier=new Database($p_dossier); // if not access to DB if ( $repo_cnx->get_value("select count(*) from jnt_use_dos where use_id=$1 and dos_id=$2", array($user[0]['use_id'], $p_dossier))==0 ) { $repo_cnx->exec_sql("insert into jnt_use_dos(use_id,dos_id) values ($1,$2)", array($user[0]['use_id'], $p_dossier)); } //------ Give him the admin menu if ($cn_dossier->get_value("select count(*) from profile_user where user_name=$1", array($user[0]['use_login']))==0) { $cn_dossier->exec_sql('insert into profile_user(user_name,p_id) values($1,1)', array($user[0]['use_login'])); } // Grant all action + ledger to him $cn_dossier->exec_sql("delete from user_sec_act where ua_login=$1", array($p_login)); $cn_dossier->exec_sql("insert into user_sec_act (ua_login,ua_act_id)" ." select $1 ,ac_id from action ", array($p_login)); $cn_dossier->exec_sql("delete from user_sec_jrn where uj_login=$1", array($p_login)); $cn_dossier->exec_sql("insert into user_sec_jrn(uj_login,uj_jrn_id,uj_priv)" ." select $1,jrn_def_id,'W' from jrn_def", array($p_login)); } /** * @brief cleansing : remove inexistant user * @param $p_dossier (int) dossier id * @param $db_repository ( \Database default null) database * to repository, if null is given the database will be defined in config.inc.php * @return bool : true if success , false if no change */ static function remove_inexistant_user($p_dossier,$db_repository=null) { // connect to the repository if ( $db_repository == null ) { $cnx_repo=new Database(0); } else { $cnx_repo=$db_repository; } $name=$cnx_repo->format_name($p_dossier, 'dos'); if ($cnx_repo->exist_database($name)==0) return false; $cnx_dossier=new Database($p_dossier); if ($cnx_dossier->exist_table('profile_user')) $a_user=$cnx_dossier->get_array('select user_name from profile_user'); else return false; if (!$a_user) return; $nb=count($a_user); for ($i=0; $i<$nb; $i++) { if ($cnx_repo->get_value('select count(*) from ac_users where use_login=$1', array($a_user[$i]['user_name']))==0) { if ($cnx_dossier->exist_table('user_sec_jrn')) $cnx_dossier->exec_sql("delete from user_sec_jrn where uj_login=$1", array($a_user[$i]['user_name'])); $cnx_dossier->exec_sql("delete from profile_user where user_name=$1", array($a_user[$i]['user_name'])); if ($cnx_dossier->exist_table('user_sec_act')) $cnx_dossier->exec_sql("delete from user_sec_act where ua_login=$1", array($a_user[$i]['user_name'])); if ($cnx_dossier->exist_table('user_sec_jrn')) $cnx_dossier->exec_sql("delete from user_sec_jrn where uj_login=$1", array($a_user[$i]['user_name'])); if ($cnx_dossier->exist_table('user_active_security')) $cnx_dossier->exec_sql("delete from user_active_security where us_login=$1", array($a_user[$i]['user_name'])); } } return true; } /** * @brief Check the security on ledger for the user , it returns 1 if the security * on ledgers is enabled, otherwise 0 */ function get_status_security_ledger() { $security=$this->db->get_value("select us_ledger from user_active_security where us_login=$1", [$this->login]); $n_security=($security=="Y")?1:0; return $n_security; } /** * @brief Set the flag in the table user_active_security * @param int $p_value 1==enable , 0 = disable * @exceptions invalid value */ function set_status_security_ledger($p_value) { if ($p_value!=0&&$p_value!=1) throw new Exception(_("Valeur invalide")); $exist=$this->db->get_value("select count(*) from user_active_security where us_login=$1", [$this->login]); $flag=($p_value==1)?"Y":"N"; if ($exist==0) { $this->db->exec_sql("insert into user_active_security (us_login,us_ledger,us_action) values ($1,$2,$3)", [$this->login, $flag, 'Y']); } else { $this->db->exec_sql("update user_active_security set us_ledger=$1 where us_login = $2", [$flag, $this->login]); } } /** * Check the security on ledger for the user , it returns 1 if the security * on ledgers is enabled, otherwise 0 */ function get_status_security_action() { $security=$this->db->get_value("select us_action from user_active_security where us_login=$1", [$this->login]); $n_security=($security=="Y")?1:0; return $n_security; } /** * Set the flag in the table user_active_security * @param int $p_value 1==enable , 0 = disable * @exceptions invalid value */ function set_status_security_action($p_value) { if ($p_value!=0&&$p_value!=1) throw new Exception(_("Valeur invalide")); $exist=$this->db->get_value("select count(*) from user_active_security where us_login=$1", [$this->login]); $flag=($p_value==1)?"Y":"N"; if ($exist==0) { $this->db->exec_sql("insert into user_active_security (us_login,us_action,us_ledger) values ($1,$2,$3)", [$this->login, $flag, 'Y']); } else { $this->db->exec_sql("update user_active_security set us_action=$1 where us_login = $2", [$flag, $this->login]); } } /** *@brief first day in calendar * @see IDate::set_firstDate( */ function get_first_week_day() { $result=$this->repository->get_value("select parameter_value from user_global_pref where parameter_type=$1 and user_id=$2 ", array("first_week_day", $this->login)); if ($this->repository->count()==0) { $this->save_global_preference("first_week_day", 1); return 1; } return $result; } /** * @brief clean the sessions */ static function clean_session() { $aSession=$_SESSION; foreach($aSession as $key => $value) { if(DEBUGNOALYSS>1) { echo "[$key]=>[$value]";} if ( strpos($key,SESSION_KEY) === 0) { unset($_SESSION[$key]); if(DEBUGNOALYSS>1) { echo "=> [$key] cleaned";} } } } /** *@brief Get preference , either the user see the numeric id for VAT or its code, if the preference doesn't exist * by default , 0 is saved in ACCOUNT_REPOSITORY * @see ITva_Popup::set_vat_code() * @see ITva_Popup * */ function get_vat_code_preference():int { $result=$this->repository->get_value("select parameter_value from user_global_pref where parameter_type=$1 and user_id=$2 ", array("vat_code", $this->login)); if ($this->repository->count()==0) { $this->save_global_preference("vat_code", 0); return 0; } return $result; } /** * @brief generate OTP secret to store in AC_USER.USE_OTP_SECRET */ function generate_otp() { $otp=new \Noalyss\OTP(); $this->otp_secret=$otp->build_secret(); } /** * @brief retrieve authent_method * - 0 password * - 1 password + code by email * - 2 password + OTP from application */ public function get_authent_method() { return $this->authent_method; } public function get_otp_secret() { return $this->otp_secret; } public function set_authent_method($authent_method) { $this->authent_method = $authent_method; return $this; } public function set_otp_secret($otp_secret) { $this->otp_secret = $otp_secret; return $this; } public function set_identified() { $_SESSION[SESSION_KEY."db_auth"]='ok'; } /** * @brief check is the double authentication has been successful * @return bool */ public function is_double_identified() { if ( $this->authent_method == 0 ) { $_SESSION[SESSION_KEY."db_auth"]='ok'; return true; } if ( ! isset($_SESSION[SESSION_KEY."db_auth"])) { return false; } if ($_SESSION[SESSION_KEY."db_auth"] == "ok") { return true; } return false; } /** * @brief send a code to the user and save the expected code + UUID in * a table OTP_SEND_SECRET * @return bool false if fails true if succeeds * @throws \Exception */ public function send_code_otp() { if ( $this->authent_method !=1 ) { return false; } $mail=new \Sendmail(); $mail->set_format("HTML"); $mail->set_from(ADMIN_WEB); $mail->mailto($this->getEmail()); $mail->set_subject(_("NOALYSS : votre code secret ")); $noalyss_url=NOALYSS_URL; if ( strlen(trim($this->otp_secret??"")) == 0 ) { throw new \Exception("noalyss_user.send_code_otp:secret empty",1945); } $otp=new \Noalyss\OTP(); $code=$otp->compute_code($this->otp_secret); $message="

Bonjour,

Voici votre code secret utilisable pendant 10 minutes pour NOALYSS : $code .

Merci d'utiliser NOALYSS


Cordialement,

Noalyss team

Si cet email est dans vos spams, ajoutez l'expéditeur dans votre carnet d'adresse

"; try { $uuid= guidv4(); // remove old for this user $this->repository->exec_sql("delete from otp_send_secret where use_id=$1 and os_code is not null" ,[$this->id]); // remove also old one $this->repository->exec_sql("delete from otp_send_secret where os_valid_time < now()"); $now=new \DateTime(); $valid=new \DateTime(); $valid->modify('+10 minutes'); $otp_send_secret=new Otp_Send_Secret_SQL($this->repository); $otp_send_secret->set("use_id",$this->id) ->set('os_request',$uuid) ->set("os_code",$code) ->set('os_valid_time',$valid->format('d.m.Y H:i:s')); $otp_send_secret->save(); $mail->set_message($message); $mail->compose(); $mail->send(); return $uuid; } catch (Exception $ex) { \record_log ($ex); throw new \Exception("noalyss_user.send_code_otp",1963,$ex); } } /** * @brief send an email with link to the user * @param $base_url (string) http url to scan the QRCode, the url in the * mail will be {$base_url}/index.php?otp={$uuid} */ function send_link_otp($base_url=null) { $mail = new \Sendmail(); $mail->set_format("HTML"); $mail->set_from(ADMIN_WEB); $mail->mailto($this->getEmail()); $mail->set_subject(_("NOALYSS : Double authentification lien pour 2FA: OTP")); $noalyss_url = $base_url??NOALYSS_URL; $uuid = guidv4(); $valid_time=new \DateTime(); $valid_time->add(new \DateInterval('PT12H')); $str_time=$valid_time->format('d-m-Y H:i'); /** * save in DB first */ $message = "

Bonjour,

Afin de pouvoir utiliser la double authentification avec 2FA: OTP, pourriez-vous suivre ce lien et scanner le QRCode avec votre application android freeOTP ou Google Authenticator.

Ce lien expirera le {$str_time}.


{$noalyss_url}/index.php?otp={$uuid}

Merci d'utiliser NOALYSS

Bien cordialement,

Si cet email est dans vos spams, ajoutez l'expéditeur dans votre carnet d'adresse

"; try { // remove old for this user $this->repository->exec_sql("delete from otp_send_secret where use_id=$1 and os_code is null" ,[$this->id]); // remove also old one $this->repository->exec_sql("delete from otp_send_secret where os_valid_time < now()"); $otp_send_secret_sql = new \Otp_Send_Secret_SQL($this->repository); $otp_send_secret_sql->set('use_id', $this->id) ->set('os_valid_time',$valid_time->format('d-m-Y H:i')) ->set('os_request', $uuid); $otp_send_secret_sql->save(); $mail->set_message($message); $mail->compose(); $mail->send(); return $uuid; } catch (Exception $ex) { \record_log($ex); throw new \Exception("noalyss_user.send_link_otp",1998,$ex); } } /** * @brief FORM to enter the 6 digit enter by OTP * @param $uuid (string UUID) UUID in the message, null if there is no message */ function input_otp($uuid="",$url="") { require_once NOALYSS_TEMPLATE."/noalyss_user-input_otp.php" ; } /** * @brief check that the OTP code is the one on smartphone * returns false if the given does not match the OTP */ function check_otp($code) { $otp=new \Noalyss\OTP(); if ( $otp->compute_code($this->otp_secret) == $code ) { return true; } return false; } } ?>