mediawiki-extensions-Confir.../ReCaptcha/ReCaptcha.class.php

183 lines
5.3 KiB
PHP
Raw Normal View History

<?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',
];
}
}