From 12533377e9371216991fb2a9ae21ab6ae9848934 Mon Sep 17 00:00:00 2001
From: Tim Starling <tstarling@wikimedia.org>
Date: Tue, 15 Apr 2025 09:06:43 +1000
Subject: [PATCH] [PATCH] SECURITY: BlockList: Hide rows containing suppressed
 users

Bug: T391343
Co-Authored-by: MusikAnimal <musikanimal@gmail.com>
Change-Id: Id5462b942f5e916c2f1dc725739615d54a1070de
---
 includes/specials/pagers/BlockListPager.php   | 22 ++++++++-----
 .../specials/pagers/BlockListPagerTest.php    | 33 +++++++++++++++++++
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/includes/specials/pagers/BlockListPager.php b/includes/specials/pagers/BlockListPager.php
index 3b05637dd77..111f4880893 100644
--- a/includes/specials/pagers/BlockListPager.php
+++ b/includes/specials/pagers/BlockListPager.php
@@ -514,16 +514,20 @@ class BlockListPager extends TablePager {
 		# be private and could be included in block lists and logs for
 		# transparency purposes. Previously, filtering out deleted blocks
 		# was a convenient way to avoid showing the target name.
-		if ( !$this->getAuthority()->isAllowed( 'hideuser' ) ) {
-			$info['conds']['bl_deleted'] = 0;
+		if ( $this->getAuthority()->isAllowed( 'hideuser' ) ) {
+			$info['fields']['hu_deleted'] = $this->hideUserUtils->getExpression(
+				$db,
+				'block_target.bt_user',
+				HideUserUtils::HIDDEN_USERS
+			);
+		} else {
+			$info['fields']['hu_deleted'] = 0;
+			$info['conds'][] = $this->hideUserUtils->getExpression(
+				$db,
+				'block_target.bt_user',
+				HideUserUtils::SHOWN_USERS
+			);
 		}
-
-		# Determine if the user is hidden
-		# With multiblocks we can't just rely on bl_deleted in the row being formatted
-		$info['fields']['hu_deleted'] = $this->hideUserUtils->getExpression(
-			$db,
-			'block_target.bt_user',
-			HideUserUtils::HIDDEN_USERS );
 		return $info;
 	}
 
diff --git a/tests/phpunit/includes/specials/pagers/BlockListPagerTest.php b/tests/phpunit/includes/specials/pagers/BlockListPagerTest.php
index 4f92cb617d3..5f394c5f572 100644
--- a/tests/phpunit/includes/specials/pagers/BlockListPagerTest.php
+++ b/tests/phpunit/includes/specials/pagers/BlockListPagerTest.php
@@ -13,6 +13,7 @@ use MediaWiki\Context\RequestContext;
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\MainConfigNames;
 use MediaWiki\Pager\BlockListPager;
+use MediaWiki\Permissions\SimpleAuthority;
 use MediaWiki\Permissions\UltimateAuthority;
 use MediaWiki\Request\FauxRequest;
 use MediaWiki\SpecialPage\SpecialPageFactory;
@@ -391,4 +392,36 @@ class BlockListPagerTest extends MediaWikiIntegrationTestCase {
 		// Check that we didn't leak the IP address into it
 		$this->assertStringNotContainsString( $addr, $body );
 	}
+
+	/**
+	 * T391343 regression test
+	 * @coversNothing
+	 */
+	public function testBlockLinkSuppression() {
+		$user = $this->getTestUser()->getUserIdentity();
+		$store = $this->getServiceContainer()->getDatabaseBlockStore();
+		$store->insertBlockWithParams( [
+			'targetUser' => $user,
+			'by' => $this->getTestSysop()->getUser(),
+		] );
+		$store->insertBlockWithParams( [
+			'targetUser' => $user,
+			'by' => $this->getTestSysop()->getUser(),
+			'hideName' => true
+		] );
+
+		RequestContext::getMain()->setAuthority(
+			new SimpleAuthority(
+				$this->getTestSysop()->getUserIdentity(),
+				[ 'block' ]
+			)
+		);
+
+		$pager = $this->getBlockListPager();
+		$body = $pager->getBody();
+		$this->assertStringNotContainsString( $user->getName(), $body );
+		// Fail even if punctuation in the name was replaced
+		$regex = '/' . preg_replace( '/[^A-Za-z0-9]+/', '.+', $user->getName() ) . '/';
+		$this->assertDoesNotMatchRegularExpression( $regex, $body );
+	}
 }
-- 
2.43.0

