Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.89% covered (warning)
88.89%
16 / 18
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbuseFilterPreAuthenticationProvider
88.89% covered (warning)
88.89%
16 / 18
50.00% covered (danger)
50.00%
2 / 4
7.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 testForAccountCreation
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 testUserForCreation
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 testUser
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
2.00
1<?php
2
3namespace MediaWiki\Extension\AbuseFilter;
4
5use MediaWiki\Auth\AbstractPreAuthenticationProvider;
6use MediaWiki\Auth\AuthenticationRequest;
7use MediaWiki\Extension\AbuseFilter\VariableGenerator\VariableGeneratorFactory;
8use MediaWiki\SpecialPage\SpecialPage;
9use MediaWiki\User\User;
10use MediaWiki\User\UserFactory;
11use StatusValue;
12use Wikimedia\Stats\StatsFactory;
13use Wikimedia\Timestamp\ConvertibleTimestamp;
14
15/**
16 * AuthenticationProvider used to filter account creations. This runs after normal preauth providers
17 * to keep the log cleaner.
18 */
19class AbuseFilterPreAuthenticationProvider extends AbstractPreAuthenticationProvider {
20
21    public function __construct(
22        private readonly VariableGeneratorFactory $variableGeneratorFactory,
23        private readonly FilterRunnerFactory $filterRunnerFactory,
24        private readonly StatsFactory $statsFactory,
25        private readonly UserFactory $userFactory
26    ) {
27    }
28
29    /**
30     * @param User $user
31     * @param User $creator
32     * @param AuthenticationRequest[] $reqs
33     * @return StatusValue
34     */
35    public function testForAccountCreation( $user, $creator, array $reqs ): StatusValue {
36        return $this->testUser( $user, $creator, false );
37    }
38
39    /**
40     * @param User $user
41     * @param bool|string $autocreate
42     * @param array $options
43     * @return StatusValue
44     */
45    public function testUserForCreation( $user, $autocreate, array $options = [] ): StatusValue {
46        // if this is not an autocreation, testForAccountCreation already handled it
47        if ( $autocreate && !( $options['canAlwaysAutocreate'] ?? false ) ) {
48            // Make sure to use an anon as the creator, see T272244
49            return $this->testUser( $user, $this->userFactory->newAnonymous(), true );
50        }
51        return StatusValue::newGood();
52    }
53
54    /**
55     * @param User $user The user being created or autocreated
56     * @param User $creator The user who caused $user to be created (can be anonymous)
57     * @param bool $autocreate Is this an autocreation?
58     * @return StatusValue
59     */
60    private function testUser( $user, $creator, $autocreate ): StatusValue {
61        $startTime = ConvertibleTimestamp::hrtime();
62        if ( $user->getName() === wfMessage( 'abusefilter-blocker' )->inContentLanguage()->text() ) {
63            return StatusValue::newFatal( 'abusefilter-accountreserved' );
64        }
65
66        $title = SpecialPage::getTitleFor( 'Userlogin' );
67        $builder = $this->variableGeneratorFactory->newRunGenerator( $creator, $title );
68        $vars = $builder->getAccountCreationVars( $user, $autocreate );
69
70        // pass creator in explicitly to prevent recording the current user on autocreation - T135360
71        $runner = $this->filterRunnerFactory->newRunner( $creator, $title, $vars, 'default' );
72        $status = $runner->run();
73
74        $this->statsFactory->withComponent( 'AbuseFilter' )
75            ->getTiming( 'filter_run_duration_seconds' )
76            ->setLabel( 'action', 'createaccount' )
77            ->observeNanoseconds( ConvertibleTimestamp::hrtime() - $startTime );
78
79        return $status->getStatusValue();
80    }
81}