Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.83% covered (success)
96.83%
61 / 63
83.33% covered (warning)
83.33%
10 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
Recover2FAForUser
96.83% covered (success)
96.83%
61 / 63
83.33% covered (warning)
83.33%
10 / 12
16
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%
10 / 10
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%
29 / 29
100.00% covered (success)
100.00%
1 / 1
5
 onSubmit
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 onSuccess
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Extension\OATHAuth\Special;
4
5use MediaWiki\Extension\OATHAuth\ExpiringRecoveryCodeGenerator;
6use MediaWiki\Extension\OATHAuth\OATHUserRepository;
7use MediaWiki\HTMLForm\HTMLForm;
8use MediaWiki\Linker\LinkRenderer;
9use MediaWiki\SpecialPage\FormSpecialPage;
10use MediaWiki\Status\Status;
11use MediaWiki\User\User;
12
13class Recover2FAForUser extends FormSpecialPage {
14
15    public function __construct(
16        private readonly ExpiringRecoveryCodeGenerator $generator,
17        private readonly LinkRenderer $linkRenderer,
18        private readonly OATHUserRepository $userRepo,
19    ) {
20        // messages used: recover2faforuser (display "name" on Special:SpecialPages)
21        parent::__construct( 'Recover2FAForUser' );
22    }
23
24    /** @inheritDoc */
25    public function getRestriction(): string {
26        // messages used: right-oathauth-recover-for-user, action-oathauth-recover-for-user
27        return 'oathauth-recover-for-user';
28    }
29
30    /** @inheritDoc */
31    protected function getGroupName() {
32        return 'users';
33    }
34
35    /** @inheritDoc */
36    public function doesWrites() {
37        return true;
38    }
39
40    /** @inheritDoc */
41    protected function getLoginSecurityLevel() {
42        return $this->getName();
43    }
44
45    /**
46     * Set the page title and add JavaScript RL modules
47     */
48    public function alterForm( HTMLForm $form ) {
49        $form->setMessagePrefix( 'oathauth' );
50
51        $codesCount = $this->generator->getCodesCount();
52        $legendMsg = $this->msg( 'oathauth-recover-for-user-legend', $codesCount );
53        $introMsg = $this->msg( 'oathauth-recover-intro' )
54            ->params( $codesCount )
55            ->numParams( $codesCount )
56            ->parse();
57        $form->setWrapperLegendMsg( $legendMsg );
58        $form->setPreHtml( $introMsg );
59        $form->getOutput()->setPageTitleMsg( $this->msg( 'oathauth-recover-for-user' ) );
60    }
61
62    /** @inheritDoc */
63    protected function getDisplayFormat() {
64        return 'ooui';
65    }
66
67    /** @inheritDoc */
68    protected function checkExecutePermissions( User $user ) {
69        $this->requireNamedUser();
70
71        parent::checkExecutePermissions( $user );
72    }
73
74    /** @inheritDoc */
75    public function execute( $par ) {
76        $this->getOutput()->disallowUserJs();
77        parent::execute( $par );
78    }
79
80    /** @inheritDoc */
81    protected function getFormFields() {
82        $user = $this->generator->getUserByName( $this->getRequest()->getText( 'user' ) );
83        $oathUser = $user ? $this->userRepo->findByUser( $user ) : null;
84        $showEmailField = $user && $this->generator->getUserEmail( $user ) === null
85            && $oathUser?->isTwoFactorAuthEnabled();
86
87        return [
88            'user' => [
89                'type' => 'user',
90                'default' => '',
91                'label-message' => 'oathauth-enteruser',
92                'name' => 'user',
93                'required' => true,
94                'excludetemp' => true,
95            ],
96            'reason' => [
97                'type' => 'text',
98                'default' => '',
99                'label-message' => 'oathauth-enterrecoverreason',
100                'name' => 'reason',
101                'required' => true,
102            ],
103            'email' => [
104                'type' => $showEmailField ? 'email' : 'hidden',
105                'default' => '',
106                'label-message' => 'oathauth-enterrecoveremail',
107                'help-message' => 'oathauth-enterrecoveremail-help',
108                'name' => 'email',
109                'required' => false,
110            ],
111        ];
112    }
113
114    /** @inheritDoc */
115    public function onSubmit( array $formData ): Status {
116        return $this->generator->attemptToGenerateRecoveryCodes(
117            $this->getUser(),
118            $formData['user'],
119            $formData['email'],
120            $formData['reason']
121        );
122    }
123
124    public function onSuccess() {
125        $targetUser = $this->generator->getTargetUser();
126        $targetUserName = $targetUser->getName();
127        // @phan-suppress-next-line PhanTypeMismatchArgumentNullable; already proven not-null: line above not fatalling
128        $targetUserLink = $this->linkRenderer->makeUserLink( $targetUser, $this->getContext() );
129
130        $successMsg = $this->msg( 'oathauth-recoveredoath' )
131            ->params( $this->generator->getCodesCount(), $targetUserName )
132            ->rawParams( $targetUserLink );
133        $this->getOutput()->addWikiMsg( $successMsg );
134        $this->getOutput()->returnToMain();
135    }
136}