From 10b9276855737ec0042ffa3d353fad5637bd92a8 Mon Sep 17 00:00:00 2001 From: Kosta Harlan Date: Sat, 4 May 2024 23:28:51 +0300 Subject: [PATCH] Allow showing a CAPTCHA in response to AbuseFilter consequence Why: - We want to allow administrators to invoke a CAPTCHA if an AbuseFilter is configured to do so. What: - Implement the AbuseFilterCustomActions hook and define CaptchaConsequence, which will inform AbuseFilter's implementation of onConfirmEditTriggersCaptcha that it should show a CAPTCHA - Deliberately do not register the "showcaptcha" action as a "dangerous action", because filters that use this action are aimed at bot traffic, and we don't want a bot to be able to get past the "showcaptcha" action just by making repeat requests Soft depends on I110a5f5321649dcf85993a0c209ab70b9886057c Bug: T20110 Change-Id: Ie87e3d850541c7dc44aaeb6b30489a32a0c8cc60 --- extension.json | 6 +++- i18n/en.json | 3 +- i18n/qqq.json | 3 +- includes/AbuseFilter/CaptchaConsequence.php | 22 +++++++++++++ includes/AbuseFilterHooks.php | 18 +++++++++++ .../AbuseFilter/CaptchaConsequenceTest.php | 31 +++++++++++++++++++ tests/phpunit/unit/AbuseFilterHooksTest.php | 19 ++++++++++++ 7 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 includes/AbuseFilter/CaptchaConsequence.php create mode 100644 includes/AbuseFilterHooks.php create mode 100644 tests/phpunit/integration/AbuseFilter/CaptchaConsequenceTest.php create mode 100644 tests/phpunit/unit/AbuseFilterHooksTest.php diff --git a/extension.json b/extension.json index cd8ed69d2..74b982b0d 100644 --- a/extension.json +++ b/extension.json @@ -94,6 +94,9 @@ "services": [ "MainWANObjectCache" ] + }, + "AbuseFilterHooks": { + "class": "MediaWiki\\Extension\\ConfirmEdit\\AbuseFilterHooks" } }, "Hooks": { @@ -107,7 +110,8 @@ "EditPage::showEditForm:fields": "ConfirmEditHooks", "EditFilterMergedContent": "ConfirmEditHooks", "APIGetAllowedParams": "ConfirmEditHooks", - "AuthChangeFormFields": "ConfirmEditHooks" + "AuthChangeFormFields": "ConfirmEditHooks", + "AbuseFilterCustomActions": "AbuseFilterHooks" }, "AuthManagerAutoConfig": { "preauth": { diff --git a/i18n/en.json b/i18n/en.json index 60231935b..29b2e269f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -31,5 +31,6 @@ "confirmedit-preview-validity": "Validity", "confirmedit-preview-valid": "valid", "confirmedit-preview-invalid": "invalid", - "confirmedit-preview-description": "The following table shows the list of lines on this page and whether it's a valid IP address or IP address range. If the line is a valid IP address or IP address range, it will be excluded from CAPTCHA checks but invalid lines will be ignored. An example of a valid IP address range would be: 69.208.0.0/16 which goes from 69.208.0.0 to 69.208.255.255. [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Range_blocks#Calculating_the_CIDR_suffix More information] about calculating an IP address range." + "confirmedit-preview-description": "The following table shows the list of lines on this page and whether it's a valid IP address or IP address range. If the line is a valid IP address or IP address range, it will be excluded from CAPTCHA checks but invalid lines will be ignored. An example of a valid IP address range would be: 69.208.0.0/16 which goes from 69.208.0.0 to 69.208.255.255. [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Range_blocks#Calculating_the_CIDR_suffix More information] about calculating an IP address range.", + "abusefilter-edit-action-showcaptcha": "Require the user to complete a CAPTCHA in order to proceed with the action. Users with permission to skip a CAPTCHA are exempt." } diff --git a/i18n/qqq.json b/i18n/qqq.json index 3b7ed0706..40bdc90ee 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -47,5 +47,6 @@ "confirmedit-preview-validity": "Used as a table heading for the edit preview of [[MediaWiki:Captcha-ip-whitelist]] to indicate the validity of a content of a line (if it's an IP address or not).\n{{Identical|Validity}}", "confirmedit-preview-valid": "Used to indicate a valid IP address in the edit preview of [[MediaWiki:Captcha-ip-whitelist]].\n{{Identical|Valid}}", "confirmedit-preview-invalid": "Used to indicate an invalid IP address in the edit preview of [[MediaWiki:Captcha-ip-whitelist]].\n{{Identical|Invalid}}", - "confirmedit-preview-description": "Explains the edit preview of [[MediaWiki:Captcha-ip-whitelist]]." + "confirmedit-preview-description": "Explains the edit preview of [[MediaWiki:Captcha-ip-whitelist]].", + "abusefilter-edit-action-showcaptcha": "Label shown in [[Special:AbuseFilter]] for the show CAPTCHA consequence." } diff --git a/includes/AbuseFilter/CaptchaConsequence.php b/includes/AbuseFilter/CaptchaConsequence.php new file mode 100644 index 000000000..f08239c40 --- /dev/null +++ b/includes/AbuseFilter/CaptchaConsequence.php @@ -0,0 +1,22 @@ +getRequest()->setVal( self::FLAG, true ); + return true; + } +} diff --git a/includes/AbuseFilterHooks.php b/includes/AbuseFilterHooks.php new file mode 100644 index 000000000..6326d2b4c --- /dev/null +++ b/includes/AbuseFilterHooks.php @@ -0,0 +1,18 @@ +createMock( Parameters::class ); + $parameters->method( 'getAction' )->willReturn( 'edit' ); + $captchaConsequence = new CaptchaConsequence( $parameters ); + $request = RequestContext::getMain(); + $this->assertNull( $request->getRequest()->getVal( + CaptchaConsequence::FLAG + ) ); + $captchaConsequence->execute(); + $this->assertTrue( + $request->getRequest()->getBool( + CaptchaConsequence::FLAG + ) + ); + } + +} diff --git a/tests/phpunit/unit/AbuseFilterHooksTest.php b/tests/phpunit/unit/AbuseFilterHooksTest.php new file mode 100644 index 000000000..6bd6a68f4 --- /dev/null +++ b/tests/phpunit/unit/AbuseFilterHooksTest.php @@ -0,0 +1,19 @@ +onAbuseFilterCustomActions( $actions ); + $this->assertArrayHasKey( 'showcaptcha', $actions ); + } +}