Add support for Argon2 password hashing
[lhc/web/wiklou.git] / tests / phpunit / includes / specials / SpecialBlockTest.php
1 <?php
2
3 use MediaWiki\Block\BlockRestriction;
4 use MediaWiki\Block\Restriction\PageRestriction;
5 use MediaWiki\Block\Restriction\NamespaceRestriction;
6 use Wikimedia\TestingAccessWrapper;
7
8 /**
9 * @group Blocking
10 * @group Database
11 * @coversDefaultClass SpecialBlock
12 */
13 class SpecialBlockTest extends SpecialPageTestBase {
14 /**
15 * {@inheritdoc}
16 */
17 protected function newSpecialPage() {
18 return new SpecialBlock();
19 }
20
21 public function tearDown() {
22 parent::tearDown();
23 $this->resetTables();
24 }
25
26 /**
27 * @covers ::getFormFields()
28 */
29 public function testGetFormFields() {
30 $this->setMwGlobals( [
31 'wgEnablePartialBlocks' => false,
32 'wgBlockAllowsUTEdit' => true,
33 ] );
34 $page = $this->newSpecialPage();
35 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
36 $fields = $wrappedPage->getFormFields();
37 $this->assertInternalType( 'array', $fields );
38 $this->assertArrayHasKey( 'Target', $fields );
39 $this->assertArrayHasKey( 'Expiry', $fields );
40 $this->assertArrayHasKey( 'Reason', $fields );
41 $this->assertArrayHasKey( 'CreateAccount', $fields );
42 $this->assertArrayHasKey( 'DisableUTEdit', $fields );
43 $this->assertArrayHasKey( 'AutoBlock', $fields );
44 $this->assertArrayHasKey( 'HardBlock', $fields );
45 $this->assertArrayHasKey( 'PreviousTarget', $fields );
46 $this->assertArrayHasKey( 'Confirm', $fields );
47
48 $this->assertArrayNotHasKey( 'EditingRestriction', $fields );
49 $this->assertArrayNotHasKey( 'PageRestrictions', $fields );
50 $this->assertArrayNotHasKey( 'NamespaceRestrictions', $fields );
51 }
52
53 /**
54 * @covers ::getFormFields()
55 */
56 public function testGetFormFieldsPartialBlocks() {
57 $this->setMwGlobals( [
58 'wgEnablePartialBlocks' => true,
59 ] );
60 $page = $this->newSpecialPage();
61 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
62 $fields = $wrappedPage->getFormFields();
63
64 $this->assertArrayHasKey( 'EditingRestriction', $fields );
65 $this->assertArrayHasKey( 'PageRestrictions', $fields );
66 $this->assertArrayHasKey( 'NamespaceRestrictions', $fields );
67 }
68
69 /**
70 * @covers ::maybeAlterFormDefaults()
71 */
72 public function testMaybeAlterFormDefaults() {
73 $this->setMwGlobals( [
74 'wgEnablePartialBlocks' => false,
75 'wgBlockAllowsUTEdit' => true,
76 ] );
77
78 $block = $this->insertBlock();
79
80 // Refresh the block from the database.
81 $block = Block::newFromTarget( $block->getTarget() );
82
83 $page = $this->newSpecialPage();
84
85 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
86 $wrappedPage->target = $block->getTarget();
87 $fields = $wrappedPage->getFormFields();
88
89 $this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
90 $this->assertSame( $block->isHardblock(), $fields['HardBlock']['default'] );
91 $this->assertSame( $block->prevents( 'createaccount' ), $fields['CreateAccount']['default'] );
92 $this->assertSame( $block->isAutoblocking(), $fields['AutoBlock']['default'] );
93 $this->assertSame( $block->prevents( 'editownusertalk' ), $fields['DisableUTEdit']['default'] );
94 $this->assertSame( $block->mReason, $fields['Reason']['default'] );
95 $this->assertSame( 'infinite', $fields['Expiry']['default'] );
96 }
97
98 /**
99 * @covers ::maybeAlterFormDefaults()
100 */
101 public function testMaybeAlterFormDefaultsPartial() {
102 $this->setMwGlobals( [
103 'wgEnablePartialBlocks' => true,
104 ] );
105
106 $badActor = $this->getTestUser()->getUser();
107 $sysop = $this->getTestSysop()->getUser();
108 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
109 $pageMars = $this->getExistingTestPage( 'Mars' );
110
111 $block = new \Block( [
112 'address' => $badActor->getName(),
113 'user' => $badActor->getId(),
114 'by' => $sysop->getId(),
115 'expiry' => 'infinity',
116 'sitewide' => 0,
117 'enableAutoblock' => true,
118 ] );
119
120 $block->setRestrictions( [
121 new PageRestriction( 0, $pageSaturn->getId() ),
122 new PageRestriction( 0, $pageMars->getId() ),
123 new NamespaceRestriction( 0, NS_TALK ),
124 ] );
125
126 $block->insert();
127
128 // Refresh the block from the database.
129 $block = Block::newFromTarget( $block->getTarget() );
130
131 $page = $this->newSpecialPage();
132
133 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
134 $wrappedPage->target = $block->getTarget();
135 $fields = $wrappedPage->getFormFields();
136
137 $titles = [
138 $pageMars->getTitle()->getPrefixedText(),
139 $pageSaturn->getTitle()->getPrefixedText(),
140 ];
141
142 $this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
143 $this->assertSame( 'partial', $fields['EditingRestriction']['default'] );
144 $this->assertSame( implode( "\n", $titles ), $fields['PageRestrictions']['default'] );
145 }
146
147 /**
148 * @covers ::processForm()
149 */
150 public function testProcessForm() {
151 $this->setMwGlobals( [
152 'wgEnablePartialBlocks' => false,
153 ] );
154 $badActor = $this->getTestUser()->getUser();
155 $context = RequestContext::getMain();
156
157 $page = $this->newSpecialPage();
158 $reason = 'test';
159 $expiry = 'infinity';
160 $data = [
161 'Target' => (string)$badActor,
162 'Expiry' => 'infinity',
163 'Reason' => [
164 $reason,
165 ],
166 'Confirm' => '1',
167 'CreateAccount' => '0',
168 'DisableUTEdit' => '0',
169 'DisableEmail' => '0',
170 'HardBlock' => '0',
171 'AutoBlock' => '1',
172 'HideUser' => '0',
173 'Watch' => '0',
174 ];
175 $result = $page->processForm( $data, $context );
176
177 $this->assertTrue( $result );
178
179 $block = Block::newFromTarget( $badActor );
180 $this->assertSame( $reason, $block->mReason );
181 $this->assertSame( $expiry, $block->getExpiry() );
182 }
183
184 /**
185 * @covers ::processForm()
186 */
187 public function testProcessFormExisting() {
188 $this->setMwGlobals( [
189 'wgEnablePartialBlocks' => false,
190 ] );
191 $badActor = $this->getTestUser()->getUser();
192 $sysop = $this->getTestSysop()->getUser();
193 $context = RequestContext::getMain();
194
195 // Create a block that will be updated.
196 $block = new \Block( [
197 'address' => $badActor->getName(),
198 'user' => $badActor->getId(),
199 'by' => $sysop->getId(),
200 'expiry' => 'infinity',
201 'sitewide' => 0,
202 'enableAutoblock' => false,
203 ] );
204 $block->insert();
205
206 $page = $this->newSpecialPage();
207 $reason = 'test';
208 $expiry = 'infinity';
209 $data = [
210 'Target' => (string)$badActor,
211 'Expiry' => 'infinity',
212 'Reason' => [
213 $reason,
214 ],
215 'Confirm' => '1',
216 'CreateAccount' => '0',
217 'DisableUTEdit' => '0',
218 'DisableEmail' => '0',
219 'HardBlock' => '0',
220 'AutoBlock' => '1',
221 'HideUser' => '0',
222 'Watch' => '0',
223 ];
224 $result = $page->processForm( $data, $context );
225
226 $this->assertTrue( $result );
227
228 $block = Block::newFromTarget( $badActor );
229 $this->assertSame( $reason, $block->mReason );
230 $this->assertSame( $expiry, $block->getExpiry() );
231 $this->assertSame( '1', $block->isAutoblocking() );
232 }
233
234 /**
235 * @covers ::processForm()
236 */
237 public function testProcessFormRestrictions() {
238 $this->setMwGlobals( [
239 'wgEnablePartialBlocks' => true,
240 ] );
241 $badActor = $this->getTestUser()->getUser();
242 $context = RequestContext::getMain();
243
244 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
245 $pageMars = $this->getExistingTestPage( 'Mars' );
246
247 $titles = [
248 $pageSaturn->getTitle()->getText(),
249 $pageMars->getTitle()->getText(),
250 ];
251
252 $page = $this->newSpecialPage();
253 $reason = 'test';
254 $expiry = 'infinity';
255 $data = [
256 'Target' => (string)$badActor,
257 'Expiry' => 'infinity',
258 'Reason' => [
259 $reason,
260 ],
261 'Confirm' => '1',
262 'CreateAccount' => '0',
263 'DisableUTEdit' => '0',
264 'DisableEmail' => '0',
265 'HardBlock' => '0',
266 'AutoBlock' => '1',
267 'HideUser' => '0',
268 'Watch' => '0',
269 'EditingRestriction' => 'partial',
270 'PageRestrictions' => implode( "\n", $titles ),
271 'NamespaceRestrictions' => '',
272 ];
273 $result = $page->processForm( $data, $context );
274
275 $this->assertTrue( $result );
276
277 $block = Block::newFromTarget( $badActor );
278 $this->assertSame( $reason, $block->mReason );
279 $this->assertSame( $expiry, $block->getExpiry() );
280 $this->assertCount( 2, $block->getRestrictions() );
281 $this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
282 new PageRestriction( $block->getId(), $pageMars->getId() ),
283 new PageRestriction( $block->getId(), $pageSaturn->getId() ),
284 ] ) );
285 }
286
287 /**
288 * @covers ::processForm()
289 */
290 public function testProcessFormRestrictionsChange() {
291 $this->setMwGlobals( [
292 'wgEnablePartialBlocks' => true,
293 ] );
294 $badActor = $this->getTestUser()->getUser();
295 $context = RequestContext::getMain();
296
297 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
298 $pageMars = $this->getExistingTestPage( 'Mars' );
299
300 $titles = [
301 $pageSaturn->getTitle()->getText(),
302 $pageMars->getTitle()->getText(),
303 ];
304
305 // Create a partial block.
306 $page = $this->newSpecialPage();
307 $reason = 'test';
308 $expiry = 'infinity';
309 $data = [
310 'Target' => (string)$badActor,
311 'Expiry' => 'infinity',
312 'Reason' => [
313 $reason,
314 ],
315 'Confirm' => '1',
316 'CreateAccount' => '0',
317 'DisableUTEdit' => '0',
318 'DisableEmail' => '0',
319 'HardBlock' => '0',
320 'AutoBlock' => '1',
321 'HideUser' => '0',
322 'Watch' => '0',
323 'EditingRestriction' => 'partial',
324 'PageRestrictions' => implode( "\n", $titles ),
325 'NamespaceRestrictions' => '',
326 ];
327 $result = $page->processForm( $data, $context );
328
329 $this->assertTrue( $result );
330
331 $block = Block::newFromTarget( $badActor );
332 $this->assertSame( $reason, $block->mReason );
333 $this->assertSame( $expiry, $block->getExpiry() );
334 $this->assertFalse( $block->isSitewide() );
335 $this->assertCount( 2, $block->getRestrictions() );
336 $this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
337 new PageRestriction( $block->getId(), $pageMars->getId() ),
338 new PageRestriction( $block->getId(), $pageSaturn->getId() ),
339 ] ) );
340
341 // Remove a page from the partial block.
342 $data['PageRestrictions'] = $pageMars->getTitle()->getText();
343 $result = $page->processForm( $data, $context );
344
345 $this->assertTrue( $result );
346
347 $block = Block::newFromTarget( $badActor );
348 $this->assertSame( $reason, $block->mReason );
349 $this->assertSame( $expiry, $block->getExpiry() );
350 $this->assertFalse( $block->isSitewide() );
351 $this->assertCount( 1, $block->getRestrictions() );
352 $this->assertTrue( BlockRestriction::equals( $block->getRestrictions(), [
353 new PageRestriction( $block->getId(), $pageMars->getId() ),
354 ] ) );
355
356 // Remove the last page from the block.
357 $data['PageRestrictions'] = '';
358 $result = $page->processForm( $data, $context );
359
360 $this->assertTrue( $result );
361
362 $block = Block::newFromTarget( $badActor );
363 $this->assertSame( $reason, $block->mReason );
364 $this->assertSame( $expiry, $block->getExpiry() );
365 $this->assertFalse( $block->isSitewide() );
366 $this->assertCount( 0, $block->getRestrictions() );
367
368 // Change to sitewide.
369 $data['EditingRestriction'] = 'sitewide';
370 $result = $page->processForm( $data, $context );
371
372 $this->assertTrue( $result );
373
374 $block = Block::newFromTarget( $badActor );
375 $this->assertSame( $reason, $block->mReason );
376 $this->assertSame( $expiry, $block->getExpiry() );
377 $this->assertTrue( $block->isSitewide() );
378 $this->assertCount( 0, $block->getRestrictions() );
379
380 // Ensure that there are no restrictions where the blockId is 0.
381 $count = $this->db->selectRowCount(
382 'ipblocks_restrictions',
383 '*',
384 [ 'ir_ipb_id' => 0 ],
385 __METHOD__
386 );
387 $this->assertSame( 0, $count );
388 }
389
390 /**
391 * @dataProvider provideCheckUnblockSelf
392 * @covers ::checkUnblockSelf
393 */
394 public function testCheckUnblockSelf(
395 $blockedUser,
396 $blockPerformer,
397 $adjustPerformer,
398 $adjustTarget,
399 $expectedResult,
400 $reason
401 ) {
402 $this->setGroupPermissions( 'sysop', 'unblockself', true );
403 $this->setGroupPermissions( 'user', 'block', true );
404 // Getting errors about creating users in db in provider.
405 // Need to use mutable to ensure different named testusers.
406 $users = [
407 'u1' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
408 'u2' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
409 'u3' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
410 'u4' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
411 'nonsysop' => $this->getTestUser()->getUser()
412 ];
413 foreach ( [ 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget' ] as $var ) {
414 $$var = $users[$$var];
415 }
416
417 $block = new \Block( [
418 'address' => $blockedUser->getName(),
419 'user' => $blockedUser->getId(),
420 'by' => $blockPerformer->getId(),
421 'expiry' => 'infinity',
422 'sitewide' => 1,
423 'enableAutoblock' => true,
424 ] );
425
426 $block->insert();
427
428 $this->assertSame(
429 SpecialBlock::checkUnblockSelf( $adjustTarget, $adjustPerformer ),
430 $expectedResult,
431 $reason
432 );
433 }
434
435 public function provideCheckUnblockSelf() {
436 // 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget'
437 return [
438 [ 'u1', 'u2', 'u3', 'u4', true, 'Unrelated users' ],
439 [ 'u1', 'u2', 'u1', 'u4', 'ipbblocked', 'Block unrelated while blocked' ],
440 [ 'u1', 'u2', 'u1', 'u1', true, 'Has unblockself' ],
441 [ 'nonsysop', 'u2', 'nonsysop', 'nonsysop', 'ipbnounblockself', 'no unblockself' ],
442 [ 'nonsysop', 'nonsysop', 'nonsysop', 'nonsysop', true, 'no unblockself but can de-selfblock' ],
443 [ 'u1', 'u2', 'u1', 'u2', true, 'Can block user who blocked' ],
444 ];
445 }
446
447 protected function insertBlock() {
448 $badActor = $this->getTestUser()->getUser();
449 $sysop = $this->getTestSysop()->getUser();
450
451 $block = new \Block( [
452 'address' => $badActor->getName(),
453 'user' => $badActor->getId(),
454 'by' => $sysop->getId(),
455 'expiry' => 'infinity',
456 'sitewide' => 1,
457 'enableAutoblock' => true,
458 ] );
459
460 $block->insert();
461
462 return $block;
463 }
464
465 protected function resetTables() {
466 $this->db->delete( 'ipblocks', '*', __METHOD__ );
467 $this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
468 }
469 }