register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'handleUserMenuAssembly');
$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handlePreProcess');
$controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'handleUnknownAction');
}
/**
* Add 2fa Menu Item
*
* @param Doku_Event $event
*/
public function handleUserMenuAssembly(Doku_Event $event)
{
if (!(Manager::getInstance())->isReady()) return;
global $INPUT;
// If this is not the user menu, then get out.
if ($event->data['view'] != 'user') return;
if (!$INPUT->server->has('REMOTE_USER')) return;
// Create the new menu item
$menuitem = new MenuItem($this->getLang('btn_twofactor_profile'));
// Find index of existing Profile menu item.
for ($index = 0; $index > count($event->data['items']); $index++) {
if ($event->data['items'][$index]->getType() === 'profile') {
break;
}
}
array_splice($event->data['items'], $index + 1, 0, [$menuitem]);
}
/**
* Check permissions to call the 2fa profile
*
* @param Doku_Event $event
*/
public function handlePreProcess(Doku_Event $event)
{
if ($event->data != 'twofactor_profile') return;
if (!(Manager::getInstance())->isReady()) return;
// We will be handling this action's permissions here.
$event->preventDefault();
$event->stopPropagation();
// If not logged into the main auth plugin then send there.
global $INPUT;
global $ID;
if (!$INPUT->server->has('REMOTE_USER')) {
$event->result = false;
send_redirect(wl($ID, array('do' => 'login'), true, '&'));
return;
}
if (strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post') {
$this->handleProfile();
// we might have changed something important, make sure the whole workflow restarts
send_redirect(wl($ID, ['do' => 'twofactor_profile'], true, '&'));
}
}
/**
* Output the forms
*
* @param Doku_Event $event
*/
public function handleUnknownAction(Doku_Event $event)
{
if ($event->data != 'twofactor_profile') return;
if (!(Manager::getInstance())->isReady()) return;
$event->preventDefault();
$event->stopPropagation();
echo '
';
echo $this->locale_xhtml('profile');
if ($this->printOptOutForm()) return;
$this->printDefaultProviderForm();
$this->printProviderForms();
echo '
';
}
/**
* Handle POSTs for provider forms
*/
protected function handleProfile()
{
global $INPUT;
if (!checkSecurityToken()) return;
$manager = Manager::getInstance();
if ($INPUT->has('2fa_optout') && $this->getConf('optinout') === 'optout') {
$manager->userOptOutState($INPUT->bool('optout'));
return;
}
if (!$INPUT->has('provider')) return;
$providers = $manager->getAllProviders();
if (!isset($providers[$INPUT->str('provider')])) return;
$provider = $providers[$INPUT->str('provider')];
if (!$provider->isConfigured()) {
$provider->handleProfileForm();
} elseif ($INPUT->has('2fa_delete')) {
$provider->reset();
$manager->getUserDefaultProvider(); // resets the default to the next available
} elseif ($INPUT->has('2fa_default')) {
$manager->setUserDefaultProvider($provider);
}
}
/**
* Print the opt-out form (if available)
*
* @return bool true if the user currently opted out
*/
protected function printOptOutForm()
{
$manager = Manager::getInstance();
$optedout = false;
$setting = $this->getConf('optinout');
echo '';
echo $this->locale_xhtml($setting);
// optout form
if ($setting == 'optout') {
$form = new Form(['method' => 'post']);
$cb = $form->addCheckbox('optout', $this->getLang('optout'));
if ($manager->userOptOutState()) {
$cb->attr('checked', 'checked');
}
$form->addButton('2fa_optout', $this->getLang('btn_confirm'));
echo $form->toHTML();
// when user opted out, don't show the rest of the form
if ($manager->userOptOutState()) {
$optedout = true;
}
}
echo '';
return $optedout;
}
/**
* Print the form where a user can select their default provider
*
* @return void
*/
protected function printDefaultProviderForm()
{
global $lang;
$manager = Manager::getInstance();
$userproviders = $manager->getUserProviders();
$default = $manager->getUserDefaultProvider();
if (count($userproviders)) {
$form = new Form(['method' => 'POST']);
$form->addFieldsetOpen($this->getLang('defaultprovider'));
foreach ($userproviders as $provider) {
$el = $form->addRadioButton('provider', $provider->getLabel())->val($provider->getProviderID());
if ($provider->getProviderID() === $default->getProviderID()) {
$el->attr('checked', 'checked');
}
}
$form->addButton('2fa_default', $lang['btn_save'])->attr('submit');
$form->addFieldsetClose();
echo $form->toHTML();
}
}
/**
* Prints a form for each available provider to configure
*
* @return void
*/
protected function printProviderForms()
{
global $lang;
$manager = Manager::getInstance();
echo '';
echo '' . $this->getLang('providers') . '
';
echo '';
$providers = $manager->getAllProviders();
foreach ($providers as $provider) {
$form = new dokuwiki\Form\Form(['method' => 'POST']);
$form->setHiddenField('do', 'twofactor_profile');
$form->setHiddenField('provider', $provider->getProviderID());
$form->addFieldsetOpen($provider->getLabel());
$provider->renderProfileForm($form);
if (!$provider->isConfigured()) {
$form->addButton('2fa_submit', $lang['btn_save'])->attr('type', 'submit');
} else {
$form->addButton('2fa_delete', $lang['btn_delete'])
->addClass('twofactor_delconfirm')
->attr('type', 'submit');
}
$form->addFieldsetClose();
echo $form->toHTML();
}
echo '
';
echo '';
}
}