Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.83% covered (success)
94.83%
55 / 58
75.00% covered (warning)
75.00%
9 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
DisableOATHForUser
94.83% covered (success)
94.83%
55 / 58
75.00% covered (warning)
75.00%
9 / 12
17.04
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
 getRestriction
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doesWrites
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLoginSecurityLevel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 alterForm
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getDisplayFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 checkExecutePermissions
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getFormFields
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 onSubmit
96.00% covered (success)
96.00%
24 / 25
0.00% covered (danger)
0.00%
0 / 1
6
 onSuccess
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare( strict_types=1 );
3
4namespace MediaWiki\Extension\OATHAuth\Special;
5
6use MediaWiki\CheckUser\Services\CheckUserInsert;
7use MediaWiki\Extension\OATHAuth\OATHUserRepository;
8use MediaWiki\HTMLForm\HTMLForm;
9use MediaWiki\Logger\LoggerFactory;
10use MediaWiki\Logging\ManualLogEntry;
11use MediaWiki\MediaWikiServices;
12use MediaWiki\Registration\ExtensionRegistry;
13use MediaWiki\SpecialPage\FormSpecialPage;
14use MediaWiki\User\CentralId\CentralIdLookup;
15use MediaWiki\User\User;
16use MediaWiki\User\UserFactory;
17
18class DisableOATHForUser extends FormSpecialPage {
19
20    public function __construct(
21        private readonly OATHUserRepository $userRepo,
22        private readonly UserFactory $userFactory,
23        private readonly CentralIdLookup $centralIdLookup,
24        private readonly ExtensionRegistry $extensionRegistry,
25    ) {
26        // messages used: disableoathforuser (display "name" on Special:SpecialPages)
27        parent::__construct( 'DisableOATHForUser' );
28    }
29
30    /** @inheritDoc */
31    public function getRestriction(): string {
32        // messages used: right-oathauth-disable-for-user, action-oathauth-disable-for-user
33        return 'oathauth-disable-for-user';
34    }
35
36    /** @inheritDoc */
37    protected function getGroupName() {
38        return 'users';
39    }
40
41    /** @inheritDoc */
42    public function doesWrites() {
43        return true;
44    }
45
46    /** @inheritDoc */
47    protected function getLoginSecurityLevel() {
48        return $this->getName();
49    }
50
51    /**
52     * Set the page title and add JavaScript RL modules
53     */
54    public function alterForm( HTMLForm $form ) {
55        $form->setMessagePrefix( 'oathauth' );
56        $form->setWrapperLegendMsg( 'oathauth-disable-for-user' );
57        $form->setPreHtml( $this->msg( 'oathauth-disable-intro' )->parse() );
58        $form->getOutput()->setPageTitleMsg( $this->msg( 'oathauth-disable-for-user' ) );
59    }
60
61    /** @inheritDoc */
62    protected function getDisplayFormat() {
63        return 'ooui';
64    }
65
66    /** @inheritDoc */
67    protected function checkExecutePermissions( User $user ) {
68        $this->requireNamedUser();
69
70        parent::checkExecutePermissions( $user );
71    }
72
73    /** @inheritDoc */
74    public function execute( $par ) {
75        $this->getOutput()->disallowUserJs();
76        parent::execute( $par );
77    }
78
79    /** @inheritDoc */
80    protected function getFormFields() {
81        return [
82            'user' => [
83                'type' => 'user',
84                'default' => '',
85                'label-message' => 'oathauth-enteruser',
86                'name' => 'user',
87                'required' => true,
88                'excludetemp' => true,
89            ],
90            'reason' => [
91                'type' => 'text',
92                'default' => '',
93                'label-message' => 'oathauth-enterdisablereason',
94                'name' => 'reason',
95                'required' => true,
96            ],
97        ];
98    }
99
100    /**
101     * @param array $formData
102     * @return array|bool
103     */
104    public function onSubmit( array $formData ) {
105        $user = $this->userFactory->newFromName( $formData['user'] );
106        // T393253 - Check the username is valid, but don't check if it exists on the local wiki.
107        // Instead, check there is a valid central ID.
108        if ( !$user || $this->centralIdLookup->centralIdFromName( $formData['user'] ) === 0 ) {
109            return [ 'oathauth-user-not-found' ];
110        }
111
112        if ( $this->getUser()->pingLimiter( 'disableoath' ) ) {
113            return [ 'oathauth-throttled' ];
114        }
115
116        $oathUser = $this->userRepo->findByUser( $user );
117
118        if ( !$oathUser->isTwoFactorAuthEnabled() ) {
119            return [ 'oathauth-user-not-does-not-have-oath-enabled' ];
120        }
121
122        $this->userRepo->removeAll( $oathUser, $this->getRequest()->getIP(), false );
123
124        // messages used: logentry-oath-disable-other, log-action-oath-disable-other
125        $logEntry = new ManualLogEntry( 'oath', 'disable-other' );
126        $logEntry->setPerformer( $this->getUser() );
127        $logEntry->setTarget( $user->getUserPage() );
128        $logEntry->setComment( $formData['reason'] );
129        $logId = $logEntry->insert();
130
131        if ( $this->extensionRegistry->isLoaded( 'CheckUser' ) ) {
132            /** @var CheckUserInsert $checkUserInsert */
133            $checkUserInsert = MediaWikiServices::getInstance()->get( 'CheckUserInsert' );
134            $checkUserInsert->updateCheckUserData( $logEntry->getRecentChange( $logId ) );
135        }
136
137        LoggerFactory::getInstance( 'authentication' )->info(
138            'OATHAuth disabled for {usertarget} by {user} from {clientip}', [
139                'user' => $this->getUser()->getName(),
140                'usertarget' => $formData['user'],
141                'clientip' => $this->getRequest()->getIP(),
142            ]
143        );
144
145        return true;
146    }
147
148    public function onSuccess() {
149        $this->getOutput()->addWikiMsg( 'oathauth-disabledoath' );
150        $this->getOutput()->returnToMain();
151    }
152
153}