Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
11.11% covered (danger)
11.11%
5 / 45
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
QuestyCaptcha
11.11% covered (danger)
11.11%
5 / 45
16.67% covered (danger)
16.67%
1 / 6
80.23
0.00% covered (danger)
0.00%
0 / 1
 keyMatch
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 describeCaptchaType
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getCaptcha
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getFormInformation
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
6
 getCaptchaInfo
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAuthChangeFormFields
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare( strict_types=1 );
4
5/**
6 * QuestyCaptcha class
7 *
8 * @file
9 * @author Benjamin Lees <emufarmers@gmail.com>
10 * @ingroup Extensions
11 */
12
13namespace MediaWiki\Extension\ConfirmEdit\QuestyCaptcha;
14
15use MediaWiki\Auth\AuthenticationRequest;
16use MediaWiki\Extension\ConfirmEdit\Auth\CaptchaAuthenticationRequest;
17use MediaWiki\Extension\ConfirmEdit\SimpleCaptcha\SimpleCaptcha;
18use MediaWiki\Html\Html;
19use MediaWiki\Output\OutputPage;
20
21class QuestyCaptcha extends SimpleCaptcha {
22    /**
23     * @var string used for questycaptcha-edit, questycaptcha-addurl, questycaptcha-badlogin,
24     * questycaptcha-createaccount, questycaptcha-create, questycaptcha-sendemail via getMessage()
25     */
26    protected static $messagePrefix = 'questycaptcha';
27
28    /**
29     * Validate a CAPTCHA response
30     *
31     * @note Trimming done as per T368112
32     *
33     * @param string $answer
34     * @param array $info
35     * @return bool
36     */
37    protected function keyMatch( $answer, $info ) {
38        if ( is_array( $info['answer'] ) ) {
39            return in_array( strtolower( trim( $answer ) ), array_map( 'strtolower', $info['answer'] ) );
40        } else {
41            return strtolower( trim( $answer ) ) == strtolower( $info['answer'] );
42        }
43    }
44
45    /** @inheritDoc */
46    public function describeCaptchaType( ?string $action = null ) {
47        return [
48            'type' => 'question',
49            'mime' => 'text/html',
50        ];
51    }
52
53    /** @inheritDoc */
54    public function getCaptcha() {
55        global $wgCaptchaQuestions;
56
57        // Backwards compatibility
58        if ( $wgCaptchaQuestions === array_values( $wgCaptchaQuestions ) ) {
59            return $wgCaptchaQuestions[ random_int( 0, count( $wgCaptchaQuestions ) - 1 ) ];
60        }
61
62        $question = array_rand( $wgCaptchaQuestions, 1 );
63        $answer = $wgCaptchaQuestions[ $question ];
64        return [ 'question' => $question, 'answer' => $answer ];
65    }
66
67    /** @inheritDoc */
68    public function getFormInformation( $tabIndex = 1, ?OutputPage $out = null ) {
69        $captcha = $this->getCaptcha();
70        if ( !$captcha ) {
71            die(
72                "No questions found; set some in LocalSettings.php using the format from QuestyCaptcha.php."
73            );
74        }
75        $index = $this->storeCaptcha( $captcha );
76        return [
77            'html' => "<p><label for=\"wpCaptchaWord\">{$captcha['question']}</label> " .
78                Html::element( 'input', [
79                    'name' => 'wpCaptchaWord',
80                    'id'   => 'wpCaptchaWord',
81                    'required',
82                    'autocomplete' => 'off',
83                    // tab in before the edit textarea
84                    'tabindex' => $tabIndex ]
85                ) . "</p>\n" .
86                Html::element( 'input', [
87                    'type'  => 'hidden',
88                    'name'  => 'wpCaptchaId',
89                    'id'    => 'wpCaptchaId',
90                    'value' => $index ]
91                )
92        ];
93    }
94
95    /**
96     * @param array $captchaData
97     * @param string $id
98     * @return mixed
99     */
100    public function getCaptchaInfo( $captchaData, $id ) {
101        return $captchaData['question'];
102    }
103
104    /**
105     * @param array $requests
106     * @param array $fieldInfo
107     * @param array &$formDescriptor
108     * @param string $action
109     */
110    public function onAuthChangeFormFields( array $requests, array $fieldInfo,
111        array &$formDescriptor, $action ) {
112        /** @var CaptchaAuthenticationRequest $req */
113        $req =
114            AuthenticationRequest::getRequestByClass(
115                $requests,
116                CaptchaAuthenticationRequest::class,
117                true
118            );
119        if ( !$req ) {
120            return;
121        }
122
123        // declare RAW HTML output.
124        $formDescriptor['captchaInfo']['raw'] = true;
125        $formDescriptor['captchaWord']['label-message'] = null;
126    }
127}