MediaWiki REL1_32
BlockTest.php
Go to the documentation of this file.
1<?php
2
8
12 private function getUserForBlocking() {
13 $testUser = $this->getMutableTestUser();
14 $user = $testUser->getUser();
15 $user->addToDatabase();
16 TestUser::setPasswordForUser( $user, 'UTBlockeePassword' );
17 $user->saveSettings();
18 return $user;
19 }
20
27 private function addBlockForUser( User $user ) {
28 // Delete the last round's block if it's still there
29 $oldBlock = Block::newFromTarget( $user->getName() );
30 if ( $oldBlock ) {
31 // An old block will prevent our new one from saving.
32 $oldBlock->delete();
33 }
34
35 $blockOptions = [
36 'address' => $user->getName(),
37 'user' => $user->getId(),
38 'by' => $this->getTestSysop()->getUser()->getId(),
39 'reason' => 'Parce que',
40 'expiry' => time() + 100500,
41 ];
42 $block = new Block( $blockOptions );
43
44 $block->insert();
45 // save up ID for use in assertion. Since ID is an autoincrement,
46 // its value might change depending on the order the tests are run.
47 // ApiBlockTest insert its own blocks!
48 if ( !$block->getId() ) {
49 throw new MWException( "Failed to insert block for BlockTest; old leftover block remaining?" );
50 }
51
52 $this->addXffBlocks();
53
54 return $block;
55 }
56
61 $user = $this->getUserForBlocking();
62 $block = $this->addBlockForUser( $user );
63
64 $this->assertTrue(
65 $block->equals( Block::newFromTarget( $user->getName() ) ),
66 "newFromTarget() returns the same block as the one that was made"
67 );
68 }
69
74 $user = $this->getUserForBlocking();
75 $block = $this->addBlockForUser( $user );
76
77 $this->assertTrue(
78 $block->equals( Block::newFromID( $block->getId() ) ),
79 "newFromID() returns the same block as the one that was made"
80 );
81 }
82
88 $user = $this->getUserForBlocking();
89 $block = $this->addBlockForUser( $user );
90 $madeAt = wfTimestamp( TS_MW );
91
92 // delta to stop one-off errors when things happen to go over a second mark.
93 $delta = abs( $madeAt - $block->mTimestamp );
94 $this->assertLessThan(
95 2,
96 $delta,
97 "If no timestamp is specified, the block is recorded as time()"
98 );
99 }
100
109 public function testT31116NewFromTargetWithEmptyIp( $vagueTarget ) {
110 $user = $this->getUserForBlocking();
111 $initialBlock = $this->addBlockForUser( $user );
112 $block = Block::newFromTarget( $user->getName(), $vagueTarget );
113
114 $this->assertTrue(
115 $initialBlock->equals( $block ),
116 "newFromTarget() returns the same block as the one that was made when "
117 . "given empty vagueTarget param " . var_export( $vagueTarget, true )
118 );
119 }
120
121 public static function provideT31116Data() {
122 return [
123 [ null ],
124 [ '' ],
125 [ false ]
126 ];
127 }
128
133 $username = 'BlockedUserToCreateAccountWith';
135 $u->addToDatabase();
136 $userId = $u->getId();
137 $this->assertNotEquals( 0, $userId, 'sanity' );
138 TestUser::setPasswordForUser( $u, 'NotRandomPass' );
139 unset( $u );
140
141 // Sanity check
142 $this->assertNull(
144 "$username should not be blocked"
145 );
146
147 // Reload user
149 $this->assertFalse(
150 $u->isBlockedFromCreateAccount(),
151 "Our sandbox user should be able to create account before being blocked"
152 );
153
154 // Foreign perspective (blockee not on current wiki)...
155 $blockOptions = [
156 'address' => $username,
157 'user' => $userId,
158 'reason' => 'crosswiki block...',
159 'timestamp' => wfTimestampNow(),
160 'expiry' => $this->db->getInfinity(),
161 'createAccount' => true,
162 'enableAutoblock' => true,
163 'hideName' => true,
164 'blockEmail' => true,
165 'byText' => 'm>MetaWikiUser',
166 ];
167 $block = new Block( $blockOptions );
168 $block->insert();
169
170 // Reload block from DB
171 $userBlock = Block::newFromTarget( $username );
172 $this->assertTrue(
173 (bool)$block->prevents( 'createaccount' ),
174 "Block object in DB should prevents 'createaccount'"
175 );
176
177 $this->assertInstanceOf(
178 Block::class,
179 $userBlock,
180 "'$username' block block object should be existent"
181 );
182
183 // Reload user
185 $this->assertTrue(
186 (bool)$u->isBlockedFromCreateAccount(),
187 "Our sandbox user '$username' should NOT be able to create account"
188 );
189 }
190
194 public function testCrappyCrossWikiBlocks() {
195 // Delete the last round's block if it's still there
196 $oldBlock = Block::newFromTarget( 'UserOnForeignWiki' );
197 if ( $oldBlock ) {
198 // An old block will prevent our new one from saving.
199 $oldBlock->delete();
200 }
201
202 // Local perspective (blockee on current wiki)...
203 $user = User::newFromName( 'UserOnForeignWiki' );
204 $user->addToDatabase();
205 $userId = $user->getId();
206 $this->assertNotEquals( 0, $userId, 'sanity' );
207
208 // Foreign perspective (blockee not on current wiki)...
209 $blockOptions = [
210 'address' => 'UserOnForeignWiki',
211 'user' => $user->getId(),
212 'reason' => 'crosswiki block...',
213 'timestamp' => wfTimestampNow(),
214 'expiry' => $this->db->getInfinity(),
215 'createAccount' => true,
216 'enableAutoblock' => true,
217 'hideName' => true,
218 'blockEmail' => true,
219 'byText' => 'Meta>MetaWikiUser',
220 ];
221 $block = new Block( $blockOptions );
222
223 $res = $block->insert( $this->db );
224 $this->assertTrue( (bool)$res['id'], 'Block succeeded' );
225
226 $user = null; // clear
227
228 $block = Block::newFromID( $res['id'] );
229 $this->assertEquals(
230 'UserOnForeignWiki',
231 $block->getTarget()->getName(),
232 'Correct blockee name'
233 );
234 $this->assertEquals( $userId, $block->getTarget()->getId(), 'Correct blockee id' );
235 $this->assertEquals( 'Meta>MetaWikiUser', $block->getBlocker()->getName(),
236 'Correct blocker name' );
237 $this->assertEquals( 'Meta>MetaWikiUser', $block->getByName(), 'Correct blocker name' );
238 $this->assertEquals( 0, $block->getBy(), 'Correct blocker id' );
239 }
240
241 protected function addXffBlocks() {
242 static $inited = false;
243
244 if ( $inited ) {
245 return;
246 }
247
248 $inited = true;
249
250 $blockList = [
251 [ 'target' => '70.2.0.0/16',
252 'type' => Block::TYPE_RANGE,
253 'desc' => 'Range Hardblock',
254 'ACDisable' => false,
255 'isHardblock' => true,
256 'isAutoBlocking' => false,
257 ],
258 [ 'target' => '2001:4860:4001::/48',
259 'type' => Block::TYPE_RANGE,
260 'desc' => 'Range6 Hardblock',
261 'ACDisable' => false,
262 'isHardblock' => true,
263 'isAutoBlocking' => false,
264 ],
265 [ 'target' => '60.2.0.0/16',
266 'type' => Block::TYPE_RANGE,
267 'desc' => 'Range Softblock with AC Disabled',
268 'ACDisable' => true,
269 'isHardblock' => false,
270 'isAutoBlocking' => false,
271 ],
272 [ 'target' => '50.2.0.0/16',
273 'type' => Block::TYPE_RANGE,
274 'desc' => 'Range Softblock',
275 'ACDisable' => false,
276 'isHardblock' => false,
277 'isAutoBlocking' => false,
278 ],
279 [ 'target' => '50.1.1.1',
280 'type' => Block::TYPE_IP,
281 'desc' => 'Exact Softblock',
282 'ACDisable' => false,
283 'isHardblock' => false,
284 'isAutoBlocking' => false,
285 ],
286 ];
287
288 $blocker = $this->getTestUser()->getUser();
289 foreach ( $blockList as $insBlock ) {
290 $target = $insBlock['target'];
291
292 if ( $insBlock['type'] === Block::TYPE_IP ) {
293 $target = User::newFromName( IP::sanitizeIP( $target ), false )->getName();
294 } elseif ( $insBlock['type'] === Block::TYPE_RANGE ) {
295 $target = IP::sanitizeRange( $target );
296 }
297
298 $block = new Block();
299 $block->setTarget( $target );
300 $block->setBlocker( $blocker );
301 $block->mReason = $insBlock['desc'];
302 $block->mExpiry = 'infinity';
303 $block->prevents( 'createaccount', $insBlock['ACDisable'] );
304 $block->isHardblock( $insBlock['isHardblock'] );
305 $block->isAutoblocking( $insBlock['isAutoBlocking'] );
306 $block->insert();
307 }
308 }
309
310 public static function providerXff() {
311 return [
312 [ 'xff' => '1.2.3.4, 70.2.1.1, 60.2.1.1, 2.3.4.5',
313 'count' => 2,
314 'result' => 'Range Hardblock'
315 ],
316 [ 'xff' => '1.2.3.4, 50.2.1.1, 60.2.1.1, 2.3.4.5',
317 'count' => 2,
318 'result' => 'Range Softblock with AC Disabled'
319 ],
320 [ 'xff' => '1.2.3.4, 70.2.1.1, 50.1.1.1, 2.3.4.5',
321 'count' => 2,
322 'result' => 'Exact Softblock'
323 ],
324 [ 'xff' => '1.2.3.4, 70.2.1.1, 50.2.1.1, 50.1.1.1, 2.3.4.5',
325 'count' => 3,
326 'result' => 'Exact Softblock'
327 ],
328 [ 'xff' => '1.2.3.4, 70.2.1.1, 50.2.1.1, 2.3.4.5',
329 'count' => 2,
330 'result' => 'Range Hardblock'
331 ],
332 [ 'xff' => '1.2.3.4, 70.2.1.1, 60.2.1.1, 2.3.4.5',
333 'count' => 2,
334 'result' => 'Range Hardblock'
335 ],
336 [ 'xff' => '50.2.1.1, 60.2.1.1, 2.3.4.5',
337 'count' => 2,
338 'result' => 'Range Softblock with AC Disabled'
339 ],
340 [ 'xff' => '1.2.3.4, 50.1.1.1, 60.2.1.1, 2.3.4.5',
341 'count' => 2,
342 'result' => 'Exact Softblock'
343 ],
344 [ 'xff' => '1.2.3.4, <$A_BUNCH-OF{INVALID}TEXT>, 60.2.1.1, 2.3.4.5',
345 'count' => 1,
346 'result' => 'Range Softblock with AC Disabled'
347 ],
348 [ 'xff' => '1.2.3.4, 50.2.1.1, 2001:4860:4001:802::1003, 2.3.4.5',
349 'count' => 2,
350 'result' => 'Range6 Hardblock'
351 ],
352 ];
353 }
354
360 public function testBlocksOnXff( $xff, $exCount, $exResult ) {
361 $user = $this->getUserForBlocking();
362 $this->addBlockForUser( $user );
363
364 $list = array_map( 'trim', explode( ',', $xff ) );
365 $xffblocks = Block::getBlocksForIPList( $list, true );
366 $this->assertEquals( $exCount, count( $xffblocks ), 'Number of blocks for ' . $xff );
367 $block = Block::chooseBlock( $xffblocks, $list );
368 $this->assertEquals( $exResult, $block->mReason, 'Correct block type for XFF header ' . $xff );
369 }
370
374 public function testDeprecatedConstructor() {
375 $this->hideDeprecated( 'Block::__construct with multiple arguments' );
376 $username = 'UnthinkablySecretRandomUsername';
377 $reason = 'being irrational';
378
379 # Set up the target
381 if ( $u->getId() == 0 ) {
382 $u->addToDatabase();
383 TestUser::setPasswordForUser( $u, 'TotallyObvious' );
384 }
385 unset( $u );
386
387 # Make sure the user isn't blocked
388 $this->assertNull(
390 "$username should not be blocked"
391 );
392
393 # Perform the block
394 $block = new Block(
395 /* address */ $username,
396 /* user */ 0,
397 /* by */ $this->getTestSysop()->getUser()->getId(),
398 /* reason */ $reason,
399 /* timestamp */ 0,
400 /* auto */ false,
401 /* expiry */ 0
402 );
403 $block->insert();
404
405 # Check target
406 $this->assertEquals(
407 $block->getTarget()->getName(),
408 $username,
409 "Target should be set properly"
410 );
411
412 # Check supplied parameter
413 $this->assertEquals(
414 $block->mReason,
415 $reason,
416 "Reason should be non-default"
417 );
418
419 # Check default parameter
420 $this->assertFalse(
421 (bool)$block->prevents( 'createaccount' ),
422 "Account creation should not be blocked by default"
423 );
424 }
425
431 public function testSystemBlocks() {
432 $user = $this->getUserForBlocking();
433 $this->addBlockForUser( $user );
434
435 $blockOptions = [
436 'address' => $user->getName(),
437 'reason' => 'test system block',
438 'timestamp' => wfTimestampNow(),
439 'expiry' => $this->db->getInfinity(),
440 'byText' => 'MediaWiki default',
441 'systemBlock' => 'test',
442 'enableAutoblock' => true,
443 ];
444 $block = new Block( $blockOptions );
445
446 $this->assertSame( 'test', $block->getSystemBlockType() );
447
448 try {
449 $block->insert();
450 $this->fail( 'Expected exception not thrown' );
451 } catch ( MWException $ex ) {
452 $this->assertSame( 'Cannot insert a system block into the database', $ex->getMessage() );
453 }
454
455 try {
456 $block->doAutoblock( '192.0.2.2' );
457 $this->fail( 'Expected exception not thrown' );
458 } catch ( MWException $ex ) {
459 $this->assertSame( 'Cannot autoblock from a system block', $ex->getMessage() );
460 }
461 }
462
463}
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Database Blocking.
Definition BlockTest.php:7
testDeprecatedConstructor()
Block::__construct.
getUserForBlocking()
Definition BlockTest.php:12
testBlockedUserCanNotCreateAccount()
Block::prevents.
testINewFromIDReturnsCorrectBlock()
Block::newFromID.
Definition BlockTest.php:73
addBlockForUser(User $user)
Definition BlockTest.php:27
testT31116NewFromTargetWithEmptyIp( $vagueTarget)
CheckUser since being changed to use Block::newFromTarget started failing because the new function di...
testCrappyCrossWikiBlocks()
Block::insert.
static providerXff()
testINewFromTargetReturnsCorrectBlock()
Block::newFromTarget.
Definition BlockTest.php:60
testT28425BlockTimestampDefaultsToTime()
per T28425 Block::__construct
Definition BlockTest.php:87
testSystemBlocks()
Block::getSystemBlockType Block::insert Block::doAutoblock.
static provideT31116Data()
testBlocksOnXff( $xff, $exCount, $exResult)
providerXff Block::getBlocksForIPList Block::chooseBlock
static newFromID( $id)
Load a blocked user from their block id.
Definition Block.php:184
static getBlocksForIPList(array $ipChain, $isAnon, $fromMaster=false)
Get all blocks that match any IP from an array of IP addresses.
Definition Block.php:1213
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest Block.
Definition Block.php:1294
const TYPE_RANGE
Definition Block.php:85
static newFromTarget( $specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target's type, get an existing Block object if possible.
Definition Block.php:1174
const TYPE_IP
Definition Block.php:84
MediaWiki exception.
Base class that store and restore the Language objects.
static getMutableTestUser( $groups=[])
Convenience method for getting a mutable test user.
static getTestSysop()
Convenience method for getting an immutable admin test user.
hideDeprecated( $function)
Don't throw a warning if $function is deprecated and called later.
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
static setPasswordForUser(User $user, $password)
Set the password on a testing user.
Definition TestUser.php:129
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:47
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition User.php:592
$res
Definition database.txt:21
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
this hook is for auditing only or null if authentication failed before getting that far $username
Definition hooks.txt:815
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition hooks.txt:247
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37