From: Máté Szabó Date: Mon, 3 Jun 2019 10:48:02 +0000 (+0200) Subject: Migrate remaining usages of Title::userCan() to PermissionManager X-Git-Tag: 1.34.0-rc.0~1401^2 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=6420c79320bc099cb4ff77232beabd72040146d0 Migrate remaining usages of Title::userCan() to PermissionManager 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 --- diff --git a/img_auth.php b/img_auth.php index ba4ed74834..1434125af9 100644 --- a/img_auth.php +++ b/img_auth.php @@ -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; } diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 54b3ee5f68..da14f6f21d 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -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 { diff --git a/includes/Revision/RevisionRecord.php b/includes/Revision/RevisionRecord.php index 95749c5643..70a891cfed 100644 --- a/includes/Revision/RevisionRecord.php +++ b/includes/Revision/RevisionRecord.php @@ -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 diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php index bfba59a02c..e325c9e22f 100644 --- a/includes/actions/InfoAction.php +++ b/includes/actions/InfoAction.php @@ -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() ), diff --git a/includes/actions/McrUndoAction.php b/includes/actions/McrUndoAction.php index e9de84675a..41cd24e701 100644 --- a/includes/actions/McrUndoAction.php +++ b/includes/actions/McrUndoAction.php @@ -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 ); } diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index f7658fc54d..86d1a43517 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -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(); diff --git a/includes/import/WikiImporter.php b/includes/import/WikiImporter.php index 8f583442ce..00bb61f7b2 100644 --- a/includes/import/WikiImporter.php +++ b/includes/import/WikiImporter.php @@ -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 ]; diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 3814112f6a..7909ed3360 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -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 ); } diff --git a/includes/specials/SpecialExport.php b/includes/specials/SpecialExport.php index ef61ac5b33..5a6358147f 100644 --- a/includes/specials/SpecialExport.php +++ b/includes/specials/SpecialExport.php @@ -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 tag or something. continue; } diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php index 456facef12..05c622a71c 100644 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@ -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 ); } diff --git a/includes/specials/pagers/ImageListPager.php b/includes/specials/pagers/ImageListPager.php index 8f31f3e630..8adef984b8 100644 --- a/includes/specials/pagers/ImageListPager.php +++ b/includes/specials/pagers/ImageListPager.php @@ -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( diff --git a/includes/widget/search/FullSearchResultWidget.php b/includes/widget/search/FullSearchResultWidget.php index 66fc030ca4..1cbc7907c4 100644 --- a/includes/widget/search/FullSearchResultWidget.php +++ b/includes/widget/search/FullSearchResultWidget.php @@ -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 "
  • {$link}
  • "; } diff --git a/tests/phpunit/includes/Revision/RevisionRendererTest.php b/tests/phpunit/includes/Revision/RevisionRendererTest.php index 071ea68347..d57625b510 100644 --- a/tests/phpunit/includes/Revision/RevisionRendererTest.php +++ b/tests/phpunit/includes/Revision/RevisionRendererTest.php @@ -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 ); } ); diff --git a/thumb.php b/thumb.php index 43dd5d472f..e38e62604d 100644 --- 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;