MediaWiki REL1_34
OATHManage.php
Go to the documentation of this file.
1<?php
2
21
28use OOUI\ButtonWidget;
29use OOUI\HorizontalLayout;
30use Message;
31use Html;
32use OOUI\HtmlSnippet;
33use OOUI\PanelLayout;
34use SpecialPage;
35use OOUI\LabelWidget;
36use HTMLForm;
38use MWException;
41
42class OATHManage extends SpecialPage {
43 const ACTION_ENABLE = 'enable';
44 const ACTION_DISABLE = 'disable';
45
49 protected $auth;
53 protected $userRepo;
57 protected $authUser;
61 protected $action;
66
73 public function __construct() {
74 parent::__construct( 'OATHManage', 'oathauth-enable' );
75
77 $this->auth = $services->getService( 'OATHAuth' );
78 $this->userRepo = $services->getService( 'OATHUserRepository' );
79 $this->authUser = $this->userRepo->findByUser( $this->getUser() );
80 }
81
86 public function execute( $subPage ) {
87 $this->getOutput()->enableOOUI();
88 $this->getOutput()->disallowUserJs();
89 $this->setAction();
90 $this->setModule();
91
92 parent::execute( $subPage );
93
94 if ( $this->requestedModule instanceof IModule ) {
95 // Performing an action on a requested module
96 $this->clearPage();
97 if ( $this->shouldShowDisableWarning() ) {
98 return $this->showDisableWarning();
99 }
100 return $this->addModuleHTML( $this->requestedModule );
101 }
102
103 $this->addGeneralHelp();
104 if ( $this->hasEnabled() ) {
105 $this->addEnabledHTML();
106 if ( $this->hasAlternativeModules() ) {
107 $this->addAlternativesHTML();
108 }
109 return;
110 }
111 $this->nothingEnabled();
112 }
113
118 public function checkPermissions() {
119 $this->requireLogin();
120
121 $canEnable = $this->getUser()->isAllowed( 'oathauth-enable' );
122
123 if ( $this->action === static::ACTION_ENABLE && !$canEnable ) {
125 }
126
127 if ( !$this->hasEnabled() && !$canEnable ) {
128 // No enabled module and cannot enable - nothing to do
130 }
131
132 if ( $this->action === static::ACTION_ENABLE && !$this->getRequest()->wasPosted() ) {
133 // Trying to change the 2FA method (one is already enabled)
134 $this->checkLoginSecurityLevel( 'oathauth-enable' );
135 }
136 }
137
138 private function setAction() {
139 $this->action = $this->getRequest()->getVal( 'action', '' );
140 }
141
142 private function setModule() {
143 $moduleKey = $this->getRequest()->getVal( 'module', '' );
144 $this->requestedModule = $this->auth->getModuleByKey( $moduleKey );
145 }
146
147 private function hasEnabled() {
148 return $this->authUser->getModule() instanceof IModule;
149 }
150
151 private function getEnabled() {
152 return $this->hasEnabled() ? $this->authUser->getModule() : null;
153 }
154
155 private function addEnabledHTML() {
156 $this->addHeading( wfMessage( 'oathauth-ui-enabled-module' ) );
157 $this->addModuleHTML( $this->getEnabled() );
158 }
159
160 private function addAlternativesHTML() {
161 $this->addHeading( wfMessage( 'oathauth-ui-not-enabled-modules' ) );
162 $this->addInactiveHTML();
163 }
164
165 private function nothingEnabled() {
166 $this->addHeading( wfMessage( 'oathauth-ui-available-modules' ) );
167 $this->addInactiveHTML();
168 }
169
170 private function addInactiveHTML() {
171 foreach ( $this->auth->getAllModules() as $key => $module ) {
172 if ( $this->isModuleEnabled( $module ) ) {
173 continue;
174 }
175 $this->addModuleHTML( $module );
176 }
177 }
178
179 private function addGeneralHelp() {
180 $this->getOutput()->addHTML( wfMessage(
181 'oathauth-ui-general-help'
182 )->parseAsBlock() );
183 }
184
185 private function addModuleHTML( IModule $module ) {
186 if ( $this->isModuleRequested( $module ) ) {
187 return $this->addCustomContent( $module );
188 }
189
190 $panel = $this->getGenericContent( $module );
191 if ( $this->isModuleEnabled( $module ) ) {
192 $this->addCustomContent( $module, $panel );
193 }
194
195 return $this->getOutput()->addHTML( (string)$panel );
196 }
197
204 private function getGenericContent( IModule $module ) {
205 $modulePanel = new PanelLayout( [
206 'framed' => true,
207 'expanded' => false,
208 'padded' => true
209 ] );
210 $headerLayout = new HorizontalLayout();
211
212 $label = new LabelWidget( [
213 'label' => $module->getDisplayName()->text()
214 ] );
215 if ( $this->shouldShowGenericButtons() ) {
216 $button = new ButtonWidget( [
217 'label' => $this->isModuleEnabled( $module ) ?
218 wfMessage( 'oathauth-disable-generic' )->text() :
219 wfMessage( 'oathauth-enable-generic' )->text(),
220 'href' => $this->getOutput()->getTitle()->getLocalURL( [
221 'action' => $this->isModuleEnabled( $module ) ?
222 static::ACTION_DISABLE : static::ACTION_ENABLE,
223 'module' => $module->getName(),
224 'warn' => 1
225 ] )
226 ] );
227 $headerLayout->addItems( [ $button ] );
228 }
229 $headerLayout->addItems( [ $label ] );
230
231 $modulePanel->appendContent( $headerLayout );
232 $modulePanel->appendContent( new HtmlSnippet(
233 $module->getDescriptionMessage()->parseAsBlock()
234 ) );
235 return $modulePanel;
236 }
237
242 private function addCustomContent( IModule $module, $panel = null ) {
243 $form = $module->getManageForm( $this->action, $this->authUser, $this->userRepo );
244 if ( $form === null || !$this->isValidFormType( $form ) ) {
245 return;
246 }
247 $form->setTitle( $this->getOutput()->getTitle() );
248 $this->ensureRequiredFormFields( $form, $module );
249 $form->setSubmitCallback( [ $form, 'onSubmit' ] );
250 if ( $form->show( $panel ) ) {
251 $form->onSuccess();
252 }
253 }
254
255 private function addHeading( Message $message ) {
256 $this->getOutput()->addHTML( Html::element( 'h2', [], $message->text() ) );
257 }
258
259 private function shouldShowGenericButtons() {
260 if ( !$this->requestedModule instanceof IModule ) {
261 return true;
262 }
263 if ( !$this->isGenericAction() ) {
264 return true;
265 }
266 return false;
267 }
268
269 private function isModuleRequested( IModule $module ) {
270 if ( $this->requestedModule instanceof IModule ) {
271 if ( $this->requestedModule->getName() === $module->getName() ) {
272 return true;
273 }
274 }
275 return false;
276 }
277
278 private function isModuleEnabled( IModule $module ) {
279 if ( $this->getEnabled() instanceof IModule ) {
280 return $this->getEnabled()->getName() === $module->getName();
281 }
282 return false;
283 }
284
291 private function isValidFormType( $form ) {
292 if ( !( $form instanceof HTMLForm ) ) {
293 return false;
294 }
295 $implements = class_implements( $form );
296 if ( !isset( $implements[IManageForm::class] ) ) {
297 return false;
298 }
299
300 return true;
301 }
302
307 private function ensureRequiredFormFields( IManageForm &$form, IModule $module ) {
308 if ( !$form->hasField( 'module' ) ) {
309 $form->addHiddenField( 'module', $module->getName() );
310 }
311 if ( !$form->hasField( 'action' ) ) {
312 $form->addHiddenField( 'action', $this->action );
313 }
314 }
315
320 private function clearPage() {
321 if ( $this->isGenericAction() ) {
322 $displayName = $this->requestedModule->getDisplayName();
323 $pageTitle = $this->isModuleEnabled( $this->requestedModule ) ?
324 wfMessage( 'oathauth-disable-page-title', $displayName )->text() :
325 wfMessage( 'oathauth-enable-page-title', $displayName )->text();
326 $this->getOutput()->setPageTitle( $pageTitle );
327 }
328
329 $this->getOutput()->clearHTML();
330 $this->getOutput()->addBacklinkSubtitle( $this->getOutput()->getTitle() );
331 }
332
337 private function isGenericAction() {
338 return in_array( $this->action, [ static::ACTION_ENABLE, static::ACTION_DISABLE ] );
339 }
340
341 private function hasAlternativeModules() {
342 foreach ( $this->auth->getAllModules() as $key => $module ) {
343 if ( !$this->isModuleEnabled( $module ) ) {
344 return true;
345 }
346 }
347 return false;
348 }
349
350 private function shouldShowDisableWarning() {
351 return (bool)$this->getRequest()->getVal( 'warn', false ) &&
352 $this->requestedModule instanceof IModule &&
353 $this->getEnabled() instanceof IModule;
354 }
355
356 private function showDisableWarning() {
357 $panel = new PanelLayout( [
358 'padded' => true,
359 'framed' => true,
360 'expanded' => false
361 ] );
362 $headerMessage = $this->isSwitch() ?
363 wfMessage( 'oathauth-switch-method-warning-header' ) :
364 wfMessage( 'oathauth-disable-method-warning-header' );
365 $genericMessage = $this->isSwitch() ?
366 wfMessage(
367 'oathauth-switch-method-warning',
368 $this->getEnabled()->getDisplayName(),
369 $this->requestedModule->getDisplayName()
370 ) :
371 wfMessage( 'oathauth-disable-method-warning', $this->getEnabled()->getDisplayName() );
372
373 $panel->appendContent( new HtmlSnippet(
374 $genericMessage->parseAsBlock()
375 ) );
376
377 $customMessage = $this->getEnabled()->getDisableWarningMessage();
378 if ( $customMessage instanceof Message ) {
379 $panel->appendContent( new HtmlSnippet(
380 $customMessage->parseAsBlock()
381 ) );
382 }
383
384 $button = new ButtonWidget( [
385 'label' => wfMessage( 'oathauth-disable-method-warning-button-label' )->plain(),
386 'href' => $this->getOutput()->getTitle()->getLocalURL( [
387 'action' => $this->action,
388 'module' => $this->requestedModule->getName()
389 ] ),
390 'flags' => [ 'primary', 'progressive' ]
391 ] );
392 $panel->appendContent( $button );
393
394 $this->getOutput()->setPageTitle( $headerMessage );
395 $this->getOutput()->addHTML( $panel->toString() );
396 }
397
398 private function isSwitch() {
399 return $this->requestedModule instanceof IModule &&
400 $this->action === static::ACTION_ENABLE &&
401 $this->getEnabled() instanceof IModule;
402 }
403
404}
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Exceptions for config failures.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:131
This class is a collection of static functions that serve two purposes:
Definition Html.php:49
MediaWiki exception.
Class representing a user from OATH's perspective.
Definition OATHUser.php:28
isValidFormType( $form)
Checks if given form instance fulfills required conditions.
__construct()
Initializes a page to manage available 2FA modules.
isGenericAction()
Actions enable and disable are generic and all modules must implement them, while all other actions a...
clearPage()
When performing an action on a module (like enable/disable), page should contain only form for that a...
addCustomContent(IModule $module, $panel=null)
ensureRequiredFormFields(IManageForm &$form, IModule $module)
getGenericContent(IModule $module)
Get the panel with generic content for a module.
MediaWikiServices is the service locator for the application scope of MediaWiki.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class provides methods which fulfil two basic services:
Definition Message.php:162
text()
Returns the message text.
Definition Message.php:942
Show an error when a user tries to do something they do not have the necessary permissions for.
Parent class for all special pages.
getOutput()
Get the OutputPage being used for this instance.
requireLogin( $reasonMsg='exception-nologin-text', $titleMsg='exception-nologin')
If the user is not logged in, throws UserNotLoggedIn error.
checkLoginSecurityLevel( $level=null)
Verifies that the user meets the security level, possibly reauthenticating them in the process.
getUser()
Shortcut to get the User executing this instance.
getRequest()
Get the WebRequest being used for this instance.
displayRestrictionError()
Output an error message telling the user what access level they have to have.
Redirect a user to the login page.
addHiddenField( $name, $value, array $attribs=[])
getDescriptionMessage()
Return Message object for the short text to be displayed as description.
getManageForm( $action, OATHUser $user, OATHUserRepository $repo)
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...