<?php
-use MediaWiki\MediaWikiServices;
-
/**
* Parent class for all special pages.
*
* @ingroup SpecialPage
*/
+use MediaWiki\Auth\AuthManager;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
+
/**
* Parent class for all special pages.
*
*/
protected $mContext;
+ /**
+ * @var \MediaWiki\Linker\LinkRenderer|null
+ */
+ private $linkRenderer;
+
/**
* Get a localised Title object for a specified special page name
*
return $this->mIncludable;
}
+ /**
+ * How long to cache page when it is being included.
+ *
+ * @note If cache time is not 0, then the current user becomes an anon
+ * if you want to do any per-user customizations, than this method
+ * must be overriden to return 0.
+ * @since 1.26
+ * @return int Time in seconds, 0 to disable caching altogether,
+ * false to use the parent page's cache settings
+ */
+ public function maxIncludeCacheTime() {
+ return $this->getConfig()->get( 'MiserMode' ) ? $this->getCacheTTL() : 0;
+ }
+
+ /**
+ * @return int Seconds that this page can be cached
+ */
+ protected function getCacheTTL() {
+ return 60 * 60;
+ }
+
/**
* Whether the special page is being evaluated via transclusion
* @param bool $x
}
}
+ /**
+ * Tells if the special page does something security-sensitive and needs extra defense against
+ * a stolen account (e.g. a reauthentication). What exactly that will mean is decided by the
+ * authentication framework.
+ * @return bool|string False or the argument for AuthManager::securitySensitiveOperationStatus().
+ * Typically a special page needing elevated security would return its name here.
+ */
+ protected function getLoginSecurityLevel() {
+ return false;
+ }
+
+ /**
+ * Verifies that the user meets the security level, possibly reauthenticating them in the process.
+ *
+ * This should be used when the page does something security-sensitive and needs extra defense
+ * against a stolen account (e.g. a reauthentication). The authentication framework will make
+ * an extra effort to make sure the user account is not compromised. What that exactly means
+ * will depend on the system and user settings; e.g. the user might be required to log in again
+ * unless their last login happened recently, or they might be given a second-factor challenge.
+ *
+ * Calling this method will result in one if these actions:
+ * - return true: all good.
+ * - return false and set a redirect: caller should abort; the redirect will take the user
+ * to the login page for reauthentication, and back.
+ * - throw an exception if there is no way for the user to meet the requirements without using
+ * a different access method (e.g. this functionality is only available from a specific IP).
+ *
+ * Note that this does not in any way check that the user is authorized to use this special page
+ * (use checkPermissions() for that).
+ *
+ * @param string $level A security level. Can be an arbitrary string, defaults to the page name.
+ * @return bool False means a redirect to the reauthentication page has been set and processing
+ * of the special page should be aborted.
+ * @throws ErrorPageError If the security level cannot be met, even with reauthentication.
+ */
+ protected function checkLoginSecurityLevel( $level = null ) {
+ $level = $level ?: $this->getName();
+ $securityStatus = AuthManager::singleton()->securitySensitiveOperationStatus( $level );
+ if ( $securityStatus === AuthManager::SEC_OK ) {
+ return true;
+ } elseif ( $securityStatus === AuthManager::SEC_REAUTH ) {
+ $request = $this->getRequest();
+ $title = SpecialPage::getTitleFor( 'Userlogin' );
+ $query = [
+ 'returnto' => $this->getFullTitle()->getPrefixedDBkey(),
+ 'returntoquery' => wfArrayToCgi( array_diff_key( $request->getQueryValues(),
+ [ 'title' => true ] ) ),
+ 'force' => $level,
+ ];
+ $url = $title->getFullURL( $query, false, PROTO_HTTPS );
+
+ $this->getOutput()->redirect( $url );
+ return false;
+ }
+
+ $titleMessage = wfMessage( 'specialpage-securitylevel-not-allowed-title' );
+ $errorMessage = wfMessage( 'specialpage-securitylevel-not-allowed' );
+ throw new ErrorPageError( $titleMessage, $errorMessage );
+ }
+
/**
* Return an array of subpages beginning with $search that this special page will accept.
*
public function execute( $subPage ) {
$this->setHeaders();
$this->checkPermissions();
+ $this->checkLoginSecurityLevel( $this->getLoginSecurityLevel() );
$this->outputHeader();
}
wfTransactionalTimeLimit();
}
}
+
+ /**
+ * @since 1.28
+ * @return \MediaWiki\Linker\LinkRenderer
+ */
+ protected function getLinkRenderer() {
+ if ( $this->linkRenderer ) {
+ return $this->linkRenderer;
+ } else {
+ return MediaWikiServices::getInstance()->getLinkRenderer();
+ }
+ }
+
+ /**
+ * @since 1.28
+ * @param \MediaWiki\Linker\LinkRenderer $linkRenderer
+ */
+ public function setLinkRenderer( LinkRenderer $linkRenderer ) {
+ $this->linkRenderer = $linkRenderer;
+ }
}