wiki.techinc.nl/tests/phpunit/integration/includes/user/TempUser/TempUserCreatorTest.php
Ebrahim Byagowi 697e19e461 Add MediaWiki\Registration namespace to registration classes
Bug: T353458
Change-Id: Ifa3b6a6e0353bb4ce21a3f4456f1fc696c8d377c
2024-08-10 10:08:22 +00:00

287 lines
9.6 KiB
PHP

<?php
namespace MediaWiki\Tests\Integration\User\TempUser;
use MediaWiki\Auth\AuthManager;
use MediaWiki\Auth\Throttler;
use MediaWiki\MainConfigNames;
use MediaWiki\Registration\ExtensionRegistry;
use MediaWiki\Request\FauxRequest;
use MediaWiki\Session\Session;
use MediaWiki\Tests\User\TempUser\TempUserTestTrait;
use MediaWiki\User\CentralId\CentralIdLookup;
use MediaWiki\User\TempUser\RealTempUserConfig;
use MediaWiki\User\TempUser\SerialMapping;
use MediaWiki\User\TempUser\SerialProvider;
use MediaWiki\User\TempUser\TempUserCreator;
use MediaWiki\User\UserFactory;
use Wikimedia\TestingAccessWrapper;
use Wikimedia\Timestamp\ConvertibleTimestamp;
/**
* @group Database
* @covers \MediaWiki\User\TempUser\DBSerialProvider
* @covers \MediaWiki\User\TempUser\LocalSerialProvider
* @covers \MediaWiki\User\TempUser\TempUserCreator
* @covers \MediaWiki\User\TempUser\CreateStatus
*/
class TempUserCreatorTest extends \MediaWikiIntegrationTestCase {
use TempUserTestTrait;
public function testCreate() {
$this->enableAutoCreateTempUser( [
'serialProvider' => [ 'type' => 'local', 'useYear' => false ],
'matchPattern' => '~$1',
] );
$tuc = $this->getServiceContainer()->getTempUserCreator();
$this->assertTrue( $tuc->isAutoCreateAction( 'edit' ) );
$this->assertTrue( $tuc->isTempName( '~1' ) );
// Create a temporary account
$status = $tuc->create( null, new FauxRequest() );
$this->assertSame( '~1', $status->getUser()->getName() );
$this->assertSame(
1,
$this->getDb()->newSelectQueryBuilder()
->from( 'logging' )
->join( 'actor', null, 'log_actor=actor_id' )
->where( [ 'actor_name' => '~1', 'log_action' => 'autocreate' ] )
->fetchRowCount(),
'A logging entry indicating the autocreation of ~1 was expected.'
);
// Repeat the test to verify that the serial number increments
$status = $tuc->create( null, new FauxRequest() );
$this->assertSame( '~2', $status->getUser()->getName() );
$this->assertSame(
1,
$this->getDb()->newSelectQueryBuilder()
->from( 'logging' )
->join( 'actor', null, 'log_actor=actor_id' )
->where( [ 'actor_name' => '~2', 'log_action' => 'autocreate' ] )
->fetchRowCount(),
'A logging entry indicating the autocreation of ~2 was expected.'
);
}
private function getTempUserCreatorUnit() {
$scope1 = ExtensionRegistry::getInstance()->setAttributeForTest(
'TempUserSerialProviders',
[
'test' => [
'factory' => static function () {
return new class implements SerialProvider {
public function acquireIndex( int $year = 0 ): int {
return 1;
}
};
}
],
]
);
$scope2 = ExtensionRegistry::getInstance()->setAttributeForTest(
'TempUserSerialMappings',
[
'test' => [
'factory' => static function () {
return new class implements SerialMapping {
public function getSerialIdForIndex( int $index ): string {
$index--;
$adjective = (int)( $index / 2 );
$animal = $index % 2;
return [ 'active' ][$adjective] . ' ' . [ 'aardvark' ][$animal];
}
};
}
]
]
);
$config = new RealTempUserConfig( [
'enabled' => true,
'expireAfterDays' => null,
'actions' => [ 'edit' ],
'genPattern' => '*Unregistered $1',
'matchPattern' => '*$1',
'serialProvider' => [ 'type' => 'test' ],
'serialMapping' => [ 'type' => 'test' ],
] );
$creator = new TempUserCreator(
$config,
$this->createSimpleObjectFactory(),
$this->createMock( UserFactory::class ),
$this->createMock( AuthManager::class ),
$this->createMock( CentralIdLookup::class ),
$this->createMock( Throttler::class ),
$this->createMock( Throttler::class )
);
return [ $creator, [ $scope1, $scope2 ] ];
}
public function testAcquireName_unit() {
[ $creator, $scope ] = $this->getTempUserCreatorUnit();
/** @var TempUserCreator $creator */
$creator = TestingAccessWrapper::newFromObject( $creator );
$this->assertSame(
'*Unregistered active aardvark',
$creator->acquireName( '127.0.0.1' )
);
}
public function testAcquireName_db() {
$this->enableAutoCreateTempUser( [
'serialProvider' => [ 'type' => 'local', 'useYear' => false ],
'matchPattern' => '~$1',
] );
$tuc = TestingAccessWrapper::newFromObject(
$this->getServiceContainer()->getTempUserCreator()
);
$this->assertSame( '~1', $tuc->acquireName( '127.0.0.1' ) );
$this->assertSame( '~2', $tuc->acquireName( '127.0.0.1' ) );
}
public function testAcquireName_dbWithYear() {
$this->enableAutoCreateTempUser( [ 'serialProvider' => [ 'type' => 'local', 'useYear' => true ] ] );
ConvertibleTimestamp::setFakeTime( '20000101000000' );
$tuc = TestingAccessWrapper::newFromObject(
$this->getServiceContainer()->getTempUserCreator()
);
$this->assertSame( '~2000-1', $tuc->acquireName( '127.0.0.1' ) );
$this->assertSame( '~2000-2', $tuc->acquireName( '127.0.0.1' ) );
ConvertibleTimestamp::setFakeTime( '20010101000000' );
$this->assertSame( '~2001-1', $tuc->acquireName( '127.0.0.1' ) );
}
public function testAcquireNameOnDuplicate_db() {
$this->enableAutoCreateTempUser();
$tuc = TestingAccessWrapper::newFromObject(
$this->getServiceContainer()->getTempUserCreator()
);
// Create a temporary account
$this->assertSame( '~2024-1', $tuc->create( null, new FauxRequest() )->value->getName() );
// Reset the user_autocreate_serial table
$this->truncateTable( 'user_autocreate_serial' );
// Because user_autocreate_serial was truncated, the ::acquireName method should
// return null as the code attempts to return a temporary account that already exists.
$this->assertSame( null, $tuc->acquireName( '127.0.0.1' ) );
}
public function testCreateOnDuplicate_db() {
$this->enableAutoCreateTempUser();
$tuc = $this->getServiceContainer()->getTempUserCreator();
// Create a temporary account
$this->assertSame( '~2024-1', $tuc->create( null, new FauxRequest() )->value->getName() );
// Create a temporary account with an existing temporary account username.
$secondCreateStatus = $tuc->create( '~2024-1', new FauxRequest() );
$this->assertStatusError( 'temp-user-unable-to-acquire', $secondCreateStatus );
// Assert that only one log entry for autocreation exists for ~2024-1, as the second call should have not
// created a new log entry.
$this->assertSame(
1,
$this->getDb()->newSelectQueryBuilder()
->from( 'logging' )
->join( 'actor', null, 'log_actor=actor_id' )
->where( [ 'actor_name' => '~2024-1', 'log_action' => 'autocreate' ] )
->fetchRowCount(),
'Only one logging entry indicating the autocreation of ~2024-1 was expected.'
);
}
public function testCreateOnInvalidUsername() {
$this->enableAutoCreateTempUser();
$tuc = $this->getServiceContainer()->getTempUserCreator();
// Attempt to create the temporary account with an invalid username.
$secondCreateStatus = $tuc->create( 'Template:InvalidUsername#test', new FauxRequest() );
$this->assertStatusError( 'internalerror_info', $secondCreateStatus );
}
public function testAcquireNameThrottled() {
$this->enableAutoCreateTempUser();
$this->overrideConfigValue(
MainConfigNames::TempAccountNameAcquisitionThrottle,
[
'count' => 1,
'seconds' => 30 * 86400,
]
);
$tuc = TestingAccessWrapper::newFromObject(
$this->getServiceContainer()->getTempUserCreator()
);
// Create a temporary account
$this->assertSame( '~2024-1', $tuc->create( null, new FauxRequest() )->value->getName() );
// Attempt again; name acquisition should be limited
$this->assertStatusError( 'temp-user-unable-to-acquire', $tuc->create( null, new FauxRequest() ) );
}
public function testAcquireAndStashName() {
/** @var TempUserCreator $creator */
[ $creator, $scope ] = $this->getTempUserCreatorUnit();
$session = new class extends Session {
private $data = [];
public function __construct() {
}
public function __destruct() {
}
public function get( $key, $default = null ) {
return array_key_exists( $key, $this->data ) ? $this->data[$key] : $default;
}
public function set( $key, $value ) {
$this->data[$key] = $value;
}
public function save() {
}
public function getRequest() {
return new FauxRequest();
}
};
$name = $creator->acquireAndStashName( $session );
$this->assertSame( '*Unregistered active aardvark', $name );
$name = $creator->acquireAndStashName( $session );
$this->assertSame( '*Unregistered active aardvark', $name );
}
public function testRateLimit() {
$this->enableAutoCreateTempUser( [
'serialProvider' => [ 'type' => 'local', 'useYear' => false ],
'matchPattern' => '~$1',
] );
$this->overrideConfigValues( [
MainConfigNames::AccountCreationThrottle => [
'count' => 10,
'seconds' => 86400
],
MainConfigNames::TempAccountCreationThrottle => [
'count' => 1,
'seconds' => 86400
],
] );
$tuc = $this->getServiceContainer()->getTempUserCreator();
$status = $tuc->create( null, new FauxRequest() );
$this->assertSame( '~1', $status->getUser()->getName() );
// Repeat creating a temporary account, and verify that this fails due to the rate limit.
$status = $tuc->create( null, new FauxRequest() );
// TODO: Use new message key (T357777, T357802)
$this->assertStatusError( 'acct_creation_throttle_hit', $status );
// If the temporary account creation failed due to the rate limit, then no log entry should have been created.
$this->assertSame(
0,
$this->getDb()->newSelectQueryBuilder()
->from( 'logging' )
->join( 'actor', null, 'log_actor=actor_id' )
->where( [ 'actor_name' => '~2', 'log_action' => 'autocreate' ] )
->fetchRowCount(),
'A logging entry indicating the autocreation of ~2 was not expected.'
);
}
}