return !count( $this->getPermissionErrorsInternal( $action, $user, $page, $rigor, true ) );
}
+ /**
+ * A convenience method for calling PermissionManager::userCan
+ * with PermissionManager::RIGOR_QUICK
+ *
+ * Suitable for use for nonessential UI controls in common cases, but
+ * _not_ for functional access control.
+ * May provide false positives, but should never provide a false negative.
+ *
+ * @see PermissionManager::userCan()
+ *
+ * @param string $action
+ * @param User $user
+ * @param LinkTarget $page
+ * @return bool
+ */
+ public function quickUserCan( $action, User $user, LinkTarget $page ) {
+ return $this->userCan( $action, $user, $page, self::RIGOR_QUICK );
+ }
+
/**
* Can $user perform $action on a page?
*
* Check permissions on special pages & namespaces
*
* @param string $action The action to check
- * @param User $user User to check
+ * @param UserIdentity $user User to check
* @param array $errors List of current errors
* @param string $rigor One of PermissionManager::RIGOR_ constants
* - RIGOR_QUICK : does cheap permission checks from replica DBs (usable for GUI creation)
*/
private function checkSpecialsAndNSPermissions(
$action,
- User $user,
+ UserIdentity $user,
$errors,
$rigor,
$short,
}
# Check $wgNamespaceProtection for restricted namespaces
- if ( $title->isNamespaceProtected( $user ) ) {
+ if ( $this->isNamespaceProtected( $title->getNamespace(), $user ) ) {
$ns = $title->getNamespace() == NS_MAIN ?
wfMessage( 'nstab-main' )->text() : $title->getNsText();
$errors[] = $title->getNamespace() == NS_MEDIAWIKI ?
*/
public function getUserPermissions( UserIdentity $user ) {
$user = User::newFromIdentity( $user );
- if ( !isset( $this->usersRights[ $user->getId() ] ) ) {
- $this->usersRights[ $user->getId() ] = $this->getGroupPermissions(
+ $rightsCacheKey = $this->getRightsCacheKey( $user );
+ if ( !isset( $this->usersRights[ $rightsCacheKey ] ) ) {
+ $this->usersRights[ $rightsCacheKey ] = $this->getGroupPermissions(
$user->getEffectiveGroups()
);
- Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $user->getId() ] ] );
+ Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $rightsCacheKey ] ] );
// Deny any rights denied by the user's session, unless this
// endpoint has no sessions.
// FIXME: $user->getRequest().. need to be replaced with something else
$allowedRights = $user->getRequest()->getSession()->getAllowedUserRights();
if ( $allowedRights !== null ) {
- $this->usersRights[ $user->getId() ] = array_intersect(
- $this->usersRights[ $user->getId() ],
+ $this->usersRights[ $rightsCacheKey ] = array_intersect(
+ $this->usersRights[ $rightsCacheKey ],
$allowedRights
);
}
}
- Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $user->getId() ] ] );
+ Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $rightsCacheKey ] ] );
// Force reindexation of rights when a hook has unset one of them
- $this->usersRights[ $user->getId() ] = array_values(
- array_unique( $this->usersRights[ $user->getId() ] )
+ $this->usersRights[ $rightsCacheKey ] = array_values(
+ array_unique( $this->usersRights[ $rightsCacheKey ] )
);
if (
$user->getBlock()
) {
$anon = new User;
- $this->usersRights[ $user->getId() ] = array_intersect(
- $this->usersRights[ $user->getId() ],
+ $this->usersRights[ $rightsCacheKey ] = array_intersect(
+ $this->usersRights[ $rightsCacheKey ],
$this->getUserPermissions( $anon )
);
}
}
- $rights = $this->usersRights[ $user->getId() ];
+ $rights = $this->usersRights[ $rightsCacheKey ];
foreach ( $this->temporaryUserRights[ $user->getId() ] ?? [] as $overrides ) {
$rights = array_values( array_unique( array_merge( $rights, $overrides ) ) );
}
*/
public function invalidateUsersRightsCache( $user = null ) {
if ( $user !== null ) {
- if ( isset( $this->usersRights[ $user->getId() ] ) ) {
- unset( $this->usersRights[$user->getId()] );
+ $rightsCacheKey = $this->getRightsCacheKey( $user );
+ if ( isset( $this->usersRights[ $rightsCacheKey ] ) ) {
+ unset( $this->usersRights[ $rightsCacheKey ] );
}
} else {
$this->usersRights = null;
}
}
+ /**
+ * Gets a unique key for user rights cache.
+ * @param UserIdentity $user
+ * @return string
+ */
+ private function getRightsCacheKey( UserIdentity $user ) {
+ return $user->isRegistered() ? "u:{$user->getId()}" : "anon:{$user->getName()}";
+ }
+
/**
* Check, if the given group has the given permission
*
return $this->allRights;
}
+ /**
+ * Determines if $user is unable to edit pages in namespace because it has been protected.
+ * @param $index
+ * @param UserIdentity $user
+ * @return bool
+ */
+ private function isNamespaceProtected( $index, UserIdentity $user ) {
+ $namespaceProtection = $this->options->get( 'NamespaceProtection' );
+ if ( isset( $namespaceProtection[$index] ) ) {
+ return !$this->userHasAllRights( $user, ...(array)$namespaceProtection[$index] );
+ }
+ return false;
+ }
+
/**
* Determine which restriction levels it makes sense to use in a namespace,
* optionally filtered by a user's rights.
if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
throw new Exception( __METHOD__ . ' can not be called outside of tests' );
}
- $this->usersRights[ $user->getId() ] = is_array( $rights ) ? $rights : [ $rights ];
+ $this->usersRights[ $this->getRightsCacheKey( $user ) ] =
+ is_array( $rights ) ? $rights : [ $rights ];
}
}