* @since Version 2.0 */ class sysUsersManagerController extends cCore { public $sDir; public $sName; public $oModule; private $oModSession; // Module variable session public $bIsUserProfile = false; static $CMS_FORM_THEMES = array( 'default' => array( 't' => 'CMS Default', 'default' => 1, 'f' => '/css/cms/themes/default.css' ), 'default-light' => array( 't' => 'CMS Default light', 'default' => 0, 'f' => '/css/cms/themes/default-light.css' ), /*'vikrem' => array( 't' => 'Vikrem custom', 'default' => 0, 'f' => '/css/cms/themes/vikrem.css' ),*/ ); /** * Class constructor * * @author Mareks Keišs * @category sysUsers Manager Controller * @param bool|array $vUriData - uri data array * @param bool|string $sDir - Module file path * @param bool|string $sName - Module name * @param bool $bLoadData - load user permission data */ public function __construct($vUriData = false, $sDir = false, $sName = false, $bLoadData = false) { if($vUriData){ $this->sDir = $sDir; $this->sName = $sName; parent :: __construct($vUriData); $this->oView->setTemplateDir($this->sDir . "/tmpl/"); if(!$this->oView->cacheUsed()){ $this->oView->setJs(getCurrentFolder($this->sDir) . '/js/' . $this->sName . '.js'); $this->oView->setCss(getCurrentFolder($this->sDir) . '/css/' . $this->sName . '.css'); } // Set JS module init title $this->oView->setAsJSON(cCore::JS_MOD, ucfirst($sName)); } $this->oModule = new sysUsersManagerModule(); $this->oModSession = new cSession('sysUsers'); } /** * SYSTEM USERS MODULE - Function to show main form in the module * * @category sysUsers Manager Controller * @author Mareks Keišs * @returns bool true */ public function run($initEditMode = false){ $this->oView->TABLE = true; $this->oView->setAsJSON('initEdit', $initEditMode); $this->oView->setAsJSON('baseUrl', $this->gL()); $this->oView->setAsJSON('gM', $this->getTranslations()); $this->oView->setAsJSON('vcfg', $this->getUserValCfg()); // Custom form 4 2fa $this->oView->CMS_CUSTOM_TPL_DATA = $this->oView->genTemplate('twoFA/create2fa'); $this->oView->display(); } /** * Function to create cms table & return for direct & ajax input * * @author Mareks Keišs * @category sysUsers Manager Controller * @param int $page - page to display * @param string $filter_json - (optional) filter json string * @param bool $headers - flag whether to send header data or not * @return array of data * @version 1.1 */ public function createCmsTable($page = 1, $filter_json = '', $headers = false) { $pages = 0; $filter = array(); if($filter_json){ $filter = cJSON::decode($filter_json, true); } $this->oView->MODULE_TITLE = $this->gM("User Management"); if(!!$filter && is_array($filter)) $this->oView->DEFAULT_SEARCH_VALUES = prepForDisplayHtml($filter); $this->oView->LIST_HEADER = reOrderTableFields($this->getTableFields(), $this->oUser->oCfg->getTableProperty($this->sName)); $this->oView->LIST_DATA = $this->getModuleData($page, $filter, $pages); $this->oView->LIST_ACTIONS = $this->getTableActions(); $data = array( 'data' => $this->oView->genHelperView('cmsc/table/data-table'), 'pcount' => $pages, 'rlimit' => $this->cmsTableRecordsPerPage ); // Send data to client if($headers) $data['header'] = $this->oView->genHelperView('cmsc/table/data-table-search'); return $data; } /** * Function to get module data * * @author Mareks Keišs * @category sysUsers Manager Controller * @param int $page * @param array $filter * @param int $pages * @return array of data * @version 1.1 */ public function getModuleData($page = 1, $filter = array(), &$pages) { $where = "AND 1"; $sort = "id ASC"; $offset = (($page?$page:1)-1) * $this->cmsTableRecordsPerPage; $tFields = $this->getTableFields(); // Create sort by if(getP('sortBy')) $sort = $this->oModule->oDb->genOrderByQuery(getP('sortBy'), getP('sortWay'), $tFields); // Create where clause if(count($filter)) $where = $this->oModule->oDb->genSearchFieldQuery($filter, $tFields); $subWhere = ""; /* if(isset($filter['user_search'])){ $filter['user_search'] = $this->oModule->db->prepData($filter['user_search']); $subWhere = " AND ( su.user_name like '%{$filter['user_search']}%' OR su.user_surname like '%{$filter['user_search']}%' OR su.user_login like '%{$filter['user_search']}%' OR su.user_last_ip like '%{$filter['user_search']}%' )"; unset($filter['user_search']); }*/ $data = $this->oModule->getModuleRecords($where . $subWhere, $sort, $offset, $this->cmsTableRecordsPerPage); if(!!$data){ foreach($data as &$v){ if($v['user_last_login']){ // Activity indicators $bIndicator = ($v['user_last_login'] > strtotime("-1 month") ? '' : ''); if(date('d-m-Y', $v['user_last_login']) == date('d-m-Y')){ $v['sclass'] = 'bggreen'; $v['user_last_login'] = date('H:i', $v['user_last_login']) . $bIndicator; }else{ $v['user_last_login'] = date('d/m/Y', $v['user_last_login']) . $bIndicator; } }else{ $v['user_last_login'] = '-'; } if($v['user_last_location_url']) $v['user_last_location_url'] = substr($v['user_last_location_url'], strpos($v['user_last_location_url'],'/',2)); $v['tfa'] = ($v['tfa'] ? '✓' : ''); } unset($v); } $this->oView->ROWS = $rows = $this->oModule->oDb->getSelectedRecordsCount(); $pages = floor($rows / $this->cmsTableRecordsPerPage) + ($rows%$this->cmsTableRecordsPerPage?1:0); return $data; } /** * Function to disable / enable enum records marked in table * * @author Mareks Keišs * @category sysUsers Manager Controller * @param array $baseField - base field to handle * @param string $rows - passed user ids in JSON string * @return array of data */ public function changeEnumFields($baseField, $rows) { if($baseField && $rows = cJSON::decode($rows, true)){ $baseField = substr($baseField, 2); $fields = $this->getTableFields(); if(isset($fields[$baseField]['db_field'])){ if($this->oModule->changeRecordsStatus($this->oModule->oDb->prepData($rows), $fields[$baseField]['db_field'])){ return true; } } } cJSON::sendError(); return false; } /** * Function to delete records marked in table * * @author Mareks Keišs * @category sysUsers Manager Controller * @param string $rows - passed user ids in JSON string * @return array of data */ public function delete($rows) { if($rows = cJSON::decode($rows, true)){ if($this->oModule->deleteRecords($this->oModule->oDb->prepData($rows))){ return true; }else{ cJSON::sendError(); } } return false; } /** * Function to create table headers + search * * @author Mareks Keišs * @category sysUsers Manager Controller * @return array of data * @version 1.1 */ public function getTableFields() { if(!$this->oUser->chkPermission('SYS_USER_SHOW_MANAGEMENT', false, false)){ return false; } $statusData = array( '' => array( 'title' => $this->gM("Select") ), 0 => array( 'title' => $this->gM("Active") ), 1 => array( 'title' => $this->gM("Inactive") ), ); $tFields = array( "checkbox" => array( 'sort' => false, 'title' => '', 'class' => 'w4 center rchk' ), "id" => array( 'sort' => true, 'search' => true, 'title' => $this->gM("ID"), 'class' => 'w8 center sort', 'db_field' => 'su.id', 'type' => 'input', ), "user_name" => array( 'sort' => true, 'search' => true, 'title' => $this->gM("User name"), 'class' => 'w14', 'db_field' => 'su.user_name', 'type' => 'input', ), "user_surname" => array( 'sort' => true, 'search' => true, 'title' => $this->gM("User surname"), 'class' => 'w14', 'db_field' => 'su.user_surname', 'type' => 'input', ), "user_login" => array( 'sort' => true, 'search' => true, 'title' => $this->gM("User login"), 'class' => 'w14', 'db_field' => 'su.user_login', 'type' => 'input', ), "user_last_login" => array( 'sort' => true, 'search' => false, 'title' => $this->gM("Last login"), 'class' => 'w12 center', 'db_field' => 'su.user_last_login', 'type' => 'input', ), "user_email" => array( 'sort' => true, 'search' => true, 'title' => $this->gM("User email"), 'class' => 'w26', 'db_field' => 'su.user_email', 'type' => 'input', ), "tfa" => array( 'sort' => true, 'search' => false, 'title' => $this->gM("2FA"), 'class' => 'w8 center', 'db_field' => 'mu.tfa', 'type' => 'input', ), "user_last_ip" => array( 'sort' => false, 'search' => true, 'title' => $this->gM("User IP"), 'class' => 'w14', 'db_field' => 'su.user_last_ip', 'type' => 'input', ), "user_last_location_url" => array( 'sort' => true, 'search' => true, 'title' => $this->gM("Users last location"), 'class' => 'w18', 'db_field' => 'su.user_last_location_url', 'type' => 'input', ), "status" => array( 'sort' => false, 'search' => false, 'title' => $this->gM("Inactive"), 'class' => 'w9 center', 'field' => 'user_blocked', 'db_field' => 'su.user_blocked', 'type' => 'dropBox', 'data' => $statusData, 'default' => '', //'checkbox' => true, ), "buttons" => array( 'sort' => false, 'class' => 'w20', 'title' => $this->gM("Actions"), 'btnset' => array( 'ledit' => array( 'edit' => true, 'title' => $this->gM("Edit"), ), 'ldelete' => array( 'title' => $this->gM("Delete"), ) ) ) ); if(!$this->chkP('SYS_SHOW_TABLE_IDS')) unset($tFields['id']); return $tFields; } /** * Function to get js translations for view * * @author Mareks Keišs * @category sysUsers Manager Controller * @return array of data */ public function getTranslations(){ return cValidator::getJSTranslations( $this, $this->getUserValCfg(), array( 'no' => $this->gM('No'), 'yes' => $this->gM('Yes'), 'delTitle' => $this->gM('Delete system user?'), 'delMessage' => $this->gM('Selected users will be permanently deleted and cannot be recovered. Confirm delete?'), 'buttonYes' => $this->gM('Delete selected users'), 'buttonCancel' => $this->gM('Cancel operation'), 'sCreateQRTitle' => $this->gM('Create QR code'), 'sGenQR' => $this->gM('Create code'), ) ); } /** * Function to get table actions * * @author Mareks Keišs * @category sysUsers Manager Controller * @return array of data */ public function getTableActions(){ $actions = array( 'inew' => array( 'lbl' => $this->gM("Add new"), 'icon' => 'nico-add' ), 'iclone' => array( 'lbl' => $this->gM("Clone user"), 'icon' => 'nico-add' ), 'istatus' => array( 'lbl' => $this->gM("Change item status"), ), 'sepline', 'idelete' => array( 'lbl' => $this->gM("Delete selected"), 'icon' => 'nico-delete' ), 'sepline', 'iCreateQRCode' => array( 'lbl' => $this->gM("Create QR code"), 'icon' => '' ), ); // Reformat drop down reformatDropDown($actions, false); return $actions; } /** * Function to set my personal profile form layout * * @author Mareks Keišs * @category sysUsers Manager Controller * @param bool $selfedit - indicates selfedit profile * @return array of data */ public function setMyProfileForm($selfedit = false){ $this->oView->setAsJSON('profile', true); $this->oView->setAsJSON('selfedit', $selfedit); $this->oView->setAsJSON('vcfg', $this->getUserValCfg()); $this->oView->setAsJSON('gL', $this->getTranslations()); $this->oView->display(); } /** * Function to get user data * * @author Mareks Keišs * @category sysUsers Manager Controller * @param bool|int $iUserId - user id * @return array of data */ public function loadUserDataById($iUserId = false){ // Base user data $user = array(); // Set value classes $this->oView->PROP_CLASSES = array( 'iRecordsPerPage' => 'short' ); // Set user profile id - current id if($this->bIsUserProfile) $iUserId = $this->oUser->iUserId; // Load user configuration data $oCfg = new sysUsersCfg($iUserId); $config = $oCfg->getBaseCFG(sysUsersCfg::bools); $config_inp = $oCfg->getBaseCFG(sysUsersCfg::values); if($iUserId && !getV('clone')){ $user = $this->oModule->getUserDataById($iUserId); $vConfig = $oCfg->getUserCFG(); $config = $vConfig[sysUsersCfg::bools]; $config_inp = $vConfig[sysUsersCfg::values]; if(date('d-m-Y', $user['user_created']) == date('d-m-Y')){ $user['user_created'] = date('H:i', $user['user_created']); }else{ $user['user_created'] = date($this->CMSDateFormat, $user['user_created']); } if(date('d-m-Y', $user['user_modified']) == date('d-m-Y')){ $user['user_modified'] = date('H:i', $user['user_modified']); }else{ $user['user_modified'] = date($this->CMSDateFormat, $user['user_modified']); } if($user['user_last_login']){ if(date('d-m-Y', $user['user_last_login']) == date('d-m-Y')){ $user['user_last_login'] = date('H:i', $user['user_last_login']); }else{ $user['user_last_login'] = date($this->CMSDateFormat, $user['user_last_login']); } } } $this->oView->CFG = $config; $this->oView->CFG_INP = $config_inp; $this->oView->USER = $user; $this->oView->LANG = $this->oMessages->getAllCMSLanguages(); $this->oView->TPASSWD = $this->oModSession->TPASSWD = cNumbers::getRandomChString(16, true); $data = array( 'groups' => array(), 'permissions' => array(), ); // Load user permissions if($gr = $this->oModule->getUserPermissionsByUserId($iUserId)){ foreach($gr as $v){ if(!isset($data['permissions'][$v['type_name']])){ $data['permissions'][$v['type_name']] = array(); } $v['p_name'] = ucfirst(strtolower(str_replace('_', ' ', $v['p_name']))); $data['permissions'][$v['type_name']][] = $v; } } // Load user groups if($gr = $this->oModule->getUserPermissionGroupsByUserId($iUserId)){ if(count($gr)){ foreach($gr as $v){ $v['group_name'] = ucfirst(strtolower(str_replace('_', ' ', $v['group_name']))); $data['groups'][] = $v; } } } $this->oView->P = $data; return array( 'show' => array('buttons_top' => false, 'buttons_bottom' => true), 'btn' => $this->getFormButtons(), 'html' => $this->oView->genTemplate(($this->bIsUserProfile ? 'myProfile' : 'userProfile')), ); } /** * Function to get form buttons * * @author Mareks Keišs * @category sysUsers Manager Controller * @return array of data */ public function getFormButtons(){ return array( 1 => array( 'id' => 'fsave', 'lbl' => $this->gM('Save') ), 2 => array( 'id' => 'fcancel', 'lbl' => $this->gM('Cancel') ) ); } /** * Function to get js validator cfg for user edit for / profile * * @author Mareks Keišs * @category sysUsers Manager Controller * @param bool $bPrepDataCfg - reconfigure cfg data array * @return array of data */ public function getUserValCfg($bPrepDataCfg = true){ $valCfg = array( // Additional validation config 'cfg' => array( //cValidator::CFG_CONTAINERS => array('pbase'), cValidator::CFG_BIND_FIELD => 'data-validator', //cValidator::CFG_CHK_FIELDS_SET => true, // Check all fields in config are present - or pass an array with groups to check ), 'user_name' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), cValidator::P_MBSET => 1, ), 'user_surname' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), cValidator::P_MBSET => 1, ), 'user_login' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), ), 'user_email' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_EMAIL), cValidator::P_MBSET => 1, ), 'user_lang' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), cValidator::P_MBSET => 1, ), 'user_oldpass' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), ), 'user_newpass' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_LEN => $this->gM('Min password length is 6 symbols!'), cValidator::CHK_EQUAL => $this->gM('Passwords must match!')), cValidator::P_LINK => 'user_newpassre', cValidator::P_ADDS => array('min' => 6) ), 'user_newpassre' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_LEN => $this->gM('Min password length is 6 symbols!'), cValidator::CHK_EQUAL => $this->gM('Passwords must match!')), cValidator::P_LINK => 'user_newpass', cValidator::P_ADDS => array('min' => 6) ), ); return ($bPrepDataCfg ? cValidator::prepValCfgForValidation($valCfg) : $valCfg); } /** * Function to save user data * * @author Mareks Keišs * @category sysUsers Manager Controller * @param int $userId - user id * @param string $fields - param JSON string * @return array of data */ public function saveUserDataById($userId, $fields){ $vUserPermissionsInsert = array(); if($fields) $fields = $this->getSubmittedDataAsArray($fields); // Set user profile id - current id if($this->bIsUserProfile) $userId = $this->oUser->iUserId; // Save user profile if(!!$fields){ // Validate fields $valid = new cValidator($this); $errors = $valid->checkArrayAdvance($fields, $this->getUserValCfg(false)); if(!!$errors) cJSON::sendError(array('data' => $errors)); // Get user data by login only if($userId) $vUserData = $this->oModule->getUserDataById($userId); //--------------------------------------------------------------- // Profile case //--------------------------------------------------------------- if($this->bIsUserProfile){ if($userId && $vUserData['user_lang_id'] != $fields['pbase']['user_lang']){ $this->oUser->suser->data['user_lang_id'] = $fields['pbase']['user_lang']; } $update = array( 'user_name' => $fields['pbase']['user_name'], 'user_surname' => $fields['pbase']['user_surname'], 'user_lang_id' => $fields['pbase']['user_lang'], 'user_email' => $fields['pbase']['user_email'] ); //--------------------------------------------------------------- // Base user save case //--------------------------------------------------------------- }else{ // Check user exists by login name if($this->oModule->getUserDataByLogin($userId, $fields['pbase']['user_login'])){ cJSON::sendError(array('data' => array('user_login' => $this->gM('User login already exists!')))); } $update = array( 'user_name' => $fields['pbase']['user_name'], 'user_surname' => $fields['pbase']['user_surname'], 'user_lang_id' => $fields['pbase']['user_lang'], 'user_email' => $fields['pbase']['user_email'], 'user_login' => $fields['pbase']['user_login'], 'user_blocked' => ($fields['psettings']['user_blocked'] ? 1 : 0), 'user_fchange' => ($fields['psettings']['user_pass_change'] ? 1 : 0), 'user_modified' => time(), ); if(!$userId) $update['user_created'] = time(); // Drop 2FA key if($fields['psettings']['user_2fa_reset']) $update['user_2fa_secret_enabled'] = ''; // Update user permission data if(isset($fields['user_permissions'])){ foreach($fields['user_permissions'] as $k=>$v){ if($v == "1"){ $vUserPermissionsInsert[] = array( 'user_id' => &$userId, 'groups_id' => 0, 'permissions_id' => substr($k, 1) ); } } } // Update user groups data if(isset($fields['user_groups'])){ foreach($fields['user_groups'] as $k=>$v){ if($v == "1"){ $vUserPermissionsInsert[] = array( 'user_id' => &$userId, 'groups_id' => substr($k, 1), 'permissions_id' => 0 ); } } } } // Check pass change if(isset($fields['ppasschange']) && isset($fields['ppasschange']['user_newpass'])){ $oPwdMaster = new cPasswordMaster(); // Verify user old password if($this->bIsUserProfile){ if(!$oPwdMaster->password_verify($fields['ppasschange']['user_oldpass'], $vUserData['user_password'])) cJSON::sendError(array('data' => array('user_oldpass' => $this->gM('Old password incorrect!')))); } // Update new password $update['user_password'] = $oPwdMaster->password_hash($fields['ppasschange']['user_newpass']); // Force password change on new generated pwd if(!empty($fields['psettings']['user_passgen']) && $this->oModSession->TPASSWD == $fields['ppasschange']['user_newpass']) $update['user_fchange'] = 1; } //--------------------------------------------------------------- // Validate specific input field values or reset to defaults //--------------------------------------------------------------- if(!empty($fields['user_values']['iRecordsPerPage'])){ $fields['user_values']['iRecordsPerPage'] = ($fields['user_values']['iRecordsPerPage'] <= 100 ? $fields['user_values']['iRecordsPerPage'] : 100); } //--------------------------------------------------------------- // Save data block //--------------------------------------------------------------- $oldId = $userId; if(!($userId = $this->oModule->saveUserDataById($userId, $update))){ cJSON::sendError(); } if(!$this->bIsUserProfile){ // Send inserts & delete old $this->oModule->updateUserPermissions($userId, $vUserPermissionsInsert); } $vReturn = array(); if(!$oldId) $vReturn['newid'] = $userId; if($this->bIsUserProfile && $update['user_lang_id'] != $vUserData['user_lang_id']) $vReturn['url'] = $this->getLinkForID(false, $update['user_lang_id']); // Update settings if(count($fields['psettings'])){ $oCfg = new sysUsersCfg($userId); // Save setting properties $oCfg->addProperties($fields['psettings']); // Check & save user Theme if(isset($fields['user_theme']) && !!$fields['user_theme']){ foreach($fields['user_theme'] as $k=>$v){ if($v){ if(!isset($fields['user_values'])) $fields['user_values'] = array(); $fields['user_values']['sThemetitle'] = $k; break; } } } // Save value properties if(isset($fields['user_values']) && !!$fields['user_values'] && is_array($fields['user_values'])) $oCfg->addPropertiesAdvanced($fields['user_values'], sysUsersCfg::values); // Save table values if($fields['tablescfg'] && count($fields['tablescfg'])){ $tables = array(); foreach($fields['tablescfg'] as $k=>$v){ $tables[$k] = array(); foreach($v as $kk => $vv){ if($vv){ $tables[$k][] = $kk; } } } $_POST['table'] = true; $oCfg->addProperties($tables); } // Save portlets config if($fields['portletscfg'] && count($fields['portletscfg'])){ $vCfg = $oCfg->getUserCFG(sysUsersCfg::plugins); foreach($fields['portletscfg'] as $k=>$v) if(isset($vCfg[$k])) $vCfg[$k]['e'] = $v; $oCfg->addPropertiesAdvanced($vCfg, sysUsersCfg::plugins); } } cJSON::sendOk($vReturn); } } /** * Function to get & create portlet layout config form for user * * @author Mareks Keišs * @category sysUsers Manager Controller * @param int $userId - user id for configuration * @return array of data */ public function createPortletConfigForm($userId){ if($userId){ // Load user configuration data $cfg = new sysUsersCfg($userId); $config = $cfg->getUserCFG(); // Load table column titles from configuration modules if(isset($config[sysUsersCfg::plugins]) && count($config[sysUsersCfg::plugins])){ foreach($config[sysUsersCfg::plugins] as $k=>&$v){ $pluginData = false; $module = new $k($this->uri_data); if($module){ if(method_exists($module->controller, $run = 'getPluginData')){ $pluginData = $module->controller->$run(true); } } // Add titles if($pluginData){ $v['title'] = $this->gM($k); }else{ unset($config[sysUsersCfg::plugins][$k]); } unset($fields, $module); } unset($v); } $this->oView->CFG = $config[sysUsersCfg::plugins]; } return array( 'html' => $this->oView->genTemplate('userPortlets'), ); } /** * Function to get & create table layout config form for user * * @author Mareks Keišs * @category sysUsers Manager Controller * @param int $userId - user id for configuration * @return array of data */ public function createTablesConfigForm($userId) { if ($userId) { // Load user configuration data $cfg = new sysUsersCfg($userId); $config = $cfg->getUserCFG(); // Load User permission array $vUserPermissions = array(); $vProfilePermissions = $this->oUser->suser->permissions; $vUserPermissions = ($this->oUser->iUserId == $userId ? $vProfilePermissions : $this->oModule->loadUserPermissionArray($userId)); // Load table column titles from configuration modules if ( isset($config[sysUsersCfg::tables]) && count($config[sysUsersCfg::tables]) ) { foreach ($config[sysUsersCfg::tables] as $k => &$v) { $fields = []; $cClassName = $k; $run = 'getTableFields'; // Check if there's additional tables in one module if (!empty($cfg->tablesToControllers[$k]['m'])) { $run = (!empty($cfg->tablesToControllers[$k]['f']) ? $cfg->tablesToControllers[$k]['f'] : $run); $cClassName = $cfg->tablesToControllers[$k]['m']; } // Reset admin permission array before new module inti $this->oUser->suser->permissions = $vProfilePermissions; // Get Namespaced class name $cClassName = getModuleNamespacePath($cClassName); if (class_exists($cClassName)) { $module = new $cClassName($this->uri_data); if ($module) { // Rewrite user permission array to get only user available tables $module->controller->oUser->suser->permissions = $vUserPermissions; if (method_exists($module->controller, $run)) { $fields = $module->controller->$run(); } unset($module->controller->oModule, $module->controller, $module); //gc_collect_cycles(); // Free memory from connections // Remove current table from user cfg if (!!!$fields) { unset($config[sysUsersCfg::tables][$k]); continue; } } } // Add titles if ($fields && count($fields)) { $v = reOrderTableFields($fields, $v, false); } else { $v = []; } unset($fields, $module); } } $this->oView->CFG = $config[sysUsersCfg::tables]; } return array( 'html' => $this->oView->genTemplate('userTableOrders'), ); } /******************************************************************************************************************* * 2FA function block ↓↓↓↓↓ * * Function to load user 2FA QR code & secret data * * @author Mareks Keišs keiss.mareks@gmail.com> * @category sysUsers Manager Controller * @param bool $bReload - reload secret only * @return array */ public function get2FAQRCodeForm($bReload = false){ $userData = $this->oUser->suser->data; $oGoogle2FA = new cGoogle2FA(); $this->oView->TWO_FA_SECRET = $sSecret = $oGoogle2FA->getNewGoogleAuthSecret(); $this->oView->TWO_FA_SECRET_QR = $sUrl = $oGoogle2FA->getNewGoogleAuthSecretQRCodeLink($sSecret, $userData['user_email'], $this->gM('MSG_CMS_2FA_ISSUER')); $compData = $this->oView->genTemplate('twoFA/enable2fa'); if($bReload){ return array( 'sUrl' => $sUrl, 'sSecret' => $sSecret ); }else{ return array( 'html' => $compData, 'msgEnableAuth' => $this->gM('Login 2FA Security'), 'buttonYes' => $this->gM('Next step'), 'buttonCancel' => $this->gM('Cancel operation'), 'buttonBack' => $this->gM('Go Back'), 'buttonActivate' => $this->gM('Activate'), ); } } /** * Function to activate user 2FA * * @author Mareks Keišs keiss.mareks@gmail.com> * @category sysUsers Manager Controller * @param string $sSecret - secret to link to the account * @param string $sCode - validate code before save * @return array */ public function set2FAQRCode($sSecret, $sCode){ if(strlen($sSecret) && strlen($sCode)){ // Validate fields $valid = new cValidator($this); $fields = array('code' => $sCode, 'secret' => $sSecret); $errors = $valid->checkArrayAdvance($fields, $this->getGen2FAQRCodeCfg(false)); if(!!$errors) cJSON::sendError(array('data' => $errors)); $oGoogle2FA = new cGoogle2FA(); // Check if code is valid if($oGoogle2FA->verifyCode($sSecret, $sCode)){ // Enable 2FA for user & save data if($this->oModule->saveUserDataById($this->selUserId, array('user_2fa_secret_enabled' => $sSecret))){ // Setup session variables $this->oUser->suser->b2FAEnabled = true; return true; } } } cJSON::sendError(array('data' => array('code' => $this->gM('Login 2FA Security setup code input error!')))); } /** * Function to load form for user 2FA removal * * @author Mareks Keišs keiss.mareks@gmail.com> * @category sysUsers Manager Controller * @return array */ public function get2FAUnsetForm(){ $compData = $this->oView->genTemplate('twoFA/disable2fa.twig'); return array( 'html' => $compData, 'msgDisableAuth' => $this->gM('Login 2FA Security'), 'buttonCancel' => $this->gM('Cancel operation'), 'buttonDeactivate' => $this->gM('Deactivate'), ); } /** * Function to generate 2FA QR code * * @author Aivars Žukovskis keiss.mareks@gmail.com> * @category sysUsers Manager Controller * @param $vData - array of data * @return array */ public function generate2FAQRCode($vData){ if(strlen($vData)){ $vData = cJSON::decode($vData, true); if(!empty($vData) && is_array($vData)){ // Validate fields $valid = new cValidator($this); $errors = $valid->checkArrayAdvance($fields, $this->getGen2FAQRCodeCfg(false)); if(!!$errors) cJSON::sendError(array('data' => $errors)); // Create QR Code $oGoogle2FA = new cGoogle2FA(); $sUrl = $oGoogle2FA->getNewGoogleAuthSecretQRCodeLink($vData['sc_key'], $vData['user'], $vData['issue']); return array('sUrl' => $sUrl); } } return false; } /** * Function to get randomly generated password * * @author Mareks Keišs * @category sysUsers Manager Controller * @category cmsPubUsers Controller * @return array of data */ public function genTempPWD() { $this->oView->TPASSWD = $this->oModSession->TPASSWD = cNumbers::getRandomChString(16, true); return array('key' => $this->oModSession->TPASSWD); } /** * Function to get cfg for 2FA QRCode generator * * @author Aivars Žukovskis keiss.mareks@gmail.com> * @category sysUsers Manager Controller * @param bool $bPrepDataCfg - reconfigure cfg data array * @return array */ public function getGen2FAQRCodeCfg($bPrepDataCfg = true){ $valCfg = array( // Additional validation config 'cfg' => array( //cValidator::CFG_CONTAINERS => array('pbase'), cValidator::CFG_BIND_FIELD => 'data-validator', //cValidator::CFG_CHK_FIELDS_SET => true, // Check all fields in config are present - or pass an array with groups to check ), 'code' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_INT, cValidator::CHK_LEN), cValidator::P_ADDS => array('min' => 6, 'max' => 6) ), 'secret' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), ), 'sc_key' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), ), 'issue' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), ), 'user' => array( cValidator::P_TYPE => cValidator::TY_STR, cValidator::P_COMP => 1, cValidator::P_TEST => array(cValidator::CHK_STR), ), ); return ($bPrepDataCfg ? cValidator::prepValCfgForValidation($valCfg) : $valCfg); } /** * Function to activate user 2FA * * @author Mareks Keišs keiss.mareks@gmail.com> * @category sysUsers Manager Controller * @param string $sCode - validate code before save * @return array */ public function unset2FA($sCode){ if(strlen($sCode)){ // Validate fields $valid = new cValidator($this); $fields = array('code' => $sCode); $errors = $valid->checkArrayAdvance($fields, $this->getGen2FAQRCodeCfg()); if(!!$errors) cJSON::sendError(array('data' => $errors)); $oGoogle2FA = new cGoogle2FA(); // Get user secret key $vUserData = $this->oModule->getUserDataById($this->selUserId); if(!empty($vUserData['user_2fa_secret_enabled'])){ // Check if code is valid if($oGoogle2FA->verifyCode($vUserData['user_2fa_secret_enabled'], $sCode)){ // Disable 2FA for user & save data if($this->oModule->saveUserDataById($this->selUserId, array('user_2fa_secret_enabled' => ''))){ // Setup session variables $this->oUser->suser->b2FAEnabled = false; return true; } } } } cJSON::sendError(array('data' => array('code' => $this->gM('Login 2FA Security removal code input error!')))); } /******************************************************************************************************************* * Function block to save profile cfg data * * @author Mareks Keišs * @category sysUsers Manager Controller * @param mixed $prop - property name / property array * @param mixed $value - property value * @return bool true / false */ public function saveProfileCfgProp($prop, $value = false){ return $this->oUser->oCfg->addProperties($prop, $value); } }