*/ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_TWOFACTOR_PLUGIN_IMAGES')) define('DOKU_TWOFACTOR_PLUGIN_IMAGES',DOKU_BASE.'lib/plugins/twofactor/images/'); /** * All DokuWiki plugins to extend the admin function * need to inherit from this class */ class admin_plugin_twofactor extends DokuWiki_Admin_Plugin { protected $_user_list = array(); // list of users with attributes protected $_filter = array(); // user selection filter(s) protected $_start = 0; // index of first user to be displayed protected $_last = 0; // index of the last user to be displayed protected $_pagesize = 20; // number of users to list on one page protected $_disabled = ''; // if disabled set to explanatory string protected $_lastdisabled = false; // set to true if last user is unknown and last button is hence buggy /** * Constructor */ public function __construct(){ global $auth; $this->setupLocale(); if (!isset($auth)) { $this->_disabled = $this->lang['noauth']; } $requireAttribute = $this->getConf("enable") === 1; $this->attribute = $requireAttribute ? $this->loadHelper('attribute', 'TwoFactor depends on the Attribute plugin, but the Attribute plugin is not installed!') : null; $available = Twofactor_Auth_Module::_listModules(); $allmodules = Twofactor_Auth_Module::_loadModules($available); $failed = array_diff($available, array_keys($allmodules)); if (count($failed) > 0) { msg('At least one loaded module did not have a properly named class.' . ' ' . implode(', ', $failed), -1); } $this->modules = &$allmodules; $this->_getUsers(); } protected function _getUsers() { if ($this->getConf("enable") === 1) { if (!is_null($this->attribute)) { $attr = $this->attribute; $this->_user_list = $this->attribute->enumerateUsers('twofactor'); } else { msg($this->lang['no_purpose'], -1); } } } /** * Return prompt for admin menu * * @param string $language * @return string */ public function getMenuText($language) { global $INFO; if (!$INFO['isadmin']) return parent::getMenuText($language); return $this->getLang('menu').' '.$this->_disabled; } /** * return sort order for position in admin menu * * @return int */ public function getMenuSort() { return 2; } /** * @return int current start value for pageination */ public function getStart() { return $this->_start; } /** * @return int number of users per page */ public function getPagesize() { return $this->_pagesize; } /** * @param boolean $lastdisabled */ public function setLastdisabled($lastdisabled) { $this->_lastdisabled = $lastdisabled; } /** * Handle user request * * @return bool */ public function handle() { global $INPUT, $INFO; if (!$INFO['isadmin']) return false; if ($this->_disabled) { // If disabled, don't process anything. return true; } // extract the command and any specific parameters // submit button name is of the form - fn[cmd][param(s)] $fn = $INPUT->param('fn'); if (is_array($fn)) { $cmd = key($fn); $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; } else { $cmd = $fn; $param = null; } if ($cmd != "search") { $this->_start = $INPUT->int('start', 0); $this->_filter = $this->_retrieveFilter(); } switch($cmd){ case "reset" : $this->_resetUser(); break; case "search" : $this->_setFilter($param); $this->_start = 0; break; } $this->_user_total = count($this->_user_list) > 0 ? $this->_getUserCount($this->_filter) : -1; // page handling switch($cmd){ case 'start' : $this->_start = 0; break; case 'prev' : $this->_start -= $this->_pagesize; break; case 'next' : $this->_start += $this->_pagesize; break; case 'last' : $this->_start = $this->_user_total; break; } $this->_validatePagination(); return true; } /** * Output appropriate html * * @return bool */ public function html() { global $ID, $INFO; if(!$INFO['isadmin']) { print $this->lang['badauth']; return false; } if ($this->disabled) { msg($this->_disabled, -1); return true; } $user_list = $this->_retrieveUsers($this->_start, $this->_pagesize, $this->_filter); $page_buttons = $this->_pagination(); print $this->locale_xhtml('intro'); print $this->locale_xhtml('list'); ptln("
"); ptln("
"); if (count($this->_user_list) > 0) { ptln("

".sprintf($this->lang['summary'],$this->_start+1,$this->_last,$this->_getUserCount($this->_filter),count($this->_user_list))."

"); } else { if(count($this->_user_list) < 0) { $allUserTotal = 0; } else { $allUserTotal = count($this->_user_list); } ptln("

".sprintf($this->lang['nonefound'], $allUserTotal)."

"); } ptln("
"); formSecurityToken(); ptln("
"); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); if ($this->_user_total) { ptln(" "); foreach ($user_list as $user => $userinfo) { extract($userinfo); /** * @var string $name * @var string $pass * @var string $mail * @var array $grps */ ptln(" "); ptln(" "); if ($editable) { ptln(" "); } else { ptln(" "); } ptln(" "); ptln(" "); } ptln(" "); } ptln(" "); ptln(" "); ptln(" "); ptln("
 ".$this->lang["user_id"]."".$this->lang["user_name"]."".$this->lang["user_mail"]."
lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" />_htmlFilter('user')."\" />_htmlFilter('name')."\" />_htmlFilter('mail')."\" />
1, 'do' => 'admin', 'page' => 'usermanager', 'sectok' => getSecurityToken())). "\" title=\"".$this->lang['edit_prompt']."\">".hsc($user)."".hsc($user)."".hsc($name)."".hsc($mail)."
"); ptln(" "); ptln(" "); ptln(" "); if (!empty($this->_filter)) { ptln(" "); } ptln(" "); ptln(" "); $this->_htmlFilterSettings(2); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln(" "); ptln("
"); ptln("
"); ptln("
"); ptln("
"); ptln("
"); return true; } /** * Prints a inputfield * * @param string $id * @param string $name * @param string $label * @param string $value * @param bool $cando whether auth backend is capable to do this action * @param int $indent */ protected function _htmlInputField($id, $name, $label, $value, $cando, $indent=0) { $class = $cando ? '' : ' class="disabled"'; echo str_pad('',$indent); if($name == 'userpass' || $name == 'userpass2'){ $fieldtype = 'password'; $autocomp = 'autocomplete="off"'; }elseif($name == 'usermail'){ $fieldtype = 'email'; $autocomp = ''; }else{ $fieldtype = 'text'; $autocomp = ''; } $value = hsc($value); echo ""; echo ""; echo ""; if($cando){ echo ""; }else{ echo ""; echo ""; } echo ""; echo ""; } /** * Returns htmlescaped filter value * * @param string $key name of search field * @return string html escaped value */ protected function _htmlFilter($key) { if (empty($this->_filter)) return ''; return (isset($this->_filter[$key]) ? hsc($this->_filter[$key]) : ''); } /** * Print hidden inputs with the current filter values * * @param int $indent */ protected function _htmlFilterSettings($indent=0) { ptln("_start."\" />",$indent); foreach ($this->_filter as $key => $filter) { ptln("",$indent); } } /** * Reset user (a user has been selected to remove two factor authentication) * * @param string $param id of the user * @return bool whether succesful */ protected function _resetUser() { global $INPUT; if (!checkSecurityToken()) return false; $selected = $INPUT->arr('delete'); if (empty($selected)) return false; $selected = array_keys($selected); if(in_array($_SERVER['REMOTE_USER'], $selected)) { msg($this->lang['reset_not_self'], -1); return false; } $count = 0; foreach($selected as $user) { // All users here have a attribute namespace file. Purge them. $purged = $this->attribute->purge('twofactor', $user); foreach($this->modules as $mod) { $purged |= $this->attribute->purge($mod->moduleName, $user); } $count += $purged ? 1 : 0; } if ($count == count($selected)) { $text = str_replace('%d', $count, $this->lang['reset_ok']); msg("$text.", 1); } else { $part1 = str_replace('%d', $count, $this->lang['reset_ok']); $part2 = str_replace('%d', (count($selected)-$count), $this->lang['reset_fail']); // Output results. msg("$part1, $part2",-1); } // Now refresh the user list. $this->_getUsers(); return true; } protected function _retrieveFilteredUsers($filter = array()) { global $auth; $users = array(); $noUsers = is_null($auth) || !$auth->canDo('getUsers'); foreach ($this->_user_list as $user) { if ($noUsers) { $userdata = array('user'=>$user, 'name'=>$user, 'mail'=>null); } else { $userdata = $auth->getUserData($user); if (!is_array($userdata)) { $userdata = array('user'=>$user, 'name'=>null, 'mail'=>null); } } $include = true; foreach ($filter as $key=>$value) { $include &= strstr($userdata[$key], $value); } if ($include) { $users[$user] = $userdata; } } return $users; } protected function _getUserCount($filter) { return count($this->_retrieveFilteredUsers($filter)); } protected function _retrieveUsers($start, $pagesize, $filter) { $users = $this->_retrieveFilteredUsers($filter); return $users; } /** * Retrieve & clean user data from the form * * @param bool $clean whether the cleanUser method of the authentication backend is applied * @return array (user, password, full name, email, array(groups)) */ protected function _retrieveUser($clean=true) { /** @var DokuWiki_Auth_Plugin $auth */ global $auth; global $INPUT; $user = array(); $user[] = $INPUT->str('userid'); $user[] = $INPUT->str('username'); $user[] = $INPUT->str('usermail'); return $user; } /** * Set the filter with the current search terms or clear the filter * * @param string $op 'new' or 'clear' */ protected function _setFilter($op) { $this->_filter = array(); if ($op == 'new') { list($user,$name,$mail) = $this->_retrieveUser(); if (!empty($user)) $this->_filter['user'] = $user; if (!empty($name)) $this->_filter['name'] = $name; if (!empty($mail)) $this->_filter['mail'] = $mail; } } /** * Get the current search terms * * @return array */ protected function _retrieveFilter() { global $INPUT; $t_filter = $INPUT->arr('filter'); // messy, but this way we ensure we aren't getting any additional crap from malicious users $filter = array(); if (isset($t_filter['user'])) $filter['user'] = $t_filter['user']; if (isset($t_filter['name'])) $filter['name'] = $t_filter['name']; if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail']; return $filter; } /** * Validate and improve the pagination values */ protected function _validatePagination() { if ($this->_start >= $this->_user_total) { $this->_start = $this->_user_total - $this->_pagesize; } if ($this->_start < 0) $this->_start = 0; $this->_last = min($this->_user_total, $this->_start + $this->_pagesize); } /** * Return an array of strings to enable/disable pagination buttons * * @return array with enable/disable attributes */ protected function _pagination() { $disabled = 'disabled="disabled"'; $buttons = array(); $buttons['start'] = $buttons['prev'] = ($this->_start == 0) ? $disabled : ''; if ($this->_user_total == -1) { $buttons['last'] = $disabled; $buttons['next'] = ''; } else { $buttons['last'] = $buttons['next'] = (($this->_start + $this->_pagesize) >= $this->_user_total) ? $disabled : ''; } if ($this->_lastdisabled) { $buttons['last'] = $disabled; } return $buttons; } }