diff --git a/extension.json b/extension.json index d82548a2f..454fcc8a4 100644 --- a/extension.json +++ b/extension.json @@ -27,7 +27,8 @@ "abusefilter-log-private", "abusefilter-hidden-log", "abusefilter-hide-log", - "abusefilter-modify-global" + "abusefilter-modify-global", + "abusefilter-modify-blocked-external-domains" ], "GroupPermissions": { "*": { @@ -40,7 +41,8 @@ "abusefilter-log-private": true, "abusefilter-modify": true, "abusefilter-modify-restricted": true, - "abusefilter-revert": true + "abusefilter-revert": true, + "abusefilter-modify-blocked-external-domains": true }, "suppress": { "abusefilter-hidden-log": true, @@ -349,6 +351,9 @@ "UserRename": { "class": "MediaWiki\\Extension\\AbuseFilter\\Hooks\\Handlers\\UserRenameHandler" }, + "EditPermission": { + "class": "MediaWiki\\Extension\\AbuseFilter\\Hooks\\Handlers\\EditPermissionHandler" + }, "PageSave": { "class": "MediaWiki\\Extension\\AbuseFilter\\Hooks\\Handlers\\PageSaveHandler", "services": [ @@ -397,6 +402,7 @@ "UploadStashFile": "FilteredActions", "PageSaveComplete": "PageSave", "RenameUserSQL": "UserRename", + "getUserPermissionsErrors": "EditPermission", "CheckUserInsertChangesRow": "CheckUser", "CheckUserInsertPrivateEventRow": "CheckUser", "CheckUserInsertLogEventRow": "CheckUser", diff --git a/i18n/en.json b/i18n/en.json index 9a0fca062..00544bcbb 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -593,5 +593,8 @@ "notification-header-throttle-filter-actions": "The abuse filter $2 {{GENDER:$1|you}} recently edited had a high rate of matches and the following {{PLURAL:$4|action was|actions were}} automatically disabled: $3.", "notification-header-throttle-filter-no-actions": "The abuse filter $2 {{GENDER:$1|you}} recently edited had a high rate of matches but no actions were automatically disabled.", "notification-subject-throttle-filter": "An abuse filter {{GENDER:$1|you}} edited was throttled on {{SITENAME}}", - "notification-link-text-show-filter": "Show filter" + "notification-link-text-show-filter": "Show filter", + "right-abusefilter-modify-blocked-external-domains": "Create or modify what external domains are blocked from being linked", + "action-abusefilter-modify-blocked-external-domains": "create or modify what external domains are blocked from being linked", + "abusefilter-blocked-domains-cannot-edit-directly": "Create or modify what external domains are blocked from being linked must be done through [[Special:BlockedExternalDomains|the special page]]." } diff --git a/i18n/qqq.json b/i18n/qqq.json index d5e8d2d7d..7639db937 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -635,5 +635,8 @@ "notification-header-throttle-filter-actions": "Header text for a notification when an abuse filter was throttled after the user edited it and some actions were automatically disabled. Parameters:\n* $1 - the username of the viewing user, for use in GENDER\n* $2 - filter ID\n* $3 - list of actions that were disabled\n* $4 - number of disabled actions, for PLURAL", "notification-header-throttle-filter-no-actions": "Header text for a notification when an abuse filter was throttled after the user edited it but no actions were automatically disabled. Parameters:\n* $1 - the username of the viewing user, for use in GENDER\n* $2 - filter ID", "notification-subject-throttle-filter": "Email subject line for email notice when an abuse filter was throttled after the user edited it. Parameters:\n* $1 - the username of the receiving user, for use in GENDER", - "notification-link-text-show-filter": "Label for button that links to the filter that was throttled." + "notification-link-text-show-filter": "Label for button that links to the filter that was throttled.", + "right-abusefilter-modify-blocked-external-domains": "{{doc-right|abusefilter-modify-blocked-external-domains}}", + "action-abusefilter-modify-blocked-external-domains": "{{doc-action|abusefilter-modify-blocked-external-domains}}", + "abusefilter-blocked-domains-cannot-edit-directly": "Error message shown when someone tries to edit the list of blocked domains directly and bypass the Special page." } diff --git a/includes/BlockedDomainStorage.php b/includes/BlockedDomainStorage.php index e5828f0b3..111506690 100644 --- a/includes/BlockedDomainStorage.php +++ b/includes/BlockedDomainStorage.php @@ -44,6 +44,8 @@ use Wikimedia\LightweightObjectStore\ExpirationAwareness; class BlockedDomainStorage implements IDBAccessObject { public const SERVICE_NAME = 'AbuseFilterBlockedDomainStorage'; + public const TARGET_PAGE = 'BlockedExternalDomains.json'; + private RevisionLookup $revisionLookup; private BagOStuff $cache; private UserFactory $userFactory; @@ -279,6 +281,6 @@ class BlockedDomainStorage implements IDBAccessObject { * @return TitleValue TitleValue of the config json page */ public function getBlockedDomainPage() { - return new TitleValue( NS_MEDIAWIKI, 'BlockedExternalDomains.json' ); + return new TitleValue( NS_MEDIAWIKI, self::TARGET_PAGE ); } } diff --git a/includes/Hooks/Handlers/EditPermissionHandler.php b/includes/Hooks/Handlers/EditPermissionHandler.php new file mode 100644 index 000000000..ff77a1e95 --- /dev/null +++ b/includes/Hooks/Handlers/EditPermissionHandler.php @@ -0,0 +1,51 @@ +getMainConfig()->get( 'AbuseFilterEnableBlockedExternalDomain' ) ) { + return; + } + + // Ignore all actions and pages except MediaWiki: edits (and creates) + // to the page we care about + if ( + !( $action == 'create' || $action == 'edit' ) || + !$title->inNamespace( NS_MEDIAWIKI ) || + $title->getDBkey() !== BlockedDomainStorage::TARGET_PAGE + ) { + return; + } + + // Prohibit direct actions on our page. + $result = [ 'abusefilter-blocked-domains-cannot-edit-directly', BlockedDomainStorage::TARGET_PAGE ]; + return false; + } + +} diff --git a/includes/Special/BlockedExternalDomains.php b/includes/Special/BlockedExternalDomains.php index 45234cfb7..d77ce7a3c 100644 --- a/includes/Special/BlockedExternalDomains.php +++ b/includes/Special/BlockedExternalDomains.php @@ -72,10 +72,8 @@ class BlockedExternalDomains extends SpecialPage { $out->setPageTitle( $this->msg( 'abusefilter-blocked-domains-title' ) ); $out->wrapWikiMsg( "$1", 'abusefilter-blocked-domains-intro' ); - // Since everything is stored as a json page in MediaWiki namespace, if we use any - // other right, it could be bypassed by the user simply editing the json directly - // so let's make the right the exact same to avoid complications. - $userCanManage = $this->getAuthority()->isAllowed( 'editsitejson' ); + // Direct editing of this page is blocked via EditPermissionHandler + $userCanManage = $this->getAuthority()->isAllowed( 'abusefilter-modify-blocked-external-domains' ); // Show form to add a blocked domain if ( $userCanManage ) {