wiki.techinc.nl/tests/phpunit/includes/specials/SpecialBlockTest.php
Brian Wolff 6585277528 Allow users to block the user that blocked them.
This is to make it so that blocking all other admins is not
a succesful attack plan, as the blocked admins can block the
blocker, and then it ends in a stalemate with everyone blocked.

This also allows users with unblock-self right to adjust their
own blocks. The code already existed for this but was broken.

Credit for this idea goes to Tgr.

Bug: T150826
Change-Id: I0418279fdb2a59f8f1d7eeb8931d874123d03e4f
2018-12-09 15:24:57 -08:00

462 lines
13 KiB
PHP

<?php
use MediaWiki\Block\BlockRestriction;
use MediaWiki\Block\Restriction\PageRestriction;
use Wikimedia\TestingAccessWrapper;
/**
* @group Blocking
* @group Database
* @coversDefaultClass SpecialBlock
*/
class SpecialBlockTest extends SpecialPageTestBase {
/**
* {@inheritdoc}
*/
protected function newSpecialPage() {
return new SpecialBlock();
}
public function tearDown() {
parent::tearDown();
$this->resetTables();
}
/**
* @covers ::getFormFields()
*/
public function testGetFormFields() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => false,
] );
$page = $this->newSpecialPage();
$wrappedPage = TestingAccessWrapper::newFromObject( $page );
$fields = $wrappedPage->getFormFields();
$this->assertInternalType( 'array', $fields );
$this->assertArrayHasKey( 'Target', $fields );
$this->assertArrayHasKey( 'Expiry', $fields );
$this->assertArrayHasKey( 'Reason', $fields );
$this->assertArrayHasKey( 'CreateAccount', $fields );
$this->assertArrayHasKey( 'DisableUTEdit', $fields );
$this->assertArrayHasKey( 'DisableUTEdit', $fields );
$this->assertArrayHasKey( 'AutoBlock', $fields );
$this->assertArrayHasKey( 'HardBlock', $fields );
$this->assertArrayHasKey( 'PreviousTarget', $fields );
$this->assertArrayHasKey( 'Confirm', $fields );
$this->assertArrayNotHasKey( 'EditingRestriction', $fields );
$this->assertArrayNotHasKey( 'PageRestrictions', $fields );
}
/**
* @covers ::getFormFields()
*/
public function testGetFormFieldsPartialBlocks() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => true,
] );
$page = $this->newSpecialPage();
$wrappedPage = TestingAccessWrapper::newFromObject( $page );
$fields = $wrappedPage->getFormFields();
$this->assertArrayHasKey( 'EditingRestriction', $fields );
$this->assertArrayHasKey( 'PageRestrictions', $fields );
}
/**
* @covers ::maybeAlterFormDefaults()
*/
public function testMaybeAlterFormDefaults() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => false,
] );
$block = $this->insertBlock();
// Refresh the block from the database.
$block = Block::newFromTarget( $block->getTarget() );
$page = $this->newSpecialPage();
$wrappedPage = TestingAccessWrapper::newFromObject( $page );
$wrappedPage->target = $block->getTarget();
$fields = $wrappedPage->getFormFields();
$this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
$this->assertSame( $block->isHardblock(), $fields['HardBlock']['default'] );
$this->assertSame( $block->prevents( 'createaccount' ), $fields['CreateAccount']['default'] );
$this->assertSame( $block->isAutoblocking(), $fields['AutoBlock']['default'] );
$this->assertSame( $block->prevents( 'editownusertalk' ), $fields['DisableUTEdit']['default'] );
$this->assertSame( $block->mReason, $fields['Reason']['default'] );
$this->assertSame( 'infinite', $fields['Expiry']['default'] );
}
/**
* @covers ::maybeAlterFormDefaults()
*/
public function testMaybeAlterFormDefaultsPartial() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => true,
] );
$badActor = $this->getTestUser()->getUser();
$sysop = $this->getTestSysop()->getUser();
$pageSaturn = $this->getExistingTestPage( 'Saturn' );
$pageMars = $this->getExistingTestPage( 'Mars' );
$block = new \Block( [
'address' => $badActor->getName(),
'user' => $badActor->getId(),
'by' => $sysop->getId(),
'expiry' => 'infinity',
'sitewide' => 0,
'enableAutoblock' => true,
] );
$block->setRestrictions( [
new PageRestriction( 0, $pageSaturn->getId() ),
new PageRestriction( 0, $pageMars->getId() ),
] );
$block->insert();
// Refresh the block from the database.
$block = Block::newFromTarget( $block->getTarget() );
$page = $this->newSpecialPage();
$wrappedPage = TestingAccessWrapper::newFromObject( $page );
$wrappedPage->target = $block->getTarget();
$fields = $wrappedPage->getFormFields();
$titles = [
$pageMars->getTitle()->getPrefixedText(),
$pageSaturn->getTitle()->getPrefixedText(),
];
$this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
$this->assertSame( 'partial', $fields['EditingRestriction']['default'] );
$this->assertSame( implode( "\n", $titles ), $fields['PageRestrictions']['default'] );
}
/**
* @covers ::processForm()
*/
public function testProcessForm() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => false,
] );
$badActor = $this->getTestUser()->getUser();
$context = RequestContext::getMain();
$page = $this->newSpecialPage();
$reason = 'test';
$expiry = 'infinity';
$data = [
'Target' => (string)$badActor,
'Expiry' => 'infinity',
'Reason' => [
$reason,
],
'Confirm' => '1',
'CreateAccount' => '0',
'DisableUTEdit' => '0',
'DisableEmail' => '0',
'HardBlock' => '0',
'AutoBlock' => '1',
'HideUser' => '0',
'Watch' => '0',
];
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
}
/**
* @covers ::processForm()
*/
public function testProcessFormExisting() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => false,
] );
$badActor = $this->getTestUser()->getUser();
$sysop = $this->getTestSysop()->getUser();
$context = RequestContext::getMain();
// Create a block that will be updated.
$block = new \Block( [
'address' => $badActor->getName(),
'user' => $badActor->getId(),
'by' => $sysop->getId(),
'expiry' => 'infinity',
'sitewide' => 0,
'enableAutoblock' => false,
] );
$block->insert();
$page = $this->newSpecialPage();
$reason = 'test';
$expiry = 'infinity';
$data = [
'Target' => (string)$badActor,
'Expiry' => 'infinity',
'Reason' => [
$reason,
],
'Confirm' => '1',
'CreateAccount' => '0',
'DisableUTEdit' => '0',
'DisableEmail' => '0',
'HardBlock' => '0',
'AutoBlock' => '1',
'HideUser' => '0',
'Watch' => '0',
];
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
$this->assertSame( '1', $block->isAutoblocking() );
}
/**
* @covers ::processForm()
*/
public function testProcessFormRestictions() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => true,
] );
$badActor = $this->getTestUser()->getUser();
$context = RequestContext::getMain();
$pageSaturn = $this->getExistingTestPage( 'Saturn' );
$pageMars = $this->getExistingTestPage( 'Mars' );
$titles = [
$pageSaturn->getTitle()->getText(),
$pageMars->getTitle()->getText(),
];
$page = $this->newSpecialPage();
$reason = 'test';
$expiry = 'infinity';
$data = [
'Target' => (string)$badActor,
'Expiry' => 'infinity',
'Reason' => [
$reason,
],
'Confirm' => '1',
'CreateAccount' => '0',
'DisableUTEdit' => '0',
'DisableEmail' => '0',
'HardBlock' => '0',
'AutoBlock' => '1',
'HideUser' => '0',
'Watch' => '0',
'EditingRestriction' => 'partial',
'PageRestrictions' => implode( "\n", $titles ),
];
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
$this->assertCount( 2, $block->getRestrictions() );
$this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
new PageRestriction( $block->getId(), $pageMars->getId() ),
new PageRestriction( $block->getId(), $pageSaturn->getId() ),
] ) );
}
/**
* @covers ::processForm()
*/
public function testProcessFormRestrictionsChange() {
$this->setMwGlobals( [
'wgEnablePartialBlocks' => true,
] );
$badActor = $this->getTestUser()->getUser();
$context = RequestContext::getMain();
$pageSaturn = $this->getExistingTestPage( 'Saturn' );
$pageMars = $this->getExistingTestPage( 'Mars' );
$titles = [
$pageSaturn->getTitle()->getText(),
$pageMars->getTitle()->getText(),
];
// Create a partial block.
$page = $this->newSpecialPage();
$reason = 'test';
$expiry = 'infinity';
$data = [
'Target' => (string)$badActor,
'Expiry' => 'infinity',
'Reason' => [
$reason,
],
'Confirm' => '1',
'CreateAccount' => '0',
'DisableUTEdit' => '0',
'DisableEmail' => '0',
'HardBlock' => '0',
'AutoBlock' => '1',
'HideUser' => '0',
'Watch' => '0',
'EditingRestriction' => 'partial',
'PageRestrictions' => implode( "\n", $titles ),
];
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
$this->assertFalse( $block->isSitewide() );
$this->assertCount( 2, $block->getRestrictions() );
$this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
new PageRestriction( $block->getId(), $pageMars->getId() ),
new PageRestriction( $block->getId(), $pageSaturn->getId() ),
] ) );
// Remove a page from the partial block.
$data['PageRestrictions'] = $pageMars->getTitle()->getText();
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
$this->assertFalse( $block->isSitewide() );
$this->assertCount( 1, $block->getRestrictions() );
$this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
new PageRestriction( $block->getId(), $pageMars->getId() ),
] ) );
// Remove the last page from the block.
$data['PageRestrictions'] = '';
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
$this->assertFalse( $block->isSitewide() );
$this->assertCount( 0, $block->getRestrictions() );
// Change to sitewide.
$data['EditingRestriction'] = 'sitewide';
$result = $page->processForm( $data, $context );
$this->assertTrue( $result );
$block = Block::newFromTarget( $badActor );
$this->assertSame( $reason, $block->mReason );
$this->assertSame( $expiry, $block->getExpiry() );
$this->assertTrue( $block->isSitewide() );
$this->assertCount( 0, $block->getRestrictions() );
// Ensure that there are no restrictions where the blockId is 0.
$count = $this->db->selectRowCount(
'ipblocks_restrictions',
'*',
[ 'ir_ipb_id' => 0 ],
__METHOD__
);
$this->assertSame( 0, $count );
}
/**
* @dataProvider provideCheckUnblockSelf
* @covers ::checkUnblockSelf
*/
public function testCheckUnblockSelf(
$blockedUser,
$blockPerformer,
$adjustPerformer,
$adjustTarget,
$expectedResult,
$reason
) {
$this->setGroupPermissions( 'sysop', 'unblockself', true );
$this->setGroupPermissions( 'user', 'block', true );
// Getting errors about creating users in db in provider.
// Need to use mutable to ensure different named testusers.
$users = [
'u1' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
'u2' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
'u3' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
'u4' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
'nonsysop' => $this->getTestUser()->getUser()
];
foreach ( [ 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget' ] as $var ) {
$$var = $users[$$var];
}
$block = new \Block( [
'address' => $blockedUser->getName(),
'user' => $blockedUser->getId(),
'by' => $blockPerformer->getId(),
'expiry' => 'infinity',
'sitewide' => 1,
'enableAutoblock' => true,
] );
$block->insert();
$this->assertSame(
SpecialBlock::checkUnblockSelf( $adjustTarget, $adjustPerformer ),
$expectedResult,
$reason
);
}
public function provideCheckUnblockSelf() {
// 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget'
return [
[ 'u1', 'u2', 'u3', 'u4', true, 'Unrelated users' ],
[ 'u1', 'u2', 'u1', 'u4', 'ipbblocked', 'Block unrelated while blocked' ],
[ 'u1', 'u2', 'u1', 'u1', true, 'Has unblockself' ],
[ 'nonsysop', 'u2', 'nonsysop', 'nonsysop', 'ipbnounblockself', 'no unblockself' ],
[ 'nonsysop', 'nonsysop', 'nonsysop', 'nonsysop', true, 'no unblockself but can de-selfblock' ],
[ 'u1', 'u2', 'u1', 'u2', true, 'Can block user who blocked' ],
];
}
protected function insertBlock() {
$badActor = $this->getTestUser()->getUser();
$sysop = $this->getTestSysop()->getUser();
$block = new \Block( [
'address' => $badActor->getName(),
'user' => $badActor->getId(),
'by' => $sysop->getId(),
'expiry' => 'infinity',
'sitewide' => 1,
'enableAutoblock' => true,
] );
$block->insert();
return $block;
}
protected function resetTables() {
$this->db->delete( 'ipblocks', '*', __METHOD__ );
$this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
}
}