1<?php 2 3/** 4 * DokuWiki Plugin twofactor (Action Component) 5 * 6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7 */ 8class action_plugin_twofactor_profile extends \dokuwiki\Extension\ActionPlugin 9{ 10 11 /** @inheritDoc */ 12 public function register(Doku_Event_Handler $controller) 13 { 14 // Adds our twofactor profile to the user menu. 15 $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'handleUserMenuAssembly'); 16 17 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handlePreProcess'); 18 $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'handleUnknownAction'); 19 } 20 21 /** 22 * Add 2fa Menu Item 23 * 24 * @param Doku_Event $event 25 */ 26 public function handleUserMenuAssembly(Doku_Event $event) 27 { 28 global $INPUT; 29 // If this is not the user menu, then get out. 30 if ($event->data['view'] != 'user') return; 31 if (!$INPUT->server->has('REMOTE_USER')) return; 32 33 // Create the new menu item 34 $menuitem = new dokuwiki\plugin\twofactor\MenuItem($this->getLang('btn_twofactor_profile')); 35 36 // Find index of existing Profile menu item. 37 for ($index = 0; $index > count($event->data['items']); $index++) { 38 if ($event->data['items'][$index]->getType() === 'profile') { 39 break; 40 } 41 } 42 array_splice($event->data['items'], $index + 1, 0, [$menuitem]); 43 } 44 45 /** 46 * Check permissions to call the 2fa profile 47 * 48 * @param Doku_Event $event 49 */ 50 public function handlePreProcess(Doku_Event $event) 51 { 52 if ($event->data != 'twofactor_profile') return; 53 54 // We will be handling this action's permissions here. 55 $event->preventDefault(); 56 $event->stopPropagation(); 57 58 // If not logged into the main auth plugin then send there. 59 global $INPUT; 60 global $ID; 61 62 if (!$INPUT->server->has('REMOTE_USER')) { 63 $event->result = false; 64 send_redirect(wl($ID, array('do' => 'login'), true, '&')); 65 return; 66 } 67 68 /** FIXME 69 * 70 * // If not logged into twofactor then send there. 71 * if (!$this->get_clearance()) { 72 * $event->result = false; 73 * send_redirect(wl($ID, array('do' => 'twofactor_login'), true, '&')); 74 * return; 75 * } 76 * // Otherwise handle the action. 77 * $event->result = $this->_process_changes($event, $param); 78 */ 79 80 } 81 82 /** 83 * @param Doku_Event $event 84 */ 85 public function handleUnknownAction(Doku_Event $event) 86 { 87 if ($event->data != 'twofactor_profile') return; 88 89 $event->preventDefault(); 90 $event->stopPropagation(); 91 $this->printProfile(); 92 } 93 94 /** 95 * Handles the profile form rendering. Displays user manageable settings. 96 * @todo move elsewhere 97 */ 98 public function printProfile() 99 { 100 global $lang; 101 102 103 $form = new dokuwiki\Form\Form(); 104 $form->addHTML($this->locale_xhtml('profile')); 105 106 // FIXME iterate over providers, add a fieldset for each and add the elements provided 107 108 $form->addButton('save', $lang['btn_save']); 109 echo $form->toHTML(); 110 111 /* FIXME 112 113 114 $optinout = $this->getConf("optinout"); 115 $optinvalue = $optinout == 'mandatory' ? 'in' : ($this->attribute ? $this->attribute->get("twofactor", 116 "state") : ''); 117 $available = count($this->tokenMods) + count($this->otpMods) > 0; 118 // If the user is being redirected here because of mandatory two factor, then display a message saying so. 119 if (!$available && $optinout == 'mandatory') { 120 msg($this->getLang('mandatory'), -1); 121 } elseif ($this->attribute->get("twofactor", "state") == '' && $optinout == 'optout') { 122 msg($this->getLang('optout_notice'), 2); 123 } elseif ($this->attribute->get("twofactor", 124 "state") == 'in' && count($this->tokenMods) == 0 && count($this->otpMods) == 0) { 125 msg($this->getLang('not_configured_notice'), 2); 126 } 127 global $USERINFO, $lang, $conf; 128 $form = new Doku_Form(array('id' => 'twofactor_setup')); 129 // Add the checkbox to opt in and out, only if optinout is not mandatory. 130 $items = array(); 131 if ($optinout != 'mandatory') { 132 if (!$this->attribute || !$optinvalue) { // If there is no personal setting for optin, the default is based on the wiki default. 133 $optinvalue = $this->getConf("optinout") == 'optout'; 134 } 135 $items[] = form_makeCheckboxField('optinout', '1', $this->getLang('twofactor_optin'), '', 'block', 136 $optinvalue == 'in' ? array('checked' => 'checked') : array()); 137 } 138 // Add the notification checkbox if appropriate. 139 if ($this->getConf('loginnotice') == 'user' && $optinvalue == 'in' && count($this->otpMods) > 0) { 140 $loginnotice = $this->attribute ? $this->attribute->get("twofactor", "loginnotice") : false; 141 $items[] = form_makeCheckboxField('loginnotice', '1', $this->getLang('twofactor_notify'), '', 'block', 142 $loginnotice === true ? array('checked' => 'checked') : array()); 143 } 144 // Select a notification provider. 145 if ($optinvalue == 'in') { 146 // If there is more than one choice, have the user select the default. 147 if (count($this->otpMods) > 1) { 148 $defaultMod = $this->attribute->exists("twofactor", "defaultmod") ? $this->attribute->get("twofactor", 149 "defaultmod") : null; 150 $modList = array_merge(array($this->getLang('useallotp')), array_keys($this->otpMods)); 151 $items[] = form_makeListboxField('default_module', $modList, $defaultMod, 152 $this->getLang('defaultmodule'), '', 'block'); 153 } 154 } 155 if (count($items) > 0) { 156 $form->startFieldset($this->getLang('settings')); 157 foreach ($items as $item) { 158 $form->addElement($item); 159 } 160 $form->endFieldset(); 161 } 162 // TODO: Make this AJAX so that the user does not have to keep clicking 163 // submit them Update Profile! 164 // Loop through all modules and render the profile components. 165 if ($optinvalue == 'in') { 166 $parts = array(); 167 foreach ($this->modules as $mod) { 168 if ($mod->getConf("enable") == 1) { 169 $this->log('twofactor_profile_form: processing ' . get_class($mod) . '::renderProfileForm()', 170 self::LOGGING_DEBUG); 171 $items = $mod->renderProfileForm(); 172 if (count($items) > 0) { 173 $form->startFieldset($mod->getLang('name')); 174 foreach ($items as $item) { 175 $form->addElement($item); 176 } 177 $form->endFieldset(); 178 } 179 } 180 } 181 } 182 if ($conf['profileconfirm']) { 183 $form->addElement('<br />'); 184 $form->startFieldset($this->getLang('verify_password')); 185 $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', 186 array('size' => '50', 'required' => 'required'))); 187 $form->endFieldset(); 188 } 189 $form->addElement('<br />'); 190 $form->addElement(form_makeButton('submit', '', $lang['btn_save'])); 191 $form->addElement('<a href="' . wl($ID, array('do' => 'show'), true, 192 '&') . '">' . $this->getLang('btn_return') . '</a>'); 193 $form->addHidden('do', 'twofactor_profile'); 194 $form->addHidden('save', '1'); 195 echo '<div class="centeralign">' . NL . $form->getForm() . '</div>' . NL; 196 197 */ 198 } 199} 200 201