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