Merge "build: Upgrade eslint-utils dependency from 1.3.1 to 1.4.2 for security issues"
[lhc/web/wiklou.git] / tests / phpunit / includes / Permissions / PermissionManagerTest.php
1 <?php
2
3 namespace MediaWiki\Tests\Permissions;
4
5 use Action;
6 use ContentHandler;
7 use FauxRequest;
8 use LoggedServiceOptions;
9 use MediaWiki\Block\DatabaseBlock;
10 use MediaWiki\Block\Restriction\NamespaceRestriction;
11 use MediaWiki\Block\Restriction\PageRestriction;
12 use MediaWiki\Block\SystemBlock;
13 use MediaWiki\Linker\LinkTarget;
14 use MediaWiki\MediaWikiServices;
15 use MediaWiki\Permissions\PermissionManager;
16 use MediaWiki\Revision\MutableRevisionRecord;
17 use MediaWiki\Revision\RevisionLookup;
18 use MWException;
19 use TestAllServiceOptionsUsed;
20 use Wikimedia\ScopedCallback;
21 use MediaWiki\Session\SessionId;
22 use MediaWiki\Session\TestUtils;
23 use MediaWikiLangTestCase;
24 use RequestContext;
25 use stdClass;
26 use Title;
27 use User;
28 use Wikimedia\TestingAccessWrapper;
29
30 /**
31 * @group Database
32 *
33 * @covers \MediaWiki\Permissions\PermissionManager
34 */
35 class PermissionManagerTest extends MediaWikiLangTestCase {
36 use TestAllServiceOptionsUsed;
37
38 /**
39 * @var string
40 */
41 protected $userName, $altUserName;
42
43 /**
44 * @var Title
45 */
46 protected $title;
47
48 /**
49 * @var User
50 */
51 protected $user, $anonUser, $userUser, $altUser;
52
53 /** Constant for self::testIsBlockedFrom */
54 const USER_TALK_PAGE = '<user talk page>';
55
56 protected function setUp() {
57 parent::setUp();
58
59 $localZone = 'UTC';
60 $localOffset = date( 'Z' ) / 60;
61
62 $this->setMwGlobals( [
63 'wgLocaltimezone' => $localZone,
64 'wgLocalTZoffset' => $localOffset,
65 'wgNamespaceProtection' => [
66 NS_MEDIAWIKI => 'editinterface',
67 ],
68 'wgRevokePermissions' => [
69 'formertesters' => [
70 'runtest' => true
71 ]
72 ],
73 'wgAvailableRights' => [
74 'test',
75 'runtest',
76 'writetest',
77 'nukeworld',
78 'modifytest',
79 'editmyoptions'
80 ]
81 ] );
82
83 $this->setGroupPermissions( 'unittesters', 'test', true );
84 $this->setGroupPermissions( 'unittesters', 'runtest', true );
85 $this->setGroupPermissions( 'unittesters', 'writetest', false );
86 $this->setGroupPermissions( 'unittesters', 'nukeworld', false );
87
88 $this->setGroupPermissions( 'testwriters', 'test', true );
89 $this->setGroupPermissions( 'testwriters', 'writetest', true );
90 $this->setGroupPermissions( 'testwriters', 'modifytest', true );
91
92 $this->setGroupPermissions( '*', 'editmyoptions', true );
93
94 // Without this testUserBlock will use a non-English context on non-English MediaWiki
95 // installations (because of how Title::checkUserBlock is implemented) and fail.
96 RequestContext::resetMain();
97
98 $this->userName = 'Useruser';
99 $this->altUserName = 'Altuseruser';
100 date_default_timezone_set( $localZone );
101
102 $this->title = Title::makeTitle( NS_MAIN, "Main Page" );
103 if ( !isset( $this->userUser ) || !( $this->userUser instanceof User ) ) {
104 $this->userUser = User::newFromName( $this->userName );
105
106 if ( !$this->userUser->getId() ) {
107 $this->userUser = User::createNew( $this->userName, [
108 "email" => "test@example.com",
109 "real_name" => "Test User" ] );
110 $this->userUser->load();
111 }
112
113 $this->altUser = User::newFromName( $this->altUserName );
114 if ( !$this->altUser->getId() ) {
115 $this->altUser = User::createNew( $this->altUserName, [
116 "email" => "alttest@example.com",
117 "real_name" => "Test User Alt" ] );
118 $this->altUser->load();
119 }
120
121 $this->anonUser = User::newFromId( 0 );
122
123 $this->user = $this->userUser;
124 }
125 }
126
127 public function tearDown() {
128 parent::tearDown();
129 $this->restoreMwServices();
130 }
131
132 protected function setTitle( $ns, $title = "Main_Page" ) {
133 $this->title = Title::makeTitle( $ns, $title );
134 }
135
136 protected function setUser( $userName = null ) {
137 if ( $userName === 'anon' ) {
138 $this->user = $this->anonUser;
139 } elseif ( $userName === null || $userName === $this->userName ) {
140 $this->user = $this->userUser;
141 } else {
142 $this->user = $this->altUser;
143 }
144 }
145
146 /**
147 * @todo This test method should be split up into separate test methods and
148 * data providers
149 *
150 * This test is failing per T201776.
151 *
152 * @group Broken
153 * @covers \MediaWiki\Permissions\PermissionManager::checkQuickPermissions
154 */
155 public function testQuickPermissions() {
156 $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
157 getFormattedNsText( NS_PROJECT );
158
159 $this->setUser( 'anon' );
160 $this->setTitle( NS_TALK );
161 $this->overrideUserPermissions( $this->user, "createtalk" );
162 $res = MediaWikiServices::getInstance()->getPermissionManager()
163 ->getPermissionErrors( 'create', $this->user, $this->title );
164 $this->assertEquals( [], $res );
165
166 $this->setTitle( NS_TALK );
167 $this->overrideUserPermissions( $this->user, "createpage" );
168 $res = MediaWikiServices::getInstance()->getPermissionManager()
169 ->getPermissionErrors( 'create', $this->user, $this->title );
170 $this->assertEquals( [ [ "nocreatetext" ] ], $res );
171
172 $this->setTitle( NS_TALK );
173 $this->overrideUserPermissions( $this->user, "" );
174 $res = MediaWikiServices::getInstance()->getPermissionManager()
175 ->getPermissionErrors( 'create', $this->user, $this->title );
176 $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
177
178 $this->setTitle( NS_MAIN );
179 $this->overrideUserPermissions( $this->user, "createpage" );
180 $res = MediaWikiServices::getInstance()->getPermissionManager()
181 ->getPermissionErrors( 'create', $this->user, $this->title );
182 $this->assertEquals( [], $res );
183
184 $this->setTitle( NS_MAIN );
185 $this->overrideUserPermissions( $this->user, "createtalk" );
186 $res = MediaWikiServices::getInstance()->getPermissionManager()
187 ->getPermissionErrors( 'create', $this->user, $this->title );
188 $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
189
190 $this->setUser( $this->userName );
191 $this->setTitle( NS_TALK );
192 $this->overrideUserPermissions( $this->user, "createtalk" );
193 $res = MediaWikiServices::getInstance()->getPermissionManager()
194 ->getPermissionErrors( 'create', $this->user, $this->title );
195 $this->assertEquals( [], $res );
196
197 $this->setTitle( NS_TALK );
198 $this->overrideUserPermissions( $this->user, "createpage" );
199 $res = MediaWikiServices::getInstance()->getPermissionManager()
200 ->getPermissionErrors( 'create', $this->user, $this->title );
201 $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
202
203 $this->setTitle( NS_TALK );
204 $this->overrideUserPermissions( $this->user, "" );
205 $res = MediaWikiServices::getInstance()->getPermissionManager()
206 ->getPermissionErrors( 'create', $this->user, $this->title );
207 $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
208
209 $this->setTitle( NS_MAIN );
210 $this->overrideUserPermissions( $this->user, "createpage" );
211 $res = MediaWikiServices::getInstance()->getPermissionManager()
212 ->getPermissionErrors( 'create', $this->user, $this->title );
213 $this->assertEquals( [], $res );
214
215 $this->setTitle( NS_MAIN );
216 $this->overrideUserPermissions( $this->user, "createtalk" );
217 $res = MediaWikiServices::getInstance()->getPermissionManager()
218 ->getPermissionErrors( 'create', $this->user, $this->title );
219 $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
220
221 $this->setTitle( NS_MAIN );
222 $this->overrideUserPermissions( $this->user, "" );
223 $res = MediaWikiServices::getInstance()->getPermissionManager()
224 ->getPermissionErrors( 'create', $this->user, $this->title );
225 $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
226
227 $this->setUser( 'anon' );
228 $this->setTitle( NS_USER, $this->userName . '' );
229 $this->overrideUserPermissions( $this->user, "" );
230 $res = MediaWikiServices::getInstance()->getPermissionManager()
231 ->getPermissionErrors( 'move', $this->user, $this->title );
232 $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
233
234 $this->setTitle( NS_USER, $this->userName . '/subpage' );
235 $this->overrideUserPermissions( $this->user, "" );
236 $res = MediaWikiServices::getInstance()->getPermissionManager()
237 ->getPermissionErrors( 'move', $this->user, $this->title );
238 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
239
240 $this->setTitle( NS_USER, $this->userName . '' );
241 $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
242 $res = MediaWikiServices::getInstance()->getPermissionManager()
243 ->getPermissionErrors( 'move', $this->user, $this->title );
244 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
245
246 $this->setTitle( NS_USER, $this->userName . '/subpage' );
247 $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
248 $res = MediaWikiServices::getInstance()->getPermissionManager()
249 ->getPermissionErrors( 'move', $this->user, $this->title );
250 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
251
252 $this->setTitle( NS_USER, $this->userName . '' );
253 $this->overrideUserPermissions( $this->user, "" );
254 $res = MediaWikiServices::getInstance()->getPermissionManager()
255 ->getPermissionErrors( 'move', $this->user, $this->title );
256 $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
257
258 $this->setTitle( NS_USER, $this->userName . '/subpage' );
259 $this->overrideUserPermissions( $this->user, "" );
260 $res = MediaWikiServices::getInstance()->getPermissionManager()
261 ->getPermissionErrors( 'move', $this->user, $this->title );
262 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
263
264 $this->setTitle( NS_USER, $this->userName . '' );
265 $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
266 $res = MediaWikiServices::getInstance()->getPermissionManager()
267 ->getPermissionErrors( 'move', $this->user, $this->title );
268 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
269
270 $this->setTitle( NS_USER, $this->userName . '/subpage' );
271 $this->overrideUserPermissions( $this->user, "move-rootuserpages" );
272 $res = MediaWikiServices::getInstance()->getPermissionManager()
273 ->getPermissionErrors( 'move', $this->user, $this->title );
274 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
275
276 $this->setUser( $this->userName );
277 $this->setTitle( NS_FILE, "img.png" );
278 $this->overrideUserPermissions( $this->user, "" );
279 $res = MediaWikiServices::getInstance()->getPermissionManager()
280 ->getPermissionErrors( 'move', $this->user, $this->title );
281 $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ], $res );
282
283 $this->setTitle( NS_FILE, "img.png" );
284 $this->overrideUserPermissions( $this->user, "movefile" );
285 $res = MediaWikiServices::getInstance()->getPermissionManager()
286 ->getPermissionErrors( 'move', $this->user, $this->title );
287 $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
288
289 $this->setUser( 'anon' );
290 $this->setTitle( NS_FILE, "img.png" );
291 $this->overrideUserPermissions( $this->user, "" );
292 $res = MediaWikiServices::getInstance()->getPermissionManager()
293 ->getPermissionErrors( 'move', $this->user, $this->title );
294 $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ], $res );
295
296 $this->setTitle( NS_FILE, "img.png" );
297 $this->overrideUserPermissions( $this->user, "movefile" );
298 $res = MediaWikiServices::getInstance()->getPermissionManager()
299 ->getPermissionErrors( 'move', $this->user, $this->title );
300 $this->assertEquals( [ [ 'movenologintext' ] ], $res );
301
302 $this->setUser( $this->userName );
303 // $this->setUserPerm( "move" );
304 $this->runGroupPermissions( 'move', 'move', [ [ 'movenotallowedfile' ] ] );
305
306 // $this->setUserPerm( "" );
307 $this->runGroupPermissions(
308 '',
309 'move',
310 [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ]
311 );
312
313 $this->setUser( 'anon' );
314 //$this->setUserPerm( "move" );
315 $this->runGroupPermissions( 'move', 'move', [ [ 'movenotallowedfile' ] ] );
316
317 // $this->setUserPerm( "" );
318 $this->runGroupPermissions(
319 '',
320 'move',
321 [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ],
322 [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ]
323 );
324
325 if ( $this->isWikitextNS( NS_MAIN ) ) {
326 // NOTE: some content models don't allow moving
327 // @todo find a Wikitext namespace for testing
328
329 $this->setTitle( NS_MAIN );
330 $this->setUser( 'anon' );
331 // $this->setUserPerm( "move" );
332 $this->runGroupPermissions( 'move', 'move', [] );
333
334 // $this->setUserPerm( "" );
335 $this->runGroupPermissions( '', 'move', [ [ 'movenotallowed' ] ],
336 [ [ 'movenologintext' ] ] );
337
338 $this->setUser( $this->userName );
339 // $this->setUserPerm( "" );
340 $this->runGroupPermissions( '', 'move', [ [ 'movenotallowed' ] ] );
341
342 //$this->setUserPerm( "move" );
343 $this->runGroupPermissions( 'move', 'move', [] );
344
345 $this->setUser( 'anon' );
346 $this->overrideUserPermissions( $this->user, 'move' );
347 $res = MediaWikiServices::getInstance()->getPermissionManager()
348 ->getPermissionErrors( 'move-target', $this->user, $this->title );
349 $this->assertEquals( [], $res );
350
351 $this->overrideUserPermissions( $this->user, '' );
352 $res = MediaWikiServices::getInstance()->getPermissionManager()
353 ->getPermissionErrors( 'move-target', $this->user, $this->title );
354 $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
355 }
356
357 $this->setTitle( NS_USER );
358 $this->setUser( $this->userName );
359 $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
360 $res = MediaWikiServices::getInstance()->getPermissionManager()
361 ->getPermissionErrors( 'move-target', $this->user, $this->title );
362 $this->assertEquals( [], $res );
363
364 $this->overrideUserPermissions( $this->user, "move" );
365 $res = MediaWikiServices::getInstance()->getPermissionManager()
366 ->getPermissionErrors( 'move-target', $this->user, $this->title );
367 $this->assertEquals( [ [ 'cant-move-to-user-page' ] ], $res );
368
369 $this->setUser( 'anon' );
370 $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
371 $res = MediaWikiServices::getInstance()->getPermissionManager()
372 ->getPermissionErrors( 'move-target', $this->user, $this->title );
373 $this->assertEquals( [], $res );
374
375 $this->setTitle( NS_USER, "User/subpage" );
376 $this->overrideUserPermissions( $this->user, [ "move", "move-rootuserpages" ] );
377 $res = MediaWikiServices::getInstance()->getPermissionManager()
378 ->getPermissionErrors( 'move-target', $this->user, $this->title );
379 $this->assertEquals( [], $res );
380
381 $this->overrideUserPermissions( $this->user, "move" );
382 $res = MediaWikiServices::getInstance()->getPermissionManager()
383 ->getPermissionErrors( 'move-target', $this->user, $this->title );
384 $this->assertEquals( [], $res );
385
386 $this->setUser( 'anon' );
387 $check = [
388 'edit' => [
389 [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ] ],
390 [ [ 'badaccess-group0' ] ],
391 [],
392 true
393 ],
394 'protect' => [
395 [ [
396 'badaccess-groups',
397 "[[$prefix:Administrators|Administrators]]", 1 ],
398 [ 'protect-cantedit'
399 ] ],
400 [ [ 'badaccess-group0' ], [ 'protect-cantedit' ] ],
401 [ [ 'protect-cantedit' ] ],
402 false
403 ],
404 '' => [ [], [], [], true ]
405 ];
406
407 foreach ( [ "edit", "protect", "" ] as $action ) {
408 $this->overrideUserPermissions( $this->user );
409 $this->assertEquals( $check[$action][0],
410 MediaWikiServices::getInstance()->getPermissionManager()
411 ->getPermissionErrors( $action, $this->user, $this->title, true ) );
412 $this->assertEquals( $check[$action][0],
413 MediaWikiServices::getInstance()->getPermissionManager()
414 ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
415 $this->assertEquals( $check[$action][0],
416 MediaWikiServices::getInstance()->getPermissionManager()
417 ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
418
419 global $wgGroupPermissions;
420 $old = $wgGroupPermissions;
421 $this->setMwGlobals( 'wgGroupPermissions', [] );
422
423 $this->assertEquals( $check[$action][1],
424 MediaWikiServices::getInstance()->getPermissionManager()
425 ->getPermissionErrors( $action, $this->user, $this->title, true ) );
426 $this->assertEquals( $check[$action][1],
427 MediaWikiServices::getInstance()->getPermissionManager()
428 ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
429 $this->assertEquals( $check[$action][1],
430 MediaWikiServices::getInstance()->getPermissionManager()
431 ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
432 $this->setMwGlobals( 'wgGroupPermissions', $old );
433
434 $this->overrideUserPermissions( $this->user, $action );
435 $this->assertEquals( $check[$action][2],
436 MediaWikiServices::getInstance()->getPermissionManager()
437 ->getPermissionErrors( $action, $this->user, $this->title, true ) );
438 $this->assertEquals( $check[$action][2],
439 MediaWikiServices::getInstance()->getPermissionManager()
440 ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
441 $this->assertEquals( $check[$action][2],
442 MediaWikiServices::getInstance()->getPermissionManager()
443 ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
444
445 $this->overrideUserPermissions( $this->user, $action );
446 $this->assertEquals( $check[$action][3],
447 MediaWikiServices::getInstance()->getPermissionManager()
448 ->userCan( $action, $this->user, $this->title, true ) );
449 $this->assertEquals( $check[$action][3],
450 MediaWikiServices::getInstance()->getPermissionManager()
451 ->userCan( $action, $this->user, $this->title,
452 PermissionManager::RIGOR_QUICK ) );
453 # count( User::getGroupsWithPermissions( $action ) ) < 1
454 }
455 }
456
457 protected function runGroupPermissions( $perm, $action, $result, $result2 = null ) {
458 if ( $result2 === null ) {
459 $result2 = $result;
460 }
461
462 $this->setGroupPermissions( 'autoconfirmed', 'move', false );
463 $this->setGroupPermissions( 'user', 'move', false );
464 $this->overrideUserPermissions( $this->user, $perm );
465 $res = MediaWikiServices::getInstance()->getPermissionManager()
466 ->getPermissionErrors( $action, $this->user, $this->title );
467 $this->assertEquals( $result, $res );
468
469 $this->setGroupPermissions( 'autoconfirmed', 'move', true );
470 $this->setGroupPermissions( 'user', 'move', false );
471 $this->overrideUserPermissions( $this->user, $perm );
472 $res = MediaWikiServices::getInstance()->getPermissionManager()
473 ->getPermissionErrors( $action, $this->user, $this->title );
474 $this->assertEquals( $result2, $res );
475
476 $this->setGroupPermissions( 'autoconfirmed', 'move', true );
477 $this->setGroupPermissions( 'user', 'move', true );
478 $this->overrideUserPermissions( $this->user, $perm );
479 $res = MediaWikiServices::getInstance()->getPermissionManager()
480 ->getPermissionErrors( $action, $this->user, $this->title );
481 $this->assertEquals( $result2, $res );
482
483 $this->setGroupPermissions( 'autoconfirmed', 'move', false );
484 $this->setGroupPermissions( 'user', 'move', true );
485 $this->overrideUserPermissions( $this->user, $perm );
486 $res = MediaWikiServices::getInstance()->getPermissionManager()
487 ->getPermissionErrors( $action, $this->user, $this->title );
488 $this->assertEquals( $result2, $res );
489 }
490
491 /**
492 * @todo This test method should be split up into separate test methods and
493 * data providers
494 * @covers MediaWiki\Permissions\PermissionManager::checkSpecialsAndNSPermissions
495 */
496 public function testSpecialsAndNSPermissions() {
497 $this->setUser( $this->userName );
498
499 $this->setTitle( NS_SPECIAL );
500
501 $this->assertEquals( [ [ 'badaccess-group0' ], [ 'ns-specialprotected' ] ],
502 MediaWikiServices::getInstance()->getPermissionManager()
503 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
504
505 $this->setTitle( NS_MAIN );
506 $this->overrideUserPermissions( $this->user, 'bogus' );
507 $this->assertEquals( [],
508 MediaWikiServices::getInstance()->getPermissionManager()
509 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
510
511 $this->setTitle( NS_MAIN );
512 $this->overrideUserPermissions( $this->user, '' );
513 $this->assertEquals( [ [ 'badaccess-group0' ] ],
514 MediaWikiServices::getInstance()->getPermissionManager()
515 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
516
517 $this->mergeMwGlobalArrayValue( 'wgNamespaceProtection', [
518 NS_USER => [ 'bogus' ]
519 ] );
520 $this->resetServices();
521 $this->overrideUserPermissions( $this->user, '' );
522
523 $this->setTitle( NS_USER );
524 $this->assertEquals( [ [ 'badaccess-group0' ],
525 [ 'namespaceprotected', 'User', 'bogus' ] ],
526 MediaWikiServices::getInstance()->getPermissionManager()
527 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
528
529 $this->setTitle( NS_MEDIAWIKI );
530 $this->overrideUserPermissions( $this->user, 'bogus' );
531 $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
532 MediaWikiServices::getInstance()->getPermissionManager()
533 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
534
535 $this->setTitle( NS_MEDIAWIKI );
536 $this->overrideUserPermissions( $this->user, 'bogus' );
537 $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
538 MediaWikiServices::getInstance()->getPermissionManager()
539 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
540
541 $this->setMwGlobals( 'wgNamespaceProtection', null );
542 $this->resetServices();
543 $this->overrideUserPermissions( $this->user, 'bogus' );
544
545 $this->assertEquals( [],
546 MediaWikiServices::getInstance()->getPermissionManager()
547 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
548 $this->assertEquals( true,
549 MediaWikiServices::getInstance()->getPermissionManager()
550 ->userCan( 'bogus', $this->user, $this->title ) );
551
552 $this->overrideUserPermissions( $this->user, '' );
553 $this->assertEquals( [ [ 'badaccess-group0' ] ],
554 MediaWikiServices::getInstance()->getPermissionManager()
555 ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
556 $this->assertEquals( false,
557 MediaWikiServices::getInstance()->getPermissionManager()
558 ->userCan( 'bogus', $this->user, $this->title ) );
559 }
560
561 /**
562 * @todo This test method should be split up into separate test methods and
563 * data providers
564 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
565 */
566 public function testJsConfigEditPermissions() {
567 $this->setUser( $this->userName );
568
569 $this->setTitle( NS_USER, $this->userName . '/test.js' );
570 $this->runConfigEditPermissions(
571 [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
572
573 [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
574 [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
575 [ [ 'badaccess-group0' ] ],
576
577 [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
578 [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
579 [ [ 'badaccess-group0' ] ],
580 [ [ 'badaccess-groups' ] ]
581 );
582 }
583
584 /**
585 * @todo This test method should be split up into separate test methods and
586 * data providers
587 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
588 */
589 public function testJsonConfigEditPermissions() {
590 $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
591 getFormattedNsText( NS_PROJECT );
592 $this->setUser( $this->userName );
593
594 $this->setTitle( NS_USER, $this->userName . '/test.json' );
595 $this->runConfigEditPermissions(
596 [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
597
598 [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
599 [ [ 'badaccess-group0' ] ],
600 [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
601
602 [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
603 [ [ 'badaccess-group0' ] ],
604 [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
605 [ [ 'badaccess-groups' ] ]
606 );
607 }
608
609 /**
610 * @todo This test method should be split up into separate test methods and
611 * data providers
612 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
613 */
614 public function testCssConfigEditPermissions() {
615 $this->setUser( $this->userName );
616
617 $this->setTitle( NS_USER, $this->userName . '/test.css' );
618 $this->runConfigEditPermissions(
619 [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
620
621 [ [ 'badaccess-group0' ] ],
622 [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
623 [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
624
625 [ [ 'badaccess-group0' ] ],
626 [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
627 [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
628 [ [ 'badaccess-groups' ] ]
629 );
630 }
631
632 /**
633 * @todo This test method should be split up into separate test methods and
634 * data providers
635 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
636 */
637 public function testOtherJsConfigEditPermissions() {
638 $this->setUser( $this->userName );
639
640 $this->setTitle( NS_USER, $this->altUserName . '/test.js' );
641 $this->runConfigEditPermissions(
642 [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
643
644 [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
645 [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
646 [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
647
648 [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
649 [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
650 [ [ 'badaccess-group0' ] ],
651 [ [ 'badaccess-groups' ] ]
652 );
653 }
654
655 /**
656 * @todo This test method should be split up into separate test methods and
657 * data providers
658 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
659 */
660 public function testOtherJsonConfigEditPermissions() {
661 $this->setUser( $this->userName );
662
663 $this->setTitle( NS_USER, $this->altUserName . '/test.json' );
664 $this->runConfigEditPermissions(
665 [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
666
667 [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
668 [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
669 [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
670
671 [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
672 [ [ 'badaccess-group0' ] ],
673 [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
674 [ [ 'badaccess-groups' ] ]
675 );
676 }
677
678 /**
679 * @todo This test method should be split up into separate test methods and
680 * data providers
681 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
682 */
683 public function testOtherCssConfigEditPermissions() {
684 $this->setUser( $this->userName );
685
686 $this->setTitle( NS_USER, $this->altUserName . '/test.css' );
687 $this->runConfigEditPermissions(
688 [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
689
690 [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
691 [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
692 [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
693
694 [ [ 'badaccess-group0' ] ],
695 [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
696 [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
697 [ [ 'badaccess-groups' ] ]
698 );
699 }
700
701 public function testJsConfigRedirectEditPermissions() {
702 $revision = null;
703 $user = $this->getTestUser()->getUser();
704 $otherUser = $this->getTestUser( 'sysop' )->getUser();
705 $localJsTitle = Title::newFromText( 'User:' . $user->getName() . '/foo.js' );
706 $otherLocalJsTitle = Title::newFromText( 'User:' . $user->getName() . '/foo2.js' );
707 $nonlocalJsTitle = Title::newFromText( 'User:' . $otherUser->getName() . '/foo.js' );
708
709 $services = MediaWikiServices::getInstance();
710 $revisionLookup = $this->getMockBuilder( RevisionLookup::class )
711 ->setMethods( [ 'getRevisionByTitle' ] )
712 ->getMockForAbstractClass();
713 $revisionLookup->method( 'getRevisionByTitle' )
714 ->willReturnCallback( function ( LinkTarget $page ) use (
715 $services, &$revision, $localJsTitle
716 ) {
717 if ( $localJsTitle->equals( Title::newFromLinkTarget( $page ) ) ) {
718 return $revision;
719 } else {
720 return $services->getRevisionLookup()->getRevisionByTitle( $page );
721 }
722 } );
723 $permissionManager = new PermissionManager(
724 new LoggedServiceOptions(
725 self::$serviceOptionsAccessLog,
726 PermissionManager::$constructorOptions,
727 [
728 'WhitelistRead' => [],
729 'WhitelistReadRegexp' => [],
730 'EmailConfirmToEdit' => false,
731 'BlockDisablesLogin' => false,
732 'GroupPermissions' => [],
733 'RevokePermissions' => [],
734 'AvailableRights' => [],
735 'NamespaceProtection' => [],
736 'RestrictionLevels' => []
737 ]
738 ),
739 $services->getSpecialPageFactory(),
740 $revisionLookup,
741 MediaWikiServices::getInstance()->getNamespaceInfo()
742 );
743 $this->setService( 'PermissionManager', $permissionManager );
744
745 $permissionManager->overrideUserRightsForTesting( $user, [ 'edit', 'editmyuserjs' ] );
746
747 $revision = $this->getJavascriptRevision( $localJsTitle, $user, '/* script */' );
748 $errors = $permissionManager->getPermissionErrors( 'edit', $user, $localJsTitle );
749 $this->assertSame( [], $errors );
750
751 $revision = $this->getJavascriptRedirectRevision( $localJsTitle, $otherLocalJsTitle, $user );
752 $errors = $permissionManager->getPermissionErrors( 'edit', $user, $localJsTitle );
753 $this->assertSame( [], $errors );
754
755 $revision = $this->getJavascriptRedirectRevision( $localJsTitle, $nonlocalJsTitle, $user );
756 $errors = $permissionManager->getPermissionErrors( 'edit', $user, $localJsTitle );
757 $this->assertSame( [ [ 'mycustomjsredirectprotected', 'edit' ] ], $errors );
758
759 $permissionManager->overrideUserRightsForTesting( $user,
760 [ 'edit', 'editmyuserjs', 'editmyuserjsredirect' ] );
761
762 $revision = $this->getJavascriptRedirectRevision( $localJsTitle, $nonlocalJsTitle, $user );
763 $errors = $permissionManager->getPermissionErrors( 'edit', $user, $localJsTitle );
764 $this->assertSame( [], $errors );
765 }
766
767 /**
768 * @todo This test method should be split up into separate test methods and
769 * data providers
770 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
771 */
772 public function testOtherNonConfigEditPermissions() {
773 $this->setUser( $this->userName );
774
775 $this->setTitle( NS_USER, $this->altUserName . '/tempo' );
776 $this->runConfigEditPermissions(
777 [ [ 'badaccess-group0' ] ],
778
779 [ [ 'badaccess-group0' ] ],
780 [ [ 'badaccess-group0' ] ],
781 [ [ 'badaccess-group0' ] ],
782
783 [ [ 'badaccess-group0' ] ],
784 [ [ 'badaccess-group0' ] ],
785 [ [ 'badaccess-group0' ] ],
786 [ [ 'badaccess-groups' ] ]
787 );
788 }
789
790 /**
791 * @todo This should use data providers like the other methods here.
792 * @covers \MediaWiki\Permissions\PermissionManager::checkUserConfigPermissions
793 */
794 public function testPatrolActionConfigEditPermissions() {
795 $this->setUser( 'anon' );
796 $this->setTitle( NS_USER, 'ToPatrolOrNotToPatrol' );
797 $this->runConfigEditPermissions(
798 [ [ 'badaccess-group0' ] ],
799
800 [ [ 'badaccess-group0' ] ],
801 [ [ 'badaccess-group0' ] ],
802 [ [ 'badaccess-group0' ] ],
803
804 [ [ 'badaccess-group0' ] ],
805 [ [ 'badaccess-group0' ] ],
806 [ [ 'badaccess-group0' ] ],
807 [ [ 'badaccess-groups' ] ]
808 );
809 }
810
811 protected function runConfigEditPermissions(
812 $resultNone,
813 $resultMyCss,
814 $resultMyJson,
815 $resultMyJs,
816 $resultUserCss,
817 $resultUserJson,
818 $resultUserJs,
819 $resultPatrol
820 ) {
821 $this->overrideUserPermissions( $this->user );
822 $result = MediaWikiServices::getInstance()->getPermissionManager()
823 ->getPermissionErrors( 'bogus', $this->user, $this->title );
824 $this->assertEquals( $resultNone, $result );
825
826 $this->overrideUserPermissions( $this->user, 'editmyusercss' );
827 $result = MediaWikiServices::getInstance()->getPermissionManager()
828 ->getPermissionErrors( 'bogus', $this->user, $this->title );
829 $this->assertEquals( $resultMyCss, $result );
830
831 $this->overrideUserPermissions( $this->user, 'editmyuserjson' );
832 $result = MediaWikiServices::getInstance()->getPermissionManager()
833 ->getPermissionErrors( 'bogus', $this->user, $this->title );
834 $this->assertEquals( $resultMyJson, $result );
835
836 $this->overrideUserPermissions( $this->user, 'editmyuserjs' );
837 $result = MediaWikiServices::getInstance()->getPermissionManager()
838 ->getPermissionErrors( 'bogus', $this->user, $this->title );
839 $this->assertEquals( $resultMyJs, $result );
840
841 $this->overrideUserPermissions( $this->user, 'editusercss' );
842 $result = MediaWikiServices::getInstance()->getPermissionManager()
843 ->getPermissionErrors( 'bogus', $this->user, $this->title );
844 $this->assertEquals( $resultUserCss, $result );
845
846 $this->overrideUserPermissions( $this->user, 'edituserjson' );
847 $result = MediaWikiServices::getInstance()->getPermissionManager()
848 ->getPermissionErrors( 'bogus', $this->user, $this->title );
849 $this->assertEquals( $resultUserJson, $result );
850
851 $this->overrideUserPermissions( $this->user, 'edituserjs' );
852 $result = MediaWikiServices::getInstance()->getPermissionManager()
853 ->getPermissionErrors( 'bogus', $this->user, $this->title );
854 $this->assertEquals( $resultUserJs, $result );
855
856 $this->overrideUserPermissions( $this->user );
857 $result = MediaWikiServices::getInstance()->getPermissionManager()
858 ->getPermissionErrors( 'patrol', $this->user, $this->title );
859 $this->assertEquals( reset( $resultPatrol[0] ), reset( $result[0] ) );
860
861 $this->overrideUserPermissions( $this->user, [ 'edituserjs', 'edituserjson', 'editusercss' ] );
862 $result = MediaWikiServices::getInstance()->getPermissionManager()
863 ->getPermissionErrors( 'bogus', $this->user, $this->title );
864 $this->assertEquals( [ [ 'badaccess-group0' ] ], $result );
865 }
866
867 /**
868 * @todo This test method should be split up into separate test methods and
869 * data providers
870 *
871 * This test is failing per T201776.
872 *
873 * @group Broken
874 * @covers \MediaWiki\Permissions\PermissionManager::checkPageRestrictions
875 */
876 public function testPageRestrictions() {
877 $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
878 getFormattedNsText( NS_PROJECT );
879
880 $this->setTitle( NS_MAIN );
881 $this->title->mRestrictionsLoaded = true;
882 $this->overrideUserPermissions( $this->user, "edit" );
883 $this->title->mRestrictions = [ "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
884
885 $this->assertEquals( [],
886 MediaWikiServices::getInstance()->getPermissionManager()
887 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
888
889 $this->assertEquals( true,
890 MediaWikiServices::getInstance()->getPermissionManager()
891 ->userCan( 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
892
893 $this->title->mRestrictions = [ "edit" => [ 'bogus', "sysop", "protect", "" ],
894 "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
895
896 $this->assertEquals( [ [ 'badaccess-group0' ],
897 [ 'protectedpagetext', 'bogus', 'bogus' ],
898 [ 'protectedpagetext', 'editprotected', 'bogus' ],
899 [ 'protectedpagetext', 'protect', 'bogus' ] ],
900 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
901 'bogus', $this->user, $this->title ) );
902 $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
903 [ 'protectedpagetext', 'editprotected', 'edit' ],
904 [ 'protectedpagetext', 'protect', 'edit' ] ],
905 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
906 'edit', $this->user, $this->title ) );
907 $this->overrideUserPermissions( $this->user );
908 $this->assertEquals( [ [ 'badaccess-group0' ],
909 [ 'protectedpagetext', 'bogus', 'bogus' ],
910 [ 'protectedpagetext', 'editprotected', 'bogus' ],
911 [ 'protectedpagetext', 'protect', 'bogus' ] ],
912 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
913 'bogus', $this->user, $this->title ) );
914 $this->assertEquals( [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ],
915 [ 'protectedpagetext', 'bogus', 'edit' ],
916 [ 'protectedpagetext', 'editprotected', 'edit' ],
917 [ 'protectedpagetext', 'protect', 'edit' ] ],
918 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
919 'edit', $this->user, $this->title ) );
920 $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
921 $this->assertEquals( [ [ 'badaccess-group0' ],
922 [ 'protectedpagetext', 'bogus', 'bogus' ],
923 [ 'protectedpagetext', 'protect', 'bogus' ] ],
924 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
925 'bogus', $this->user, $this->title ) );
926 $this->assertEquals( [
927 [ 'protectedpagetext', 'bogus', 'edit' ],
928 [ 'protectedpagetext', 'protect', 'edit' ] ],
929 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
930 'edit', $this->user, $this->title ) );
931
932 $this->title->mCascadeRestriction = true;
933 $this->overrideUserPermissions( $this->user, "edit" );
934
935 $this->assertEquals( false,
936 MediaWikiServices::getInstance()->getPermissionManager()
937 ->userCan( 'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
938
939 $this->assertEquals( false,
940 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
941 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
942
943 $this->assertEquals( [ [ 'badaccess-group0' ],
944 [ 'protectedpagetext', 'bogus', 'bogus' ],
945 [ 'protectedpagetext', 'editprotected', 'bogus' ],
946 [ 'protectedpagetext', 'protect', 'bogus' ] ],
947 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
948 'bogus', $this->user, $this->title ) );
949 $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
950 [ 'protectedpagetext', 'editprotected', 'edit' ],
951 [ 'protectedpagetext', 'protect', 'edit' ] ],
952 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
953 'edit', $this->user, $this->title ) );
954
955 $this->overrideUserPermissions( $this->user, [ "edit", "editprotected" ] );
956 $this->assertEquals( false,
957 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
958 'bogus', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
959
960 $this->assertEquals( false,
961 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
962 'edit', $this->user, $this->title, PermissionManager::RIGOR_QUICK ) );
963
964 $this->assertEquals( [ [ 'badaccess-group0' ],
965 [ 'protectedpagetext', 'bogus', 'bogus' ],
966 [ 'protectedpagetext', 'protect', 'bogus' ],
967 [ 'protectedpagetext', 'protect', 'bogus' ] ],
968 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
969 'bogus', $this->user, $this->title ) );
970 $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
971 [ 'protectedpagetext', 'protect', 'edit' ],
972 [ 'protectedpagetext', 'protect', 'edit' ] ],
973 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
974 'edit', $this->user, $this->title ) );
975 }
976
977 /**
978 * @covers \MediaWiki\Permissions\PermissionManager::checkCascadingSourcesRestrictions
979 */
980 public function testCascadingSourcesRestrictions() {
981 $this->setTitle( NS_MAIN, "test page" );
982 $this->overrideUserPermissions( $this->user, [ "edit", "bogus" ] );
983
984 $this->title->mCascadeSources = [
985 Title::makeTitle( NS_MAIN, "Bogus" ),
986 Title::makeTitle( NS_MAIN, "UnBogus" )
987 ];
988 $this->title->mCascadingRestrictions = [
989 "bogus" => [ 'bogus', "sysop", "protect", "" ]
990 ];
991
992 $this->assertEquals( false,
993 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
994 'bogus', $this->user, $this->title ) );
995 $this->assertEquals( [
996 [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
997 [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
998 [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ] ],
999 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
1000 'bogus', $this->user, $this->title ) );
1001
1002 $this->assertEquals( true,
1003 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1004 'edit', $this->user, $this->title ) );
1005 $this->assertEquals( [],
1006 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
1007 'edit', $this->user, $this->title ) );
1008 }
1009
1010 /**
1011 * @todo This test method should be split up into separate test methods and
1012 * data providers
1013 * @covers \MediaWiki\Permissions\PermissionManager::checkActionPermissions
1014 */
1015 public function testActionPermissions() {
1016 $this->overrideUserPermissions( $this->user, [ "createpage" ] );
1017 $this->setTitle( NS_MAIN, "test page" );
1018 $this->title->mTitleProtection['permission'] = '';
1019 $this->title->mTitleProtection['user'] = $this->user->getId();
1020 $this->title->mTitleProtection['expiry'] = 'infinity';
1021 $this->title->mTitleProtection['reason'] = 'test';
1022 $this->title->mCascadeRestriction = false;
1023
1024 $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
1025 MediaWikiServices::getInstance()->getPermissionManager()
1026 ->getPermissionErrors( 'create', $this->user, $this->title ) );
1027 $this->assertEquals( false,
1028 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1029 'create', $this->user, $this->title ) );
1030
1031 $this->title->mTitleProtection['permission'] = 'editprotected';
1032 $this->overrideUserPermissions( $this->user, [ 'createpage', 'protect' ] );
1033 $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
1034 MediaWikiServices::getInstance()->getPermissionManager()
1035 ->getPermissionErrors( 'create', $this->user, $this->title ) );
1036 $this->assertEquals( false,
1037 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1038 'create', $this->user, $this->title ) );
1039
1040 $this->overrideUserPermissions( $this->user, [ 'createpage', 'editprotected' ] );
1041 $this->assertEquals( [],
1042 MediaWikiServices::getInstance()->getPermissionManager()
1043 ->getPermissionErrors( 'create', $this->user, $this->title ) );
1044 $this->assertEquals( true,
1045 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1046 'create', $this->user, $this->title ) );
1047
1048 $this->overrideUserPermissions( $this->user, [ 'createpage' ] );
1049 $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
1050 MediaWikiServices::getInstance()->getPermissionManager()
1051 ->getPermissionErrors( 'create', $this->user, $this->title ) );
1052 $this->assertEquals( false,
1053 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1054 'create', $this->user, $this->title ) );
1055
1056 $this->setTitle( NS_MEDIA, "test page" );
1057 $this->overrideUserPermissions( $this->user, [ "move" ] );
1058 $this->assertEquals( false,
1059 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1060 'move', $this->user, $this->title ) );
1061 $this->assertEquals( [ [ 'immobile-source-namespace', 'Media' ] ],
1062 MediaWikiServices::getInstance()->getPermissionManager()
1063 ->getPermissionErrors( 'move', $this->user, $this->title ) );
1064
1065 $this->setTitle( NS_HELP, "test page" );
1066 $this->assertEquals( [],
1067 MediaWikiServices::getInstance()->getPermissionManager()
1068 ->getPermissionErrors( 'move', $this->user, $this->title ) );
1069 $this->assertEquals( true,
1070 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1071 'move', $this->user, $this->title ) );
1072
1073 $this->title->mInterwiki = "no";
1074 $this->assertEquals( [ [ 'immobile-source-page' ] ],
1075 MediaWikiServices::getInstance()->getPermissionManager()
1076 ->getPermissionErrors( 'move', $this->user, $this->title ) );
1077 $this->assertEquals( false,
1078 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1079 'move', $this->user, $this->title ) );
1080
1081 $this->setTitle( NS_MEDIA, "test page" );
1082 $this->assertEquals( false,
1083 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1084 'move-target', $this->user, $this->title ) );
1085 $this->assertEquals( [ [ 'immobile-target-namespace', 'Media' ] ],
1086 MediaWikiServices::getInstance()->getPermissionManager()
1087 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1088
1089 $this->setTitle( NS_HELP, "test page" );
1090 $this->assertEquals( [],
1091 MediaWikiServices::getInstance()->getPermissionManager()
1092 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1093 $this->assertEquals( true,
1094 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1095 'move-target', $this->user, $this->title ) );
1096
1097 $this->title->mInterwiki = "no";
1098 $this->assertEquals( [ [ 'immobile-target-page' ] ],
1099 MediaWikiServices::getInstance()->getPermissionManager()
1100 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1101 $this->assertEquals( false,
1102 MediaWikiServices::getInstance()->getPermissionManager()->userCan(
1103 'move-target', $this->user, $this->title ) );
1104 }
1105
1106 /**
1107 * @covers \MediaWiki\Permissions\PermissionManager::checkUserBlock
1108 */
1109 public function testUserBlock() {
1110 $this->setMwGlobals( [
1111 'wgEmailConfirmToEdit' => true,
1112 'wgEmailAuthentication' => true,
1113 'wgBlockDisablesLogin' => false,
1114 ] );
1115
1116 $this->overrideUserPermissions( $this->user, [
1117 'createpage',
1118 'edit',
1119 'move',
1120 'rollback',
1121 'patrol',
1122 'upload',
1123 'purge'
1124 ] );
1125 $this->setTitle( NS_HELP, "test page" );
1126
1127 # $wgEmailConfirmToEdit only applies to 'edit' action
1128 $this->assertEquals( [],
1129 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
1130 'move-target', $this->user, $this->title ) );
1131 $this->assertContains( [ 'confirmedittext' ],
1132 MediaWikiServices::getInstance()->getPermissionManager()
1133 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1134
1135 $this->setMwGlobals( 'wgEmailConfirmToEdit', false );
1136 $this->overrideUserPermissions( $this->user, [
1137 'createpage',
1138 'edit',
1139 'move',
1140 'rollback',
1141 'patrol',
1142 'upload',
1143 'purge'
1144 ] );
1145
1146 $this->assertNotContains( [ 'confirmedittext' ],
1147 MediaWikiServices::getInstance()->getPermissionManager()
1148 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1149
1150 # $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount'
1151 $this->assertEquals( [],
1152 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
1153 'move-target', $this->user, $this->title ) );
1154
1155 global $wgLang;
1156 $prev = time();
1157 $now = time() + 120;
1158 $this->user->mBlockedby = $this->user->getId();
1159 $this->user->mBlock = new DatabaseBlock( [
1160 'address' => '127.0.8.1',
1161 'by' => $this->user->getId(),
1162 'reason' => 'no reason given',
1163 'timestamp' => $prev + 3600,
1164 'auto' => true,
1165 'expiry' => 0
1166 ] );
1167 $this->user->mBlock->setTimestamp( 0 );
1168 $this->assertEquals( [ [ 'autoblockedtext',
1169 "[[User:Useruser|\u{202A}Useruser\u{202C}]]", 'no reason given', '127.0.0.1',
1170 "\u{202A}Useruser\u{202C}", null, 'infinite', '127.0.8.1',
1171 $wgLang->timeanddate( wfTimestamp( TS_MW, $prev ), true ) ] ],
1172 MediaWikiServices::getInstance()->getPermissionManager()->getPermissionErrors(
1173 'move-target', $this->user, $this->title ) );
1174
1175 $this->assertEquals( false, MediaWikiServices::getInstance()->getPermissionManager()
1176 ->userCan( 'move-target', $this->user, $this->title ) );
1177 // quickUserCan should ignore user blocks
1178 $this->assertEquals( true, MediaWikiServices::getInstance()->getPermissionManager()
1179 ->userCan( 'move-target', $this->user, $this->title,
1180 PermissionManager::RIGOR_QUICK ) );
1181
1182 global $wgLocalTZoffset;
1183 $wgLocalTZoffset = -60;
1184 $this->user->mBlockedby = $this->user->getName();
1185 $this->user->mBlock = new DatabaseBlock( [
1186 'address' => '127.0.8.1',
1187 'by' => $this->user->getId(),
1188 'reason' => 'no reason given',
1189 'timestamp' => $now,
1190 'auto' => false,
1191 'expiry' => 10,
1192 ] );
1193 $this->assertEquals( [ [ 'blockedtext',
1194 "[[User:Useruser|\u{202A}Useruser\u{202C}]]", 'no reason given', '127.0.0.1',
1195 "\u{202A}Useruser\u{202C}", null, '23:00, 31 December 1969', '127.0.8.1',
1196 $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ],
1197 MediaWikiServices::getInstance()->getPermissionManager()
1198 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1199 # $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this )
1200 # $user->blockedFor() == ''
1201 # $user->mBlock->mExpiry == 'infinity'
1202
1203 $this->user->mBlockedby = $this->user->getName();
1204 $this->user->mBlock = new SystemBlock( [
1205 'address' => '127.0.8.1',
1206 'by' => $this->user->getId(),
1207 'reason' => 'no reason given',
1208 'timestamp' => $now,
1209 'auto' => false,
1210 'systemBlock' => 'test',
1211 ] );
1212
1213 $errors = [ [ 'systemblockedtext',
1214 "[[User:Useruser|\u{202A}Useruser\u{202C}]]", 'no reason given', '127.0.0.1',
1215 "\u{202A}Useruser\u{202C}", 'test', 'infinite', '127.0.8.1',
1216 $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
1217
1218 $this->assertEquals( $errors,
1219 MediaWikiServices::getInstance()->getPermissionManager()
1220 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1221 $this->assertEquals( $errors,
1222 MediaWikiServices::getInstance()->getPermissionManager()
1223 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1224 $this->assertEquals( $errors,
1225 MediaWikiServices::getInstance()->getPermissionManager()
1226 ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
1227 $this->assertEquals( $errors,
1228 MediaWikiServices::getInstance()->getPermissionManager()
1229 ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
1230 $this->assertEquals( $errors,
1231 MediaWikiServices::getInstance()->getPermissionManager()
1232 ->getPermissionErrors( 'upload', $this->user, $this->title ) );
1233 $this->assertEquals( [],
1234 MediaWikiServices::getInstance()->getPermissionManager()
1235 ->getPermissionErrors( 'purge', $this->user, $this->title ) );
1236
1237 // partial block message test
1238 $this->user->mBlockedby = $this->user->getName();
1239 $this->user->mBlock = new DatabaseBlock( [
1240 'address' => '127.0.8.1',
1241 'by' => $this->user->getId(),
1242 'reason' => 'no reason given',
1243 'timestamp' => $now,
1244 'sitewide' => false,
1245 'expiry' => 10,
1246 ] );
1247
1248 $this->assertEquals( [],
1249 MediaWikiServices::getInstance()->getPermissionManager()
1250 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1251 $this->assertEquals( [],
1252 MediaWikiServices::getInstance()->getPermissionManager()
1253 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1254 $this->assertEquals( [],
1255 MediaWikiServices::getInstance()->getPermissionManager()
1256 ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
1257 $this->assertEquals( [],
1258 MediaWikiServices::getInstance()->getPermissionManager()
1259 ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
1260 $this->assertEquals( [],
1261 MediaWikiServices::getInstance()->getPermissionManager()
1262 ->getPermissionErrors( 'upload', $this->user, $this->title ) );
1263 $this->assertEquals( [],
1264 MediaWikiServices::getInstance()->getPermissionManager()
1265 ->getPermissionErrors( 'purge', $this->user, $this->title ) );
1266
1267 $this->user->mBlock->setRestrictions( [
1268 ( new PageRestriction( 0, $this->title->getArticleID() ) )->setTitle( $this->title ),
1269 ] );
1270
1271 $errors = [ [ 'blockedtext-partial',
1272 "[[User:Useruser|\u{202A}Useruser\u{202C}]]", 'no reason given', '127.0.0.1',
1273 "\u{202A}Useruser\u{202C}", null, '23:00, 31 December 1969', '127.0.8.1',
1274 $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
1275
1276 $this->assertEquals( $errors,
1277 MediaWikiServices::getInstance()->getPermissionManager()
1278 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1279 $this->assertEquals( $errors,
1280 MediaWikiServices::getInstance()->getPermissionManager()
1281 ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1282 $this->assertEquals( $errors,
1283 MediaWikiServices::getInstance()->getPermissionManager()
1284 ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
1285 $this->assertEquals( $errors,
1286 MediaWikiServices::getInstance()->getPermissionManager()
1287 ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
1288 $this->assertEquals( [],
1289 MediaWikiServices::getInstance()->getPermissionManager()
1290 ->getPermissionErrors( 'upload', $this->user, $this->title ) );
1291 $this->assertEquals( [],
1292 MediaWikiServices::getInstance()->getPermissionManager()
1293 ->getPermissionErrors( 'purge', $this->user, $this->title ) );
1294
1295 // Test no block.
1296 $this->user->mBlockedby = null;
1297 $this->user->mBlock = null;
1298
1299 $this->assertEquals( [],
1300 MediaWikiServices::getInstance()->getPermissionManager()
1301 ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1302 }
1303
1304 /**
1305 * @covers \MediaWiki\Permissions\PermissionManager::checkUserBlock
1306 *
1307 * Tests to determine that the passed in permission does not get mixed up with
1308 * an action of the same name.
1309 */
1310 public function testUserBlockAction() {
1311 global $wgLang;
1312
1313 $tester = $this->getMockBuilder( Action::class )
1314 ->disableOriginalConstructor()
1315 ->getMock();
1316 $tester->method( 'getName' )
1317 ->willReturn( 'tester' );
1318 $tester->method( 'getRestriction' )
1319 ->willReturn( 'test' );
1320 $tester->method( 'requiresUnblock' )
1321 ->willReturn( false );
1322
1323 $this->setMwGlobals( [
1324 'wgActions' => [
1325 'tester' => $tester,
1326 ],
1327 'wgGroupPermissions' => [
1328 '*' => [
1329 'tester' => true,
1330 ],
1331 ],
1332 ] );
1333
1334 $now = time();
1335 $this->user->mBlockedby = $this->user->getName();
1336 $this->user->mBlock = new DatabaseBlock( [
1337 'address' => '127.0.8.1',
1338 'by' => $this->user->getId(),
1339 'reason' => 'no reason given',
1340 'timestamp' => $now,
1341 'auto' => false,
1342 'expiry' => 'infinity',
1343 ] );
1344
1345 $errors = [ [ 'blockedtext',
1346 "[[User:Useruser|\u{202A}Useruser\u{202C}]]", 'no reason given', '127.0.0.1',
1347 "\u{202A}Useruser\u{202C}", null, 'infinite', '127.0.8.1',
1348 $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
1349
1350 $this->assertEquals( $errors,
1351 MediaWikiServices::getInstance()->getPermissionManager()
1352 ->getPermissionErrors( 'tester', $this->user, $this->title ) );
1353 }
1354
1355 /**
1356 * @covers \MediaWiki\Permissions\PermissionManager::isBlockedFrom
1357 */
1358 public function testBlockInstanceCache() {
1359 // First, check the user isn't blocked
1360 $user = $this->getMutableTestUser()->getUser();
1361 $ut = Title::makeTitle( NS_USER_TALK, $user->getName() );
1362 $this->assertNull( $user->getBlock( false ), 'sanity check' );
1363 //$this->assertSame( '', $user->blockedBy(), 'sanity check' );
1364 //$this->assertSame( '', $user->blockedFor(), 'sanity check' );
1365 //$this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
1366 $this->assertFalse( MediaWikiServices::getInstance()->getPermissionManager()
1367 ->isBlockedFrom( $user, $ut ), 'sanity check' );
1368
1369 // Block the user
1370 $blocker = $this->getTestSysop()->getUser();
1371 $block = new DatabaseBlock( [
1372 'hideName' => true,
1373 'allowUsertalk' => false,
1374 'reason' => 'Because',
1375 ] );
1376 $block->setTarget( $user );
1377 $block->setBlocker( $blocker );
1378 $res = $block->insert();
1379 $this->assertTrue( (bool)$res['id'], 'sanity check: Failed to insert block' );
1380
1381 // Clear cache and confirm it loaded the block properly
1382 $user->clearInstanceCache();
1383 $this->assertInstanceOf( DatabaseBlock::class, $user->getBlock( false ) );
1384 //$this->assertSame( $blocker->getName(), $user->blockedBy() );
1385 //$this->assertSame( 'Because', $user->blockedFor() );
1386 //$this->assertTrue( (bool)$user->isHidden() );
1387 $this->assertTrue( MediaWikiServices::getInstance()->getPermissionManager()
1388 ->isBlockedFrom( $user, $ut ) );
1389
1390 // Unblock
1391 $block->delete();
1392
1393 // Clear cache and confirm it loaded the not-blocked properly
1394 $user->clearInstanceCache();
1395 $this->assertNull( $user->getBlock( false ) );
1396 //$this->assertSame( '', $user->blockedBy() );
1397 //$this->assertSame( '', $user->blockedFor() );
1398 //$this->assertFalse( (bool)$user->isHidden() );
1399 $this->assertFalse( MediaWikiServices::getInstance()->getPermissionManager()
1400 ->isBlockedFrom( $user, $ut ) );
1401 }
1402
1403 /**
1404 * @covers \MediaWiki\Permissions\PermissionManager::isBlockedFrom
1405 * @dataProvider provideIsBlockedFrom
1406 * @param string|null $title Title to test.
1407 * @param bool $expect Expected result from User::isBlockedFrom()
1408 * @param array $options Additional test options:
1409 * - 'blockAllowsUTEdit': (bool, default true) Value for $wgBlockAllowsUTEdit
1410 * - 'allowUsertalk': (bool, default false) Passed to DatabaseBlock::__construct()
1411 * - 'pageRestrictions': (array|null) If non-empty, page restriction titles for the block.
1412 */
1413 public function testIsBlockedFrom( $title, $expect, array $options = [] ) {
1414 $this->setMwGlobals( [
1415 'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
1416 ] );
1417
1418 $user = $this->getTestUser()->getUser();
1419
1420 if ( $title === self::USER_TALK_PAGE ) {
1421 $title = $user->getTalkPage();
1422 } else {
1423 $title = Title::newFromText( $title );
1424 }
1425
1426 $restrictions = [];
1427 foreach ( $options['pageRestrictions'] ?? [] as $pagestr ) {
1428 $page = $this->getExistingTestPage(
1429 $pagestr === self::USER_TALK_PAGE ? $user->getTalkPage() : $pagestr
1430 );
1431 $restrictions[] = new PageRestriction( 0, $page->getId() );
1432 }
1433 foreach ( $options['namespaceRestrictions'] ?? [] as $ns ) {
1434 $restrictions[] = new NamespaceRestriction( 0, $ns );
1435 }
1436
1437 $block = new DatabaseBlock( [
1438 'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
1439 'allowUsertalk' => $options['allowUsertalk'] ?? false,
1440 'sitewide' => !$restrictions,
1441 ] );
1442 $block->setTarget( $user );
1443 $block->setBlocker( $this->getTestSysop()->getUser() );
1444 if ( $restrictions ) {
1445 $block->setRestrictions( $restrictions );
1446 }
1447 $block->insert();
1448
1449 try {
1450 $this->assertSame( $expect, MediaWikiServices::getInstance()->getPermissionManager()
1451 ->isBlockedFrom( $user, $title ) );
1452 } finally {
1453 $block->delete();
1454 }
1455 }
1456
1457 public static function provideIsBlockedFrom() {
1458 return [
1459 'Sitewide block, basic operation' => [ 'Test page', true ],
1460 'Sitewide block, not allowing user talk' => [
1461 self::USER_TALK_PAGE, true, [
1462 'allowUsertalk' => false,
1463 ]
1464 ],
1465 'Sitewide block, allowing user talk' => [
1466 self::USER_TALK_PAGE, false, [
1467 'allowUsertalk' => true,
1468 ]
1469 ],
1470 'Sitewide block, allowing user talk but $wgBlockAllowsUTEdit is false' => [
1471 self::USER_TALK_PAGE, true, [
1472 'allowUsertalk' => true,
1473 'blockAllowsUTEdit' => false,
1474 ]
1475 ],
1476 'Partial block, blocking the page' => [
1477 'Test page', true, [
1478 'pageRestrictions' => [ 'Test page' ],
1479 ]
1480 ],
1481 'Partial block, not blocking the page' => [
1482 'Test page 2', false, [
1483 'pageRestrictions' => [ 'Test page' ],
1484 ]
1485 ],
1486 'Partial block, not allowing user talk but user talk page is not blocked' => [
1487 self::USER_TALK_PAGE, false, [
1488 'allowUsertalk' => false,
1489 'pageRestrictions' => [ 'Test page' ],
1490 ]
1491 ],
1492 'Partial block, allowing user talk but user talk page is blocked' => [
1493 self::USER_TALK_PAGE, true, [
1494 'allowUsertalk' => true,
1495 'pageRestrictions' => [ self::USER_TALK_PAGE ],
1496 ]
1497 ],
1498 'Partial block, user talk page is not blocked but $wgBlockAllowsUTEdit is false' => [
1499 self::USER_TALK_PAGE, false, [
1500 'allowUsertalk' => false,
1501 'pageRestrictions' => [ 'Test page' ],
1502 'blockAllowsUTEdit' => false,
1503 ]
1504 ],
1505 'Partial block, user talk page is blocked and $wgBlockAllowsUTEdit is false' => [
1506 self::USER_TALK_PAGE, true, [
1507 'allowUsertalk' => true,
1508 'pageRestrictions' => [ self::USER_TALK_PAGE ],
1509 'blockAllowsUTEdit' => false,
1510 ]
1511 ],
1512 'Partial user talk namespace block, not allowing user talk' => [
1513 self::USER_TALK_PAGE, true, [
1514 'allowUsertalk' => false,
1515 'namespaceRestrictions' => [ NS_USER_TALK ],
1516 ]
1517 ],
1518 'Partial user talk namespace block, allowing user talk' => [
1519 self::USER_TALK_PAGE, false, [
1520 'allowUsertalk' => true,
1521 'namespaceRestrictions' => [ NS_USER_TALK ],
1522 ]
1523 ],
1524 'Partial user talk namespace block, where $wgBlockAllowsUTEdit is false' => [
1525 self::USER_TALK_PAGE, true, [
1526 'allowUsertalk' => true,
1527 'namespaceRestrictions' => [ NS_USER_TALK ],
1528 'blockAllowsUTEdit' => false,
1529 ]
1530 ],
1531 ];
1532 }
1533
1534 /**
1535 * @covers \MediaWiki\Permissions\PermissionManager::getUserPermissions
1536 */
1537 public function testGetUserPermissions() {
1538 $user = $this->getTestUser( [ 'unittesters' ] )->getUser();
1539 $rights = MediaWikiServices::getInstance()->getPermissionManager()
1540 ->getUserPermissions( $user );
1541 $this->assertContains( 'runtest', $rights );
1542 $this->assertNotContains( 'writetest', $rights );
1543 $this->assertNotContains( 'modifytest', $rights );
1544 $this->assertNotContains( 'nukeworld', $rights );
1545 }
1546
1547 /**
1548 * @covers \MediaWiki\Permissions\PermissionManager::getUserPermissions
1549 */
1550 public function testGetUserPermissionsHooks() {
1551 $user = $this->getTestUser( [ 'unittesters', 'testwriters' ] )->getUser();
1552 $userWrapper = TestingAccessWrapper::newFromObject( $user );
1553
1554 $rights = MediaWikiServices::getInstance()
1555 ->getPermissionManager()
1556 ->getUserPermissions( $user );
1557 $this->assertContains( 'test', $rights, 'sanity check' );
1558 $this->assertContains( 'runtest', $rights, 'sanity check' );
1559 $this->assertContains( 'writetest', $rights, 'sanity check' );
1560 $this->assertNotContains( 'nukeworld', $rights, 'sanity check' );
1561
1562 // Add a hook manipluating the rights
1563 $this->setTemporaryHook( 'UserGetRights', function ( $user, &$rights ) {
1564 $rights[] = 'nukeworld';
1565 $rights = array_diff( $rights, [ 'writetest' ] );
1566 } );
1567
1568 $rights = MediaWikiServices::getInstance()
1569 ->getPermissionManager()
1570 ->getUserPermissions( $user );
1571 $this->assertContains( 'test', $rights );
1572 $this->assertContains( 'runtest', $rights );
1573 $this->assertNotContains( 'writetest', $rights );
1574 $this->assertContains( 'nukeworld', $rights );
1575
1576 // Add a Session that limits rights
1577 $mock = $this->getMockBuilder( stdClass::class )
1578 ->setMethods( [ 'getAllowedUserRights', 'deregisterSession', 'getSessionId' ] )
1579 ->getMock();
1580 $mock->method( 'getAllowedUserRights' )->willReturn( [ 'test', 'writetest' ] );
1581 $mock->method( 'getSessionId' )->willReturn(
1582 new SessionId( str_repeat( 'X', 32 ) )
1583 );
1584 $session = TestUtils::getDummySession( $mock );
1585 $mockRequest = $this->getMockBuilder( FauxRequest::class )
1586 ->setMethods( [ 'getSession' ] )
1587 ->getMock();
1588 $mockRequest->method( 'getSession' )->willReturn( $session );
1589 $userWrapper->mRequest = $mockRequest;
1590
1591 $this->resetServices();
1592 $rights = MediaWikiServices::getInstance()
1593 ->getPermissionManager()
1594 ->getUserPermissions( $user );
1595 $this->assertContains( 'test', $rights );
1596 $this->assertNotContains( 'runtest', $rights );
1597 $this->assertNotContains( 'writetest', $rights );
1598 $this->assertNotContains( 'nukeworld', $rights );
1599 }
1600
1601 /**
1602 * @covers \MediaWiki\Permissions\PermissionManager::getGroupPermissions
1603 */
1604 public function testGroupPermissions() {
1605 $rights = MediaWikiServices::getInstance()->getPermissionManager()
1606 ->getGroupPermissions( [ 'unittesters' ] );
1607 $this->assertContains( 'runtest', $rights );
1608 $this->assertNotContains( 'writetest', $rights );
1609 $this->assertNotContains( 'modifytest', $rights );
1610 $this->assertNotContains( 'nukeworld', $rights );
1611
1612 $rights = MediaWikiServices::getInstance()->getPermissionManager()
1613 ->getGroupPermissions( [ 'unittesters', 'testwriters' ] );
1614 $this->assertContains( 'runtest', $rights );
1615 $this->assertContains( 'writetest', $rights );
1616 $this->assertContains( 'modifytest', $rights );
1617 $this->assertNotContains( 'nukeworld', $rights );
1618 }
1619
1620 /**
1621 * @covers \MediaWiki\Permissions\PermissionManager::getGroupPermissions
1622 */
1623 public function testRevokePermissions() {
1624 $rights = MediaWikiServices::getInstance()->getPermissionManager()
1625 ->getGroupPermissions( [ 'unittesters', 'formertesters' ] );
1626 $this->assertNotContains( 'runtest', $rights );
1627 $this->assertNotContains( 'writetest', $rights );
1628 $this->assertNotContains( 'modifytest', $rights );
1629 $this->assertNotContains( 'nukeworld', $rights );
1630 }
1631
1632 /**
1633 * @dataProvider provideGetGroupsWithPermission
1634 * @covers \MediaWiki\Permissions\PermissionManager::getGroupsWithPermission
1635 */
1636 public function testGetGroupsWithPermission( $expected, $right ) {
1637 $result = MediaWikiServices::getInstance()->getPermissionManager()
1638 ->getGroupsWithPermission( $right );
1639 sort( $result );
1640 sort( $expected );
1641
1642 $this->assertEquals( $expected, $result, "Groups with permission $right" );
1643 }
1644
1645 public static function provideGetGroupsWithPermission() {
1646 return [
1647 [
1648 [ 'unittesters', 'testwriters' ],
1649 'test'
1650 ],
1651 [
1652 [ 'unittesters' ],
1653 'runtest'
1654 ],
1655 [
1656 [ 'testwriters' ],
1657 'writetest'
1658 ],
1659 [
1660 [ 'testwriters' ],
1661 'modifytest'
1662 ],
1663 ];
1664 }
1665
1666 /**
1667 * @covers \MediaWiki\Permissions\PermissionManager::userHasRight
1668 */
1669 public function testUserHasRight() {
1670 $result = MediaWikiServices::getInstance()->getPermissionManager()->userHasRight(
1671 $this->getTestUser( 'unittesters' )->getUser(),
1672 'test'
1673 );
1674 $this->assertTrue( $result );
1675
1676 $result = MediaWikiServices::getInstance()->getPermissionManager()->userHasRight(
1677 $this->getTestUser( 'formertesters' )->getUser(),
1678 'runtest'
1679 );
1680 $this->assertFalse( $result );
1681
1682 $result = MediaWikiServices::getInstance()->getPermissionManager()->userHasRight(
1683 $this->getTestUser( 'formertesters' )->getUser(),
1684 ''
1685 );
1686 $this->assertTrue( $result );
1687 }
1688
1689 /**
1690 * @covers \MediaWiki\Permissions\PermissionManager::groupHasPermission
1691 */
1692 public function testGroupHasPermission() {
1693 $result = MediaWikiServices::getInstance()->getPermissionManager()->groupHasPermission(
1694 'unittesters',
1695 'test'
1696 );
1697 $this->assertTrue( $result );
1698
1699 $result = MediaWikiServices::getInstance()->getPermissionManager()->groupHasPermission(
1700 'formertesters',
1701 'runtest'
1702 );
1703 $this->assertFalse( $result );
1704 }
1705
1706 /**
1707 * @covers \MediaWiki\Permissions\PermissionManager::isEveryoneAllowed
1708 */
1709 public function testIsEveryoneAllowed() {
1710 $result = MediaWikiServices::getInstance()->getPermissionManager()
1711 ->isEveryoneAllowed( 'editmyoptions' );
1712 $this->assertTrue( $result );
1713
1714 $result = MediaWikiServices::getInstance()->getPermissionManager()
1715 ->isEveryoneAllowed( 'test' );
1716 $this->assertFalse( $result );
1717 }
1718
1719 /**
1720 * @covers \MediaWiki\Permissions\PermissionManager::addTemporaryUserRights
1721 */
1722 public function testAddTemporaryUserRights() {
1723 $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
1724 $this->overrideUserPermissions( $this->user, [ 'read', 'edit' ] );
1725 // sanity checks
1726 $this->assertEquals( [ 'read', 'edit' ], $permissionManager->getUserPermissions( $this->user ) );
1727 $this->assertFalse( $permissionManager->userHasRight( $this->user, 'move' ) );
1728
1729 $scope = $permissionManager->addTemporaryUserRights( $this->user, [ 'move', 'delete' ] );
1730 $this->assertEquals( [ 'read', 'edit', 'move', 'delete' ],
1731 $permissionManager->getUserPermissions( $this->user ) );
1732 $this->assertTrue( $permissionManager->userHasRight( $this->user, 'move' ) );
1733
1734 $scope2 = $permissionManager->addTemporaryUserRights( $this->user, [ 'delete', 'upload' ] );
1735 $this->assertEquals( [ 'read', 'edit', 'move', 'delete', 'upload' ],
1736 $permissionManager->getUserPermissions( $this->user ) );
1737
1738 ScopedCallback::consume( $scope );
1739 $this->assertEquals( [ 'read', 'edit', 'delete', 'upload' ],
1740 $permissionManager->getUserPermissions( $this->user ) );
1741 ScopedCallback::consume( $scope2 );
1742 $this->assertEquals( [ 'read', 'edit' ],
1743 $permissionManager->getUserPermissions( $this->user ) );
1744 $this->assertFalse( $permissionManager->userHasRight( $this->user, 'move' ) );
1745
1746 ( function () use ( $permissionManager ) {
1747 $scope = $permissionManager->addTemporaryUserRights( $this->user, 'move' );
1748 $this->assertTrue( $permissionManager->userHasRight( $this->user, 'move' ) );
1749 } )();
1750 $this->assertFalse( $permissionManager->userHasRight( $this->user, 'move' ) );
1751 }
1752
1753 /**
1754 * Create a RevisionRecord with a single Javascript main slot.
1755 * @param Title $title
1756 * @param User $user
1757 * @param string $text
1758 * @return MutableRevisionRecord
1759 */
1760 private function getJavascriptRevision( Title $title, User $user, $text ) {
1761 $content = ContentHandler::makeContent( $text, $title, CONTENT_MODEL_JAVASCRIPT );
1762 $revision = new MutableRevisionRecord( $title );
1763 $revision->setContent( 'main', $content );
1764 return $revision;
1765 }
1766
1767 /**
1768 * Create a RevisionRecord with a single Javascript redirect main slot.
1769 * @param Title $title
1770 * @param Title $redirectTargetTitle
1771 * @param User $user
1772 * @return MutableRevisionRecord
1773 */
1774 private function getJavascriptRedirectRevision(
1775 Title $title, Title $redirectTargetTitle, User $user
1776 ) {
1777 $content = ContentHandler::getForModelID( CONTENT_MODEL_JAVASCRIPT )
1778 ->makeRedirectContent( $redirectTargetTitle );
1779 $revision = new MutableRevisionRecord( $title );
1780 $revision->setContent( 'main', $content );
1781 return $revision;
1782 }
1783
1784 public function provideGetRestrictionLevels() {
1785 return [
1786 'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK ],
1787 'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN ],
1788 'Restricted to sysop' => [ [ '' ], NS_USER ],
1789 'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
1790 'No special permissions' => [
1791 [ '' ],
1792 NS_TALK,
1793 []
1794 ],
1795 'autoconfirmed' => [
1796 [ '', 'autoconfirmed' ],
1797 NS_TALK,
1798 [ 'autoconfirmed' ]
1799 ],
1800 'autoconfirmed revoked' => [
1801 [ '' ],
1802 NS_TALK,
1803 [ 'autoconfirmed', 'noeditsemiprotected' ]
1804 ],
1805 'sysop' => [
1806 [ '', 'autoconfirmed', 'sysop' ],
1807 NS_TALK,
1808 [ 'sysop' ]
1809 ],
1810 'sysop with autoconfirmed revoked (a bit silly)' => [
1811 [ '', 'sysop' ],
1812 NS_TALK,
1813 [ 'sysop', 'noeditsemiprotected' ]
1814 ],
1815 ];
1816 }
1817
1818 /**
1819 * @dataProvider provideGetRestrictionLevels
1820 * @covers \MediaWiki\Permissions\PermissionManager::getNamespaceRestrictionLevels
1821 *
1822 * @param array $expected
1823 * @param int $ns
1824 * @param array|null $userGroups
1825 * @throws MWException
1826 */
1827 public function testGetRestrictionLevels( array $expected, $ns, array $userGroups = null ) {
1828 $this->setMwGlobals( [
1829 'wgGroupPermissions' => [
1830 '*' => [ 'edit' => true ],
1831 'autoconfirmed' => [ 'editsemiprotected' => true ],
1832 'sysop' => [
1833 'editsemiprotected' => true,
1834 'editprotected' => true,
1835 ],
1836 'privileged' => [ 'privileged' => true ],
1837 ],
1838 'wgRevokePermissions' => [
1839 'noeditsemiprotected' => [ 'editsemiprotected' => true ],
1840 ],
1841 'wgNamespaceProtection' => [
1842 NS_MAIN => 'autoconfirmed',
1843 NS_USER => 'sysop',
1844 101 => [ 'editsemiprotected', 'privileged' ],
1845 ],
1846 'wgRestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
1847 'wgAutopromote' => []
1848 ] );
1849 $user = is_null( $userGroups ) ? null : $this->getTestUser( $userGroups )->getUser();
1850 $this->assertSame( $expected, MediaWikiServices::getInstance()
1851 ->getPermissionManager()
1852 ->getNamespaceRestrictionLevels( $ns, $user ) );
1853 }
1854
1855 /**
1856 * @covers \MediaWiki\Permissions\PermissionManager::getRightsCacheKey
1857 * @throws \Exception
1858 */
1859 public function testAnonPermissionsNotClash() {
1860 $user1 = User::newFromName( 'User1' );
1861 $user2 = User::newFromName( 'User2' );
1862 $pm = MediaWikiServices::getInstance()->getPermissionManager();
1863 $pm->overrideUserRightsForTesting( $user2, [] );
1864 $this->assertNotSame( $pm->getUserPermissions( $user1 ), $pm->getUserPermissions( $user2 ) );
1865 }
1866
1867 /**
1868 * @covers \MediaWiki\Permissions\PermissionManager::getRightsCacheKey
1869 */
1870 public function testAnonPermissionsNotClashOneRegistered() {
1871 $user1 = User::newFromName( 'User1' );
1872 $user2 = $this->getTestSysop()->getUser();
1873 $pm = MediaWikiServices::getInstance()->getPermissionManager();
1874 $this->assertNotSame( $pm->getUserPermissions( $user1 ), $pm->getUserPermissions( $user2 ) );
1875 }
1876 }