mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/AbuseFilter.git
synced 2024-12-03 18:16:15 +00:00
c469fb4b76
There are lots of cases where we can inject a User object without additional efforts. Now $wgUser is only used inside AFComputedVariable, which is a little bit harder to handle because some instances of that class are serialized in the DB, and thus we cannot easily change the constructor until T213006 is resolved. This partly copies what Ia474f02dfeee8c7d067ee7e555c08cbfef08f6a6 tried to do, but adopting a different approach for various can*() methods: they're now static methods in the AbuseFilter class, so future callers don't need to instantiate an AbuseFilterView class. This also allows to re-use those methods in an API module for editing filters (T213037). Bug: T213037 Bug: T159299 Change-Id: I22743557e162fd23b3b4e52951a649d8c21109c8
322 lines
9.5 KiB
PHP
322 lines
9.5 KiB
PHP
<?php
|
|
/**
|
|
* Created on Mar 28, 2009
|
|
*
|
|
* AbuseFilter extension
|
|
*
|
|
* Copyright © 2008 Alex Z. mrzmanwiki AT gmail DOT com
|
|
* Based mostly on code by Bryan Tong Minh and Roan Kattouw
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
/**
|
|
* Query module to list abuse log entries.
|
|
*
|
|
* @ingroup API
|
|
* @ingroup Extensions
|
|
*/
|
|
class ApiQueryAbuseLog extends ApiQueryBase {
|
|
/**
|
|
* @param ApiQuery $query
|
|
* @param string $moduleName
|
|
*/
|
|
public function __construct( ApiQuery $query, $moduleName ) {
|
|
parent::__construct( $query, $moduleName, 'afl' );
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function execute() {
|
|
// Same check as in SpecialAbuseLog
|
|
$this->checkUserRightsAny( 'abusefilter-log' );
|
|
|
|
$user = $this->getUser();
|
|
$params = $this->extractRequestParams();
|
|
|
|
$prop = array_flip( $params['prop'] );
|
|
$fld_ids = isset( $prop['ids'] );
|
|
$fld_filter = isset( $prop['filter'] );
|
|
$fld_user = isset( $prop['user'] );
|
|
$fld_title = isset( $prop['title'] );
|
|
$fld_action = isset( $prop['action'] );
|
|
$fld_details = isset( $prop['details'] );
|
|
$fld_result = isset( $prop['result'] );
|
|
$fld_timestamp = isset( $prop['timestamp'] );
|
|
$fld_hidden = isset( $prop['hidden'] );
|
|
$fld_revid = isset( $prop['revid'] );
|
|
$isCentral = $this->getConfig()->get( 'AbuseFilterIsCentral' );
|
|
$fld_wiki = $isCentral && isset( $prop['wiki'] );
|
|
|
|
if ( $fld_details ) {
|
|
$this->checkUserRightsAny( 'abusefilter-log-detail' );
|
|
}
|
|
// Match permissions for viewing events on private filters to SpecialAbuseLog (bug 42814)
|
|
if ( $params['filter'] &&
|
|
!( AbuseFilter::canViewPrivate( $user ) || $user->isAllowed( 'abusefilter-log-private' ) )
|
|
) {
|
|
// A specific filter parameter is set but the user isn't allowed to view all filters
|
|
if ( !is_array( $params['filter'] ) ) {
|
|
$params['filter'] = [ $params['filter'] ];
|
|
}
|
|
foreach ( $params['filter'] as $filter ) {
|
|
list( $filterID, $global ) = AbuseFilter::splitGlobalName( $filter );
|
|
if ( AbuseFilter::filterHidden( $filterID, $global ) ) {
|
|
$this->dieWithError(
|
|
[ 'apierror-permissiondenied', $this->msg( 'action-abusefilter-log-private' ) ]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
$result = $this->getResult();
|
|
|
|
$this->addTables( 'abuse_filter_log' );
|
|
$this->addFields( 'afl_timestamp' );
|
|
$this->addFields( 'afl_rev_id' );
|
|
$this->addFields( 'afl_deleted' );
|
|
$this->addFields( 'afl_filter' );
|
|
$this->addFieldsIf( 'afl_id', $fld_ids );
|
|
$this->addFieldsIf( 'afl_user_text', $fld_user );
|
|
$this->addFieldsIf( [ 'afl_namespace', 'afl_title' ], $fld_title );
|
|
$this->addFieldsIf( 'afl_action', $fld_action );
|
|
$this->addFieldsIf( 'afl_var_dump', $fld_details );
|
|
$this->addFieldsIf( 'afl_actions', $fld_result );
|
|
$this->addFieldsIf( 'afl_wiki', $fld_wiki );
|
|
|
|
if ( $fld_filter ) {
|
|
$this->addTables( 'abuse_filter' );
|
|
$this->addFields( 'af_public_comments' );
|
|
$this->addJoinConds( [ 'abuse_filter' => [ 'LEFT JOIN',
|
|
'af_id=afl_filter' ] ] );
|
|
}
|
|
|
|
$this->addOption( 'LIMIT', $params['limit'] + 1 );
|
|
|
|
$this->addWhereIf( [ 'afl_id' => $params['logid'] ], isset( $params['logid'] ) );
|
|
|
|
$this->addWhereRange( 'afl_timestamp', $params['dir'], $params['start'], $params['end'] );
|
|
|
|
if ( isset( $params['user'] ) ) {
|
|
$u = User::newFromName( $params['user'] );
|
|
if ( $u ) {
|
|
// Username normalisation
|
|
$params['user'] = $u->getName();
|
|
$userId = $u->getId();
|
|
} elseif ( IP::isIPAddress( $params['user'] ) ) {
|
|
// It's an IP, sanitize it
|
|
$params['user'] = IP::sanitizeIP( $params['user'] );
|
|
$userId = 0;
|
|
}
|
|
|
|
if ( isset( $userId ) ) {
|
|
// Only add the WHERE for user in case it's either a valid user
|
|
// (but not necessary an existing one) or an IP.
|
|
$this->addWhere(
|
|
[
|
|
'afl_user' => $userId,
|
|
'afl_user_text' => $params['user']
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
$this->addWhereIf(
|
|
[ 'afl_filter' => $params['filter'] ],
|
|
isset( $params['filter'] ) && $params['filter'] !== []
|
|
);
|
|
$this->addWhereIf( [ 'afl_deleted' => 0 ], !SpecialAbuseLog::canSeeHidden( $user ) );
|
|
if ( isset( $params['wiki'] ) ) {
|
|
// 'wiki' won't be set if $wgAbuseFilterIsCentral = false
|
|
$this->addWhereIf( [ 'afl_wiki' => $params['wiki'] ], $isCentral );
|
|
}
|
|
|
|
$title = $params['title'];
|
|
if ( !is_null( $title ) ) {
|
|
$titleObj = Title::newFromText( $title );
|
|
if ( is_null( $titleObj ) ) {
|
|
$this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $title ) ] );
|
|
}
|
|
$this->addWhereFld( 'afl_namespace', $titleObj->getNamespace() );
|
|
$this->addWhereFld( 'afl_title', $titleObj->getDBkey() );
|
|
}
|
|
$res = $this->select( __METHOD__ );
|
|
|
|
$count = 0;
|
|
foreach ( $res as $row ) {
|
|
if ( ++$count > $params['limit'] ) {
|
|
// We've had enough
|
|
$ts = new MWTimestamp( $row->afl_timestamp );
|
|
$this->setContinueEnumParameter( 'start', $ts->getTimestamp( TS_ISO_8601 ) );
|
|
break;
|
|
}
|
|
$hidden = SpecialAbuseLog::isHidden( $row );
|
|
if ( $hidden === true && !SpecialAbuseLog::canSeeHidden( $user ) ) {
|
|
continue;
|
|
} elseif ( $hidden === 'implicit' ) {
|
|
$rev = Revision::newFromId( $row->afl_rev_id );
|
|
if ( !$rev->userCan( Revision::SUPPRESSED_ALL, $user ) ) {
|
|
continue;
|
|
}
|
|
}
|
|
list( $filterID, $global ) = AbuseFilter::splitGlobalName( $row->afl_filter );
|
|
$canSeeDetails = SpecialAbuseLog::canSeeDetails( $user, $filterID, $global );
|
|
|
|
$entry = [];
|
|
if ( $fld_ids ) {
|
|
$entry['id'] = intval( $row->afl_id );
|
|
$entry['filter_id'] = $canSeeDetails ? $row->afl_filter : '';
|
|
}
|
|
if ( $fld_filter ) {
|
|
if ( $global ) {
|
|
$entry['filter'] = AbuseFilter::getGlobalFilterDescription( $filterID );
|
|
} else {
|
|
$entry['filter'] = $row->af_public_comments;
|
|
}
|
|
}
|
|
if ( $fld_user ) {
|
|
$entry['user'] = $row->afl_user_text;
|
|
}
|
|
if ( $fld_wiki ) {
|
|
$entry['wiki'] = $row->afl_wiki;
|
|
}
|
|
if ( $fld_title ) {
|
|
$title = Title::makeTitle( $row->afl_namespace, $row->afl_title );
|
|
ApiQueryBase::addTitleInfo( $entry, $title );
|
|
}
|
|
if ( $fld_action ) {
|
|
$entry['action'] = $row->afl_action;
|
|
}
|
|
if ( $fld_result ) {
|
|
$entry['result'] = $row->afl_actions;
|
|
}
|
|
if ( $fld_revid && !is_null( $row->afl_rev_id ) ) {
|
|
$entry['revid'] = $canSeeDetails ? $row->afl_rev_id : '';
|
|
}
|
|
if ( $fld_timestamp ) {
|
|
$ts = new MWTimestamp( $row->afl_timestamp );
|
|
$entry['timestamp'] = $ts->getTimestamp( TS_ISO_8601 );
|
|
}
|
|
if ( $fld_details ) {
|
|
$entry['details'] = [];
|
|
if ( $canSeeDetails ) {
|
|
$vars = AbuseFilter::loadVarDump( $row->afl_var_dump );
|
|
if ( $vars instanceof AbuseFilterVariableHolder ) {
|
|
$entry['details'] = $vars->exportAllVars();
|
|
} else {
|
|
$entry['details'] = array_change_key_case( $vars, CASE_LOWER );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $fld_hidden && $hidden ) {
|
|
$entry['hidden'] = $hidden;
|
|
}
|
|
|
|
if ( $entry ) {
|
|
$fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $entry );
|
|
if ( !$fit ) {
|
|
$ts = new MWTimestamp( $row->afl_timestamp );
|
|
$this->setContinueEnumParameter( 'start', $ts->getTimestamp( TS_ISO_8601 ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'item' );
|
|
}
|
|
|
|
/**
|
|
* @see ApiQueryBase::getAllowedParams()
|
|
* @return array
|
|
*/
|
|
public function getAllowedParams() {
|
|
$params = [
|
|
'logid' => [
|
|
ApiBase::PARAM_TYPE => 'integer'
|
|
],
|
|
'start' => [
|
|
ApiBase::PARAM_TYPE => 'timestamp'
|
|
],
|
|
'end' => [
|
|
ApiBase::PARAM_TYPE => 'timestamp'
|
|
],
|
|
'dir' => [
|
|
ApiBase::PARAM_TYPE => [
|
|
'newer',
|
|
'older'
|
|
],
|
|
ApiBase::PARAM_DFLT => 'older',
|
|
ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
|
|
],
|
|
'user' => null,
|
|
'title' => null,
|
|
'filter' => [
|
|
ApiBase::PARAM_TYPE => 'string',
|
|
ApiBase::PARAM_ISMULTI => true,
|
|
ApiBase::PARAM_HELP_MSG => [
|
|
'apihelp-query+abuselog-param-filter',
|
|
AbuseFilter::GLOBAL_FILTER_PREFIX
|
|
]
|
|
],
|
|
'limit' => [
|
|
ApiBase::PARAM_DFLT => 10,
|
|
ApiBase::PARAM_TYPE => 'limit',
|
|
ApiBase::PARAM_MIN => 1,
|
|
ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
|
|
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
|
|
],
|
|
'prop' => [
|
|
ApiBase::PARAM_DFLT => 'ids|user|title|action|result|timestamp|hidden|revid',
|
|
ApiBase::PARAM_TYPE => [
|
|
'ids',
|
|
'filter',
|
|
'user',
|
|
'title',
|
|
'action',
|
|
'details',
|
|
'result',
|
|
'timestamp',
|
|
'hidden',
|
|
'revid',
|
|
],
|
|
ApiBase::PARAM_ISMULTI => true
|
|
]
|
|
];
|
|
if ( $this->getConfig()->get( 'AbuseFilterIsCentral' ) ) {
|
|
$params['wiki'] = [
|
|
ApiBase::PARAM_TYPE => 'string',
|
|
];
|
|
$params['prop'][ApiBase::PARAM_DFLT] .= '|wiki';
|
|
$params['prop'][ApiBase::PARAM_TYPE][] = 'wiki';
|
|
}
|
|
return $params;
|
|
}
|
|
|
|
/**
|
|
* @see ApiBase::getExamplesMessages()
|
|
* @return array
|
|
*/
|
|
protected function getExamplesMessages() {
|
|
return [
|
|
'action=query&list=abuselog'
|
|
=> 'apihelp-query+abuselog-example-1',
|
|
'action=query&list=abuselog&afltitle=API'
|
|
=> 'apihelp-query+abuselog-example-2',
|
|
];
|
|
}
|
|
}
|