MediaWiki  master
PermissionManagerTest.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use Action;
6 use Block;
9 use Title;
10 use User;
16 
23 
27  protected $userName, $altUserName;
28 
32  protected $title;
33 
38 
42  protected $permissionManager;
43 
45  const USER_TALK_PAGE = '<user talk page>';
46 
47  protected function setUp() {
48  parent::setUp();
49 
50  $localZone = 'UTC';
51  $localOffset = date( 'Z' ) / 60;
52 
53  $this->setMwGlobals( [
54  'wgLocaltimezone' => $localZone,
55  'wgLocalTZoffset' => $localOffset,
56  'wgNamespaceProtection' => [
57  NS_MEDIAWIKI => 'editinterface',
58  ],
59  ] );
60  // Without this testUserBlock will use a non-English context on non-English MediaWiki
61  // installations (because of how Title::checkUserBlock is implemented) and fail.
63 
64  $this->userName = 'Useruser';
65  $this->altUserName = 'Altuseruser';
66  date_default_timezone_set( $localZone );
67 
68  $this->title = Title::makeTitle( NS_MAIN, "Main Page" );
69  if ( !isset( $this->userUser ) || !( $this->userUser instanceof User ) ) {
70  $this->userUser = User::newFromName( $this->userName );
71 
72  if ( !$this->userUser->getId() ) {
73  $this->userUser = User::createNew( $this->userName, [
74  "email" => "test@example.com",
75  "real_name" => "Test User" ] );
76  $this->userUser->load();
77  }
78 
79  $this->altUser = User::newFromName( $this->altUserName );
80  if ( !$this->altUser->getId() ) {
81  $this->altUser = User::createNew( $this->altUserName, [
82  "email" => "alttest@example.com",
83  "real_name" => "Test User Alt" ] );
84  $this->altUser->load();
85  }
86 
87  $this->anonUser = User::newFromId( 0 );
88 
89  $this->user = $this->userUser;
90  }
91 
92  $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
93 
94  $this->overrideMwServices();
95  }
96 
97  protected function setUserPerm( $perm ) {
98  // Setting member variables is evil!!!
99 
100  if ( is_array( $perm ) ) {
101  $this->user->mRights = $perm;
102  } else {
103  $this->user->mRights = [ $perm ];
104  }
105  }
106 
107  protected function setTitle( $ns, $title = "Main_Page" ) {
108  $this->title = Title::makeTitle( $ns, $title );
109  }
110 
111  protected function setUser( $userName = null ) {
112  if ( $userName === 'anon' ) {
113  $this->user = $this->anonUser;
114  } elseif ( $userName === null || $userName === $this->userName ) {
115  $this->user = $this->userUser;
116  } else {
117  $this->user = $this->altUser;
118  }
119  }
120 
130  public function testQuickPermissions() {
131  $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
132  getFormattedNsText( NS_PROJECT );
133 
134  $this->setUser( 'anon' );
135  $this->setTitle( NS_TALK );
136  $this->setUserPerm( "createtalk" );
137  $res = $this->permissionManager
138  ->getPermissionErrors( 'create', $this->user, $this->title );
139  $this->assertEquals( [], $res );
140 
141  $this->setTitle( NS_TALK );
142  $this->setUserPerm( "createpage" );
143  $res = $this->permissionManager
144  ->getPermissionErrors( 'create', $this->user, $this->title );
145  $this->assertEquals( [ [ "nocreatetext" ] ], $res );
146 
147  $this->setTitle( NS_TALK );
148  $this->setUserPerm( "" );
149  $res = $this->permissionManager
150  ->getPermissionErrors( 'create', $this->user, $this->title );
151  $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
152 
153  $this->setTitle( NS_MAIN );
154  $this->setUserPerm( "createpage" );
155  $res = $this->permissionManager
156  ->getPermissionErrors( 'create', $this->user, $this->title );
157  $this->assertEquals( [], $res );
158 
159  $this->setTitle( NS_MAIN );
160  $this->setUserPerm( "createtalk" );
161  $res = $this->permissionManager
162  ->getPermissionErrors( 'create', $this->user, $this->title );
163  $this->assertEquals( [ [ 'nocreatetext' ] ], $res );
164 
165  $this->setUser( $this->userName );
166  $this->setTitle( NS_TALK );
167  $this->setUserPerm( "createtalk" );
168  $res = $this->permissionManager
169  ->getPermissionErrors( 'create', $this->user, $this->title );
170  $this->assertEquals( [], $res );
171 
172  $this->setTitle( NS_TALK );
173  $this->setUserPerm( "createpage" );
174  $res = $this->permissionManager
175  ->getPermissionErrors( 'create', $this->user, $this->title );
176  $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
177 
178  $this->setTitle( NS_TALK );
179  $this->setUserPerm( "" );
180  $res = $this->permissionManager
181  ->getPermissionErrors( 'create', $this->user, $this->title );
182  $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
183 
184  $this->setTitle( NS_MAIN );
185  $this->setUserPerm( "createpage" );
186  $res = $this->permissionManager
187  ->getPermissionErrors( 'create', $this->user, $this->title );
188  $this->assertEquals( [], $res );
189 
190  $this->setTitle( NS_MAIN );
191  $this->setUserPerm( "createtalk" );
192  $res = $this->permissionManager
193  ->getPermissionErrors( 'create', $this->user, $this->title );
194  $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
195 
196  $this->setTitle( NS_MAIN );
197  $this->setUserPerm( "" );
198  $res = $this->permissionManager
199  ->getPermissionErrors( 'create', $this->user, $this->title );
200  $this->assertEquals( [ [ 'nocreate-loggedin' ] ], $res );
201 
202  $this->setUser( 'anon' );
203  $this->setTitle( NS_USER, $this->userName . '' );
204  $this->setUserPerm( "" );
205  $res = $this->permissionManager
206  ->getPermissionErrors( 'move', $this->user, $this->title );
207  $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
208 
209  $this->setTitle( NS_USER, $this->userName . '/subpage' );
210  $this->setUserPerm( "" );
211  $res = $this->permissionManager
212  ->getPermissionErrors( 'move', $this->user, $this->title );
213  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
214 
215  $this->setTitle( NS_USER, $this->userName . '' );
216  $this->setUserPerm( "move-rootuserpages" );
217  $res = $this->permissionManager
218  ->getPermissionErrors( 'move', $this->user, $this->title );
219  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
220 
221  $this->setTitle( NS_USER, $this->userName . '/subpage' );
222  $this->setUserPerm( "move-rootuserpages" );
223  $res = $this->permissionManager
224  ->getPermissionErrors( 'move', $this->user, $this->title );
225  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
226 
227  $this->setTitle( NS_USER, $this->userName . '' );
228  $this->setUserPerm( "" );
229  $res = $this->permissionManager
230  ->getPermissionErrors( 'move', $this->user, $this->title );
231  $this->assertEquals( [ [ 'cant-move-user-page' ], [ 'movenologintext' ] ], $res );
232 
233  $this->setTitle( NS_USER, $this->userName . '/subpage' );
234  $this->setUserPerm( "" );
235  $res = $this->permissionManager
236  ->getPermissionErrors( 'move', $this->user, $this->title );
237  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
238 
239  $this->setTitle( NS_USER, $this->userName . '' );
240  $this->setUserPerm( "move-rootuserpages" );
241  $res = $this->permissionManager
242  ->getPermissionErrors( 'move', $this->user, $this->title );
243  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
244 
245  $this->setTitle( NS_USER, $this->userName . '/subpage' );
246  $this->setUserPerm( "move-rootuserpages" );
247  $res = $this->permissionManager
248  ->getPermissionErrors( 'move', $this->user, $this->title );
249  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
250 
251  $this->setUser( $this->userName );
252  $this->setTitle( NS_FILE, "img.png" );
253  $this->setUserPerm( "" );
254  $res = $this->permissionManager
255  ->getPermissionErrors( 'move', $this->user, $this->title );
256  $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ], $res );
257 
258  $this->setTitle( NS_FILE, "img.png" );
259  $this->setUserPerm( "movefile" );
260  $res = $this->permissionManager
261  ->getPermissionErrors( 'move', $this->user, $this->title );
262  $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
263 
264  $this->setUser( 'anon' );
265  $this->setTitle( NS_FILE, "img.png" );
266  $this->setUserPerm( "" );
267  $res = $this->permissionManager
268  ->getPermissionErrors( 'move', $this->user, $this->title );
269  $this->assertEquals( [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ], $res );
270 
271  $this->setTitle( NS_FILE, "img.png" );
272  $this->setUserPerm( "movefile" );
273  $res = $this->permissionManager
274  ->getPermissionErrors( 'move', $this->user, $this->title );
275  $this->assertEquals( [ [ 'movenologintext' ] ], $res );
276 
277  $this->setUser( $this->userName );
278  $this->setUserPerm( "move" );
279  $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
280 
281  $this->setUserPerm( "" );
282  $this->runGroupPermissions(
283  'move',
284  [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ]
285  );
286 
287  $this->setUser( 'anon' );
288  $this->setUserPerm( "move" );
289  $this->runGroupPermissions( 'move', [ [ 'movenotallowedfile' ] ] );
290 
291  $this->setUserPerm( "" );
292  $this->runGroupPermissions(
293  'move',
294  [ [ 'movenotallowedfile' ], [ 'movenotallowed' ] ],
295  [ [ 'movenotallowedfile' ], [ 'movenologintext' ] ]
296  );
297 
298  if ( $this->isWikitextNS( NS_MAIN ) ) {
299  // NOTE: some content models don't allow moving
300  // @todo find a Wikitext namespace for testing
301 
302  $this->setTitle( NS_MAIN );
303  $this->setUser( 'anon' );
304  $this->setUserPerm( "move" );
305  $this->runGroupPermissions( 'move', [] );
306 
307  $this->setUserPerm( "" );
308  $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ],
309  [ [ 'movenologintext' ] ] );
310 
311  $this->setUser( $this->userName );
312  $this->setUserPerm( "" );
313  $this->runGroupPermissions( 'move', [ [ 'movenotallowed' ] ] );
314 
315  $this->setUserPerm( "move" );
316  $this->runGroupPermissions( 'move', [] );
317 
318  $this->setUser( 'anon' );
319  $this->setUserPerm( 'move' );
320  $res = $this->permissionManager
321  ->getPermissionErrors( 'move-target', $this->user, $this->title );
322  $this->assertEquals( [], $res );
323 
324  $this->setUserPerm( '' );
325  $res = $this->permissionManager
326  ->getPermissionErrors( 'move-target', $this->user, $this->title );
327  $this->assertEquals( [ [ 'movenotallowed' ] ], $res );
328  }
329 
330  $this->setTitle( NS_USER );
331  $this->setUser( $this->userName );
332  $this->setUserPerm( [ "move", "move-rootuserpages" ] );
333  $res = $this->permissionManager
334  ->getPermissionErrors( 'move-target', $this->user, $this->title );
335  $this->assertEquals( [], $res );
336 
337  $this->setUserPerm( "move" );
338  $res = $this->permissionManager
339  ->getPermissionErrors( 'move-target', $this->user, $this->title );
340  $this->assertEquals( [ [ 'cant-move-to-user-page' ] ], $res );
341 
342  $this->setUser( 'anon' );
343  $this->setUserPerm( [ "move", "move-rootuserpages" ] );
344  $res = $this->permissionManager
345  ->getPermissionErrors( 'move-target', $this->user, $this->title );
346  $this->assertEquals( [], $res );
347 
348  $this->setTitle( NS_USER, "User/subpage" );
349  $this->setUserPerm( [ "move", "move-rootuserpages" ] );
350  $res = $this->permissionManager
351  ->getPermissionErrors( 'move-target', $this->user, $this->title );
352  $this->assertEquals( [], $res );
353 
354  $this->setUserPerm( "move" );
355  $res = $this->permissionManager
356  ->getPermissionErrors( 'move-target', $this->user, $this->title );
357  $this->assertEquals( [], $res );
358 
359  $this->setUser( 'anon' );
360  $check = [
361  'edit' => [
362  [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ] ],
363  [ [ 'badaccess-group0' ] ],
364  [],
365  true
366  ],
367  'protect' => [
368  [ [
369  'badaccess-groups',
370  "[[$prefix:Administrators|Administrators]]", 1 ],
371  [ 'protect-cantedit'
372  ] ],
373  [ [ 'badaccess-group0' ], [ 'protect-cantedit' ] ],
374  [ [ 'protect-cantedit' ] ],
375  false
376  ],
377  '' => [ [], [], [], true ]
378  ];
379 
380  foreach ( [ "edit", "protect", "" ] as $action ) {
381  $this->setUserPerm( null );
382  $this->assertEquals( $check[$action][0],
383  $this->permissionManager
384  ->getPermissionErrors( $action, $this->user, $this->title, true ) );
385  $this->assertEquals( $check[$action][0],
386  $this->permissionManager
387  ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
388  $this->assertEquals( $check[$action][0],
389  $this->permissionManager
390  ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
391 
392  global $wgGroupPermissions;
393  $old = $wgGroupPermissions;
394  $wgGroupPermissions = [];
395 
396  $this->assertEquals( $check[$action][1],
397  $this->permissionManager
398  ->getPermissionErrors( $action, $this->user, $this->title, true ) );
399  $this->assertEquals( $check[$action][1],
400  $this->permissionManager
401  ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
402  $this->assertEquals( $check[$action][1],
403  $this->permissionManager
404  ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
405  $wgGroupPermissions = $old;
406 
407  $this->setUserPerm( $action );
408  $this->assertEquals( $check[$action][2],
409  $this->permissionManager
410  ->getPermissionErrors( $action, $this->user, $this->title, true ) );
411  $this->assertEquals( $check[$action][2],
412  $this->permissionManager
413  ->getPermissionErrors( $action, $this->user, $this->title, 'full' ) );
414  $this->assertEquals( $check[$action][2],
415  $this->permissionManager
416  ->getPermissionErrors( $action, $this->user, $this->title, 'secure' ) );
417 
418  $this->setUserPerm( $action );
419  $this->assertEquals( $check[$action][3],
420  $this->permissionManager->userCan( $action, $this->user, $this->title, true ) );
421  $this->assertEquals( $check[$action][3],
422  $this->permissionManager->userCan( $action, $this->user, $this->title,
423  PermissionManager::RIGOR_QUICK ) );
424  # count( User::getGroupsWithPermissions( $action ) ) < 1
425  }
426  }
427 
428  protected function runGroupPermissions( $action, $result, $result2 = null ) {
429  global $wgGroupPermissions;
430 
431  if ( $result2 === null ) {
432  $result2 = $result;
433  }
434 
435  $wgGroupPermissions['autoconfirmed']['move'] = false;
436  $wgGroupPermissions['user']['move'] = false;
437  $res = $this->permissionManager
438  ->getPermissionErrors( $action, $this->user, $this->title );
439  $this->assertEquals( $result, $res );
440 
441  $wgGroupPermissions['autoconfirmed']['move'] = true;
442  $wgGroupPermissions['user']['move'] = false;
443  $res = $this->permissionManager
444  ->getPermissionErrors( $action, $this->user, $this->title );
445  $this->assertEquals( $result2, $res );
446 
447  $wgGroupPermissions['autoconfirmed']['move'] = true;
448  $wgGroupPermissions['user']['move'] = true;
449  $res = $this->permissionManager
450  ->getPermissionErrors( $action, $this->user, $this->title );
451  $this->assertEquals( $result2, $res );
452 
453  $wgGroupPermissions['autoconfirmed']['move'] = false;
454  $wgGroupPermissions['user']['move'] = true;
455  $res = $this->permissionManager
456  ->getPermissionErrors( $action, $this->user, $this->title );
457  $this->assertEquals( $result2, $res );
458  }
459 
465  public function testSpecialsAndNSPermissions() {
466  global $wgNamespaceProtection;
467  $this->setUser( $this->userName );
468 
469  $this->setTitle( NS_SPECIAL );
470 
471  $this->assertEquals( [ [ 'badaccess-group0' ], [ 'ns-specialprotected' ] ],
472  $this->permissionManager
473  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
474 
475  $this->setTitle( NS_MAIN );
476  $this->setUserPerm( 'bogus' );
477  $this->assertEquals( [],
478  $this->permissionManager
479  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
480 
481  $this->setTitle( NS_MAIN );
482  $this->setUserPerm( '' );
483  $this->assertEquals( [ [ 'badaccess-group0' ] ],
484  $this->permissionManager
485  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
486 
487  $wgNamespaceProtection[NS_USER] = [ 'bogus' ];
488 
489  $this->setTitle( NS_USER );
490  $this->setUserPerm( '' );
491  $this->assertEquals( [ [ 'badaccess-group0' ],
492  [ 'namespaceprotected', 'User', 'bogus' ] ],
493  $this->permissionManager
494  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
495 
496  $this->setTitle( NS_MEDIAWIKI );
497  $this->setUserPerm( 'bogus' );
498  $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
499  $this->permissionManager
500  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
501 
502  $this->setTitle( NS_MEDIAWIKI );
503  $this->setUserPerm( 'bogus' );
504  $this->assertEquals( [ [ 'protectedinterface', 'bogus' ] ],
505  $this->permissionManager
506  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
507 
508  $wgNamespaceProtection = null;
509 
510  $this->setUserPerm( 'bogus' );
511  $this->assertEquals( [],
512  $this->permissionManager
513  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
514  $this->assertEquals( true,
515  $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
516 
517  $this->setUserPerm( '' );
518  $this->assertEquals( [ [ 'badaccess-group0' ] ],
519  $this->permissionManager
520  ->getPermissionErrors( 'bogus', $this->user, $this->title ) );
521  $this->assertEquals( false,
522  $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
523  }
524 
530  public function testJsConfigEditPermissions() {
531  $this->setUser( $this->userName );
532 
533  $this->setTitle( NS_USER, $this->userName . '/test.js' );
535  [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
536 
537  [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
538  [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
539  [ [ 'badaccess-group0' ] ],
540 
541  [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
542  [ [ 'badaccess-group0' ], [ 'mycustomjsprotected', 'bogus' ] ],
543  [ [ 'badaccess-group0' ] ],
544  [ [ 'badaccess-groups' ] ]
545  );
546  }
547 
553  public function testJsonConfigEditPermissions() {
554  $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
555  getFormattedNsText( NS_PROJECT );
556  $this->setUser( $this->userName );
557 
558  $this->setTitle( NS_USER, $this->userName . '/test.json' );
560  [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
561 
562  [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
563  [ [ 'badaccess-group0' ] ],
564  [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
565 
566  [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
567  [ [ 'badaccess-group0' ] ],
568  [ [ 'badaccess-group0' ], [ 'mycustomjsonprotected', 'bogus' ] ],
569  [ [ 'badaccess-groups' ] ]
570  );
571  }
572 
578  public function testCssConfigEditPermissions() {
579  $this->setUser( $this->userName );
580 
581  $this->setTitle( NS_USER, $this->userName . '/test.css' );
583  [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
584 
585  [ [ 'badaccess-group0' ] ],
586  [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
587  [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
588 
589  [ [ 'badaccess-group0' ] ],
590  [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
591  [ [ 'badaccess-group0' ], [ 'mycustomcssprotected', 'bogus' ] ],
592  [ [ 'badaccess-groups' ] ]
593  );
594  }
595 
602  $this->setUser( $this->userName );
603 
604  $this->setTitle( NS_USER, $this->altUserName . '/test.js' );
606  [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
607 
608  [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
609  [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
610  [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
611 
612  [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
613  [ [ 'badaccess-group0' ], [ 'customjsprotected', 'bogus' ] ],
614  [ [ 'badaccess-group0' ] ],
615  [ [ 'badaccess-groups' ] ]
616  );
617  }
618 
625  $this->setUser( $this->userName );
626 
627  $this->setTitle( NS_USER, $this->altUserName . '/test.json' );
629  [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
630 
631  [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
632  [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
633  [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
634 
635  [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
636  [ [ 'badaccess-group0' ] ],
637  [ [ 'badaccess-group0' ], [ 'customjsonprotected', 'bogus' ] ],
638  [ [ 'badaccess-groups' ] ]
639  );
640  }
641 
648  $this->setUser( $this->userName );
649 
650  $this->setTitle( NS_USER, $this->altUserName . '/test.css' );
652  [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
653 
654  [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
655  [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
656  [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
657 
658  [ [ 'badaccess-group0' ] ],
659  [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
660  [ [ 'badaccess-group0' ], [ 'customcssprotected', 'bogus' ] ],
661  [ [ 'badaccess-groups' ] ]
662  );
663  }
664 
671  $this->setUser( $this->userName );
672 
673  $this->setTitle( NS_USER, $this->altUserName . '/tempo' );
675  [ [ 'badaccess-group0' ] ],
676 
677  [ [ 'badaccess-group0' ] ],
678  [ [ 'badaccess-group0' ] ],
679  [ [ 'badaccess-group0' ] ],
680 
681  [ [ 'badaccess-group0' ] ],
682  [ [ 'badaccess-group0' ] ],
683  [ [ 'badaccess-group0' ] ],
684  [ [ 'badaccess-groups' ] ]
685  );
686  }
687 
693  $this->setUser( 'anon' );
694  $this->setTitle( NS_USER, 'ToPatrolOrNotToPatrol' );
696  [ [ 'badaccess-group0' ] ],
697 
698  [ [ 'badaccess-group0' ] ],
699  [ [ 'badaccess-group0' ] ],
700  [ [ 'badaccess-group0' ] ],
701 
702  [ [ 'badaccess-group0' ] ],
703  [ [ 'badaccess-group0' ] ],
704  [ [ 'badaccess-group0' ] ],
705  [ [ 'badaccess-groups' ] ]
706  );
707  }
708 
709  protected function runConfigEditPermissions(
710  $resultNone,
711  $resultMyCss,
712  $resultMyJson,
713  $resultMyJs,
714  $resultUserCss,
715  $resultUserJson,
716  $resultUserJs,
717  $resultPatrol
718  ) {
719  $this->setUserPerm( '' );
720  $result = $this->permissionManager
721  ->getPermissionErrors( 'bogus', $this->user, $this->title );
722  $this->assertEquals( $resultNone, $result );
723 
724  $this->setUserPerm( 'editmyusercss' );
725  $result = $this->permissionManager
726  ->getPermissionErrors( 'bogus', $this->user, $this->title );
727  $this->assertEquals( $resultMyCss, $result );
728 
729  $this->setUserPerm( 'editmyuserjson' );
730  $result = $this->permissionManager
731  ->getPermissionErrors( 'bogus', $this->user, $this->title );
732  $this->assertEquals( $resultMyJson, $result );
733 
734  $this->setUserPerm( 'editmyuserjs' );
735  $result = $this->permissionManager
736  ->getPermissionErrors( 'bogus', $this->user, $this->title );
737  $this->assertEquals( $resultMyJs, $result );
738 
739  $this->setUserPerm( 'editusercss' );
740  $result = $this->permissionManager
741  ->getPermissionErrors( 'bogus', $this->user, $this->title );
742  $this->assertEquals( $resultUserCss, $result );
743 
744  $this->setUserPerm( 'edituserjson' );
745  $result = $this->permissionManager
746  ->getPermissionErrors( 'bogus', $this->user, $this->title );
747  $this->assertEquals( $resultUserJson, $result );
748 
749  $this->setUserPerm( 'edituserjs' );
750  $result = $this->permissionManager
751  ->getPermissionErrors( 'bogus', $this->user, $this->title );
752  $this->assertEquals( $resultUserJs, $result );
753 
754  $this->setUserPerm( '' );
755  $result = $this->permissionManager
756  ->getPermissionErrors( 'patrol', $this->user, $this->title );
757  $this->assertEquals( reset( $resultPatrol[0] ), reset( $result[0] ) );
758 
759  $this->setUserPerm( [ 'edituserjs', 'edituserjson', 'editusercss' ] );
760  $result = $this->permissionManager
761  ->getPermissionErrors( 'bogus', $this->user, $this->title );
762  $this->assertEquals( [ [ 'badaccess-group0' ] ], $result );
763  }
764 
774  public function testPageRestrictions() {
775  $prefix = MediaWikiServices::getInstance()->getContentLanguage()->
776  getFormattedNsText( NS_PROJECT );
777 
778  $this->setTitle( NS_MAIN );
779  $this->title->mRestrictionsLoaded = true;
780  $this->setUserPerm( "edit" );
781  $this->title->mRestrictions = [ "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
782 
783  $this->assertEquals( [],
784  $this->permissionManager->getPermissionErrors( 'edit',
785  $this->user, $this->title ) );
786 
787  $this->assertEquals( true,
788  $this->permissionManager->userCan( 'edit', $this->user, $this->title,
789  PermissionManager::RIGOR_QUICK ) );
790 
791  $this->title->mRestrictions = [ "edit" => [ 'bogus', "sysop", "protect", "" ],
792  "bogus" => [ 'bogus', "sysop", "protect", "" ] ];
793 
794  $this->assertEquals( [ [ 'badaccess-group0' ],
795  [ 'protectedpagetext', 'bogus', 'bogus' ],
796  [ 'protectedpagetext', 'editprotected', 'bogus' ],
797  [ 'protectedpagetext', 'protect', 'bogus' ] ],
798  $this->permissionManager->getPermissionErrors( 'bogus',
799  $this->user, $this->title ) );
800  $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
801  [ 'protectedpagetext', 'editprotected', 'edit' ],
802  [ 'protectedpagetext', 'protect', 'edit' ] ],
803  $this->permissionManager->getPermissionErrors( 'edit',
804  $this->user, $this->title ) );
805  $this->setUserPerm( "" );
806  $this->assertEquals( [ [ 'badaccess-group0' ],
807  [ 'protectedpagetext', 'bogus', 'bogus' ],
808  [ 'protectedpagetext', 'editprotected', 'bogus' ],
809  [ 'protectedpagetext', 'protect', 'bogus' ] ],
810  $this->permissionManager->getPermissionErrors( 'bogus',
811  $this->user, $this->title ) );
812  $this->assertEquals( [ [ 'badaccess-groups', "*, [[$prefix:Users|Users]]", 2 ],
813  [ 'protectedpagetext', 'bogus', 'edit' ],
814  [ 'protectedpagetext', 'editprotected', 'edit' ],
815  [ 'protectedpagetext', 'protect', 'edit' ] ],
816  $this->permissionManager->getPermissionErrors( 'edit',
817  $this->user, $this->title ) );
818  $this->setUserPerm( [ "edit", "editprotected" ] );
819  $this->assertEquals( [ [ 'badaccess-group0' ],
820  [ 'protectedpagetext', 'bogus', 'bogus' ],
821  [ 'protectedpagetext', 'protect', 'bogus' ] ],
822  $this->permissionManager->getPermissionErrors( 'bogus',
823  $this->user, $this->title ) );
824  $this->assertEquals( [
825  [ 'protectedpagetext', 'bogus', 'edit' ],
826  [ 'protectedpagetext', 'protect', 'edit' ] ],
827  $this->permissionManager->getPermissionErrors( 'edit',
828  $this->user, $this->title ) );
829 
830  $this->title->mCascadeRestriction = true;
831  $this->setUserPerm( "edit" );
832 
833  $this->assertEquals( false,
834  $this->permissionManager->userCan( 'bogus', $this->user, $this->title,
835  PermissionManager::RIGOR_QUICK ) );
836 
837  $this->assertEquals( false,
838  $this->permissionManager->userCan( 'edit', $this->user, $this->title,
839  PermissionManager::RIGOR_QUICK ) );
840 
841  $this->assertEquals( [ [ 'badaccess-group0' ],
842  [ 'protectedpagetext', 'bogus', 'bogus' ],
843  [ 'protectedpagetext', 'editprotected', 'bogus' ],
844  [ 'protectedpagetext', 'protect', 'bogus' ] ],
845  $this->permissionManager->getPermissionErrors( 'bogus',
846  $this->user, $this->title ) );
847  $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
848  [ 'protectedpagetext', 'editprotected', 'edit' ],
849  [ 'protectedpagetext', 'protect', 'edit' ] ],
850  $this->permissionManager->getPermissionErrors( 'edit',
851  $this->user, $this->title ) );
852 
853  $this->setUserPerm( [ "edit", "editprotected" ] );
854  $this->assertEquals( false,
855  $this->permissionManager->userCan( 'bogus', $this->user, $this->title,
856  PermissionManager::RIGOR_QUICK ) );
857 
858  $this->assertEquals( false,
859  $this->permissionManager->userCan( 'edit', $this->user, $this->title,
860  PermissionManager::RIGOR_QUICK ) );
861 
862  $this->assertEquals( [ [ 'badaccess-group0' ],
863  [ 'protectedpagetext', 'bogus', 'bogus' ],
864  [ 'protectedpagetext', 'protect', 'bogus' ],
865  [ 'protectedpagetext', 'protect', 'bogus' ] ],
866  $this->permissionManager->getPermissionErrors( 'bogus',
867  $this->user, $this->title ) );
868  $this->assertEquals( [ [ 'protectedpagetext', 'bogus', 'edit' ],
869  [ 'protectedpagetext', 'protect', 'edit' ],
870  [ 'protectedpagetext', 'protect', 'edit' ] ],
871  $this->permissionManager->getPermissionErrors( 'edit',
872  $this->user, $this->title ) );
873  }
874 
879  $this->setTitle( NS_MAIN, "test page" );
880  $this->setUserPerm( [ "edit", "bogus" ] );
881 
882  $this->title->mCascadeSources = [
883  Title::makeTitle( NS_MAIN, "Bogus" ),
884  Title::makeTitle( NS_MAIN, "UnBogus" )
885  ];
886  $this->title->mCascadingRestrictions = [
887  "bogus" => [ 'bogus', "sysop", "protect", "" ]
888  ];
889 
890  $this->assertEquals( false,
891  $this->permissionManager->userCan( 'bogus', $this->user, $this->title ) );
892  $this->assertEquals( [
893  [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
894  [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ],
895  [ "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ] ],
896  $this->permissionManager->getPermissionErrors( 'bogus', $this->user, $this->title ) );
897 
898  $this->assertEquals( true,
899  $this->permissionManager->userCan( 'edit', $this->user, $this->title ) );
900  $this->assertEquals( [],
901  $this->permissionManager->getPermissionErrors( 'edit', $this->user, $this->title ) );
902  }
903 
909  public function testActionPermissions() {
910  $this->setUserPerm( [ "createpage" ] );
911  $this->setTitle( NS_MAIN, "test page" );
912  $this->title->mTitleProtection['permission'] = '';
913  $this->title->mTitleProtection['user'] = $this->user->getId();
914  $this->title->mTitleProtection['expiry'] = 'infinity';
915  $this->title->mTitleProtection['reason'] = 'test';
916  $this->title->mCascadeRestriction = false;
917 
918  $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
919  $this->permissionManager
920  ->getPermissionErrors( 'create', $this->user, $this->title ) );
921  $this->assertEquals( false,
922  $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
923 
924  $this->title->mTitleProtection['permission'] = 'editprotected';
925  $this->setUserPerm( [ 'createpage', 'protect' ] );
926  $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
927  $this->permissionManager
928  ->getPermissionErrors( 'create', $this->user, $this->title ) );
929  $this->assertEquals( false,
930  $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
931 
932  $this->setUserPerm( [ 'createpage', 'editprotected' ] );
933  $this->assertEquals( [],
934  $this->permissionManager
935  ->getPermissionErrors( 'create', $this->user, $this->title ) );
936  $this->assertEquals( true,
937  $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
938 
939  $this->setUserPerm( [ 'createpage' ] );
940  $this->assertEquals( [ [ 'titleprotected', 'Useruser', 'test' ] ],
941  $this->permissionManager
942  ->getPermissionErrors( 'create', $this->user, $this->title ) );
943  $this->assertEquals( false,
944  $this->permissionManager->userCan( 'create', $this->user, $this->title ) );
945 
946  $this->setTitle( NS_MEDIA, "test page" );
947  $this->setUserPerm( [ "move" ] );
948  $this->assertEquals( false,
949  $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
950  $this->assertEquals( [ [ 'immobile-source-namespace', 'Media' ] ],
951  $this->permissionManager
952  ->getPermissionErrors( 'move', $this->user, $this->title ) );
953 
954  $this->setTitle( NS_HELP, "test page" );
955  $this->assertEquals( [],
956  $this->permissionManager
957  ->getPermissionErrors( 'move', $this->user, $this->title ) );
958  $this->assertEquals( true,
959  $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
960 
961  $this->title->mInterwiki = "no";
962  $this->assertEquals( [ [ 'immobile-source-page' ] ],
963  $this->permissionManager
964  ->getPermissionErrors( 'move', $this->user, $this->title ) );
965  $this->assertEquals( false,
966  $this->permissionManager->userCan( 'move', $this->user, $this->title ) );
967 
968  $this->setTitle( NS_MEDIA, "test page" );
969  $this->assertEquals( false,
970  $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
971  $this->assertEquals( [ [ 'immobile-target-namespace', 'Media' ] ],
972  $this->permissionManager
973  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
974 
975  $this->setTitle( NS_HELP, "test page" );
976  $this->assertEquals( [],
977  $this->permissionManager
978  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
979  $this->assertEquals( true,
980  $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
981 
982  $this->title->mInterwiki = "no";
983  $this->assertEquals( [ [ 'immobile-target-page' ] ],
984  $this->permissionManager
985  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
986  $this->assertEquals( false,
987  $this->permissionManager->userCan( 'move-target', $this->user, $this->title ) );
988  }
989 
993  public function testUserBlock() {
994  $this->setMwGlobals( [
995  'wgEmailConfirmToEdit' => true,
996  'wgEmailAuthentication' => true,
997  'wgBlockDisablesLogin' => false,
998  ] );
999 
1000  $this->overrideMwServices();
1001  $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
1002 
1003  $this->setUserPerm( [
1004  'createpage',
1005  'edit',
1006  'move',
1007  'rollback',
1008  'patrol',
1009  'upload',
1010  'purge'
1011  ] );
1012  $this->setTitle( NS_HELP, "test page" );
1013 
1014  # $wgEmailConfirmToEdit only applies to 'edit' action
1015  $this->assertEquals( [],
1016  $this->permissionManager->getPermissionErrors( 'move-target',
1017  $this->user, $this->title ) );
1018  $this->assertContains( [ 'confirmedittext' ],
1019  $this->permissionManager
1020  ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1021 
1022  $this->setMwGlobals( 'wgEmailConfirmToEdit', false );
1023  $this->overrideMwServices();
1024  $this->permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
1025 
1026  $this->assertNotContains( [ 'confirmedittext' ],
1027  $this->permissionManager
1028  ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1029 
1030  # $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount'
1031  $this->assertEquals( [],
1032  $this->permissionManager->getPermissionErrors( 'move-target',
1033  $this->user, $this->title ) );
1034 
1035  global $wgLang;
1036  $prev = time();
1037  $now = time() + 120;
1038  $this->user->mBlockedby = $this->user->getId();
1039  $this->user->mBlock = new Block( [
1040  'address' => '127.0.8.1',
1041  'by' => $this->user->getId(),
1042  'reason' => 'no reason given',
1043  'timestamp' => $prev + 3600,
1044  'auto' => true,
1045  'expiry' => 0
1046  ] );
1047  $this->user->mBlock->mTimestamp = 0;
1048  $this->assertEquals( [ [ 'autoblockedtext',
1049  '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
1050  'Useruser', null, 'infinite', '127.0.8.1',
1051  $wgLang->timeanddate( wfTimestamp( TS_MW, $prev ), true ) ] ],
1052  $this->permissionManager->getPermissionErrors( 'move-target',
1053  $this->user, $this->title ) );
1054 
1055  $this->assertEquals( false, $this->permissionManager
1056  ->userCan( 'move-target', $this->user, $this->title ) );
1057  // quickUserCan should ignore user blocks
1058  $this->assertEquals( true, $this->permissionManager
1059  ->userCan( 'move-target', $this->user, $this->title,
1060  PermissionManager::RIGOR_QUICK ) );
1061 
1062  global $wgLocalTZoffset;
1063  $wgLocalTZoffset = -60;
1064  $this->user->mBlockedby = $this->user->getName();
1065  $this->user->mBlock = new Block( [
1066  'address' => '127.0.8.1',
1067  'by' => $this->user->getId(),
1068  'reason' => 'no reason given',
1069  'timestamp' => $now,
1070  'auto' => false,
1071  'expiry' => 10,
1072  ] );
1073  $this->assertEquals( [ [ 'blockedtext',
1074  '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
1075  'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
1076  $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ],
1077  $this->permissionManager
1078  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1079  # $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this )
1080  # $user->blockedFor() == ''
1081  # $user->mBlock->mExpiry == 'infinity'
1082 
1083  $this->user->mBlockedby = $this->user->getName();
1084  $this->user->mBlock = new SystemBlock( [
1085  'address' => '127.0.8.1',
1086  'by' => $this->user->getId(),
1087  'reason' => 'no reason given',
1088  'timestamp' => $now,
1089  'auto' => false,
1090  'systemBlock' => 'test',
1091  ] );
1092 
1093  $errors = [ [ 'systemblockedtext',
1094  '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
1095  'Useruser', 'test', 'infinite', '127.0.8.1',
1096  $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
1097 
1098  $this->assertEquals( $errors,
1099  $this->permissionManager
1100  ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1101  $this->assertEquals( $errors,
1102  $this->permissionManager
1103  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1104  $this->assertEquals( $errors,
1105  $this->permissionManager
1106  ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
1107  $this->assertEquals( $errors,
1108  $this->permissionManager
1109  ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
1110  $this->assertEquals( $errors,
1111  $this->permissionManager
1112  ->getPermissionErrors( 'upload', $this->user, $this->title ) );
1113  $this->assertEquals( [],
1114  $this->permissionManager
1115  ->getPermissionErrors( 'purge', $this->user, $this->title ) );
1116 
1117  // partial block message test
1118  $this->user->mBlockedby = $this->user->getName();
1119  $this->user->mBlock = new Block( [
1120  'address' => '127.0.8.1',
1121  'by' => $this->user->getId(),
1122  'reason' => 'no reason given',
1123  'timestamp' => $now,
1124  'sitewide' => false,
1125  'expiry' => 10,
1126  ] );
1127 
1128  $this->assertEquals( [],
1129  $this->permissionManager
1130  ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1131  $this->assertEquals( [],
1132  $this->permissionManager
1133  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1134  $this->assertEquals( [],
1135  $this->permissionManager
1136  ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
1137  $this->assertEquals( [],
1138  $this->permissionManager
1139  ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
1140  $this->assertEquals( [],
1141  $this->permissionManager
1142  ->getPermissionErrors( 'upload', $this->user, $this->title ) );
1143  $this->assertEquals( [],
1144  $this->permissionManager
1145  ->getPermissionErrors( 'purge', $this->user, $this->title ) );
1146 
1147  $this->user->mBlock->setRestrictions( [
1148  ( new PageRestriction( 0, $this->title->getArticleID() ) )->setTitle( $this->title ),
1149  ] );
1150 
1151  $errors = [ [ 'blockedtext-partial',
1152  '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
1153  'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
1154  $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
1155 
1156  $this->assertEquals( $errors,
1157  $this->permissionManager
1158  ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1159  $this->assertEquals( $errors,
1160  $this->permissionManager
1161  ->getPermissionErrors( 'move-target', $this->user, $this->title ) );
1162  $this->assertEquals( $errors,
1163  $this->permissionManager
1164  ->getPermissionErrors( 'rollback', $this->user, $this->title ) );
1165  $this->assertEquals( $errors,
1166  $this->permissionManager
1167  ->getPermissionErrors( 'patrol', $this->user, $this->title ) );
1168  $this->assertEquals( [],
1169  $this->permissionManager
1170  ->getPermissionErrors( 'upload', $this->user, $this->title ) );
1171  $this->assertEquals( [],
1172  $this->permissionManager
1173  ->getPermissionErrors( 'purge', $this->user, $this->title ) );
1174 
1175  // Test no block.
1176  $this->user->mBlockedby = null;
1177  $this->user->mBlock = null;
1178 
1179  $this->assertEquals( [],
1180  $this->permissionManager
1181  ->getPermissionErrors( 'edit', $this->user, $this->title ) );
1182  }
1183 
1190  public function testUserBlockAction() {
1191  global $wgLang;
1192 
1193  $tester = $this->getMockBuilder( Action::class )
1194  ->disableOriginalConstructor()
1195  ->getMock();
1196  $tester->method( 'getName' )
1197  ->willReturn( 'tester' );
1198  $tester->method( 'getRestriction' )
1199  ->willReturn( 'test' );
1200  $tester->method( 'requiresUnblock' )
1201  ->willReturn( false );
1202 
1203  $this->setMwGlobals( [
1204  'wgActions' => [
1205  'tester' => $tester,
1206  ],
1207  'wgGroupPermissions' => [
1208  '*' => [
1209  'tester' => true,
1210  ],
1211  ],
1212  ] );
1213 
1214  $now = time();
1215  $this->user->mBlockedby = $this->user->getName();
1216  $this->user->mBlock = new Block( [
1217  'address' => '127.0.8.1',
1218  'by' => $this->user->getId(),
1219  'reason' => 'no reason given',
1220  'timestamp' => $now,
1221  'auto' => false,
1222  'expiry' => 'infinity',
1223  ] );
1224 
1225  $errors = [ [ 'blockedtext',
1226  '[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
1227  'Useruser', null, 'infinite', '127.0.8.1',
1228  $wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
1229 
1230  $this->assertEquals( $errors,
1231  $this->permissionManager
1232  ->getPermissionErrors( 'tester', $this->user, $this->title ) );
1233  }
1234 
1238  public function testBlockInstanceCache() {
1239  // First, check the user isn't blocked
1240  $user = $this->getMutableTestUser()->getUser();
1242  $this->assertNull( $user->getBlock( false ), 'sanity check' );
1243  //$this->assertSame( '', $user->blockedBy(), 'sanity check' );
1244  //$this->assertSame( '', $user->blockedFor(), 'sanity check' );
1245  //$this->assertFalse( (bool)$user->isHidden(), 'sanity check' );
1246  $this->assertFalse( $this->permissionManager
1247  ->isBlockedFrom( $user, $ut ), 'sanity check' );
1248 
1249  // Block the user
1250  $blocker = $this->getTestSysop()->getUser();
1251  $block = new Block( [
1252  'hideName' => true,
1253  'allowUsertalk' => false,
1254  'reason' => 'Because',
1255  ] );
1256  $block->setTarget( $user );
1257  $block->setBlocker( $blocker );
1258  $res = $block->insert();
1259  $this->assertTrue( (bool)$res['id'], 'sanity check: Failed to insert block' );
1260 
1261  // Clear cache and confirm it loaded the block properly
1263  $this->assertInstanceOf( Block::class, $user->getBlock( false ) );
1264  //$this->assertSame( $blocker->getName(), $user->blockedBy() );
1265  //$this->assertSame( 'Because', $user->blockedFor() );
1266  //$this->assertTrue( (bool)$user->isHidden() );
1267  $this->assertTrue( $this->permissionManager->isBlockedFrom( $user, $ut ) );
1268 
1269  // Unblock
1270  $block->delete();
1271 
1272  // Clear cache and confirm it loaded the not-blocked properly
1274  $this->assertNull( $user->getBlock( false ) );
1275  //$this->assertSame( '', $user->blockedBy() );
1276  //$this->assertSame( '', $user->blockedFor() );
1277  //$this->assertFalse( (bool)$user->isHidden() );
1278  $this->assertFalse( $this->permissionManager->isBlockedFrom( $user, $ut ) );
1279  }
1280 
1291  public function testIsBlockedFrom( $title, $expect, array $options = [] ) {
1292  $this->setMwGlobals( [
1293  'wgBlockAllowsUTEdit' => $options['blockAllowsUTEdit'] ?? true,
1294  ] );
1295 
1296  $user = $this->getTestUser()->getUser();
1297 
1298  if ( $title === self::USER_TALK_PAGE ) {
1299  $title = $user->getTalkPage();
1300  } else {
1302  }
1303 
1304  $restrictions = [];
1305  foreach ( $options['pageRestrictions'] ?? [] as $pagestr ) {
1306  $page = $this->getExistingTestPage(
1307  $pagestr === self::USER_TALK_PAGE ? $user->getTalkPage() : $pagestr
1308  );
1309  $restrictions[] = new PageRestriction( 0, $page->getId() );
1310  }
1311  foreach ( $options['namespaceRestrictions'] ?? [] as $ns ) {
1312  $restrictions[] = new NamespaceRestriction( 0, $ns );
1313  }
1314 
1315  $block = new Block( [
1316  'expiry' => wfTimestamp( TS_MW, wfTimestamp() + ( 40 * 60 * 60 ) ),
1317  'allowUsertalk' => $options['allowUsertalk'] ?? false,
1318  'sitewide' => !$restrictions,
1319  ] );
1320  $block->setTarget( $user );
1321  $block->setBlocker( $this->getTestSysop()->getUser() );
1322  if ( $restrictions ) {
1323  $block->setRestrictions( $restrictions );
1324  }
1325  $block->insert();
1326 
1327  try {
1328  $this->assertSame( $expect, $this->permissionManager->isBlockedFrom( $user, $title ) );
1329  } finally {
1330  $block->delete();
1331  }
1332  }
1333 
1334  public static function provideIsBlockedFrom() {
1335  return [
1336  'Sitewide block, basic operation' => [ 'Test page', true ],
1337  'Sitewide block, not allowing user talk' => [
1338  self::USER_TALK_PAGE, true, [
1339  'allowUsertalk' => false,
1340  ]
1341  ],
1342  'Sitewide block, allowing user talk' => [
1343  self::USER_TALK_PAGE, false, [
1344  'allowUsertalk' => true,
1345  ]
1346  ],
1347  'Sitewide block, allowing user talk but $wgBlockAllowsUTEdit is false' => [
1348  self::USER_TALK_PAGE, true, [
1349  'allowUsertalk' => true,
1350  'blockAllowsUTEdit' => false,
1351  ]
1352  ],
1353  'Partial block, blocking the page' => [
1354  'Test page', true, [
1355  'pageRestrictions' => [ 'Test page' ],
1356  ]
1357  ],
1358  'Partial block, not blocking the page' => [
1359  'Test page 2', false, [
1360  'pageRestrictions' => [ 'Test page' ],
1361  ]
1362  ],
1363  'Partial block, not allowing user talk but user talk page is not blocked' => [
1364  self::USER_TALK_PAGE, false, [
1365  'allowUsertalk' => false,
1366  'pageRestrictions' => [ 'Test page' ],
1367  ]
1368  ],
1369  'Partial block, allowing user talk but user talk page is blocked' => [
1370  self::USER_TALK_PAGE, true, [
1371  'allowUsertalk' => true,
1372  'pageRestrictions' => [ self::USER_TALK_PAGE ],
1373  ]
1374  ],
1375  'Partial block, user talk page is not blocked but $wgBlockAllowsUTEdit is false' => [
1376  self::USER_TALK_PAGE, false, [
1377  'allowUsertalk' => false,
1378  'pageRestrictions' => [ 'Test page' ],
1379  'blockAllowsUTEdit' => false,
1380  ]
1381  ],
1382  'Partial block, user talk page is blocked and $wgBlockAllowsUTEdit is false' => [
1383  self::USER_TALK_PAGE, true, [
1384  'allowUsertalk' => true,
1385  'pageRestrictions' => [ self::USER_TALK_PAGE ],
1386  'blockAllowsUTEdit' => false,
1387  ]
1388  ],
1389  'Partial user talk namespace block, not allowing user talk' => [
1390  self::USER_TALK_PAGE, true, [
1391  'allowUsertalk' => false,
1392  'namespaceRestrictions' => [ NS_USER_TALK ],
1393  ]
1394  ],
1395  'Partial user talk namespace block, allowing user talk' => [
1396  self::USER_TALK_PAGE, false, [
1397  'allowUsertalk' => true,
1398  'namespaceRestrictions' => [ NS_USER_TALK ],
1399  ]
1400  ],
1401  'Partial user talk namespace block, where $wgBlockAllowsUTEdit is false' => [
1402  self::USER_TALK_PAGE, true, [
1403  'allowUsertalk' => true,
1404  'namespaceRestrictions' => [ NS_USER_TALK ],
1405  'blockAllowsUTEdit' => false,
1406  ]
1407  ],
1408  ];
1409  }
1410 
1411 }
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition: User.php:1707
const NS_MAIN
Definition: Defines.php:64
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
getBlock( $fromReplica=true)
Get the block affecting the user, or null if the user is not blocked.
Definition: User.php:2148
const NS_SPECIAL
Definition: Defines.php:53
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 MediaWikiServices
Definition: injection.txt:23
string $action
Cache what action this request is.
Definition: MediaWiki.php:48
static getInstance()
Returns the global default instance of the top level service locator.
title
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2311
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1980
$wgGroupPermissions
Permission keys given to users in each group.
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:50
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1982
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
runConfigEditPermissions( $resultNone, $resultMyCss, $resultMyJson, $resultMyJs, $resultUserCss, $resultUserJson, $resultUserJs, $resultPatrol)
static getTestSysop()
Convenience method for getting an immutable admin test user.
const NS_PROJECT
Definition: Defines.php:68
$wgLang
Definition: Setup.php:876
const USER_TALK_PAGE
Constant for self::testIsBlockedFrom.
const NS_MEDIA
Definition: Defines.php:52
static getMutableTestUser( $groups=[])
Convenience method for getting a mutable test user.
$res
Definition: database.txt:21
System blocks are temporary blocks that are created on enforcement (e.g.
Definition: SystemBlock.php:35
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 and we might be restricted by PHP settings such as safe mode or open_basedir We cannot assume that the software even has read access anywhere useful Many shared hosts run all users web applications under the same user
Wikitext formatted, in the key only.
Definition: distributors.txt:9
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1982
static resetMain()
Resets singleton returned by getMain().
testUserBlock()
\MediaWiki\Permissions\PermissionManager::checkUserBlock
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
const NS_FILE
Definition: Defines.php:70
overrideMwServices(Config $configOverrides=null, array $services=[])
Stashes the global instance of MediaWikiServices, and installs a new one, allowing test cases to over...
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown...
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
Definition: distributors.txt:9
const NS_MEDIAWIKI
Definition: Defines.php:72
testBlockInstanceCache()
\MediaWiki\Permissions\PermissionManager::isBlockedFrom
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:589
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:35
$wgNamespaceProtection
Set the minimum permissions required to edit pages in each namespace.
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:613
testCascadingSourcesRestrictions()
\MediaWiki\Permissions\PermissionManager::checkCascadingSourcesRestrictions
const NS_HELP
Definition: Defines.php:76
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
testIsBlockedFrom( $title, $expect, array $options=[])
\MediaWiki\Permissions\PermissionManager::isBlockedFrom provideIsBlockedFrom
$wgLocalTZoffset
Set an offset from UTC in minutes to use for the default timezone setting for anonymous users and new...
const NS_TALK
Definition: Defines.php:65
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition: User.php:4174
getExistingTestPage( $title=null)
Returns a WikiPage representing an existing page.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:589
testUserBlockAction()
\MediaWiki\Permissions\PermissionManager::checkUserBlock
const NS_USER_TALK
Definition: Defines.php:67
getTalkPage()
Get this user&#39;s talk page title.
Definition: User.php:4430
Blocks (as opposed to system blocks) are stored in the database, may give rise to autoblocks and may ...
Definition: Block.php:38
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
isWikitextNS( $ns)
Returns true if the given namespace defaults to Wikitext according to $wgNamespaceContentModels.
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:319