From: Amir Sarabadani Date: Sun, 19 May 2019 12:21:42 +0000 (+0200) Subject: Deprecate logout token on GET X-Git-Tag: 1.34.0-rc.0~1489^2 X-Git-Url: https://git.cyclocoop.org/%27.WWW_URL.%27admin/?a=commitdiff_plain;h=38bbfde4480f7e7ddae4eef1e6345833df52cacf;p=lhc%2Fweb%2Fwiklou.git Deprecate logout token on GET Special page now only requires POST Bug: T222626 Change-Id: I056a97d466bde8342f7091a110f70bba3f105844 --- diff --git a/includes/skins/SkinTemplate.php b/includes/skins/SkinTemplate.php index ef45d15e2b..a7b7569f0e 100644 --- a/includes/skins/SkinTemplate.php +++ b/includes/skins/SkinTemplate.php @@ -622,7 +622,6 @@ class SkinTemplate extends Skin { $returnto['returnto'] = $page; $query = $request->getVal( 'returntoquery', $this->thisquery ); $paramsArray = wfCgiToArray( $query ); - unset( $paramsArray['logoutToken'] ); $query = wfArrayToCgi( $paramsArray ); if ( $query != '' ) { $returnto['returntoquery'] = $query; @@ -695,8 +694,7 @@ class SkinTemplate extends Skin { 'href' => self::makeSpecialUrl( 'Userlogout', // Note: userlogout link must always contain an & character, otherwise we might not be able // to detect a buggy precaching proxy (T19790) - ( $title->isSpecial( 'Preferences' ) ? [] : $returnto ) - + [ 'logoutToken' => $this->getUser()->getEditToken( 'logoutToken', $this->getRequest() ) ] ), + ( $title->isSpecial( 'Preferences' ) ? [] : $returnto ) ), 'active' => false ]; } diff --git a/includes/specials/SpecialUserLogout.php b/includes/specials/SpecialUserLogout.php index 568327d25b..62010d9fd6 100644 --- a/includes/specials/SpecialUserLogout.php +++ b/includes/specials/SpecialUserLogout.php @@ -26,7 +26,7 @@ * * @ingroup SpecialPage */ -class SpecialUserLogout extends UnlistedSpecialPage { +class SpecialUserLogout extends FormSpecialPage { function __construct() { parent::__construct( 'Userlogout' ); } @@ -35,41 +35,49 @@ class SpecialUserLogout extends UnlistedSpecialPage { return true; } - function execute( $par ) { - /** - * Some satellite ISPs use broken precaching schemes that log people out straight after - * they're logged in (T19790). Luckily, there's a way to detect such requests. - */ - if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '&' ) !== false ) { - wfDebug( "Special:UserLogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n" ); - throw new HttpError( 400, $this->msg( 'suspicious-userlogout' ), $this->msg( 'loginerror' ) ); - } + public function isListed() { + return false; + } - $this->setHeaders(); - $this->outputHeader(); + protected function getGroupName() { + return 'login'; + } - $out = $this->getOutput(); - $user = $this->getUser(); - $request = $this->getRequest(); + protected function getFormFields() { + return []; + } - $logoutToken = $request->getVal( 'logoutToken' ); - $urlParams = [ - 'logoutToken' => $user->getEditToken( 'logoutToken', $request ) - ] + $request->getValues(); - unset( $urlParams['title'] ); - $continueLink = $this->getFullTitle()->getFullUrl( $urlParams ); + protected function getDisplayFormat() { + return 'ooui'; + } - if ( $logoutToken === null ) { - $this->getOutput()->addWikiMsg( 'userlogout-continue', $continueLink ); - return; - } - if ( !$this->getUser()->matchEditToken( - $logoutToken, 'logoutToken', $this->getRequest(), 24 * 60 * 60 - ) ) { - $this->getOutput()->addWikiMsg( 'userlogout-sessionerror', $continueLink ); + public function execute( $par ) { + if ( $this->getUser()->isAnon() ) { + $this->setHeaders(); + $this->showSuccess(); return; } + parent::execute( $par ); + } + + public function alterForm( HTMLForm $form ) { + $form->setTokenSalt( 'logoutToken' ); + $form->addHeaderText( $this->msg( 'userlogout-continue' ) ); + + $form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) ); + } + + /** + * Process the form. At this point we know that the user passes all the criteria in + * userCanExecute(), and if the data array contains 'Username', etc, then Username + * resets are allowed. + * @param array $data + * @throws MWException + * @throws ThrottledError|PermissionsError + * @return Status + */ + public function onSubmit( array $data ) { // Make sure it's possible to log out $session = MediaWiki\Session\SessionManager::getGlobalSession(); if ( !$session->canSetUser() ) { @@ -83,25 +91,37 @@ class SpecialUserLogout extends UnlistedSpecialPage { } $user = $this->getUser(); - $oldName = $user->getName(); $user->logout(); + return new Status(); + } - $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL( - $this->getRequest()->getValues( 'returnto', 'returntoquery' ) ); + public function onSuccess() { + $this->showSuccess(); + $user = $this->getUser(); + $oldName = $user->getName(); $out = $this->getOutput(); - $out->addWikiMsg( 'logouttext', $loginURL ); - // Hook. $injected_html = ''; Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] ); $out->addHTML( $injected_html ); + } + + private function showSuccess() { + $loginURL = SpecialPage::getTitleFor( 'Userlogin' )->getFullURL( + $this->getRequest()->getValues( 'returnto', 'returntoquery' ) ); + + $out = $this->getOutput(); + $out->addWikiMsg( 'logouttext', $loginURL ); $out->returnToMain(); } - protected function getGroupName() { - return 'login'; + /** + * Let blocked users to log out and come back with their sockpuppets + */ + public function requiresUnblock() { + return false; } } diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 71f56332d2..1243afe6b8 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -4222,6 +4222,5 @@ "passwordpolicies-policyflag-suggestchangeonlogin": "suggest change on login", "easydeflate-invaliddeflate": "Content provided is not properly deflated", "unprotected-js": "For security reasons JavaScript cannot be loaded from unprotected pages. Please only create javascript in the MediaWiki: namespace or as a User subpage", - "userlogout-continue": "If you wish to log out please [$1 continue to the log out page].", - "userlogout-sessionerror": "Log out failed due to session error. Please [$1 try again]." + "userlogout-continue": "Do you want to log out?" } diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 4c835af93c..76133d8461 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -4429,6 +4429,5 @@ "passwordpolicies-policyflag-suggestchangeonlogin": "Password policy flag that suggests changing invalid passwords on login.", "easydeflate-invaliddeflate": "Error message if the content passed to easydeflate was not deflated (compressed) properly", "unprotected-js": "Error message shown when trying to load javascript via action=raw that is not protected", - "userlogout-continue": "Shown if user attempted to log out without a token specified. Probably the user clicked on an old link that hasn't been updated to use the new system. $1 - url that user should click on in order to log out.", - "userlogout-sessionerror": "Shown when a user tries to log out with an invalid token. $1 is url with correct token that user should click." + "userlogout-continue": "Shown if user attempted to log out without a token specified. Probably the user clicked on an old link that hasn't been updated to use the new system. $1 - url that user should click on in order to log out." } diff --git a/resources/src/mediawiki.page.ready.js b/resources/src/mediawiki.page.ready.js index 630e3a6465..4eba81d5ca 100644 --- a/resources/src/mediawiki.page.ready.js +++ b/resources/src/mediawiki.page.ready.js @@ -65,8 +65,6 @@ api.postWithToken( 'csrf', { action: 'logout' } ).done( function () { - // Horrible hack until deprecation of logoutToken in GET is done - returnUrl = returnUrl.replace( /logoutToken=.+?($|&)/g, 'logoutToken=%2B%5C' ); window.location = returnUrl; } ).fail( function ( e ) { mw.notify(