diff --git a/README.md b/README.md index 8d8ed3f..454edad 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # CrawlerProtection Protect wikis against crawler bots + +# Configuration + +* `$wgCrawlerProtectedSpecialPages` - array of special pages to protect (default: `[ 'recentchangeslinked', 'whatlinkshere' ]`). Supported values are lowercase special page names, titled spacial page names and prefixed special page names. +* `$wgCrawlerProtectionDenyFast` - drop denied requests in a quick way via `die();` with [418 I'm a teapot](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/418) code (default: `false`) diff --git a/extension.json b/extension.json index eff0a0c..43c6eb1 100644 --- a/extension.json +++ b/extension.json @@ -20,6 +20,17 @@ "MediaWikiPerformAction": "main", "SpecialPageBeforeExecute": "main" }, + "config": { + "CrawlerProtectedSpecialPages": { + "value": [ + "recentchangeslinked", + "whatlinkshere" + ] + }, + "CrawlerProtectionDenyFast": { + "value": false + } + }, "license-name": "MIT", "Tests": { "phpunit": "tests/phpunit" diff --git a/includes/Hooks.php b/includes/Hooks.php index 436d7e0..afb2066 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -26,6 +26,7 @@ class_alias( '\Article', '\MediaWiki\Page\Article' ); use MediaWiki\Actions\ActionEntryPoint; use MediaWiki\Hook\MediaWikiPerformActionHook; +use MediaWiki\MediaWikiServices; use MediaWiki\Output\OutputPage; use MediaWiki\Page\Article; use MediaWiki\Request\WebRequest; @@ -96,9 +97,21 @@ public function onSpecialPageBeforeExecute( $special, $subPage ) { return true; } + $config = MediaWikiServices::getInstance()->getMainConfig(); + $protectedSpecialPages = $config->get( 'CrawlerProtectedSpecialPages' ); + $denyFast = $config->get( 'CrawlerProtectedSpecialPages' ); + $name = strtolower( $special->getName() ); - if ( in_array( $name, [ 'recentchangeslinked', 'whatlinkshere' ], true ) ) { + if ( + // allow forgiving entries in the setting array for Special pages names + in_array( $special->getName(), $protectedSpecialPages, true ) + || in_array( $name, $protectedSpecialPages, true ) + || in_array( 'Special:' . $special->getName(), $protectedSpecialPages, true ) + ) { $out = $special->getContext()->getOutput(); + if ( $denyFast ) { + $this->denyAccessFast(); + } $this->denyAccess( $out ); return false; } @@ -106,6 +119,17 @@ public function onSpecialPageBeforeExecute( $special, $subPage ) { return true; } + /** + * Helper: output 418 Teapot and halt the processing immediately + * + * @return void + * @suppress PhanPluginNeverReturnMethod + */ + protected function denyAccessFast() { + header( 'HTTP/1.0 418 Forbidden' ); + die( 'I am a teapot' ); + } + /** * Helper: output 403 Access Denied page using i18n messages. *