/** * Test for IP::sanitizeRange() * @dataProvider provideIPCIDRs */ function testSanitizeRange($input, $expected, $description) { $this->assertEquals($expected, IP::sanitizeRange($input), $description); }
/** * @param $action string * @param $parameters array * @param $title Title * @param $vars AbuseFilterVariableHolder * @param $rule_desc * @param $rule_number int|string * * @return array|null a message describing the action that was taken, * or null if no action was taken. The message is given as an array * containing the message key followed by any message parameters. * * @note: Returning the message as an array instead of a Message object is * needed for compatibility with MW 1.20: we will be constructing a * Status object from these messages, and before 1.21, Status did * not accept Message objects to be added directly. */ public static function takeConsequenceAction($action, $parameters, $title, $vars, $rule_desc, $rule_number) { global $wgAbuseFilterCustomActionsHandlers, $wgRequest; $message = null; switch ($action) { case 'disallow': if (strlen($parameters[0])) { $message = array($parameters[0], $rule_desc, $rule_number); } else { // Generic message. $message = array('abusefilter-disallowed', $rule_desc, $rule_number); } break; case 'block': global $wgUser, $wgAbuseFilterBlockDuration, $wgAbuseFilterAnonBlockDuration; $filterUser = AbuseFilter::getFilterUser(); // Create a block. $block = new Block(); $block->setTarget($wgUser->getName()); $block->setBlocker($filterUser); $block->mReason = wfMessage('abusefilter-blockreason', $rule_desc, $rule_number)->inContentLanguage()->text(); $block->isHardblock(false); $block->isAutoblocking(true); $block->prevents('createaccount', true); $block->prevents('editownusertalk', false); if ($wgUser->isAnon() && $wgAbuseFilterAnonBlockDuration !== null) { // The user isn't logged in and the anon block duration doesn't default to $wgAbuseFilterBlockDuration $expiry = $wgAbuseFilterAnonBlockDuration; } else { $expiry = $wgAbuseFilterBlockDuration; } $block->mExpiry = SpecialBlock::parseExpiryInput($expiry); $block->insert(); // Log it # Prepare log parameters $logParams = array(); if ($block->mExpiry == 'infinity') { $logParams[] = 'indefinite'; } else { $logParams[] = $expiry; } $logParams[] = 'nocreate'; $log = new LogPage('block'); $log->addEntry('block', Title::makeTitle(NS_USER, $wgUser->getName()), wfMessage('abusefilter-blockreason', $rule_desc, $rule_number)->inContentLanguage()->text(), $logParams, self::getFilterUser()); $message = array('abusefilter-blocked-display', $rule_desc, $rule_number); break; case 'rangeblock': $filterUser = AbuseFilter::getFilterUser(); $range = IP::sanitizeRange($wgRequest->getIP() . '/16'); // Create a block. $block = new Block(); $block->setTarget($range); $block->setBlocker($filterUser); $block->mReason = wfMessage('abusefilter-blockreason', $rule_desc, $rule_number)->inContentLanguage()->text(); $block->isHardblock(false); $block->prevents('createaccount', true); $block->prevents('editownusertalk', false); $block->mExpiry = SpecialBlock::parseExpiryInput('1 week'); $block->insert(); // Log it # Prepare log parameters $logParams = array(); $logParams[] = 'indefinite'; $logParams[] = 'nocreate'; $log = new LogPage('block'); $log->addEntry('block', Title::makeTitle(NS_USER, $range), wfMessage('abusefilter-blockreason', $rule_desc, $rule_number)->inContentLanguage()->text(), $logParams, self::getFilterUser()); $message = array('abusefilter-blocked-display', $rule_desc, $rule_number); break; case 'degroup': global $wgUser; if (!$wgUser->isAnon()) { // Remove all groups from the user. Ouch. $groups = $wgUser->getGroups(); foreach ($groups as $group) { $wgUser->removeGroup($group); } $message = array('abusefilter-degrouped', $rule_desc, $rule_number); // Don't log it if there aren't any groups being removed! if (!count($groups)) { break; } // Log it. $log = new LogPage('rights'); $log->addEntry('rights', $wgUser->getUserPage(), wfMessage('abusefilter-degroupreason', $rule_desc, $rule_number)->inContentLanguage()->text(), array(implode(', ', $groups), ''), self::getFilterUser()); } break; case 'blockautopromote': global $wgUser, $wgMemc; if (!$wgUser->isAnon()) { $blockPeriod = (int) mt_rand(3 * 86400, 7 * 86400); // Block for 3-7 days. $wgMemc->set(self::autoPromoteBlockKey($wgUser), true, $blockPeriod); $message = array('abusefilter-autopromote-blocked', $rule_desc, $rule_number); } break; case 'flag': // Do nothing. Here for completeness. break; case 'tag': // Mark with a tag on recentchanges. global $wgUser; $actionID = implode('-', array($title->getPrefixedText(), $wgUser->getName(), $vars->getVar('ACTION')->toString())); if (!isset(AbuseFilter::$tagsToSet[$actionID])) { AbuseFilter::$tagsToSet[$actionID] = $parameters; } else { AbuseFilter::$tagsToSet[$actionID] = array_merge(AbuseFilter::$tagsToSet[$actionID], $parameters); } break; default: if (isset($wgAbuseFilterCustomActionsHandlers[$action])) { $custom_function = $wgAbuseFilterCustomActionsHandlers[$action]; if (is_callable($custom_function)) { $msg = call_user_func($custom_function, $action, $parameters, $title, $vars, $rule_desc, $rule_number); } if (isset($msg)) { $message = array($msg); } } else { wfDebugLog('AbuseFilter', "Unrecognised action {$action}"); } } return $message; }
protected function addXffBlocks() { static $inited = false; if ($inited) { return; } $inited = true; $blockList = array(array('target' => '70.2.0.0/16', 'type' => Block::TYPE_RANGE, 'desc' => 'Range Hardblock', 'ACDisable' => false, 'isHardblock' => true, 'isAutoBlocking' => false), array('target' => '2001:4860:4001::/48', 'type' => Block::TYPE_RANGE, 'desc' => 'Range6 Hardblock', 'ACDisable' => false, 'isHardblock' => true, 'isAutoBlocking' => false), array('target' => '60.2.0.0/16', 'type' => Block::TYPE_RANGE, 'desc' => 'Range Softblock with AC Disabled', 'ACDisable' => true, 'isHardblock' => false, 'isAutoBlocking' => false), array('target' => '50.2.0.0/16', 'type' => Block::TYPE_RANGE, 'desc' => 'Range Softblock', 'ACDisable' => false, 'isHardblock' => false, 'isAutoBlocking' => false), array('target' => '50.1.1.1', 'type' => Block::TYPE_IP, 'desc' => 'Exact Softblock', 'ACDisable' => false, 'isHardblock' => false, 'isAutoBlocking' => false)); foreach ($blockList as $insBlock) { $target = $insBlock['target']; if ($insBlock['type'] === Block::TYPE_IP) { $target = User::newFromName(IP::sanitizeIP($target), false)->getName(); } elseif ($insBlock['type'] === Block::TYPE_RANGE) { $target = IP::sanitizeRange($target); } $block = new Block(); $block->setTarget($target); $block->setBlocker('testblocker@global'); $block->mReason = $insBlock['desc']; $block->mExpiry = 'infinity'; $block->prevents('createaccount', $insBlock['ACDisable']); $block->isHardblock($insBlock['isHardblock']); $block->isAutoblocking($insBlock['isAutoBlocking']); $block->insert(); } }
/** * From an existing Block, get the target and the type of target. * Note that, except for null, it is always safe to treat the target * as a string; for User objects this will return User::__toString() * which in turn gives User::getName(). * * @param string|int|User|null $target * @return array( User|String|null, Block::TYPE_ constant|null ) */ public static function parseTarget($target) { # We may have been through this before if ($target instanceof User) { if (IP::isValid($target->getName())) { return array($target, self::TYPE_IP); } else { return array($target, self::TYPE_USER); } } elseif ($target === null) { return array(null, null); } $target = trim($target); if (IP::isValid($target)) { # We can still create a User if it's an IP address, but we need to turn # off validation checking (which would exclude IP addresses) return array(User::newFromName(IP::sanitizeIP($target), false), Block::TYPE_IP); } elseif (IP::isValidBlock($target)) { # Can't create a User from an IP range return array(IP::sanitizeRange($target), Block::TYPE_RANGE); } # Consider the possibility that this is not a username at all # but actually an old subpage (bug #29797) if (strpos($target, '/') !== false) { # An old subpage, drill down to the user behind it $parts = explode('/', $target); $target = $parts[0]; } $userObj = User::newFromName($target); if ($userObj instanceof User) { # Note that since numbers are valid usernames, a $target of "12345" will be # considered a User. If you want to pass a block ID, prepend a hash "#12345", # since hash characters are not valid in usernames or titles generally. return array($userObj, Block::TYPE_USER); } elseif (preg_match('/^#\\d+$/', $target)) { # Autoblock reference in the form "#12345" return array(substr($target, 1), Block::TYPE_AUTO); } else { # WTF? return array(null, null); } }
/** * Roughly increments the cache misses in the last hour by unique visitors * @param WebRequest $request * @return void */ public function incrMissesRecent(WebRequest $request) { if (mt_rand(0, self::MISS_FACTOR - 1) == 0) { $cache = ObjectCache::getLocalClusterInstance(); # Get a large IP range that should include the user even if that # person's IP address changes $ip = $request->getIP(); if (!IP::isValid($ip)) { return; } $ip = IP::isIPv6($ip) ? IP::sanitizeRange("{$ip}/32") : IP::sanitizeRange("{$ip}/16"); # Bail out if a request already came from this range... $key = wfMemcKey(get_class($this), 'attempt', $this->mType, $this->mKey, $ip); if ($cache->get($key)) { return; // possibly the same user } $cache->set($key, 1, self::MISS_TTL_SEC); # Increment the number of cache misses... $key = $this->cacheMissKey(); if ($cache->get($key) === false) { $cache->set($key, 1, self::MISS_TTL_SEC); } else { $cache->incr($key); } } }
public static function takeConsequenceAction($action, $parameters, $title, $vars, $rule_desc) { $display = ''; switch ($action) { case 'disallow': if (strlen($parameters[0])) { $display .= wfMsgExt($parameters[0], 'parseinline', array($rule_desc)) . "\n"; } else { // Generic message. $display .= wfMsgExt('abusefilter-disallowed', 'parseinline', array($rule_desc)) . "<br />\n"; } break; case 'block': global $wgUser, $wgAbuseFilterBlockDuration; $filterUser = AbuseFilter::getFilterUser(); // Create a block. $block = new Block(); $block->setTarget($wgUser->getName()); $block->setBlocker($filterUser); $block->mReason = wfMsgForContent('abusefilter-blockreason', $rule_desc); $block->isHardblock(false); $block->prevents('createaccount', true); $block->mExpiry = SpecialBlock::parseExpiryInput($wgAbuseFilterBlockDuration); $block->insert(); // Log it # Prepare log parameters $logParams = array(); if ($block->mExpiry == 'infinity') { $logParams[] = 'indefinite'; } else { $logParams[] = $wgAbuseFilterBlockDuration; } $logParams[] = 'nocreate, angry-autoblock'; $log = new LogPage('block'); $log->addEntry('block', Title::makeTitle(NS_USER, $wgUser->getName()), wfMsgForContent('abusefilter-blockreason', $rule_desc), $logParams, self::getFilterUser()); $display .= wfMsgExt('abusefilter-blocked-display', 'parseinline', array($rule_desc)) . "<br />\n"; break; case 'rangeblock': $filterUser = AbuseFilter::getFilterUser(); $range = IP::sanitizeRange(wfGetIP() . '/16'); // Create a block. $block = new Block(); $block->setTarget($range); $block->setBlocker($filterUser); $block->mReason = wfMsgForContent('abusefilter-blockreason', $rule_desc); $block->isHardblock(false); $block->prevents('createaccount', true); $block->mExpiry = SpecialBlock::parseExpiryInput('1 week'); $block->insert(); // Log it # Prepare log parameters $logParams = array(); $logParams[] = 'indefinite'; $logParams[] = 'nocreate, angry-autoblock'; $log = new LogPage('block'); $log->addEntry('block', Title::makeTitle(NS_USER, $range), wfMsgForContent('abusefilter-blockreason', $rule_desc), $logParams, self::getFilterUser()); $display .= wfMsgExt('abusefilter-blocked-display', 'parseinline', $rule_desc) . "<br />\n"; break; case 'degroup': global $wgUser; if (!$wgUser->isAnon()) { // Remove all groups from the user. Ouch. $groups = $wgUser->getGroups(); foreach ($groups as $group) { $wgUser->removeGroup($group); } $display .= wfMsgExt('abusefilter-degrouped', 'parseinline', array($rule_desc)) . "<br />\n"; // Don't log it if there aren't any groups being removed! if (!count($groups)) { break; } // Log it. $log = new LogPage('rights'); $log->addEntry('rights', $wgUser->getUserPage(), wfMsgForContent('abusefilter-degroupreason', $rule_desc), array(implode(', ', $groups), wfMsgForContent('rightsnone')), self::getFilterUser()); } break; case 'blockautopromote': global $wgUser, $wgMemc; if (!$wgUser->isAnon()) { $blockPeriod = (int) mt_rand(3 * 86400, 7 * 86400); // Block for 3-7 days. $wgMemc->set(self::autoPromoteBlockKey($wgUser), true, $blockPeriod); $display .= wfMsgExt('abusefilter-autopromote-blocked', 'parseinline', array($rule_desc)) . "<br />\n"; } break; case 'flag': // Do nothing. Here for completeness. break; case 'tag': // Mark with a tag on recentchanges. global $wgUser; $actionID = implode('-', array($title->getPrefixedText(), $wgUser->getName(), $vars->getVar('ACTION')->toString())); AbuseFilter::$tagsToSet[$actionID] = $parameters; break; default: wfDebugLog('AbuseFilter', "Unrecognised action {$action}"); } return $display; }