2020-10-17 11:50:21 +00:00
|
|
|
<?php
|
|
|
|
|
2020-12-18 14:05:33 +00:00
|
|
|
namespace MediaWiki\Extension\AbuseFilter\Consequences;
|
2020-10-17 11:50:21 +00:00
|
|
|
|
2020-12-18 14:05:33 +00:00
|
|
|
use MediaWiki\Extension\AbuseFilter\CentralDBManager;
|
|
|
|
use MediaWiki\Extension\AbuseFilter\GlobalNameUtils;
|
2020-10-17 11:50:21 +00:00
|
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
use Wikimedia\Rdbms\IDatabase;
|
|
|
|
use Wikimedia\Rdbms\ILoadBalancer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class for retrieving actions and parameters from the database
|
2021-01-07 20:10:52 +00:00
|
|
|
* @todo Can we better integrate this with FilterLookup?
|
2020-10-17 11:50:21 +00:00
|
|
|
*/
|
|
|
|
class ConsequencesLookup {
|
|
|
|
public const SERVICE_NAME = 'AbuseFilterConsequencesLookup';
|
|
|
|
|
|
|
|
/** @var ILoadBalancer */
|
|
|
|
private $loadBalancer;
|
|
|
|
/** @var CentralDBManager */
|
|
|
|
private $centralDBManager;
|
2020-11-29 22:55:34 +00:00
|
|
|
/** @var ConsequencesRegistry */
|
|
|
|
private $consequencesRegistry;
|
2020-10-17 11:50:21 +00:00
|
|
|
/** @var LoggerInterface */
|
|
|
|
private $logger;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param ILoadBalancer $loadBalancer
|
|
|
|
* @param CentralDBManager $centralDBManager
|
2020-11-29 22:55:34 +00:00
|
|
|
* @param ConsequencesRegistry $consequencesRegistry
|
2020-10-17 11:50:21 +00:00
|
|
|
* @param LoggerInterface $logger
|
|
|
|
*/
|
|
|
|
public function __construct(
|
|
|
|
ILoadBalancer $loadBalancer,
|
|
|
|
CentralDBManager $centralDBManager,
|
2020-11-29 22:55:34 +00:00
|
|
|
ConsequencesRegistry $consequencesRegistry,
|
2020-10-17 11:50:21 +00:00
|
|
|
LoggerInterface $logger
|
|
|
|
) {
|
|
|
|
$this->loadBalancer = $loadBalancer;
|
|
|
|
$this->centralDBManager = $centralDBManager;
|
2020-11-29 22:55:34 +00:00
|
|
|
$this->consequencesRegistry = $consequencesRegistry;
|
2020-10-17 11:50:21 +00:00
|
|
|
$this->logger = $logger;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-09-04 02:30:36 +00:00
|
|
|
* @param array<int|string> $filters
|
2020-10-17 11:50:21 +00:00
|
|
|
* @return array[][]
|
|
|
|
*/
|
2021-07-21 18:51:12 +00:00
|
|
|
public function getConsequencesForFilters( array $filters ): array {
|
2020-10-17 11:50:21 +00:00
|
|
|
$globalFilters = [];
|
|
|
|
$localFilters = [];
|
|
|
|
|
|
|
|
foreach ( $filters as $filter ) {
|
2020-12-02 22:47:40 +00:00
|
|
|
list( $filterID, $global ) = GlobalNameUtils::splitGlobalName( $filter );
|
2020-10-17 11:50:21 +00:00
|
|
|
|
|
|
|
if ( $global ) {
|
|
|
|
$globalFilters[] = $filterID;
|
|
|
|
} else {
|
2021-09-04 02:30:36 +00:00
|
|
|
$localFilters[] = (int)$filter;
|
2020-10-17 11:50:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load local filter info
|
|
|
|
$dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
|
|
|
|
// Retrieve the consequences.
|
|
|
|
$consequences = [];
|
|
|
|
|
|
|
|
if ( count( $localFilters ) ) {
|
|
|
|
$consequences = $this->loadConsequencesFromDB( $dbr, $localFilters );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( count( $globalFilters ) ) {
|
|
|
|
$consequences += $this->loadConsequencesFromDB(
|
|
|
|
$this->centralDBManager->getConnection( DB_REPLICA ),
|
|
|
|
$globalFilters,
|
2020-12-02 22:47:40 +00:00
|
|
|
GlobalNameUtils::GLOBAL_FILTER_PREFIX
|
2020-10-17 11:50:21 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $consequences;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param IDatabase $dbr
|
2021-09-04 02:30:36 +00:00
|
|
|
* @param int[] $filters
|
2020-10-17 11:50:21 +00:00
|
|
|
* @param string $prefix
|
|
|
|
* @return array[][]
|
|
|
|
*/
|
2021-07-21 18:51:12 +00:00
|
|
|
private function loadConsequencesFromDB( IDatabase $dbr, array $filters, string $prefix = '' ): array {
|
2020-10-17 11:50:21 +00:00
|
|
|
$actionsByFilter = [];
|
|
|
|
foreach ( $filters as $filter ) {
|
|
|
|
$actionsByFilter[$prefix . $filter] = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
$res = $dbr->select(
|
|
|
|
[ 'abuse_filter_action', 'abuse_filter' ],
|
|
|
|
'*',
|
|
|
|
[ 'af_id' => $filters ],
|
|
|
|
__METHOD__,
|
|
|
|
[],
|
|
|
|
[ 'abuse_filter_action' => [ 'LEFT JOIN', 'afa_filter=af_id' ] ]
|
|
|
|
);
|
|
|
|
|
2020-11-29 22:55:34 +00:00
|
|
|
$dangerousActions = $this->consequencesRegistry->getDangerousActionNames();
|
2020-10-17 11:50:21 +00:00
|
|
|
// Categorise consequences by filter.
|
|
|
|
foreach ( $res as $row ) {
|
|
|
|
if ( $row->af_throttled
|
|
|
|
&& in_array( $row->afa_consequence, $dangerousActions )
|
|
|
|
) {
|
|
|
|
// Don't do the action, just log
|
|
|
|
$this->logger->info(
|
|
|
|
'Filter {filter_id} is throttled, skipping action: {action}',
|
|
|
|
[
|
|
|
|
'filter_id' => $row->af_id,
|
|
|
|
'action' => $row->afa_consequence
|
|
|
|
]
|
|
|
|
);
|
|
|
|
} elseif ( $row->afa_filter !== $row->af_id ) {
|
|
|
|
// We probably got a NULL, as it's a LEFT JOIN. Don't add it.
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
$actionsByFilter[$prefix . $row->afa_filter][$row->afa_consequence] =
|
2022-05-22 12:47:34 +00:00
|
|
|
$row->afa_parameters !== '' ? explode( "\n", $row->afa_parameters ) : [];
|
2020-10-17 11:50:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $actionsByFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|