2012-01-11 23:24:21 +00:00
|
|
|
<?php
|
|
|
|
|
2016-05-03 16:42:00 +00:00
|
|
|
use MediaWiki\Auth\AuthenticationRequest;
|
|
|
|
|
2012-01-11 23:24:21 +00:00
|
|
|
class ReCaptcha extends SimpleCaptcha {
|
2016-04-25 20:58:18 +00:00
|
|
|
// used for recaptcha-edit, recaptcha-addurl, recaptcha-badlogin, recaptcha-createaccount,
|
|
|
|
// recaptcha-create, recaptcha-sendemail via getMessage()
|
|
|
|
protected static $messagePrefix = 'recaptcha-';
|
|
|
|
|
2012-01-12 08:58:40 +00:00
|
|
|
// reCAPTHCA error code returned from recaptcha_check_answer
|
2012-01-11 23:24:21 +00:00
|
|
|
private $recaptcha_error = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Displays the reCAPTCHA widget.
|
|
|
|
* If $this->recaptcha_error is set, it will display an error in the widget.
|
2017-09-09 18:10:12 +00:00
|
|
|
* @param int $tabIndex
|
|
|
|
* @return array
|
2012-01-11 23:24:21 +00:00
|
|
|
*/
|
Remove getForm() and replace by getFormInformation()
This commit removes SimpleCaptcha::getForm() and replaces it by its more informative
counterpart getFormInformation(), which returns an array, which provides some
more information about the form than only the html.
The information included in the array is:
* html: The HTML of the CAPTCHA form (this is the same as what you expected from
getForm() previously)
* modules: ResourceLoader modules, if any, that should be added to the output of the
page
* modulestyles: ResourceLoader style modules, if any, that should be added to th
output of the page
* headitems: Head items that should be added to the output (see OutputPage::addHeadItems)
Mostly you shouldn't need to handle the response of getFormInformation() anymore, as there's
a new function, addFormToOutput(), which takes an instance of OutputPage as a first parameter
and handles the response of getFormInformation for you (adds all information to the given
OutputPage instance, if they're provided).
Bug: T141300
Depends-On: I433afd124b57526caa13a540cda48ba2b99a9bde
Change-Id: I25f344538052fc18993c43185fbd97804a7cfc81
2016-07-26 16:08:42 +00:00
|
|
|
function getFormInformation( $tabIndex = 1 ) {
|
2012-01-11 23:24:21 +00:00
|
|
|
global $wgReCaptchaPublicKey, $wgReCaptchaTheme;
|
2012-01-12 08:58:40 +00:00
|
|
|
|
2016-11-18 17:45:52 +00:00
|
|
|
wfDeprecated( 'ConfirmEdit module ReCaptcha', '1.28' );
|
2012-01-11 23:24:21 +00:00
|
|
|
$useHttps = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on' );
|
2015-10-28 15:52:04 +00:00
|
|
|
$js = 'var RecaptchaOptions = ' . Xml::encodeJsVar(
|
2016-05-09 23:41:17 +00:00
|
|
|
[ 'theme' => $wgReCaptchaTheme, 'tabindex' => $tabIndex ]
|
2015-10-28 15:52:04 +00:00
|
|
|
);
|
2012-01-11 23:24:21 +00:00
|
|
|
|
Remove getForm() and replace by getFormInformation()
This commit removes SimpleCaptcha::getForm() and replaces it by its more informative
counterpart getFormInformation(), which returns an array, which provides some
more information about the form than only the html.
The information included in the array is:
* html: The HTML of the CAPTCHA form (this is the same as what you expected from
getForm() previously)
* modules: ResourceLoader modules, if any, that should be added to the output of the
page
* modulestyles: ResourceLoader style modules, if any, that should be added to th
output of the page
* headitems: Head items that should be added to the output (see OutputPage::addHeadItems)
Mostly you shouldn't need to handle the response of getFormInformation() anymore, as there's
a new function, addFormToOutput(), which takes an instance of OutputPage as a first parameter
and handles the response of getFormInformation for you (adds all information to the given
OutputPage instance, if they're provided).
Bug: T141300
Depends-On: I433afd124b57526caa13a540cda48ba2b99a9bde
Change-Id: I25f344538052fc18993c43185fbd97804a7cfc81
2016-07-26 16:08:42 +00:00
|
|
|
return [
|
|
|
|
'html' => Html::inlineScript( $js ) .
|
|
|
|
recaptcha_get_html( $wgReCaptchaPublicKey, $this->recaptcha_error, $useHttps )
|
|
|
|
];
|
2016-05-03 16:42:00 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
|
|
|
* @param WebRequest $request
|
|
|
|
* @return array
|
|
|
|
*/
|
2016-05-17 17:55:28 +00:00
|
|
|
protected function getCaptchaParamsFromRequest( WebRequest $request ) {
|
2016-05-03 16:42:00 +00:00
|
|
|
// API is hardwired to return captchaId and captchaWord,
|
|
|
|
// so use that if the standard two are empty
|
|
|
|
$challenge = $request->getVal( 'recaptcha_challenge_field', $request->getVal( 'captchaId' ) );
|
|
|
|
$response = $request->getVal( 'recaptcha_response_field', $request->getVal( 'captchaWord' ) );
|
2016-05-17 17:55:28 +00:00
|
|
|
return [ $challenge, $response ];
|
2012-01-11 23:24:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls the library function recaptcha_check_answer to verify the users input.
|
|
|
|
* Sets $this->recaptcha_error if the user is incorrect.
|
2016-05-03 16:42:00 +00:00
|
|
|
* @param string $challenge Challenge value
|
|
|
|
* @param string $response Response value
|
2017-09-01 04:47:36 +00:00
|
|
|
* @return bool
|
2012-01-11 23:24:21 +00:00
|
|
|
*/
|
2016-05-03 16:42:00 +00:00
|
|
|
function passCaptcha( $challenge, $response ) {
|
2012-01-11 23:24:21 +00:00
|
|
|
global $wgReCaptchaPrivateKey, $wgRequest;
|
|
|
|
|
|
|
|
if ( $response === null ) {
|
2012-01-12 08:58:40 +00:00
|
|
|
// new captcha session
|
2012-01-11 23:24:21 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-02 12:26:25 +00:00
|
|
|
$ip = $wgRequest->getIP();
|
2012-03-18 16:07:21 +00:00
|
|
|
|
2016-05-03 16:42:00 +00:00
|
|
|
$recaptcha_response =
|
|
|
|
recaptcha_check_answer( $wgReCaptchaPrivateKey, $ip, $challenge, $response );
|
2012-01-11 23:24:21 +00:00
|
|
|
|
2012-01-12 08:58:40 +00:00
|
|
|
if ( !$recaptcha_response->is_valid ) {
|
2012-01-11 23:24:21 +00:00
|
|
|
$this->recaptcha_error = $recaptcha_response->error;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$recaptcha_error = null;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
2017-09-09 18:10:12 +00:00
|
|
|
* @param array &$resultArr
|
2017-02-17 13:24:49 +00:00
|
|
|
*/
|
2012-01-11 23:24:21 +00:00
|
|
|
function addCaptchaAPI( &$resultArr ) {
|
2016-04-25 20:58:18 +00:00
|
|
|
$resultArr['captcha'] = $this->describeCaptchaType();
|
2012-01-11 23:24:21 +00:00
|
|
|
$resultArr['captcha']['error'] = $this->recaptcha_error;
|
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2016-04-25 20:58:18 +00:00
|
|
|
public function describeCaptchaType() {
|
|
|
|
global $wgReCaptchaPublicKey;
|
|
|
|
return [
|
|
|
|
'type' => 'recaptcha',
|
|
|
|
'mime' => 'image/png',
|
|
|
|
'key' => $wgReCaptchaPublicKey,
|
|
|
|
];
|
2012-01-11 23:24:21 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
2017-09-09 18:10:12 +00:00
|
|
|
* @param ApiBase &$module
|
|
|
|
* @param array &$params
|
2017-02-17 13:24:49 +00:00
|
|
|
* @param int $flags
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-03-16 15:42:51 +00:00
|
|
|
public function APIGetAllowedParams( &$module, &$params, $flags ) {
|
|
|
|
if ( $flags && $this->isAPICaptchaModule( $module ) ) {
|
2016-09-20 18:49:32 +00:00
|
|
|
$params['recaptcha_challenge_field'] = [
|
|
|
|
ApiBase::PARAM_HELP_MSG => 'recaptcha-apihelp-param-recaptcha_challenge_field',
|
|
|
|
];
|
|
|
|
$params['recaptcha_response_field'] = [
|
|
|
|
ApiBase::PARAM_HELP_MSG => 'recaptcha-apihelp-param-recaptcha_response_field',
|
|
|
|
];
|
2013-03-16 15:42:51 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 23:24:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-05-03 16:42:00 +00:00
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
|
|
|
* @return null
|
|
|
|
*/
|
2016-05-03 16:42:00 +00:00
|
|
|
public function getError() {
|
|
|
|
// do not treat failed captcha attempts as errors
|
|
|
|
if ( in_array( $this->recaptcha_error, [
|
|
|
|
'invalid-request-cookie', 'incorrect-captcha-sol',
|
|
|
|
], true ) ) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->recaptcha_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function storeCaptcha( $info ) {
|
|
|
|
// ReCaptcha is stored by Google; the ID will be generated at that time as well, and
|
|
|
|
// the one returned here won't be used. Just pretend this worked.
|
|
|
|
return 'not used';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function retrieveCaptcha( $index ) {
|
|
|
|
// just pretend it worked
|
|
|
|
return [ 'index' => $index ];
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCaptcha() {
|
|
|
|
// ReCaptcha is handled by frontend code + an external provider; nothing to do here.
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
|
|
|
* @param array $captchaData
|
|
|
|
* @param string $id
|
|
|
|
* @return Message
|
|
|
|
*/
|
2016-05-03 16:42:00 +00:00
|
|
|
public function getCaptchaInfo( $captchaData, $id ) {
|
|
|
|
return wfMessage( 'recaptcha-info' );
|
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
|
|
|
* @return ReCaptchaAuthenticationRequest
|
|
|
|
*/
|
2016-05-03 16:42:00 +00:00
|
|
|
public function createAuthenticationRequest() {
|
|
|
|
return new ReCaptchaAuthenticationRequest();
|
|
|
|
}
|
|
|
|
|
2017-02-17 13:24:49 +00:00
|
|
|
/**
|
|
|
|
* @param array $requests
|
|
|
|
* @param array $fieldInfo
|
2017-09-09 18:10:12 +00:00
|
|
|
* @param array &$formDescriptor
|
2017-02-17 13:24:49 +00:00
|
|
|
* @param string $action
|
|
|
|
*/
|
2016-05-03 16:42:00 +00:00
|
|
|
public function onAuthChangeFormFields(
|
|
|
|
array $requests, array $fieldInfo, array &$formDescriptor, $action
|
|
|
|
) {
|
|
|
|
global $wgReCaptchaPublicKey, $wgReCaptchaTheme;
|
|
|
|
|
|
|
|
$req = AuthenticationRequest::getRequestByClass( $requests,
|
|
|
|
CaptchaAuthenticationRequest::class, true );
|
|
|
|
if ( !$req ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ugly way to retrieve error information
|
|
|
|
$captcha = ConfirmEditHooks::getInstance();
|
|
|
|
|
|
|
|
$formDescriptor['captchaInfo'] = [
|
|
|
|
'class' => HTMLReCaptchaField::class,
|
|
|
|
'key' => $wgReCaptchaPublicKey,
|
|
|
|
'theme' => $wgReCaptchaTheme,
|
|
|
|
'secure' => isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on',
|
|
|
|
'error' => $captcha->getError(),
|
|
|
|
] + $formDescriptor['captchaInfo'];
|
|
|
|
|
|
|
|
// the custom form element cannot return multiple fields; work around that by
|
|
|
|
// "redirecting" ReCaptcha names to standard names
|
|
|
|
$formDescriptor['captchaId'] = [
|
|
|
|
'class' => HTMLSubmittedValueField::class,
|
|
|
|
'name' => 'recaptcha_challenge_field',
|
|
|
|
];
|
|
|
|
$formDescriptor['captchaWord'] = [
|
|
|
|
'class' => HTMLSubmittedValueField::class,
|
|
|
|
'name' => 'recaptcha_response_field',
|
|
|
|
];
|
|
|
|
}
|
2012-01-11 23:24:21 +00:00
|
|
|
}
|