2023-07-18 00:26:34 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
|
*
|
|
|
|
|
* @file
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use MediaWiki\User\TempUser\TempUserCreator;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Acquire a temporary user username and stash it in the current session, if temp account creation
|
|
|
|
|
* is enabled and the current user is logged out. If a name has already been stashed, returns the
|
|
|
|
|
* same name.
|
|
|
|
|
*
|
|
|
|
|
* If the user later performs an action that results in temp account creation, the stashed username
|
|
|
|
|
* will be used for their account. It may also be used in previews. However, the account is not
|
|
|
|
|
* created yet, and the name is not visible to other users.
|
|
|
|
|
*
|
|
|
|
|
* @ingroup API
|
|
|
|
|
*/
|
|
|
|
|
class ApiAcquireTempUserName extends ApiBase {
|
|
|
|
|
|
|
|
|
|
private TempUserCreator $tempUserCreator;
|
|
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
|
ApiMain $main,
|
|
|
|
|
string $action,
|
|
|
|
|
TempUserCreator $tempUserCreator
|
|
|
|
|
) {
|
|
|
|
|
parent::__construct( $main, $action );
|
|
|
|
|
$this->tempUserCreator = $tempUserCreator;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function execute() {
|
|
|
|
|
// Like TempUserCreator::shouldAutoCreate(), but without the action check
|
|
|
|
|
if ( !$this->tempUserCreator->isEnabled() ) {
|
|
|
|
|
$this->dieWithError( 'apierror-tempuserdisabled', 'tempuserdisabled' );
|
|
|
|
|
}
|
|
|
|
|
if ( $this->getUser()->isRegistered() ) {
|
|
|
|
|
$this->dieWithError( 'apierror-alreadyregistered', 'alreadyregistered' );
|
|
|
|
|
}
|
|
|
|
|
$this->checkUserRightsAny( 'createaccount' );
|
|
|
|
|
|
|
|
|
|
// Checks passed, acquire the name
|
|
|
|
|
$session = $this->getRequest()->getSession();
|
|
|
|
|
$name = $this->tempUserCreator->acquireAndStashName( $session );
|
Handle collisions from SerialProvider::acquireIndex
Why:
* When using the TempUserCreator::create or ::acquireAndStashName to
get temporary account when the chosen username already existed, that
temporary account is treated as if it doesn't exist. This causes
confusing "userexists" errors and also causes the user to be logged
into an already existing temporary account.
* Furthermore, because the user existence check in AuthManager::auto
CreateUser only checks the local wiki, if an existing temporary
account exists globally but not on the local wiki then the code
sign a new user into an existing temporary account.
* This is very bad behaviour, though shouldn't happen unless the
serialMapping configuration uses a SerialMapping class that could
provide duplicates and/or the configuration has been changed to
use a different SerialMapping class.
* There is a need to change the SerialMapping class in use to a
different class, which means that the code will attempt to use
temporary account usernames which already exist.
* As such, the code that is generating the temporary account usernames
based on the SerialMapping and SerialProvider should be aware that
it may produce an already existing temporary account username, even
if the SerialMapping class being used is asserted to never provide
duplicates.
* Therefore, the code that generates temporary account usernames
should always attempt to verify that a automatically generated
temporary account name does not already exist on the wiki.
What:
* Update TempUserCreator::acquireName to check to see if the username
it generates already exists centrally using the CentralIdLookup.
If it does, then the method returns null. Otherwise, the username
that hasn't been used yet is returned.
* Create the private method TempUserCreator::attemptAutoCreate that
attempts an autocreate for a temporary account name, and optionally
logs the account in.
* Update TempUserCreator::create to use ::attemptAutoCreate to
first to check if the account can be created and then again once
the account is created to actually login to that temporary account.
This is done to prevent logins to existing temporary accounts on
the local wiki. The second call to actually perform the login is
necessary as there is no other way to login to a temporary account.
* Update TempUserCreator::acquireAndStashName to respond to the changes
to ::acquireName, such that it returns null if ::acquireName returns
null and also does not modify the session.
* Update EditPage::maybeActivateTempUserCreate to return a Status and
return a good status in all cases except when a temporary account
name could not be acquired.
* Add IEditObject::AS_UNABLE_TO_ACQUIRE_TEMP_ACCOUNT, and use it as
the value of the fatal status returned by EditPage
::internalAttemptSave if a temporary account name could not be
acquired. This will cause the display of a useful error to the
user on edit.
* Update ApiEditPage and ApiAcquireTempUserName to die with an error
if a temporary account username was unable to be acquired.
* Provide tests for the untested ApiAcquireTempUserName.php file
including testing the new behaviour.
* Add and update tests for TempUserCreator.php
Bug: T353390
Change-Id: Id3a316ea0eba544d51d4ffcdfb03e35f4b3c54cc
2023-12-13 22:56:29 +00:00
|
|
|
if ( $name === null ) {
|
|
|
|
|
$this->dieWithError( 'apierror-tempuseracquirefailed', 'tempuseracquirefailed' );
|
|
|
|
|
}
|
2023-07-18 00:26:34 +00:00
|
|
|
|
Handle collisions from SerialProvider::acquireIndex
Why:
* When using the TempUserCreator::create or ::acquireAndStashName to
get temporary account when the chosen username already existed, that
temporary account is treated as if it doesn't exist. This causes
confusing "userexists" errors and also causes the user to be logged
into an already existing temporary account.
* Furthermore, because the user existence check in AuthManager::auto
CreateUser only checks the local wiki, if an existing temporary
account exists globally but not on the local wiki then the code
sign a new user into an existing temporary account.
* This is very bad behaviour, though shouldn't happen unless the
serialMapping configuration uses a SerialMapping class that could
provide duplicates and/or the configuration has been changed to
use a different SerialMapping class.
* There is a need to change the SerialMapping class in use to a
different class, which means that the code will attempt to use
temporary account usernames which already exist.
* As such, the code that is generating the temporary account usernames
based on the SerialMapping and SerialProvider should be aware that
it may produce an already existing temporary account username, even
if the SerialMapping class being used is asserted to never provide
duplicates.
* Therefore, the code that generates temporary account usernames
should always attempt to verify that a automatically generated
temporary account name does not already exist on the wiki.
What:
* Update TempUserCreator::acquireName to check to see if the username
it generates already exists centrally using the CentralIdLookup.
If it does, then the method returns null. Otherwise, the username
that hasn't been used yet is returned.
* Create the private method TempUserCreator::attemptAutoCreate that
attempts an autocreate for a temporary account name, and optionally
logs the account in.
* Update TempUserCreator::create to use ::attemptAutoCreate to
first to check if the account can be created and then again once
the account is created to actually login to that temporary account.
This is done to prevent logins to existing temporary accounts on
the local wiki. The second call to actually perform the login is
necessary as there is no other way to login to a temporary account.
* Update TempUserCreator::acquireAndStashName to respond to the changes
to ::acquireName, such that it returns null if ::acquireName returns
null and also does not modify the session.
* Update EditPage::maybeActivateTempUserCreate to return a Status and
return a good status in all cases except when a temporary account
name could not be acquired.
* Add IEditObject::AS_UNABLE_TO_ACQUIRE_TEMP_ACCOUNT, and use it as
the value of the fatal status returned by EditPage
::internalAttemptSave if a temporary account name could not be
acquired. This will cause the display of a useful error to the
user on edit.
* Update ApiEditPage and ApiAcquireTempUserName to die with an error
if a temporary account username was unable to be acquired.
* Provide tests for the untested ApiAcquireTempUserName.php file
including testing the new behaviour.
* Add and update tests for TempUserCreator.php
Bug: T353390
Change-Id: Id3a316ea0eba544d51d4ffcdfb03e35f4b3c54cc
2023-12-13 22:56:29 +00:00
|
|
|
$session->persist();
|
2023-07-18 00:26:34 +00:00
|
|
|
$this->getResult()->addValue( null, $this->getModuleName(), $name );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function isWriteMode() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function mustBePosted() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|