From cd607319c2a87ea86976b2c03b183c8469c5d46e Mon Sep 17 00:00:00 2001 From: Reedy Date: Fri, 25 Oct 2024 17:40:44 +0100 Subject: [PATCH] hCaptcha: Extra logging for captcha solve Bug: T377341 Change-Id: I53934a3a0756878e18de336fd644b54f542ee9e5 --- includes/FancyCaptcha/FancyCaptcha.php | 4 ++-- .../ReCaptchaNoCaptcha/ReCaptchaNoCaptcha.php | 4 +++- includes/SimpleCaptcha/SimpleCaptcha.php | 9 +++++---- includes/Turnstile/Turnstile.php | 4 +++- includes/hCaptcha/HCaptcha.php | 16 ++++++++++++++-- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/includes/FancyCaptcha/FancyCaptcha.php b/includes/FancyCaptcha/FancyCaptcha.php index e208e7014..1aef8fe1b 100644 --- a/includes/FancyCaptcha/FancyCaptcha.php +++ b/includes/FancyCaptcha/FancyCaptcha.php @@ -443,12 +443,12 @@ class FancyCaptcha extends SimpleCaptcha { * Delete a solved captcha image, if $wgCaptchaDeleteOnSolve is true. * @inheritDoc */ - protected function passCaptcha( $index, $word ) { + protected function passCaptcha( $index, $word, $user ) { global $wgCaptchaDeleteOnSolve; // get the captcha info before it gets deleted $info = $this->retrieveCaptcha( $index ); - $pass = parent::passCaptcha( $index, $word ); + $pass = parent::passCaptcha( $index, $word, $user ); if ( $pass && $wgCaptchaDeleteOnSolve ) { $this->getBackend()->quickDelete( [ diff --git a/includes/ReCaptchaNoCaptcha/ReCaptchaNoCaptcha.php b/includes/ReCaptchaNoCaptcha/ReCaptchaNoCaptcha.php index 5ee4d47fd..5983a517c 100644 --- a/includes/ReCaptchaNoCaptcha/ReCaptchaNoCaptcha.php +++ b/includes/ReCaptchaNoCaptcha/ReCaptchaNoCaptcha.php @@ -14,6 +14,7 @@ use MediaWiki\MediaWikiServices; use MediaWiki\Message\Message; use MediaWiki\Request\WebRequest; use MediaWiki\Status\Status; +use MediaWiki\User\UserIdentity; class ReCaptchaNoCaptcha extends SimpleCaptcha { /** @@ -122,9 +123,10 @@ HTML; * * @param mixed $_ Not used (ReCaptcha v2 puts index and solution in a single string) * @param string $word captcha solution + * @param UserIdentity $user * @return bool */ - protected function passCaptcha( $_, $word ) { + protected function passCaptcha( $_, $word, $user ) { global $wgRequest, $wgReCaptchaSecretKey, $wgReCaptchaSendRemoteIP; $url = 'https://www.recaptcha.net/recaptcha/api/siteverify'; diff --git a/includes/SimpleCaptcha/SimpleCaptcha.php b/includes/SimpleCaptcha/SimpleCaptcha.php index 2ed68d4e3..cb97da1b0 100644 --- a/includes/SimpleCaptcha/SimpleCaptcha.php +++ b/includes/SimpleCaptcha/SimpleCaptcha.php @@ -1026,7 +1026,7 @@ class SimpleCaptcha { return false; } - if ( $this->passCaptcha( $index, $word ) ) { + if ( $this->passCaptcha( $index, $word, $user ) ) { return true; } @@ -1044,17 +1044,18 @@ class SimpleCaptcha { */ public function passCaptchaFromRequest( WebRequest $request, User $user ) { [ $index, $word ] = $this->getCaptchaParamsFromRequest( $request ); - return $this->passCaptcha( $index, $word ); + return $this->passCaptcha( $index, $word, $user ); } /** * Given a required captcha run, test form input for correct * input on the open session. - * @param string $index Captcha idenitifier + * @param string $index Captcha identifier * @param string $word Captcha solution + * @param User $user * @return bool if passed, false if failed or new session */ - protected function passCaptcha( $index, $word ) { + protected function passCaptcha( $index, $word, $user ) { // Don't check the same CAPTCHA twice in one session, // if the CAPTCHA was already checked - Bug T94276 if ( $this->isCaptchaSolved() !== null ) { diff --git a/includes/Turnstile/Turnstile.php b/includes/Turnstile/Turnstile.php index 6cc090b97..1db726ccc 100644 --- a/includes/Turnstile/Turnstile.php +++ b/includes/Turnstile/Turnstile.php @@ -14,6 +14,7 @@ use MediaWiki\MediaWikiServices; use MediaWiki\Message\Message; use MediaWiki\Request\WebRequest; use MediaWiki\Status\Status; +use MediaWiki\User\UserIdentity; class Turnstile extends SimpleCaptcha { /** @@ -98,9 +99,10 @@ class Turnstile extends SimpleCaptcha { * * @param mixed $_ Not used * @param string $word captcha solution + * @param UserIdentity $user * @return bool */ - protected function passCaptcha( $_, $word ) { + protected function passCaptcha( $_, $word, $user ) { global $wgRequest, $wgTurnstileSecretKey, $wgTurnstileSendRemoteIP; $url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; diff --git a/includes/hCaptcha/HCaptcha.php b/includes/hCaptcha/HCaptcha.php index eddd9d48e..2eb6941e4 100644 --- a/includes/hCaptcha/HCaptcha.php +++ b/includes/hCaptcha/HCaptcha.php @@ -12,11 +12,13 @@ use MediaWiki\Extension\ConfirmEdit\SimpleCaptcha\SimpleCaptcha; use MediaWiki\Html\Html; use MediaWiki\Json\FormatJson; use MediaWiki\Language\RawMessage; +use MediaWiki\Logger\LoggerFactory; use MediaWiki\MediaWikiServices; use MediaWiki\Message\Message; use MediaWiki\Request\ContentSecurityPolicy; use MediaWiki\Request\WebRequest; use MediaWiki\Status\Status; +use MediaWiki\User\UserIdentity; class HCaptcha extends SimpleCaptcha { /** @@ -119,9 +121,10 @@ class HCaptcha extends SimpleCaptcha { * * @param mixed $_ Not used * @param string $token token from the POST data + * @param UserIdentity $user * @return bool */ - protected function passCaptcha( $_, $token ) { + protected function passCaptcha( $_, $token, $user ) { $webRequest = RequestContext::getMain()->getRequest(); $secretKey = $this->hCaptchaConfig->get( 'HCaptchaSecretKey' ); @@ -155,7 +158,8 @@ class HCaptcha extends SimpleCaptcha { $this->logCheckError( $status ); return false; } - $response = FormatJson::decode( $request->getContent(), true ); + $json = $request->getContent(); + $response = FormatJson::decode( $json, true ); if ( !$response ) { $this->error = 'json'; $this->logCheckError( $this->error ); @@ -167,6 +171,14 @@ class HCaptcha extends SimpleCaptcha { return false; } + LoggerFactory::getInstance( 'captcha' ) + ->debug( 'Captcha solution attempt for {user}', [ + 'event' => 'captcha.solve', + 'user' => $user->getName(), + 'success' => $response['success'], + 'blob' => $json, + ] ); + return $response['success']; }