From 68f3a22654ab5fbc2da48413f6d4ad86fe532a6e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bartosz=20Dziewo=C5=84ski?= Date: Sat, 12 Oct 2013 19:00:23 +0200 Subject: [PATCH] Consistently handle anonymous users on logged-in-only special pages Added new helper function SpecialPage#requireLogin() to check if the current user is logged in and, if not, format an error message linking to Special:Userlogin and throw UserNotLoggedIn exception, to be handled by OutputPage later. Reused old error messages. Not all use the new parameter and they're very inconsistent, but this is a matter for another patch. Used it on 7 special pages. I don't think there are any other ones which specifically require having an account, instead of just some rights usually associated with logged-in users. * SpecialChangeEmail * SpecialChangePassword: It allows anonymous users under specific circumstances, but is logged-in-only in general. * SpecialConfirmemail * SpecialEditWatchlist * SpecialPreferences * SpecialResetTokens: It was missing the check, added it. * SpecialWatchlist Change-Id: I43ceaddb370d09784021b3fc2d5d1ff6616fef1f --- includes/SpecialPage.php | 43 +++++++++++++++++++++ includes/specials/SpecialChangeEmail.php | 8 +--- includes/specials/SpecialChangePassword.php | 10 ++--- includes/specials/SpecialConfirmemail.php | 20 +++------- includes/specials/SpecialEditWatchlist.php | 15 +------ includes/specials/SpecialPreferences.php | 11 +----- includes/specials/SpecialResetTokens.php | 1 + includes/specials/SpecialWatchlist.php | 13 +------ languages/messages/MessagesEn.php | 5 ++- languages/messages/MessagesQqq.php | 8 +++- maintenance/dictionary/mediawiki.dic | 2 +- maintenance/language/messages.inc | 3 +- 12 files changed, 73 insertions(+), 66 deletions(-) diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index a6195fc41e..3aea4d9dd2 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -599,6 +599,49 @@ class SpecialPage { } } + /** + * If the user is not logged in, throws UserNotLoggedIn error. + * + * Default error message includes a link to Special:Userlogin with properly set 'returnto' query + * parameter. + * + * @since 1.23 + * @param string|Message $reasonMsg [optional] Passed on to UserNotLoggedIn constructor. Strings + * will be used as message keys. If a string is given, the message will also receive a + * formatted login link (generated using the 'loginreqlink' message) as first parameter. If a + * Message is given, it will be passed on verbatim. + * @param string|Message $titleMsg [optional] Passed on to UserNotLoggedIn constructor. Strings + * will be used as message keys. + * @throws UserNotLoggedIn + */ + public function requireLogin( $reasonMsg = null, $titleMsg = null ) { + if ( $this->getUser()->isAnon() ) { + // Use default messages if not given or explicit null passed + if ( !$reasonMsg ) { + $reasonMsg = 'exception-nologin-text-manual'; + } + if ( !$titleMsg ) { + $titleMsg = 'exception-nologin'; + } + + // Convert to Messages with current context + if ( is_string( $reasonMsg ) ) { + $loginreqlink = Linker::linkKnown( + SpecialPage::getTitleFor( 'Userlogin' ), + $this->msg( 'loginreqlink' )->escaped(), + array(), + array( 'returnto' => $this->getTitle()->getPrefixedText() ) + ); + $reasonMsg = $this->msg( $reasonMsg )->rawParams( $loginreqlink ); + } + if ( is_string( $titleMsg ) ) { + $titleMsg = $this->msg( $titleMsg ); + } + + throw new UserNotLoggedIn( $reasonMsg, $titleMsg ); + } + } + /** * Sets headers - this should be called from the execute() method of all derived classes! */ diff --git a/includes/specials/SpecialChangeEmail.php b/includes/specials/SpecialChangeEmail.php index d02886f500..e1531ccab0 100644 --- a/includes/specials/SpecialChangeEmail.php +++ b/includes/specials/SpecialChangeEmail.php @@ -75,11 +75,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { $user = $this->getUser(); $request = $this->getRequest(); - if ( !$user->isLoggedIn() ) { - $this->error( 'changeemail-no-info' ); - - return; - } + $this->requireLogin( 'changeemail-no-info' ); if ( $request->wasPosted() && $request->getBool( 'wpCancel' ) ) { $this->doReturnTo(); @@ -92,7 +88,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { // This could also let someone check the current email address, so // require both permissions. - if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) { + if ( !$user->isAllowed( 'viewmyprivateinfo' ) ) { throw new PermissionsError( 'viewmyprivateinfo' ); } diff --git a/includes/specials/SpecialChangePassword.php b/includes/specials/SpecialChangePassword.php index 7fcab1939c..8b96e6c1d5 100644 --- a/includes/specials/SpecialChangePassword.php +++ b/includes/specials/SpecialChangePassword.php @@ -45,6 +45,11 @@ class SpecialChangePassword extends UnlistedSpecialPage { $this->getOutput()->disallowUserJs(); $request = $this->getRequest(); + + if ( !$request->wasPosted() ) { + $this->requireLogin( 'resetpass-no-info' ); + } + $this->mUserName = trim( $request->getVal( 'wpName' ) ); $this->mOldpass = $request->getVal( 'wpPassword' ); $this->mNewpass = $request->getVal( 'wpNewPassword' ); @@ -52,11 +57,6 @@ class SpecialChangePassword extends UnlistedSpecialPage { $this->mDomain = $request->getVal( 'wpDomain' ); $user = $this->getUser(); - if ( !$request->wasPosted() && !$user->isLoggedIn() ) { - $this->error( $this->msg( 'resetpass-no-info' )->text() ); - - return; - } if ( $request->wasPosted() && $request->getBool( 'wpCancel' ) ) { $titleObj = Title::newFromText( $request->getVal( 'returnto' ) ); diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php index 6757990afd..bef155ca8f 100644 --- a/includes/specials/SpecialConfirmemail.php +++ b/includes/specials/SpecialConfirmemail.php @@ -45,6 +45,8 @@ class EmailConfirmation extends UnlistedSpecialPage { $this->checkReadOnly(); $this->checkPermissions(); + $this->requireLogin( 'confirmemail_needlogin' ); + // This could also let someone check the current email address, so // require both permissions. if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) { @@ -52,22 +54,10 @@ class EmailConfirmation extends UnlistedSpecialPage { } if ( $code === null || $code === '' ) { - if ( $this->getUser()->isLoggedIn() ) { - if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) { - $this->showRequestForm(); - } else { - $this->getOutput()->addWikiMsg( 'confirmemail_noemail' ); - } + if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) { + $this->showRequestForm(); } else { - $llink = Linker::linkKnown( - SpecialPage::getTitleFor( 'Userlogin' ), - $this->msg( 'loginreqlink' )->escaped(), - array(), - array( 'returnto' => $this->getTitle()->getPrefixedText() ) - ); - $this->getOutput()->addHTML( - $this->msg( 'confirmemail_needlogin' )->rawParams( $llink )->parse() - ); + $this->getOutput()->addWikiMsg( 'confirmemail_noemail' ); } } else { $this->attemptConfirm( $code ); diff --git a/includes/specials/SpecialEditWatchlist.php b/includes/specials/SpecialEditWatchlist.php index ca2daafbcb..e085240e41 100644 --- a/includes/specials/SpecialEditWatchlist.php +++ b/includes/specials/SpecialEditWatchlist.php @@ -61,21 +61,10 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { public function execute( $mode ) { $this->setHeaders(); - $out = $this->getOutput(); - # Anons don't get a watchlist - if ( $this->getUser()->isAnon() ) { - $out->setPageTitle( $this->msg( 'watchnologin' ) ); - $llink = Linker::linkKnown( - SpecialPage::getTitleFor( 'Userlogin' ), - $this->msg( 'loginreqlink' )->escaped(), - array(), - array( 'returnto' => $this->getTitle()->getPrefixedText() ) - ); - $out->addHTML( $this->msg( 'watchlistanontext' )->rawParams( $llink )->parse() ); + $this->requireLogin( 'watchlistanontext', 'watchnologin' ); - return; - } + $out = $this->getOutput(); $this->checkPermissions(); $this->checkReadOnly(); diff --git a/includes/specials/SpecialPreferences.php b/includes/specials/SpecialPreferences.php index ecee0bb79f..5f4b2084f5 100644 --- a/includes/specials/SpecialPreferences.php +++ b/includes/specials/SpecialPreferences.php @@ -37,14 +37,7 @@ class SpecialPreferences extends SpecialPage { $out = $this->getOutput(); $out->disallowUserJs(); # Prevent hijacked user scripts from sniffing passwords etc. - $user = $this->getUser(); - if ( $user->isAnon() ) { - throw new ErrorPageError( - 'prefsnologin', - 'prefsnologintext', - array( $this->getTitle()->getPrefixedDBkey() ) - ); - } + $this->requireLogin( 'prefsnologintext2', 'prefsnologin' ); $this->checkReadOnly(); if ( $par == 'reset' ) { @@ -62,7 +55,7 @@ class SpecialPreferences extends SpecialPage { ); } - $htmlForm = Preferences::getFormObject( $user, $this->getContext() ); + $htmlForm = Preferences::getFormObject( $this->getUser(), $this->getContext() ); $htmlForm->setSubmitCallback( array( 'Preferences', 'tryUISubmit' ) ); $htmlForm->show(); diff --git a/includes/specials/SpecialResetTokens.php b/includes/specials/SpecialResetTokens.php index ef2a45daad..db98beaeed 100644 --- a/includes/specials/SpecialResetTokens.php +++ b/includes/specials/SpecialResetTokens.php @@ -61,6 +61,7 @@ class SpecialResetTokens extends FormSpecialPage { public function execute( $par ) { // This is a preferences page, so no user JS for y'all. $this->getOutput()->disallowUserJs(); + $this->requireLogin(); parent::execute( $par ); diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php index 336b05bdd1..78216cab6c 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -41,18 +41,7 @@ class SpecialWatchlist extends SpecialPage { $output = $this->getOutput(); # Anons don't get a watchlist - if ( $user->isAnon() ) { - $output->setPageTitle( $this->msg( 'watchnologin' ) ); - $output->setRobotPolicy( 'noindex,nofollow' ); - $llink = Linker::linkKnown( - SpecialPage::getTitleFor( 'Userlogin' ), - $this->msg( 'loginreqlink' )->escaped(), - array(), - array( 'returnto' => $this->getTitle()->getPrefixedText() ) - ); - $output->addHTML( $this->msg( 'watchlistanontext' )->rawParams( $llink )->parse() ); - return; - } + $this->requireLogin( 'watchlistanontext', 'watchnologin' ); // Check permissions $this->checkPermissions(); diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 39f0b8a265..1ef2d5b1d3 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -1085,7 +1085,8 @@ The administrator who locked it offered this explanation: "$3".', 'invalidtitle-knownnamespace' => 'Invalid title with namespace "$2" and text "$3"', 'invalidtitle-unknownnamespace' => 'Invalid title with unknown namespace number $1 and text "$2"', 'exception-nologin' => 'Not logged in', -'exception-nologin-text' => 'This page or action requires you to be logged in on this wiki.', +'exception-nologin-text' => 'Please [[Special:Userlogin|log in]] to be able to access this page or action.', +'exception-nologin-text-manual' => 'Please $1 to be able to access this page or action.', # Virus scanner 'virus-badscanner' => "Bad configuration: Unknown virus scanner: ''$1''", @@ -1899,7 +1900,7 @@ Note that their indexes of {{SITENAME}} content may be out of date.', 'mypreferences' => 'Preferences', 'prefs-edits' => 'Number of edits:', 'prefsnologin' => 'Not logged in', -'prefsnologintext' => 'You must be [{{fullurl:{{#Special:UserLogin}}|returnto=$1}} logged in] to set user preferences.', +'prefsnologintext2' => 'Please $1 to set user preferences.', 'changepassword' => 'Change password', 'changepassword-summary' => '', # do not translate or duplicate this message to other languages 'prefs-skin' => 'Skin', diff --git a/languages/messages/MessagesQqq.php b/languages/messages/MessagesQqq.php index 14a9d3b37d..032fff2716 100644 --- a/languages/messages/MessagesQqq.php +++ b/languages/messages/MessagesQqq.php @@ -1222,6 +1222,10 @@ Parameters: 'exception-nologin' => 'Generic page title used on error page when a user is not logged in. Message used by the UserNotLoggedIn exception. {{Identical|Not logged in}}', 'exception-nologin-text' => 'Generic reason displayed on error page when a user is not logged in. Message used by the UserNotLoggedIn exception.', +'exception-nologin-text-manual' => 'Generic reason displayed on error page when a user is not logged in. + +Parameters: +* $1 - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description', # Virus scanner 'virus-badscanner' => 'Used as error message. Parameters: @@ -2963,8 +2967,8 @@ See also: {{Identical|Preferences}}', 'prefs-edits' => 'In user preferences.', 'prefsnologin' => '{{Identical|Not logged in}}', -'prefsnologintext' => 'Parameters: -* $1 - URI for "returnto" argument', +'prefsnologintext2' => 'Parameters: +* $1 - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description', 'changepassword' => "Section heading on [[Special:Preferences]], tab 'User profile'. {{Identical|Change password}}", 'prefs-skin' => 'Used in user preferences. diff --git a/maintenance/dictionary/mediawiki.dic b/maintenance/dictionary/mediawiki.dic index 164b5b05ec..b6ca281c62 100644 --- a/maintenance/dictionary/mediawiki.dic +++ b/maintenance/dictionary/mediawiki.dic @@ -3127,7 +3127,7 @@ prefixsearchdisabled prefs prefsection prefsnologin -prefsnologintext +prefsnologintext2 prefsubmit preload preloads diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc index 1ac9500164..c149ec6b74 100644 --- a/maintenance/language/messages.inc +++ b/maintenance/language/messages.inc @@ -434,6 +434,7 @@ $wgMessageStructure = array( 'invalidtitle-unknownnamespace', 'exception-nologin', 'exception-nologin-text', + 'exception-nologin-text-manual', ), 'virus' => array( 'virus-badscanner', @@ -1028,7 +1029,7 @@ $wgMessageStructure = array( 'mypreferences', 'prefs-edits', 'prefsnologin', - 'prefsnologintext', + 'prefsnologintext2', 'changepassword', 'changepassword-summary', 'prefs-skin', -- 2.20.1