1<?php 2 3use dokuwiki\plugin\twofactor\Manager; 4 5/** 6 * DokuWiki Plugin twofactor (Action Component) 7 * 8 * This adds 2fa handling to the resendpwd action. It will interrupt the normal, first step of the 9 * flow and insert our own 2fa form, initialized with the user provided in the reset form. When the user 10 * has successfully authenticated, the normal flow will continue. All within the do?do=resendpwd action. 11 * 12 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 13 * @author Andreas Gohr <dokuwiki@cosmocode.de> 14 */ 15class action_plugin_twofactor_resendpwd extends \dokuwiki\Extension\ActionPlugin 16{ 17 /** @inheritDoc */ 18 public function register(Doku_Event_Handler $controller) 19 { 20 $controller->register_hook( 21 'ACTION_ACT_PREPROCESS', 22 'BEFORE', 23 $this, 24 'handleActionPreProcess', 25 null, 26 Manager::EVENT_PRIORITY - 1 27 ); 28 29 $controller->register_hook( 30 'TPL_ACT_UNKNOWN', 31 'BEFORE', 32 $this, 33 'handleTplActUnknown', 34 null, 35 Manager::EVENT_PRIORITY - 1 36 ); 37 } 38 39 /** 40 * Event handler for ACTION_ACT_PREPROCESS 41 * 42 * @see https://www.dokuwiki.org/devel:events:ACTION_ACT_PREPROCESS 43 * @param Doku_Event $event Event object 44 * @param mixed $param optional parameter passed when event was registered 45 * @return void 46 */ 47 public function handleActionPreProcess(Doku_Event $event, $param) 48 { 49 if ($event->data !== 'resendpwd') return; 50 51 global $INPUT; 52 if ($INPUT->has('pwauth')) return; // we're already in token phase, don't interrupt 53 if (!$INPUT->str('login')) return; // no user given yet, don't interrupt 54 55 $user = $INPUT->str('login'); 56 $manager = Manager::getInstance(); 57 $manager->setUser($user); 58 59 if (!$manager->isReady()) return; // no 2fa setup, don't interrupt 60 if (!count($manager->getUserProviders())) return; // no 2fa for this user, don't interrupt 61 62 $code = $INPUT->post->str('2fa_code'); 63 $providerID = $INPUT->post->str('2fa_provider'); 64 if ($code && $manager->verifyCode($code, $providerID)) { 65 // all is good, don't interrupt 66 Manager::destroyInstance(); // remove our instance so login.php can create a new one 67 return; 68 } 69 70 // we're still here, so we need to interrupt 71 $event->preventDefault(); 72 $event->stopPropagation(); 73 74 // next, we will overwrite the resendpwd form with our own in TPL_ACT_UNKNOWN 75 } 76 77 /** 78 * Event handler for TPL_ACT_UNKNOWN 79 * 80 * This is executed only when we prevented the default action in handleActionPreProcess() 81 * 82 * @see https://www.dokuwiki.org/devel:events:TPL_ACT_UNKNOWN 83 * @param Doku_Event $event Event object 84 * @param mixed $param optional parameter passed when event was registered 85 * @return void 86 */ 87 public function handleTplActUnknown(Doku_Event $event, $param) 88 { 89 if ($event->data !== 'resendpwd') return; 90 $event->stopPropagation(); 91 $event->preventDefault(); 92 93 global $INPUT; 94 95 $providerID = $INPUT->post->str('2fa_provider'); 96 97 $manager = Manager::getInstance(); 98 $form = $manager->getCodeForm($providerID); 99 100 // overwrite form defaults, to redo the resendpwd action but with the code supplied 101 $form->setHiddenField('do', 'resendpwd'); 102 $form->setHiddenField('login', $INPUT->str('login')); 103 $form->setHiddenField('save', 1); 104 105 106 echo '<div class="plugin_twofactor_login">'; 107 echo inlineSVG(__DIR__ . '/../admin.svg'); 108 echo $this->locale_xhtml('resendpwd'); 109 echo $form->toHTML(); 110 echo '</div>'; 111 } 112} 113 114