mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/ConfirmEdit
synced 2024-12-18 10:53:01 +00:00
f97212acbf
passCaptcha was made protected in I0da671a546700110d789b79a3089460abd9cce3b, but some other extensions used it, provide passCaptchaFromRequest as a replacement. Bug: T135477 Change-Id: I47b2e2fbe3e063cd86e8a2d6bc17ca939472dbe1
183 lines
5.3 KiB
PHP
183 lines
5.3 KiB
PHP
<?php
|
|
|
|
use MediaWiki\Auth\AuthenticationRequest;
|
|
|
|
class ReCaptcha extends SimpleCaptcha {
|
|
// used for recaptcha-edit, recaptcha-addurl, recaptcha-badlogin, recaptcha-createaccount,
|
|
// recaptcha-create, recaptcha-sendemail via getMessage()
|
|
protected static $messagePrefix = 'recaptcha-';
|
|
|
|
// reCAPTHCA error code returned from recaptcha_check_answer
|
|
private $recaptcha_error = null;
|
|
|
|
/**
|
|
* Displays the reCAPTCHA widget.
|
|
* If $this->recaptcha_error is set, it will display an error in the widget.
|
|
* @param OutputPage $out
|
|
*/
|
|
function getForm( OutputPage $out, $tabIndex = 1 ) {
|
|
global $wgReCaptchaPublicKey, $wgReCaptchaTheme;
|
|
|
|
$useHttps = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on' );
|
|
$js = 'var RecaptchaOptions = ' . Xml::encodeJsVar(
|
|
[ 'theme' => $wgReCaptchaTheme, 'tabindex' => $tabIndex ]
|
|
);
|
|
|
|
return Html::inlineScript( $js ) .
|
|
recaptcha_get_html( $wgReCaptchaPublicKey, $this->recaptcha_error, $useHttps );
|
|
}
|
|
|
|
protected function getCaptchaParamsFromRequest( WebRequest $request ) {
|
|
// 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' ) );
|
|
return [ $challenge, $response ];
|
|
}
|
|
|
|
/**
|
|
* Calls the library function recaptcha_check_answer to verify the users input.
|
|
* Sets $this->recaptcha_error if the user is incorrect.
|
|
* @param string $challenge Challenge value
|
|
* @param string $response Response value
|
|
* @return boolean
|
|
*/
|
|
function passCaptcha( $challenge, $response ) {
|
|
global $wgReCaptchaPrivateKey, $wgRequest;
|
|
|
|
if ( $response === null ) {
|
|
// new captcha session
|
|
return false;
|
|
}
|
|
|
|
$ip = $wgRequest->getIP();
|
|
|
|
$recaptcha_response =
|
|
recaptcha_check_answer( $wgReCaptchaPrivateKey, $ip, $challenge, $response );
|
|
|
|
if ( !$recaptcha_response->is_valid ) {
|
|
$this->recaptcha_error = $recaptcha_response->error;
|
|
return false;
|
|
}
|
|
|
|
$recaptcha_error = null;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
function addCaptchaAPI( &$resultArr ) {
|
|
$resultArr['captcha'] = $this->describeCaptchaType();
|
|
$resultArr['captcha']['error'] = $this->recaptcha_error;
|
|
}
|
|
|
|
public function describeCaptchaType() {
|
|
global $wgReCaptchaPublicKey;
|
|
return [
|
|
'type' => 'recaptcha',
|
|
'mime' => 'image/png',
|
|
'key' => $wgReCaptchaPublicKey,
|
|
];
|
|
}
|
|
|
|
public function APIGetAllowedParams( &$module, &$params, $flags ) {
|
|
if ( $flags && $this->isAPICaptchaModule( $module ) ) {
|
|
if ( defined( 'ApiBase::PARAM_HELP_MSG' ) ) {
|
|
$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',
|
|
];
|
|
} else {
|
|
// @todo: Remove this branch when support for MediaWiki < 1.25 is dropped
|
|
$params['recaptcha_challenge_field'] = null;
|
|
$params['recaptcha_response_field'] = null;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @deprecated since MediaWiki 1.25
|
|
*/
|
|
public function APIGetParamDescription( &$module, &$desc ) {
|
|
if ( $this->isAPICaptchaModule( $module ) ) {
|
|
$desc['recaptcha_challenge_field'] = 'Field from the ReCaptcha widget';
|
|
$desc['recaptcha_response_field'] = 'Field from the ReCaptcha widget';
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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 [];
|
|
}
|
|
|
|
public function getCaptchaInfo( $captchaData, $id ) {
|
|
return wfMessage( 'recaptcha-info' );
|
|
}
|
|
|
|
public function createAuthenticationRequest() {
|
|
return new ReCaptchaAuthenticationRequest();
|
|
}
|
|
|
|
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',
|
|
];
|
|
}
|
|
}
|