Migrate remaining usages of Title::userCan() to PermissionManager
authorMáté Szabó <mszabo@wikia-inc.com>
Mon, 3 Jun 2019 10:48:02 +0000 (12:48 +0200)
committerMáté Szabó <mszabo@wikia-inc.com>
Mon, 3 Jun 2019 11:03:46 +0000 (13:03 +0200)
T208768 introduced the PermissionManager service that can now be used
for page specific permission checks. This change replaces remaining calls
to Title::userCan() with the new service in MediaWiki core.

Bug: T220191
Change-Id: Ie45e0cb6aa49a8c66147b470946161fc18160fc1

14 files changed:
img_auth.php
includes/OutputPage.php
includes/Revision/RevisionRecord.php
includes/actions/InfoAction.php
includes/actions/McrUndoAction.php
includes/diff/DifferenceEngine.php
includes/import/WikiImporter.php
includes/page/WikiPage.php
includes/specials/SpecialExport.php
includes/specials/SpecialUndelete.php
includes/specials/pagers/ImageListPager.php
includes/widget/search/FullSearchResultWidget.php
tests/phpunit/includes/Revision/RevisionRendererTest.php
thumb.php

index ba4ed74..1434125 100644 (file)
@@ -79,6 +79,8 @@ function wfImageAuthMain() {
                return;
        }
 
+       $user = RequestContext::getMain()->getUser();
+
        // Various extensions may have their own backends that need access.
        // Check if there is a special backend and storage base path for this file.
        foreach ( $wgImgAuthUrlPathMap as $prefix => $storageDir ) {
@@ -87,7 +89,7 @@ function wfImageAuthMain() {
                        $be = FileBackendGroup::singleton()->backendFromPath( $storageDir );
                        $filename = $storageDir . substr( $path, strlen( $prefix ) ); // strip prefix
                        // Check basic user authorization
-                       if ( !RequestContext::getMain()->getUser()->isAllowed( 'read' ) ) {
+                       if ( !$user->isAllowed( 'read' ) ) {
                                wfForbidden( 'img-auth-accessdenied', 'img-auth-noread', $path );
                                return;
                        }
@@ -157,7 +159,9 @@ function wfImageAuthMain() {
 
                // Check user authorization for this title
                // Checks Whitelist too
-               if ( !$title->userCan( 'read' ) ) {
+               $permissionManager = \MediaWiki\MediaWikiServices::getInstance()->getPermissionManager();
+
+               if ( !$permissionManager->userCan( 'read', $user, $title ) ) {
                        wfForbidden( 'img-auth-accessdenied', 'img-auth-noread', $name );
                        return;
                }
index 54b3ee5..da14f6f 100644 (file)
@@ -2882,8 +2882,11 @@ class OutputPage extends ContextSource {
                                        $query['returntoquery'] = wfArrayToCgi( $returntoquery );
                                }
                        }
+
+                       $services = MediaWikiServices::getInstance();
+
                        $title = SpecialPage::getTitleFor( 'Userlogin' );
-                       $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+                       $linkRenderer = $services->getLinkRenderer();
                        $loginUrl = $title->getLinkURL( $query, false, PROTO_RELATIVE );
                        $loginLink = $linkRenderer->makeKnownLink(
                                $title,
@@ -2895,9 +2898,13 @@ class OutputPage extends ContextSource {
                        $this->prepareErrorPage( $this->msg( 'loginreqtitle' ) );
                        $this->addHTML( $this->msg( $msg )->rawParams( $loginLink )->params( $loginUrl )->parse() );
 
+                       $permissionManager = $services->getPermissionManager();
+
                        # Don't return to a page the user can't read otherwise
                        # we'll end up in a pointless loop
-                       if ( $displayReturnto && $displayReturnto->userCan( 'read', $this->getUser() ) ) {
+                       if ( $displayReturnto && $permissionManager->userCan(
+                               'read', $this->getUser(), $displayReturnto
+                       ) ) {
                                $this->returnToMain( null, $displayReturnto );
                        }
                } else {
index 95749c5..70a891c 100644 (file)
@@ -27,6 +27,7 @@ use Content;
 use InvalidArgumentException;
 use LogicException;
 use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
 use MediaWiki\User\UserIdentity;
 use MWException;
 use Title;
@@ -521,8 +522,11 @@ abstract class RevisionRecord {
                        } else {
                                $text = $title->getPrefixedText();
                                wfDebug( "Checking for $permissionlist on $text due to $field match on $bitfield\n" );
+
+                               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
                                foreach ( $permissions as $perm ) {
-                                       if ( $title->userCan( $perm, $user ) ) {
+                                       if ( $permissionManager->userCan( $perm, $user, $title ) ) {
                                                return true;
                                        }
                                }
@@ -550,7 +554,7 @@ abstract class RevisionRecord {
                // null if mSlots is not empty.
 
                // NOTE: getId() and getPageId() may return null before a revision is saved, so don't
-               //check them.
+               // check them.
 
                return $this->getTimestamp() !== null
                        && $this->getComment( self::RAW ) !== null
index bfba59a..e325c9e 100644 (file)
@@ -276,11 +276,13 @@ class InfoAction extends FormlessAction {
                // Language in which the page content is (supposed to be) written
                $pageLang = $title->getPageLanguage()->getCode();
 
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
                $pageLangHtml = $pageLang . ' - ' .
                        Language::fetchLanguageName( $pageLang, $lang->getCode() );
                // Link to Special:PageLanguage with pre-filled page title if user has permissions
                if ( $config->get( 'PageLanguageUseDB' )
-                       && $title->userCan( 'pagelang', $user )
+                       && $permissionManager->userCan( 'pagelang', $user, $title )
                ) {
                        $pageLangHtml .= ' ' . $this->msg( 'parentheses' )->rawParams( $linkRenderer->makeLink(
                                SpecialPage::getTitleValueFor( 'PageLanguage', $title->getPrefixedText() ),
@@ -297,7 +299,7 @@ class InfoAction extends FormlessAction {
                $modelHtml = htmlspecialchars( ContentHandler::getLocalizedName( $title->getContentModel() ) );
                // If the user can change it, add a link to Special:ChangeContentModel
                if ( $config->get( 'ContentHandlerUseDB' )
-                       && $title->userCan( 'editcontentmodel', $user )
+                       && $permissionManager->userCan( 'editcontentmodel', $user, $title )
                ) {
                        $modelHtml .= ' ' . $this->msg( 'parentheses' )->rawParams( $linkRenderer->makeLink(
                                SpecialPage::getTitleValueFor( 'ChangeContentModel', $title->getPrefixedText() ),
index e9de846..41cd24e 100644 (file)
@@ -336,8 +336,14 @@ class McrUndoAction extends FormAction {
                        $updater->setOriginalRevisionId( false );
                        $updater->setUndidRevisionId( $this->undo );
 
+                       $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
                        // TODO: Ugh.
-                       if ( $wgUseRCPatrol && $this->getTitle()->userCan( 'autopatrol', $this->getUser() ) ) {
+                       if ( $wgUseRCPatrol && $permissionManager->userCan(
+                               'autopatrol',
+                               $this->getUser(),
+                               $this->getTitle() )
+                       ) {
                                $updater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
                        }
 
index f7658fc..86d1a43 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Revision\RevisionRecord;
 use MediaWiki\Revision\SlotRecord;
 use MediaWiki\Storage\NameTableAccessException;
@@ -538,8 +539,14 @@ class DifferenceEngine extends ContextSource {
                                $samePage = false;
                        }
 
-                       if ( $samePage && $this->mNewPage && $this->mNewPage->quickUserCan( 'edit', $user ) ) {
-                               if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan( 'rollback', $user ) ) {
+                       $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+                       if ( $samePage && $this->mNewPage && $permissionManager->userCan(
+                               'edit', $user, $this->mNewPage, PermissionManager::RIGOR_QUICK
+                       ) ) {
+                               if ( $this->mNewRev->isCurrent() && $permissionManager->userCan(
+                                       'rollback', $user, $this->mNewPage
+                               ) ) {
                                        $rollbackLink = Linker::generateRollback( $this->mNewRev, $this->getContext() );
                                        if ( $rollbackLink ) {
                                                $out->preventClickjacking();
index 8f58344..00bb61f 100644 (file)
@@ -1099,14 +1099,23 @@ class WikiImporter {
                } elseif ( !$title->canExist() ) {
                        $this->notice( 'import-error-special', $title->getPrefixedText() );
                        return false;
-               } elseif ( !$title->userCan( 'edit' ) && !$commandLineMode ) {
-                       # Do not import if the importing wiki user cannot edit this page
-                       $this->notice( 'import-error-edit', $title->getPrefixedText() );
-                       return false;
-               } elseif ( !$title->exists() && !$title->userCan( 'create' ) && !$commandLineMode ) {
-                       # Do not import if the importing wiki user cannot create this page
-                       $this->notice( 'import-error-create', $title->getPrefixedText() );
-                       return false;
+               } elseif ( !$commandLineMode ) {
+                       $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+                       $user = RequestContext::getMain()->getUser();
+
+                       if ( !$permissionManager->userCan( 'edit', $user, $title ) ) {
+                               # Do not import if the importing wiki user cannot edit this page
+                               $this->notice( 'import-error-edit', $title->getPrefixedText() );
+
+                               return false;
+                       }
+
+                       if ( !$title->exists() && !$permissionManager->userCan( 'create', $user, $title ) ) {
+                               # Do not import if the importing wiki user cannot create this page
+                               $this->notice( 'import-error-create', $title->getPrefixedText() );
+
+                               return false;
+                       }
                }
 
                return [ $title, $foreignTitle ];
index 3814112..7909ed3 100644 (file)
@@ -1904,7 +1904,11 @@ class WikiPage implements Page, IDBAccessObject {
                // TODO: this logic should not be in the storage layer, it's here for compatibility
                // with 1.31 behavior. Applying the 'autopatrol' right should be done in the same
                // place the 'bot' right is handled, which is currently in EditPage::attemptSave.
-               if ( $needsPatrol && $this->getTitle()->userCan( 'autopatrol', $user ) ) {
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+               if ( $needsPatrol && $permissionManager->userCan(
+                       'autopatrol', $user, $this->getTitle()
+               ) ) {
                        $updater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
                }
 
@@ -3267,7 +3271,11 @@ class WikiPage implements Page, IDBAccessObject {
                // TODO: this logic should not be in the storage layer, it's here for compatibility
                // with 1.31 behavior. Applying the 'autopatrol' right should be done in the same
                // place the 'bot' right is handled, which is currently in EditPage::attemptSave.
-               if ( $wgUseRCPatrol && $this->getTitle()->userCan( 'autopatrol', $guser ) ) {
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+               if ( $wgUseRCPatrol && $permissionManager->userCan(
+                       'autopatrol', $guser, $this->getTitle()
+               ) ) {
                        $updater->setRcPatrolStatus( RecentChange::PRC_AUTOPATROLLED );
                }
 
index ef61ac5..5a63581 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
 
 /**
  * A special page that allows users to export pages in a XML file
@@ -387,6 +388,8 @@ class SpecialExport extends SpecialPage {
                if ( $exportall ) {
                        $exporter->allPages();
                } else {
+                       $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
                        foreach ( $pages as $page ) {
                                # T10824: Only export pages the user can read
                                $title = Title::newFromText( $page );
@@ -395,7 +398,7 @@ class SpecialExport extends SpecialPage {
                                        continue;
                                }
 
-                               if ( !$title->userCan( 'read', $this->getUser() ) ) {
+                               if ( !$permissionManager->userCan( 'read', $this->getUser(), $title ) ) {
                                        // @todo Perhaps output an <error> tag or something.
                                        continue;
                                }
index 456face..05c622a 100644 (file)
@@ -138,8 +138,10 @@ class SpecialUndelete extends SpecialPage {
         */
        protected function isAllowed( $permission, User $user = null ) {
                $user = $user ?: $this->getUser();
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
                if ( $this->mTargetObj !== null ) {
-                       return $this->mTargetObj->userCan( $permission, $user );
+                       return $permissionManager->userCan( $permission, $user, $this->mTargetObj );
                } else {
                        return $user->isAllowed( $permission );
                }
index 8f31f3e..8adef98 100644 (file)
@@ -476,7 +476,9 @@ class ImageListPager extends TablePager {
 
                                        // Add delete links if allowed
                                        // From https://github.com/Wikia/app/pull/3859
-                                       if ( $filePage->userCan( 'delete', $this->getUser() ) ) {
+                                       $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+                                       if ( $permissionManager->userCan( 'delete', $this->getUser(), $filePage ) ) {
                                                $deleteMsg = $this->msg( 'listfiles-delete' )->text();
 
                                                $delete = $linkRenderer->makeKnownLink(
index 66fc030..1cbc790 100644 (file)
@@ -6,6 +6,7 @@ use Category;
 use Hooks;
 use HtmlArmor;
 use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\MediaWikiServices;
 use SearchResult;
 use SpecialSearch;
 use Title;
@@ -47,7 +48,10 @@ class FullSearchResultWidget implements SearchResultWidget {
                // This is not quite safe, but better than showing excerpts from
                // non-readable pages. Note that hiding the entry entirely would
                // screw up paging (really?).
-               if ( !$result->getTitle()->userCan( 'read', $this->specialPage->getUser() ) ) {
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+               if ( !$permissionManager->userCan(
+                       'read', $this->specialPage->getUser(), $result->getTitle()
+               ) ) {
                        return "<li>{$link}</li>";
                }
 
index 071ea68..d57625b 100644 (file)
@@ -6,6 +6,7 @@ use CommentStoreComment;
 use Content;
 use Language;
 use LogicException;
+use MediaWiki\Permissions\PermissionManager;
 use MediaWiki\Revision\MutableRevisionRecord;
 use MediaWiki\Revision\MainSlotRoleHandler;
 use MediaWiki\Revision\RevisionRecord;
@@ -29,6 +30,20 @@ use WikitextContent;
  */
 class RevisionRendererTest extends MediaWikiTestCase {
 
+       /** @var PermissionManager|\PHPUnit_Framework_MockObject_MockObject $permissionManagerMock */
+       private $permissionManagerMock;
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->permissionManagerMock = $this->createMock( PermissionManager::class );
+               $this->overrideMwServices( null, [
+                       'PermissionManager' => function (): PermissionManager {
+                               return $this->permissionManagerMock;
+                       }
+               ] );
+       }
+
        /**
         * @param int $articleId
         * @param int $revisionId
@@ -73,10 +88,10 @@ class RevisionRendererTest extends MediaWikiTestCase {
                                        return $mock->getArticleID() === $other->getArticleID();
                                }
                        );
-               $mock->expects( $this->any() )
+               $this->permissionManagerMock->expects( $this->any() )
                        ->method( 'userCan' )
                        ->willReturnCallback(
-                               function ( $perm, User $user ) use ( $mock ) {
+                               function ( $perm, User $user ) {
                                        return $user->isAllowed( $perm );
                                }
                        );
index 43dd5d4..e38e626 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -155,7 +155,11 @@ function wfStreamThumb( array $params ) {
        // Check permissions if there are read restrictions
        $varyHeader = [];
        if ( !in_array( 'read', User::getGroupPermissions( [ '*' ] ), true ) ) {
-               if ( !$img->getTitle() || !$img->getTitle()->userCan( 'read' ) ) {
+               $user = RequestContext::getMain()->getUser();
+               $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+               $imgTitle = $img->getTitle();
+
+               if ( !$imgTitle || !$permissionManager->userCan( 'read', $user, $imgTitle ) ) {
                        wfThumbError( 403, 'Access denied. You do not have permission to access ' .
                                'the source file.' );
                        return;