Merge "Fix PerDbnameStatsdDataFactory metric prefix"
[lhc/web/wiklou.git] / includes / specialpage / SpecialPage.php
index 9f666c2..7a39b3c 100644 (file)
@@ -182,7 +182,7 @@ class SpecialPage implements MessageLocalizer {
        /**
         * Get or set whether this special page is listed in Special:SpecialPages
         * @since 1.6
-        * @param bool $x
+        * @param bool|null $x
         * @return bool
         */
        function listed( $x = null ) {
@@ -220,7 +220,7 @@ class SpecialPage implements MessageLocalizer {
 
        /**
         * Whether the special page is being evaluated via transclusion
-        * @param bool $x
+        * @param bool|null $x
         * @return bool
         */
        function including( $x = null ) {
@@ -352,6 +352,23 @@ class SpecialPage implements MessageLocalizer {
                return false;
        }
 
+       /**
+        * Record preserved POST data after a reauthentication.
+        *
+        * This is called from checkLoginSecurityLevel() when returning from the
+        * redirect for reauthentication, if the redirect had been served in
+        * response to a POST request.
+        *
+        * The base SpecialPage implementation does nothing. If your subclass uses
+        * getLoginSecurityLevel() or checkLoginSecurityLevel(), it should probably
+        * implement this to do something with the data.
+        *
+        * @since 1.32
+        * @param array $data
+        */
+       protected function setReauthPostData( array $data ) {
+       }
+
        /**
         * Verifies that the user meets the security level, possibly reauthenticating them in the process.
         *
@@ -371,23 +388,50 @@ class SpecialPage implements MessageLocalizer {
         * 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.
+        * @param string|null $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();
+               $key = 'SpecialPage:reauth:' . $this->getName();
+               $request = $this->getRequest();
+
                $securityStatus = AuthManager::singleton()->securitySensitiveOperationStatus( $level );
                if ( $securityStatus === AuthManager::SEC_OK ) {
+                       $uniqueId = $request->getVal( 'postUniqueId' );
+                       if ( $uniqueId ) {
+                               $key = $key . ':' . $uniqueId;
+                               $session = $request->getSession();
+                               $data = $session->getSecret( $key );
+                               if ( $data ) {
+                                       $session->remove( $key );
+                                       $this->setReauthPostData( $data );
+                               }
+                       }
                        return true;
                } elseif ( $securityStatus === AuthManager::SEC_REAUTH ) {
-                       $request = $this->getRequest();
                        $title = self::getTitleFor( 'Userlogin' );
+                       $queryParams = $request->getQueryValues();
+
+                       if ( $request->wasPosted() ) {
+                               $data = array_diff_assoc( $request->getValues(), $request->getQueryValues() );
+                               if ( $data ) {
+                                       // unique ID in case the same special page is open in multiple browser tabs
+                                       $uniqueId = MWCryptRand::generateHex( 6 );
+                                       $key = $key . ':' . $uniqueId;
+                                       $queryParams['postUniqueId'] = $uniqueId;
+                                       $session = $request->getSession();
+                                       $session->persist(); // Just in case
+                                       $session->setSecret( $key, $data );
+                               }
+                       }
+
                        $query = [
                                'returnto' => $this->getFullTitle()->getPrefixedDBkey(),
-                               'returntoquery' => wfArrayToCgi( array_diff_key( $request->getQueryValues(),
-                                       [ 'title' => true ] ) ),
+                               'returntoquery' => wfArrayToCgi( array_diff_key( $queryParams, [ 'title' => true ] ) ),
                                'force' => $level,
                        ];
                        $url = $title->getFullURL( $query, false, PROTO_HTTPS );
@@ -568,7 +612,10 @@ class SpecialPage implements MessageLocalizer {
        public function execute( $subPage ) {
                $this->setHeaders();
                $this->checkPermissions();
-               $this->checkLoginSecurityLevel( $this->getLoginSecurityLevel() );
+               $securityLevel = $this->getLoginSecurityLevel();
+               if ( $securityLevel !== false && !$this->checkLoginSecurityLevel( $securityLevel ) ) {
+                       return;
+               }
                $this->outputHeader();
        }
 
@@ -615,6 +662,7 @@ class SpecialPage implements MessageLocalizer {
         * @deprecated since 1.23, use SpecialPage::getPageTitle
         */
        function getTitle( $subpage = false ) {
+               wfDeprecated( __METHOD__, '1.23' );
                return $this->getPageTitle( $subpage );
        }
 
@@ -744,10 +792,7 @@ class SpecialPage implements MessageLocalizer {
         * @see wfMessage
         */
        public function msg( $key /* $args */ ) {
-               $message = call_user_func_array(
-                       [ $this->getContext(), 'msg' ],
-                       func_get_args()
-               );
+               $message = $this->getContext()->msg( ...func_get_args() );
                // RequestContext passes context to wfMessage, and the language is set from
                // the context, but setting the language for Message class removes the
                // interface message status, which breaks for example usernameless gender