mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/AbuseFilter.git
synced 2024-09-23 18:28:20 +00:00
Merge "Overhaul Blockautopromote action"
This commit is contained in:
commit
1fa5eef94c
|
@ -74,7 +74,9 @@
|
|||
"abusefilter/create": "AbuseFilterModifyLogFormatter",
|
||||
"abusefilterprivatedetails/access": "LogFormatter",
|
||||
"suppress/hide-afl": "AbuseFilterSuppressLogFormatter",
|
||||
"suppress/unhide-afl": "AbuseFilterSuppressLogFormatter"
|
||||
"suppress/unhide-afl": "AbuseFilterSuppressLogFormatter",
|
||||
"rights/blockautopromote": "AbuseFilterRightsLogFormatter",
|
||||
"rights/restoreautopromote": "AbuseFilterRightsLogFormatter"
|
||||
},
|
||||
"ActionFilteredLogs": {
|
||||
"abusefilter": {
|
||||
|
@ -123,6 +125,7 @@
|
|||
"AbuseLogHitFormatter": "includes/AbuseLogHitFormatter.php",
|
||||
"AbuseFilterModifyLogFormatter": "includes/AbuseFilterModifyLogFormatter.php",
|
||||
"AbuseFilterSuppressLogFormatter": "includes/AbuseFilterSuppressLogFormatter.php",
|
||||
"AbuseFilterRightsLogFormatter": "includes/AbuseFilterRightsLogFormatter.php",
|
||||
"AbuseFilterViewList": "includes/Views/AbuseFilterViewList.php",
|
||||
"AbuseFilterPager": "includes/pagers/AbuseFilterPager.php",
|
||||
"GlobalAbuseFilterPager": "includes/pagers/GlobalAbuseFilterPager.php",
|
||||
|
@ -376,7 +379,7 @@
|
|||
"value": 10000,
|
||||
"description": "Number of action that determines when to reset profiling stats."
|
||||
},
|
||||
"AbuseFilterRangeBlockSize" : {
|
||||
"AbuseFilterRangeBlockSize": {
|
||||
"value": {
|
||||
"IPv4": 16,
|
||||
"IPv6": 19
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"abusefilter-blocker": "Abuse filter",
|
||||
"abusefilter-blockreason": "Automatically blocked by abuse filter.\nDescription of matched rule: $1",
|
||||
"abusefilter-degroupreason": "Rights automatically stripped by abuse filter.\nRule description: $1",
|
||||
"abusefilter-blockautopromotereason": "Autopromotion automatically delayed by abuse filter.\nRule description: $1",
|
||||
"abusefilter-accountreserved": "This account name is reserved for use by the abuse filter.",
|
||||
"right-abusefilter-modify": "Modify abuse filters",
|
||||
"right-abusefilter-view": "View abuse filters",
|
||||
|
@ -110,7 +111,11 @@
|
|||
"log-action-filter-abusefilter-create": "New filter creation",
|
||||
"log-action-filter-abusefilter-modify": "Filter modification",
|
||||
"log-action-filter-suppress-abuselog": "Abuse log suppression",
|
||||
"log-action-filter-rights-blockautopromote": "Autopromote block",
|
||||
"log-action-filter-rights-restoreautopromote": "Autopromote restore",
|
||||
"logentry-abusefilterprivatedetails-access": "$1 {{GENDER:$2|accessed}} private details for $3",
|
||||
"logentry-rights-blockautopromote": "$1 {{GENDER:$2|blocked}} the autopromotion of {{GENDER:$4|$3}} for 5 days",
|
||||
"logentry-rights-restoreautopromote": "$1 {{GENDER:$2|restored}} the autopromotion capability of {{GENDER:$4|$3}}",
|
||||
"abusefilterprivatedetails-log-name": "AbuseFilter private details access log",
|
||||
"abusefilter-management": "Abuse filter management",
|
||||
"abusefilter-list": "All filters",
|
||||
|
@ -162,6 +167,7 @@
|
|||
"abusefilter-tools-reautoconfirm": "Restore autoconfirmed status",
|
||||
"abusefilter-tools-reautoconfirm-user": "User:",
|
||||
"abusefilter-tools-reautoconfirm-submit": "Re-autoconfirm",
|
||||
"abusefilter-tools-restoreautopromote": "Autopromotion restored via AbuseFilter tools.",
|
||||
"abusefilter-reautoconfirm-none": "That user has not had {{GENDER:$1|his|her|their}} autoconfirmed status suspended.",
|
||||
"abusefilter-reautoconfirm-notallowed": "You are not allowed to restore autoconfirmed status.",
|
||||
"abusefilter-reautoconfirm-done": "Account's autoconfirmed status has been restored",
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
"abusefilter-blocker": "Username of reserved user for abuse filter actions.",
|
||||
"abusefilter-blockreason": "Message given to user because of a triggered filter. Parameters:\n* $1 is a filter description\n* $2 is the filter id",
|
||||
"abusefilter-degroupreason": "Used as log entry when removal of the user from all privileged groups performed by Abuse filter. Parameters:\n* $1 is the filter description (reason)\n* $2 is the filter id",
|
||||
"abusefilter-blockautopromotereason": "Used as log entry when delaying the autopromotion of a user. Parameters:\n* $1 is the filter description (reason)\n* $2 is the filter id",
|
||||
"abusefilter-accountreserved": "Message given when trying to register a reserved account name for AbuseFilter actions.",
|
||||
"right-abusefilter-modify": "{{doc-right|abusefilter-modify}}",
|
||||
"right-abusefilter-view": "{{doc-right|abusefilter-view}}",
|
||||
|
@ -144,7 +145,11 @@
|
|||
"log-action-filter-abusefilter-create": "{{doc-log-action-filter-action|abusefilter|create}}",
|
||||
"log-action-filter-abusefilter-modify": "{{doc-log-action-filter-action|abusefilter|modify}}",
|
||||
"log-action-filter-suppress-abuselog": "{{doc-log-action-filter-action|suppress|abuselog}}",
|
||||
"log-action-filter-rights-blockautopromote": "{{doc-log-action-filter-action|rights|blockautopromote}}",
|
||||
"log-action-filter-rights-restoreautopromote": "{{doc-log-action-filter-action|rights|restoreautopromote}}",
|
||||
"logentry-abusefilterprivatedetails-access": "This message is for a log entry. Parameters:\n* $1 User who accessed the private logs\n* $2 User who accessed the private logs (used for gender)\n* $3 The log entry of which private details were accessed",
|
||||
"logentry-rights-blockautopromote": "Message used in rights log entries when AbuseFilter delayed the autopromotion of a user. Parameters:\n* $1 The filter user\n* $2 Same as $1 but for gender support\n* $3 User whose autopromotion was delayed\n* $4 Same user as $3, but used for gender",
|
||||
"logentry-rights-restoreautopromote": "Message used in rights log entries when autopromotion capability of a user. Parameters:\n* $1 The user who restored the rights\n* $2 Same as $1 but for gender support\n* $3 User whose autopromotion status was restored\n* $4 Same user as $3, but used for gender",
|
||||
"abusefilterprivatedetails-log-name": "Log name",
|
||||
"abusefilter-management": "Title of [[Special:AbuseFilter]]",
|
||||
"abusefilter-list": "Used as HTML <code><nowiki><h2></nowiki></code> heading.\n\nFollowed by the fieldset label {{msg-mw|Abusefilter-list-options}}.",
|
||||
|
@ -196,6 +201,7 @@
|
|||
"abusefilter-tools-reautoconfirm": "Fieldset legend for a form to add a user to the autoconfirmed group again.",
|
||||
"abusefilter-tools-reautoconfirm-user": "Field label. See {{msg-mw|group-autoconfirmed}} for concept translation.\n{{Identical|User}}",
|
||||
"abusefilter-tools-reautoconfirm-submit": "Submit button text to add a user to the autoconfirmed user group. See {{msg-mw|group-autoconfirmed}} for concept translation.",
|
||||
"abusefilter-tools-restoreautopromote": "Message displayed in the logs when a user restores the autopromotion status of another user using the form on Special:AbuseFilter/tools.",
|
||||
"abusefilter-reautoconfirm-none": "{{doc-singularthey}}\nError text in case a user has not had their autoconfirmed status revoked. See {{msg-mw|group-autoconfirmed}} for concept translation.\n\nParameters:\n* $1 - the target user name used for GENDER",
|
||||
"abusefilter-reautoconfirm-notallowed": "Error text when trying to perform an action the user cannot perform. See {{msg-mw|group-autoconfirmed}} for concept translation.",
|
||||
"abusefilter-reautoconfirm-done": "See {{msg-mw|group-autoconfirmed}} for concept translation.\n* $1 is the target user name (optional, used for GENDER).",
|
||||
|
@ -476,7 +482,7 @@
|
|||
"abusefilter-action-tag": "{{doc-abusefilter-action}}\n\nThe edit or change can be 'tagged' with a particular tag, which will be shown on Recent Changes, contributions, logs, new pages, history, and everywhere else. \n\nThis is a verb in the imperative form.\n\n{{Identical|Tag}}",
|
||||
"abusefilter-action-throttle": "{{doc-abusefilter-action}}",
|
||||
"abusefilter-action-warn": "{{doc-abusefilter-action}}",
|
||||
"abusefilter-action-blockautopromote": "{{doc-abusefilter-action}}\n\n'''Revoking auto-promoted groups'''\n\nTo '''block autopromote''' means that actions matching the filter will cause the user in question to be barred from receiving any extra groups from $wgAutoPromote for a period ranging from 3 to 7 days (random). \nAdditional information available: https://www.mediawiki.org/wiki/Extension:AbuseFilter/Actions",
|
||||
"abusefilter-action-blockautopromote": "{{doc-abusefilter-action}}\n\n'''Revoking auto-promoted groups'''\n\nTo '''block autopromote''' means that actions matching the filter will cause the user in question to be barred from receiving any extra groups from $wgAutoPromote for 5 days. \nAdditional information available: https://www.mediawiki.org/wiki/Extension:AbuseFilter/Actions",
|
||||
"abusefilter-action-block": "{{doc-abusefilter-action}}\n\nUsers matching the filter will be blocked indefinitely, with a descriptive block summary indicating the rule that was triggered.\n\nThis is a verb.\n{{Identical|Block}}",
|
||||
"abusefilter-action-degroup": "{{doc-abusefilter-action}}\n\n'''Removing from privileged groups'''\n\nUsers matching the filter will be '''removed from all privileged groups''' (sysop, bureaucrat, etc). A descriptive summary will be used, detailing the rule that was triggered. \nAdditional information: https://www.mediawiki.org/wiki/Extension:AbuseFilter/Actions",
|
||||
"abusefilter-action-rangeblock": "{{doc-abusefilter-action}}\n\n'''Range-block'''\n\nSomewhat of a 'nuclear option', the entire /16 range from which the rule was triggered will be blocked for 24 hours.\n\nThis is a verb in the imperative form.",
|
||||
|
|
|
@ -895,6 +895,36 @@ class AbuseFilter {
|
|||
return $cache->makeKey( 'abusefilter', 'rules', $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks autopromotion for the given user
|
||||
*
|
||||
* @param User $target
|
||||
* @param User $performer
|
||||
* @param string $msg The message to show in the log
|
||||
* @return bool True on success, false on failure
|
||||
*/
|
||||
public static function unblockAutopromote( User $target, User $performer, $msg ) {
|
||||
$key = self::autoPromoteBlockKey( $target );
|
||||
$stash = MediaWikiServices::getInstance()->getMainObjectStash();
|
||||
if ( !$stash->get( $key ) ) {
|
||||
// Probably we already removed it
|
||||
return false;
|
||||
}
|
||||
$stash->delete( $key );
|
||||
|
||||
$logEntry = new ManualLogEntry( 'rights', 'restoreautopromote' );
|
||||
$logEntry->setTarget( Title::makeTitle( NS_USER, $target->getName() ) );
|
||||
$logEntry->setComment( $msg );
|
||||
// These parameters are unused in our message, but some parts of the code check for them
|
||||
$logEntry->setParameters( [
|
||||
'4::oldgroups' => [],
|
||||
'5::newgroups' => []
|
||||
] );
|
||||
$logEntry->setPerformer( $performer );
|
||||
$logEntry->publish( $logEntry->insert() );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return string
|
||||
|
|
|
@ -38,6 +38,15 @@ class AbuseFilterHooks {
|
|||
// Message: log-action-filter-suppress-abuselog
|
||||
[ 'abuselog' => [ 'hide-afl', 'unhide-afl' ] ]
|
||||
);
|
||||
$wgActionFilteredLogs['rights'] = array_merge(
|
||||
$wgActionFilteredLogs['rights'],
|
||||
// Messages: log-action-filter-rights-blockautopromote,
|
||||
// log-action-filter-rights-restoreautopromote
|
||||
[
|
||||
'blockautopromote' => [ 'blockautopromote' ],
|
||||
'restoreautopromote' => [ 'restoreautopromote' ]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
15
includes/AbuseFilterRightsLogFormatter.php
Normal file
15
includes/AbuseFilterRightsLogFormatter.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
class AbuseFilterRightsLogFormatter extends LogFormatter {
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getMessageKey() {
|
||||
$subtype = $this->entry->getSubtype();
|
||||
// Messages that can be used here:
|
||||
// * logentry-rights-blockautopromote
|
||||
// * logentry-rights-restoreautopromote
|
||||
return "logentry-rights-$subtype";
|
||||
}
|
||||
}
|
|
@ -958,12 +958,28 @@ class AbuseFilterRunner {
|
|||
break;
|
||||
case 'blockautopromote':
|
||||
if ( !$this->user->isAnon() ) {
|
||||
// Block for 3-7 days.
|
||||
$blockPeriod = (int)mt_rand( 3 * 86400, 7 * 86400 );
|
||||
// Block for 5 days.
|
||||
MediaWikiServices::getInstance()->getMainObjectStash()->set(
|
||||
AbuseFilter::autoPromoteBlockKey( $this->user ), true, $blockPeriod
|
||||
AbuseFilter::autoPromoteBlockKey( $this->user ), true, 5 * 86400
|
||||
);
|
||||
|
||||
$logEntry = new ManualLogEntry( 'rights', 'blockautopromote' );
|
||||
$logEntry->setPerformer( AbuseFilter::getFilterUser() );
|
||||
$logEntry->setTarget( $this->user->getUserPage() );
|
||||
// These parameters are unused in our message, but some parts of the code check for them
|
||||
$logEntry->setParameters( [
|
||||
'4::oldgroups' => [],
|
||||
'5::newgroups' => []
|
||||
] );
|
||||
$logEntry->setComment(
|
||||
wfMessage(
|
||||
'abusefilter-blockautopromotereason',
|
||||
$ruleDescription,
|
||||
$ruleNumber
|
||||
)->inContentLanguage()->text()
|
||||
);
|
||||
$logEntry->publish( $logEntry->insert() );
|
||||
|
||||
$message = [
|
||||
'abusefilter-autopromote-blocked',
|
||||
$ruleDescription,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\Block\DatabaseBlock;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
|
||||
class AbuseFilterViewRevert extends AbuseFilterView {
|
||||
/**
|
||||
|
@ -295,10 +294,12 @@ class AbuseFilterViewRevert extends AbuseFilterView {
|
|||
$logEntry->publish( $logEntry->insert() );
|
||||
return true;
|
||||
case 'blockautopromote':
|
||||
MediaWikiServices::getInstance()->getMainObjectStash()->delete(
|
||||
AbuseFilter::autoPromoteBlockKey( User::newFromId( $result['userid'] ) )
|
||||
);
|
||||
return true;
|
||||
$target = User::newFromId( $result['userid'] );
|
||||
$msg = $this->msg(
|
||||
'abusefilter-revert-reason', $this->mPage->mFilter, $this->mReason
|
||||
)->inContentLanguage()->text();
|
||||
|
||||
return AbuseFilter::unblockAutopromote( $target, $this->getUser(), $msg );
|
||||
case 'degroup':
|
||||
// Pull the user's groups from the vars.
|
||||
$oldGroups = $result['vars']->getVar( 'user_groups' )->toNative();
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\MediaWikiServices;
|
||||
|
||||
class ApiAbuseFilterUnblockAutopromote extends ApiBase {
|
||||
/**
|
||||
* @see ApiBase::execute()
|
||||
|
@ -10,9 +8,9 @@ class ApiAbuseFilterUnblockAutopromote extends ApiBase {
|
|||
$this->checkUserRightsAny( 'abusefilter-modify' );
|
||||
|
||||
$params = $this->extractRequestParams();
|
||||
$user = User::newFromName( $params['user'] );
|
||||
$target = User::newFromName( $params['user'] );
|
||||
|
||||
if ( $user === false ) {
|
||||
if ( $target === false ) {
|
||||
$encParamName = $this->encodeParamName( 'user' );
|
||||
$this->dieWithError(
|
||||
[ 'apierror-baduser', $encParamName, wfEscapeWikiText( $params['user'] ) ],
|
||||
|
@ -20,16 +18,15 @@ class ApiAbuseFilterUnblockAutopromote extends ApiBase {
|
|||
);
|
||||
}
|
||||
|
||||
$key = AbuseFilter::autoPromoteBlockKey( $user );
|
||||
$stash = MediaWikiServices::getInstance()->getMainObjectStash();
|
||||
if ( !$stash->get( $key ) ) {
|
||||
$this->dieWithError( [ 'abusefilter-reautoconfirm-none', $user->getName() ], 'notsuspended' );
|
||||
$msg = $this->msg( 'abusefilter-tools-restoreautopromote' )->inContentLanguage()->text();
|
||||
$res = AbuseFilter::unblockAutopromote( $target, $this->getUser(), $msg );
|
||||
|
||||
if ( $res === false ) {
|
||||
$this->dieWithError( [ 'abusefilter-reautoconfirm-none', $target->getName() ], 'notsuspended' );
|
||||
}
|
||||
|
||||
$stash->delete( $key );
|
||||
|
||||
$res = [ 'user' => $params['user'] ];
|
||||
$this->getResult()->addValue( null, $this->getModuleName(), $res );
|
||||
$finalResult = [ 'user' => $params['user'] ];
|
||||
$this->getResult()->addValue( null, $this->getModuleName(), $finalResult );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -293,6 +293,13 @@ class AbuseFilterConsequencesTest extends MediaWikiTestCase {
|
|||
'actions' => [
|
||||
'disallow' => [],
|
||||
]
|
||||
],
|
||||
21 => [
|
||||
'af_pattern' => '1==1',
|
||||
'af_public_comments' => 'Dangerous filter',
|
||||
'actions' => [
|
||||
'blockautopromote' => []
|
||||
]
|
||||
]
|
||||
];
|
||||
// phpcs:enable Generic.Files.LineLength
|
||||
|
@ -636,6 +643,8 @@ class AbuseFilterConsequencesTest extends MediaWikiTestCase {
|
|||
* @return array [ expected consequences, actual consequences ]
|
||||
*/
|
||||
private function checkConsequences( $result, $actionParams, $consequences ) {
|
||||
global $wgAbuseFilterRestrictions;
|
||||
|
||||
$expectedErrors = [];
|
||||
$testErrorMessage = false;
|
||||
foreach ( $consequences as $consequence => $ids ) {
|
||||
|
@ -705,6 +714,15 @@ class AbuseFilterConsequencesTest extends MediaWikiTestCase {
|
|||
break;
|
||||
case 'throttle':
|
||||
throw new UnexpectedValueException( 'Use self::testThrottleConsequence to test throttling' );
|
||||
case 'blockautopromote':
|
||||
// Aborts the hook with 'abusefilter-autopromote-blocked' error and prevent promotion.
|
||||
$expectedErrors['blockautopromote'][] = 'abusefilter-autopromote-blocked';
|
||||
$key = MediaWikiServices::getInstance()->getMainObjectStash()->get(
|
||||
AbuseFilter::autoPromoteBlockKey( self::$mUser ) );
|
||||
if ( !$key ) {
|
||||
$testErrorMessage = "The key for blocking autopromotion wasn't set.";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnexpectedValueException( 'Consequence not recognized.' );
|
||||
}
|
||||
|
@ -715,15 +733,20 @@ class AbuseFilterConsequencesTest extends MediaWikiTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
// Errors have a priority order
|
||||
$expected = $expectedErrors['warn'] ?? $expectedErrors['degroup'] ??
|
||||
$expectedErrors['block'] ?? $expectedErrors['disallow'] ?? null;
|
||||
if ( isset( $expectedErrors['degroup'] ) && $expected === $expectedErrors['degroup'] &&
|
||||
isset( $expectedErrors['block'] ) ) {
|
||||
// Degroup and block warning can be fired together
|
||||
$expected = array_merge( $expectedErrors['degroup'], $expectedErrors['block'] );
|
||||
} elseif ( !is_array( $expected ) ) {
|
||||
$expected = (array)$expected;
|
||||
if ( array_intersect_key( $expectedErrors, array_filter( $wgAbuseFilterRestrictions ) ) ) {
|
||||
$filteredExpected = array_intersect_key(
|
||||
$expectedErrors,
|
||||
array_filter( $wgAbuseFilterRestrictions )
|
||||
);
|
||||
$expected = [];
|
||||
foreach ( $filteredExpected as $values ) {
|
||||
$expected = array_merge( $expected, $values );
|
||||
}
|
||||
} else {
|
||||
$expected = $expectedErrors['warn'] ?? $expectedErrors['disallow'] ?? null;
|
||||
if ( !is_array( $expected ) ) {
|
||||
$expected = (array)$expected;
|
||||
}
|
||||
}
|
||||
|
||||
$errors = $result->getErrors();
|
||||
|
@ -736,6 +759,8 @@ class AbuseFilterConsequencesTest extends MediaWikiTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
sort( $expected );
|
||||
sort( $actual );
|
||||
return [ $expected, $actual ];
|
||||
}
|
||||
|
||||
|
@ -909,6 +934,17 @@ class AbuseFilterConsequencesTest extends MediaWikiTestCase {
|
|||
],
|
||||
[]
|
||||
],
|
||||
'Test for blockautopromote action.' => [
|
||||
[ 21 ],
|
||||
[
|
||||
'action' => 'edit',
|
||||
'target' => 'Rainbow',
|
||||
'oldText' => '',
|
||||
'newText' => '...',
|
||||
'summary' => ''
|
||||
],
|
||||
[ 'blockautopromote' => [ 21 ] ],
|
||||
],
|
||||
[
|
||||
[ 8, 10 ],
|
||||
[
|
||||
|
|
Loading…
Reference in a new issue