wiki.techinc.nl/includes/user/TempUser/RealTempUserConfig.php
Thalia 578f5ea339 RealTempUserConfig: Ensure match pattern is available when known
Why:

* When temporary accounts are known, the match patterns need to
  be available. If no match patterns are set, the match pattern
  is set to an array containing the generate pattern. Therefore
  the generate pattern must also be available if temporary
  accounts are known.
* This was not the case before this commit, and certain settings
  caused an error to be thrown from isTempName.

What:

* Use the generate pattern for the match patterns if temp accounts
  are known and no match patterns are set.
* Update the tests to use a generate pattern but no match pattern
  (the same as the default config).

Change-Id: Iadfbed40b14378a9309e8d7afab6064e25480514
2024-07-19 15:08:15 +01:00

227 lines
6.1 KiB
PHP

<?php
namespace MediaWiki\User\TempUser;
use BadMethodCallException;
use InvalidArgumentException;
use MediaWiki\Permissions\Authority;
use MediaWiki\Utils\MWTimestamp;
use Wikimedia\Rdbms\IExpression;
use Wikimedia\Rdbms\IReadableDatabase;
/**
* The real TempUserConfig including internal methods used by TempUserCreator.
*
* @since 1.39
*/
class RealTempUserConfig implements TempUserConfig {
/** @var bool */
private $known = false;
/** @var bool */
private $enabled = false;
/** @var array */
private $serialProviderConfig = [];
/** @var array */
private $serialMappingConfig = [];
/** @var string[] */
private $autoCreateActions;
/** @var Pattern|null */
private $genPattern;
/** @var Pattern[]|null */
private $matchPatterns;
/** @var Pattern|null */
private $reservedPattern;
/** @var int|null */
private $expireAfterDays;
/** @var int|null */
private $notifyBeforeExpirationDays;
/**
* @param array $config See the documentation of $wgAutoCreateTempUser.
* - known: bool
* - enabled: bool
* - actions: array
* - genPattern: string
* - matchPattern: string|string[], optional
* - reservedPattern: string, optional
* - serialProvider: array
* - serialMapping: array
* - expireAfterDays: int, optional
* - notifyBeforeExpirationDays: int, optional
*/
public function __construct( $config ) {
$this->enabled = $config['enabled'] ?? false;
$this->known = $this->enabled || ( $config['known'] ?? false );
// Configuration related to creating new temporary accounts for some actions
if ( $this->enabled ) {
$this->autoCreateActions = $config['actions'];
$this->serialProviderConfig = $config['serialProvider'];
$this->serialMappingConfig = $config['serialMapping'];
}
// Configuration related to managing and identifying existing temporary accounts,
// regardless of whether new temp accounts are being actively created via the
// 'enabled' config flag.
if ( $this->known || $this->enabled ) {
$this->genPattern = new Pattern( 'genPattern', $config['genPattern'] );
$this->expireAfterDays = $config['expireAfterDays'] ?? null;
$this->notifyBeforeExpirationDays = $config['notifyBeforeExpirationDays'] ?? null;
if ( isset( $config['matchPattern'] ) ) {
$matchPatterns = $config['matchPattern'];
if ( !is_array( $config['matchPattern'] ) ) {
$matchPatterns = [ $matchPatterns ];
}
foreach ( $matchPatterns as &$pattern ) {
$pattern = new Pattern( 'matchPattern', $pattern );
}
$this->matchPatterns = $matchPatterns;
} else {
$this->matchPatterns = [ $this->genPattern ];
}
}
// Configuration that is set regardless of whether the feature is enabled or known.
if ( isset( $config['reservedPattern'] ) ) {
$this->reservedPattern = new Pattern( 'reservedPattern', $config['reservedPattern'] );
}
}
public function isEnabled() {
return $this->enabled;
}
public function isKnown() {
return $this->known;
}
public function isAutoCreateAction( string $action ) {
if ( $action === 'create' ) {
$action = 'edit';
}
return $this->isEnabled()
&& in_array( $action, $this->autoCreateActions, true );
}
public function shouldAutoCreate( Authority $authority, string $action ) {
return $this->isAutoCreateAction( $action )
&& !$authority->isRegistered()
&& $authority->isAllowed( 'createaccount' );
}
public function isTempName( string $name ) {
if ( !$this->isKnown() ) {
return false;
}
foreach ( $this->matchPatterns as $pattern ) {
if ( $pattern->isMatch( $name ) ) {
return true;
}
}
return false;
}
public function isReservedName( string $name ) {
return $this->isTempName( $name ) || ( $this->reservedPattern && $this->reservedPattern->isMatch( $name ) );
}
public function getPlaceholderName(): string {
$year = null;
if ( $this->serialProviderConfig['useYear'] ?? false ) {
$year = MWTimestamp::getInstance()->format( 'Y' );
}
if ( $this->isEnabled() ) {
return $this->genPattern->generate( '*', $year );
} else {
throw new BadMethodCallException( __METHOD__ . ' is disabled' );
}
}
/**
* @deprecated since 1.42.
*/
public function getMatchPattern(): Pattern {
wfDeprecated( __METHOD__, '1.42' );
if ( $this->isKnown() ) {
// This method is deprecated to allow time for callers to update.
// This method only returns one Pattern, so just return the first one.
return $this->getMatchPatterns()[0];
} else {
throw new BadMethodCallException( __METHOD__ . ' is disabled' );
}
}
public function getMatchPatterns(): array {
if ( $this->isKnown() ) {
return $this->matchPatterns;
} else {
throw new BadMethodCallException( __METHOD__ . ' is disabled' );
}
}
public function getMatchCondition( IReadableDatabase $db, string $field, string $op ): IExpression {
if ( $this->isKnown() ) {
$exprs = [];
foreach ( $this->getMatchPatterns() as $pattern ) {
$exprs[] = $db->expr( $field, $op, $pattern->toLikeValue( $db ) );
}
if ( count( $exprs ) === 1 ) {
return $exprs[0];
}
if ( $op === IExpression::LIKE ) {
return $db->orExpr( $exprs );
} elseif ( $op === IExpression::NOT_LIKE ) {
return $db->andExpr( $exprs );
} else {
throw new InvalidArgumentException( "Invalid operator $op" );
}
} else {
throw new BadMethodCallException( __METHOD__ . ' is disabled' );
}
}
public function getExpireAfterDays(): ?int {
return $this->expireAfterDays;
}
public function getNotifyBeforeExpirationDays(): ?int {
return $this->notifyBeforeExpirationDays;
}
/**
* @internal For TempUserCreator only
* @return Pattern
*/
public function getGeneratorPattern(): Pattern {
if ( $this->isEnabled() ) {
return $this->genPattern;
} else {
throw new BadMethodCallException( __METHOD__ . ' is disabled' );
}
}
/**
* @internal For TempUserCreator only
* @return array
*/
public function getSerialProviderConfig(): array {
return $this->serialProviderConfig;
}
/**
* @internal For TempUserCreator only
* @return array
*/
public function getSerialMappingConfig(): array {
return $this->serialMappingConfig;
}
}