mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/ConfirmEdit
synced 2024-11-23 15:56:50 +00:00
e566dcb966
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
230 lines
6.7 KiB
PHP
230 lines
6.7 KiB
PHP
<?php
|
|
|
|
use MediaWiki\Auth\AuthenticationRequest;
|
|
|
|
class ReCaptchaNoCaptcha extends SimpleCaptcha {
|
|
// used for renocaptcha-edit, renocaptcha-addurl, renocaptcha-badlogin, renocaptcha-createaccount,
|
|
// renocaptcha-create, renocaptcha-sendemail via getMessage()
|
|
protected static $messagePrefix = 'renocaptcha-';
|
|
|
|
private $error = null;
|
|
/**
|
|
* Get the captcha form.
|
|
* @return array
|
|
*/
|
|
function getFormInformation( $tabIndex = 1 ) {
|
|
global $wgReCaptchaSiteKey, $wgLang;
|
|
$lang = htmlspecialchars( urlencode( $wgLang->getCode() ) );
|
|
|
|
$output = Html::element( 'div', [
|
|
'class' => [
|
|
'g-recaptcha',
|
|
'mw-confirmedit-captcha-fail' => !!$this->error,
|
|
],
|
|
'data-sitekey' => $wgReCaptchaSiteKey
|
|
] );
|
|
$htmlUrlencoded = htmlspecialchars( urlencode( $wgReCaptchaSiteKey ) );
|
|
$output .= <<<HTML
|
|
<noscript>
|
|
<div>
|
|
<div style="width: 302px; height: 422px; position: relative;">
|
|
<div style="width: 302px; height: 422px; position: absolute;">
|
|
<iframe src="https://www.google.com/recaptcha/api/fallback?k={$htmlUrlencoded}&hl={$lang}"
|
|
frameborder="0" scrolling="no"
|
|
style="width: 302px; height:422px; border-style: none;">
|
|
</iframe>
|
|
</div>
|
|
</div>
|
|
<div style="width: 300px; height: 60px; border-style: none;
|
|
bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px;
|
|
background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;">
|
|
<textarea id="g-recaptcha-response" name="g-recaptcha-response"
|
|
class="g-recaptcha-response"
|
|
style="width: 250px; height: 40px; border: 1px solid #c1c1c1;
|
|
margin: 10px 25px; padding: 0px; resize: none;" >
|
|
</textarea>
|
|
</div>
|
|
</div>
|
|
</noscript>
|
|
HTML;
|
|
return [
|
|
'html' => $output,
|
|
'headitems' => [
|
|
// Insert reCAPTCHA script, in display language, if available.
|
|
// Language falls back to the browser's display language.
|
|
// See https://developers.google.com/recaptcha/docs/faq
|
|
"<script src=\"https://www.google.com/recaptcha/api.js?hl={$lang}\" async defer></script>"
|
|
]
|
|
];
|
|
}
|
|
|
|
protected function logCheckError( $info ) {
|
|
if ( $info instanceof Status ) {
|
|
$errors = $info->getErrorsArray();
|
|
$error = $errors[0][0];
|
|
} elseif ( is_array( $info ) ) {
|
|
$error = implode( ',', $info );
|
|
} else {
|
|
$error = $info;
|
|
}
|
|
|
|
wfDebugLog( 'captcha', 'Unable to validate response: ' . $error );
|
|
}
|
|
|
|
protected function getCaptchaParamsFromRequest( WebRequest $request ) {
|
|
$index = 'not used'; // ReCaptchaNoCaptcha combines captcha ID + solution into a single value
|
|
// API is hardwired to return captchaWord, so use that if the standard isempty
|
|
$response = $request->getVal( 'g-recaptcha-response', $request->getVal( 'captchaWord' ) );
|
|
return [ $index, $response ];
|
|
}
|
|
|
|
/**
|
|
* Check, if the user solved the captcha.
|
|
*
|
|
* Based on reference implementation:
|
|
* https://github.com/google/recaptcha#php
|
|
*
|
|
* @param $_ mixed Not used (ReCaptcha v2 puts index and solution in a single string)
|
|
* @param $word string captcha solution
|
|
* @return boolean
|
|
*/
|
|
function passCaptcha( $_, $word ) {
|
|
global $wgRequest, $wgReCaptchaSecretKey, $wgReCaptchaSendRemoteIP;
|
|
|
|
$url = 'https://www.google.com/recaptcha/api/siteverify';
|
|
// Build data to append to request
|
|
$data = [
|
|
'secret' => $wgReCaptchaSecretKey,
|
|
'response' => $word,
|
|
];
|
|
if ( $wgReCaptchaSendRemoteIP ) {
|
|
$data['remoteip'] = $wgRequest->getIP();
|
|
}
|
|
$url = wfAppendQuery( $url, $data );
|
|
$request = MWHttpRequest::factory( $url, [ 'method' => 'GET' ] );
|
|
$status = $request->execute();
|
|
if ( !$status->isOK() ) {
|
|
$this->error = 'http';
|
|
$this->logCheckError( $status );
|
|
return false;
|
|
}
|
|
$response = FormatJson::decode( $request->getContent(), true );
|
|
if ( !$response ) {
|
|
$this->error = 'json';
|
|
$this->logCheckError( $this->error );
|
|
return false;
|
|
}
|
|
if ( isset( $response['error-codes'] ) ) {
|
|
$this->error = 'recaptcha-api';
|
|
$this->logCheckError( $response['error-codes'] );
|
|
return false;
|
|
}
|
|
|
|
return $response['success'];
|
|
}
|
|
|
|
function addCaptchaAPI( &$resultArr ) {
|
|
$resultArr['captcha'] = $this->describeCaptchaType();
|
|
$resultArr['captcha']['error'] = $this->error;
|
|
}
|
|
|
|
public function describeCaptchaType() {
|
|
global $wgReCaptchaSiteKey;
|
|
return [
|
|
'type' => 'recaptchanocaptcha',
|
|
'mime' => 'mage/png',
|
|
'key' => $wgReCaptchaSiteKey,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Show a message asking the user to enter a captcha on edit
|
|
* The result will be treated as wiki text
|
|
*
|
|
* @param $action string Action being performed
|
|
* @return string Wikitext
|
|
*/
|
|
public function getMessage( $action ) {
|
|
$msg = parent::getMessage( $action );
|
|
if ( $this->error ) {
|
|
$msg = new RawMessage( '<div class="error">$1</div>', [ $msg ] );
|
|
}
|
|
return $msg;
|
|
}
|
|
|
|
public function APIGetAllowedParams( &$module, &$params, $flags ) {
|
|
if ( $flags && $this->isAPICaptchaModule( $module ) ) {
|
|
if ( defined( 'ApiBase::PARAM_HELP_MSG' ) ) {
|
|
$params['g-recaptcha-response'] = [
|
|
ApiBase::PARAM_HELP_MSG => 'renocaptcha-apihelp-param-g-recaptcha-response',
|
|
];
|
|
} else {
|
|
// @todo: Remove this branch when support for MediaWiki < 1.25 is dropped
|
|
$params['g-recaptcha-response'] = null;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @deprecated since MediaWiki 1.25
|
|
*/
|
|
public function APIGetParamDescription( &$module, &$desc ) {
|
|
if ( $this->isAPICaptchaModule( $module ) ) {
|
|
$desc['g-recaptcha-response'] = 'Field from the ReCaptcha widget';
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function getError() {
|
|
return $this->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( 'renocaptcha-info' );
|
|
}
|
|
|
|
public function createAuthenticationRequest() {
|
|
return new ReCaptchaNoCaptchaAuthenticationRequest();
|
|
}
|
|
|
|
public function onAuthChangeFormFields(
|
|
array $requests, array $fieldInfo, array &$formDescriptor, $action
|
|
) {
|
|
global $wgReCaptchaSiteKey;
|
|
|
|
$req = AuthenticationRequest::getRequestByClass( $requests,
|
|
CaptchaAuthenticationRequest::class, true );
|
|
if ( !$req ) {
|
|
return;
|
|
}
|
|
|
|
// ugly way to retrieve error information
|
|
$captcha = ConfirmEditHooks::getInstance();
|
|
|
|
$formDescriptor['captchaWord'] = [
|
|
'class' => HTMLReCaptchaNoCaptchaField::class,
|
|
'key' => $wgReCaptchaSiteKey,
|
|
'error' => $captcha->getError(),
|
|
] + $formDescriptor['captchaWord'];
|
|
}
|
|
}
|