diff --git a/includes/EditPage.php b/includes/EditPage.php index 00e2aa23b87..0c340725492 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -1958,7 +1958,7 @@ class EditPage implements IEditObject { $query .= $extraQueryRedirect; } $anchor = $resultDetails['sectionanchor'] ?? ''; - $out->redirect( $this->mTitle->getFullURL( $query ) . $anchor ); + $this->doPostEditRedirect( $query, $anchor ); return false; case self::AS_SUCCESS_UPDATE: @@ -1982,7 +1982,7 @@ class EditPage implements IEditObject { $extraQuery .= $extraQueryRedirect; } - $out->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor ); + $this->doPostEditRedirect( $extraQuery, $sectionanchor ); return false; case self::AS_SPAM_ERROR: @@ -2031,6 +2031,29 @@ class EditPage implements IEditObject { } } + /** + * Emit the post-save redirect. The URL is modifiable with a hook. + * + * @param string $query + * @param string $anchor + * @return void + */ + private function doPostEditRedirect( $query, $anchor ) { + $out = $this->context->getOutput(); + $url = $this->mTitle->getFullURL( $query ) . $anchor; + if ( $this->tempUserCreateDone ) { + $this->getHookRunner()->onTempUserCreatedRedirect( + $this->context->getRequest()->getSession(), + $this->context->getUser(), + $this->mTitle->getPrefixedDBkey(), + $query, + $anchor, + $url + ); + } + $out->redirect( $url ); + } + /** * Return the summary to be used for a new section. * diff --git a/includes/Hook/TempUserCreatedRedirectHook.php b/includes/Hook/TempUserCreatedRedirectHook.php new file mode 100644 index 00000000000..e4c23391c92 --- /dev/null +++ b/includes/Hook/TempUserCreatedRedirectHook.php @@ -0,0 +1,38 @@ +container->run( + 'MaintenanceShellStart', + [], + [ 'abortable' => false ] + ); + } + public function onMaintenanceUpdateAddParams( &$params ) { return $this->container->run( 'MaintenanceUpdateAddParams', @@ -3817,6 +3827,20 @@ class HookRunner implements ); } + public function onTempUserCreatedRedirect( + Session $session, + UserIdentity $user, + string $returnTo, + string $returnToQuery, + string $returnToAnchor, + &$redirectUrl + ) { + return $this->container->run( + 'TempUserCreatedRedirect', + [ $session, $user, $returnTo, $returnToQuery, $returnToAnchor, &$redirectUrl ] + ); + } + public function onTestCanonicalRedirect( $request, $title, $output ) { return $this->container->run( 'TestCanonicalRedirect', @@ -4486,12 +4510,4 @@ class HookRunner implements [ $obj, &$out, $row, $text, $rev ] ); } - - public function onMaintenanceShellStart(): void { - $this->container->run( - 'MaintenanceShellStart', - [], - [ 'abortable' => false ] - ); - } } diff --git a/includes/auth/AuthManager.php b/includes/auth/AuthManager.php index 2241a6abb49..c5886f574d5 100644 --- a/includes/auth/AuthManager.php +++ b/includes/auth/AuthManager.php @@ -1722,11 +1722,10 @@ class AuthManager implements LoggerAwareInterface { } } - // Is the username creatable? - if ( $source !== self::AUTOCREATE_SOURCE_TEMP - && !$this->userNameUtils->isCreatable( $username ) - ) { - $this->logger->debug( __METHOD__ . ': name "{username}" is not creatable', [ + // Is the username valid? (Previously isCreatable() was checked here but + // that doesn't work with auto-creation of TempUser accounts by CentralAuth) + if ( !$this->userNameUtils->isValid( $username ) ) { + $this->logger->debug( __METHOD__ . ': name "{username}" is not valid', [ 'username' => $username, ] ); $session->set( 'AuthManager::AutoCreateBlacklist', 'noname' ); diff --git a/includes/specials/helpers/LoginHelper.php b/includes/specials/helpers/LoginHelper.php index 5805d008253..a44b70ad7cd 100644 --- a/includes/specials/helpers/LoginHelper.php +++ b/includes/specials/helpers/LoginHelper.php @@ -66,9 +66,11 @@ class LoginHelper extends ContextSource { * @param array|string $returnToQuery * @param bool $stickHTTPS Keep redirect link on HTTPS. Ignored (treated as * true) if $wgForceHTTPS is true. + * @param string $returnToAnchor A string to append to the URL, presumed to + * be either a fragment including the leading hash or an empty string. */ public function showReturnToPage( - $type, $returnTo = '', $returnToQuery = '', $stickHTTPS = false + $type, $returnTo = '', $returnToQuery = '', $stickHTTPS = false, $returnToAnchor = '' ) { $config = $this->getConfig(); if ( $type !== 'error' && $config->get( MainConfigNames::RedirectOnLogin ) !== null ) { @@ -97,7 +99,8 @@ class LoginHelper extends ContextSource { } if ( $type === 'successredirect' ) { - $redirectUrl = $returnToTitle->getFullUrlForRedirect( $returnToQuery, $proto ); + $redirectUrl = $returnToTitle->getFullUrlForRedirect( $returnToQuery, $proto ) + . $returnToAnchor; $this->getOutput()->redirect( $redirectUrl ); } else { $this->getOutput()->addReturnTo( $returnToTitle, $returnToQuery, null, $options ); diff --git a/tests/phpunit/includes/auth/AuthManagerTest.php b/tests/phpunit/includes/auth/AuthManagerTest.php index 87a3b5fb803..0437cf475e7 100644 --- a/tests/phpunit/includes/auth/AuthManagerTest.php +++ b/tests/phpunit/includes/auth/AuthManagerTest.php @@ -2734,18 +2734,18 @@ class AuthManagerTest extends \MediaWikiIntegrationTestCase { ], $logger->getBuffer() ); $logger->clearBuffer(); - // Uncreatable name + // Invalid name $session->clear(); - $user = \User::newFromName( $username . '@' ); + $user = \User::newFromName( $username . "\u{0080}", false ); $this->hook( 'LocalUserCreated', LocalUserCreatedHook::class, $this->never() ); $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true, true ); $this->unhook( 'LocalUserCreated' ); $this->assertEquals( Status::newFatal( 'noname' ), $ret ); $this->assertSame( 0, $user->getId() ); - $this->assertNotEquals( $username . '@', $user->getId() ); + $this->assertNotEquals( $username . "\u{0080}", $user->getId() ); $this->assertSame( 0, $session->getUser()->getId() ); $this->assertSame( [ - [ LogLevel::DEBUG, 'name "{username}" is not creatable' ], + [ LogLevel::DEBUG, 'name "{username}" is not valid' ], ], $logger->getBuffer() ); $logger->clearBuffer(); $this->assertSame( 'noname', $session->get( 'AuthManager::AutoCreateBlacklist' ) );