Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.24% covered (success)
95.24%
20 / 21
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
FilterUser
95.24% covered (success)
95.24%
20 / 21
83.33% covered (warning)
83.33%
5 / 6
9
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
 getAuthority
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUserIdentity
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isSameUserAs
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUser
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
 getFilterUserName
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\Extension\AbuseFilter;
4
5use MediaWiki\Language\MessageLocalizer;
6use MediaWiki\Permissions\Authority;
7use MediaWiki\User\User;
8use MediaWiki\User\UserGroupManager;
9use MediaWiki\User\UserIdentity;
10use MediaWiki\User\UserNameUtils;
11use Psr\Log\LoggerInterface;
12
13class FilterUser {
14    public const SERVICE_NAME = 'AbuseFilterFilterUser';
15
16    public function __construct(
17        private readonly MessageLocalizer $messageLocalizer,
18        private readonly UserGroupManager $userGroupManager,
19        private readonly UserNameUtils $userNameUtils,
20        private readonly LoggerInterface $logger
21    ) {
22    }
23
24    public function getAuthority(): Authority {
25        return $this->getUser();
26    }
27
28    public function getUserIdentity(): UserIdentity {
29        return $this->getUser();
30    }
31
32    /**
33     * Compares the given $user to see if they are the same as the FilterUser.
34     *
35     * @return bool
36     */
37    public function isSameUserAs( UserIdentity $user ): bool {
38        // Checking the usernames are equal is enough, as this is what is done by
39        // User::equals and UserIdentityValue::equals.
40        return $user->getName() === $this->getFilterUserName();
41    }
42
43    /**
44     * @todo Stop using the User class when User::newSystemUser is refactored.
45     * @return User
46     */
47    private function getUser(): User {
48        $user = User::newSystemUser( $this->getFilterUserName(), [ 'steal' => true ] );
49        if ( $user === null ) {
50            throw new \UnexpectedValueException( 'Failed to create AbuseFilter system user' );
51        }
52
53        // Promote user to 'sysop' so it doesn't look
54        // like an unprivileged account is blocking users
55        if ( !in_array( 'sysop', $this->userGroupManager->getUserGroups( $user ) ) ) {
56            $this->userGroupManager->addUserToGroup( $user, 'sysop' );
57        }
58
59        return $user;
60    }
61
62    /**
63     * Gets the username for the FilterUser.
64     */
65    private function getFilterUserName(): string {
66        $username = $this->messageLocalizer->msg( 'abusefilter-blocker' )->inContentLanguage()->text();
67        if ( !$this->userNameUtils->getCanonical( $username ) ) {
68            // User name is invalid. Don't throw because this is a system message, easy
69            // to change and make wrong either by mistake or intentionally to break the site.
70            $this->logger->warning(
71                'The AbuseFilter user\'s name is invalid. Please change it in ' .
72                'MediaWiki:abusefilter-blocker'
73            );
74            // Use the default name to avoid breaking other stuff. This should have no harm,
75            // aside from blocks temporarily attributed to another user.
76            // Don't use the database in case the English onwiki message is broken, T284364
77            $username = $this->messageLocalizer->msg( 'abusefilter-blocker' )
78                ->inLanguage( 'en' )
79                ->useDatabase( false )
80                ->text();
81        }
82        return $username;
83    }
84}