From 091a4c67215b62a0feb95d14ddf690da47725257 Mon Sep 17 00:00:00 2001
From: Daimona Eaytoy <daimona.wiki@gmail.com>
Date: Sun, 3 Jan 2021 16:13:00 +0100
Subject: [PATCH] SECURITY: Skip deleted RCs in /test if we're only showing
 matches

Otherwise we'd be telling whether the filter matches or not the edit. If
we're showing all edits regardless of whether they match the filter, we
can keep showing the row: it will be redacted (and the filter result
hidden) by AbuseFilterChangesList.

Bug: T223654
Change-Id: I03647c867ee30ced87b579768fcba177e43fdc85
---
 includes/View/AbuseFilterViewTestBatch.php | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/includes/View/AbuseFilterViewTestBatch.php b/includes/View/AbuseFilterViewTestBatch.php
index 92145e0f..81c38a75 100644
--- a/includes/View/AbuseFilterViewTestBatch.php
+++ b/includes/View/AbuseFilterViewTestBatch.php
@@ -6,12 +6,15 @@ use AbuseFilterChangesList;
 use ActorMigration;
 use HTMLForm;
 use IContextSource;
+use LogEventsList;
+use LogPage;
 use MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager;
 use MediaWiki\Extension\AbuseFilter\EditBoxBuilderFactory;
 use MediaWiki\Extension\AbuseFilter\Parser\ParserFactory as AfParserFactory;
 use MediaWiki\Extension\AbuseFilter\VariableGenerator\RCVariableGenerator;
 use MediaWiki\Extension\AbuseFilter\Variables\VariableHolder;
 use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Revision\RevisionRecord;
 use RecentChange;
 use Title;
 use User;
@@ -269,6 +272,29 @@ class AbuseFilterViewTestBatch extends AbuseFilterView {
 		foreach ( $res as $row ) {
 			$vars = new VariableHolder();
 			$rc = RecentChange::newFromRow( $row );
+			if ( !$this->mShowNegative ) {
+				$type = (int)$rc->getAttribute( 'rc_type' );
+				$deletedValue = $rc->getAttribute( 'rc_deleted' );
+				if (
+					(
+						$type === RC_LOG &&
+						!LogEventsList::userCanBitfield(
+							$deletedValue,
+							LogPage::SUPPRESSED_ACTION | LogPage::SUPPRESSED_USER,
+							$contextUser
+						)
+					) || (
+						$type !== RC_LOG &&
+						!RevisionRecord::userCanBitfield( $deletedValue, RevisionRecord::SUPPRESSED_ALL, $contextUser )
+					)
+				) {
+					// If the RC is deleted, the user can't see it, and we're only showing matches,
+					// always skip this row. If mShowNegative is true, we can still show the row
+					// because we won't tell whether it matches the given filter.
+					continue;
+				}
+			}
+
 			$varGenerator = new RCVariableGenerator( $vars, $rc, $contextUser );
 			$vars = $varGenerator->getVars();
 
