From c013e6ce1d25fe0f2b9ec416d51c674e8ef2bb44 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 19:45:44 +0000 Subject: [PATCH] Test that the unblock token only passes the unblock view A valid token must open the unblock view and nothing else: other tasks or components (also in other spellings) and non-string tokens stay blocked, and the token of another address's block is no pass. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01LhhhdjhErC9ZiaS4HyRjsh --- tests/Integration/BlockedRequestTest.php | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/Integration/BlockedRequestTest.php b/tests/Integration/BlockedRequestTest.php index af8a77e..3341592 100644 --- a/tests/Integration/BlockedRequestTest.php +++ b/tests/Integration/BlockedRequestTest.php @@ -259,6 +259,42 @@ public function testExpiredUnblockTokenIsNoPass() $this->assertBlocked('option=com_bfstop&view=tokenunblock&token='.str_repeat('ef', 20)); } + /** + * The pass a valid token gives is for the unblock view and nothing else: + * whatever else a request carries (another task or component, in any + * spelling - Joomla matches the task case-insensitively, and the backend + * decides on the component itself - or a token which isn't a plain + * string) must still be rejected. The one request which gets through is + * the unblock view itself. + */ + public function testUnblockTokenPassIsLimitedToTheUnblockView() + { + $this->configure(); + $blockId = $this->block(); + $token = (new DatabaseHelper($this->logger))->getNewUnblockToken($blockId, str_repeat('ab', 20)); + $this->assertBlocked('option=com_users&task=user.LOGIN&view=tokenunblock&token='.$token); + $this->assertBlocked('option=com_login&task=login&view=tokenunblock&token='.$token); + $this->assertBlocked('option=com_bfstop&task=user.login&view=tokenunblock&token='.$token); + $this->assertBlocked('option=COM_BFSTOP&view=tokenunblock&token='.$token); + $this->assertBlocked('option=com_bfstop&view=TOKENUNBLOCK&token='.$token); + $this->assertBlocked('option=com_bfstop&view=tokenunblock&token[]='.$token); + $this->assertNotBlocked('option=com_bfstop&view=tokenunblock&token='.$token); + } + + /** + * A token is bound to the blocks it was issued for: a valid token of + * another address's block doesn't open the unblock view, whatever the + * request looks like otherwise. + */ + public function testUnblockTokenOfAnotherAddressIsNoPassForTheUnblockView() + { + $this->configure(); + $this->block(); + $otherBlockId = $this->block('203.0.113.99'); + $otherToken = (new DatabaseHelper($this->logger))->getNewUnblockToken($otherBlockId, str_repeat('cd', 20)); + $this->assertBlocked('option=com_bfstop&view=tokenunblock&token='.$otherToken); + } + public function testRejectedRequestsAreCounted() { $this->configure();