- /**
- * Testing a permission
- *
- * @since 1.34
- *
- * @param UserIdentity $user
- * @param string $action
- *
- * @return bool
- */
- public function userHasRight( UserIdentity $user, $action = '' ) {
- if ( $action === '' ) {
- return true; // In the spirit of DWIM
- }
- // Use strict parameter to avoid matching numeric 0 accidentally inserted
- // by misconfiguration: 0 == 'foo'
- return in_array( $action, $this->getUserPermissions( $user ), true );
- }
-
- /**
- * Get the permissions this user has.
- *
- * @since 1.34
- *
- * @param UserIdentity $user
- *
- * @return string[] permission names
- */
- public function getUserPermissions( UserIdentity $user ) {
- $user = User::newFromIdentity( $user );
- if ( !isset( $this->usersRights[ $user->getId() ] ) ) {
- $this->usersRights[ $user->getId() ] = $this->getGroupPermissions(
- $user->getEffectiveGroups()
- );
- Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $user->getId() ] ] );
-
- // Deny any rights denied by the user's session, unless this
- // endpoint has no sessions.
- if ( !defined( 'MW_NO_SESSION' ) ) {
- // 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() ],
- $allowedRights
- );
- }
- }
-
- Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $user->getId() ] ] );
- // Force reindexation of rights when a hook has unset one of them
- $this->usersRights[ $user->getId() ] = array_values(
- array_unique( $this->usersRights[ $user->getId() ] )
- );
-
- if (
- $user->isLoggedIn() &&
- $this->blockDisablesLogin &&
- $user->getBlock()
- ) {
- $anon = new User;
- $this->usersRights[ $user->getId() ] = array_intersect(
- $this->usersRights[ $user->getId() ],
- $this->getUserPermissions( $anon )
- );
- }
- }
- return $this->usersRights[ $user->getId() ];
- }
-
- /**
- * Clears users permissions cache, if specific user is provided it tries to clear
- * permissions cache only for provided user.
- *
- * @since 1.34
- *
- * @param User|null $user
- */
- public function invalidateUsersRightsCache( $user = null ) {
- if ( $user !== null ) {
- if ( isset( $this->usersRights[ $user->getId() ] ) ) {
- unset( $this->usersRights[$user->getId()] );
- }
- } else {
- $this->usersRights = null;
- }
- }
-
- /**
- * Check, if the given group has the given permission
- *
- * If you're wanting to check whether all users have a permission, use
- * PermissionManager::isEveryoneAllowed() instead. That properly checks if it's revoked
- * from anyone.
- *
- * @since 1.34
- *
- * @param string $group Group to check
- * @param string $role Role to check
- *
- * @return bool
- */
- public function groupHasPermission( $group, $role ) {
- return isset( $this->groupPermissions[$group][$role] ) &&
- $this->groupPermissions[$group][$role] &&
- !( isset( $this->revokePermissions[$group][$role] ) &&
- $this->revokePermissions[$group][$role] );
- }
-
- /**
- * Get the permissions associated with a given list of groups
- *
- * @since 1.34
- *
- * @param array $groups Array of Strings List of internal group names
- * @return array Array of Strings List of permission key names for given groups combined
- */
- public function getGroupPermissions( $groups ) {
- $rights = [];
- // grant every granted permission first
- foreach ( $groups as $group ) {
- if ( isset( $this->groupPermissions[$group] ) ) {
- $rights = array_merge( $rights,
- // array_filter removes empty items
- array_keys( array_filter( $this->groupPermissions[$group] ) ) );
- }
- }
- // now revoke the revoked permissions
- foreach ( $groups as $group ) {
- if ( isset( $this->revokePermissions[$group] ) ) {
- $rights = array_diff( $rights,
- array_keys( array_filter( $this->revokePermissions[$group] ) ) );
- }
- }
- return array_unique( $rights );
- }
-
- /**
- * Get all the groups who have a given permission
- *
- * @since 1.34
- *
- * @param string $role Role to check
- * @return array Array of Strings List of internal group names with the given permission
- */
- public function getGroupsWithPermission( $role ) {
- $allowedGroups = [];
- foreach ( array_keys( $this->groupPermissions ) as $group ) {
- if ( $this->groupHasPermission( $group, $role ) ) {
- $allowedGroups[] = $group;
- }
- }
- return $allowedGroups;
- }
-
- /**
- * Check if all users may be assumed to have the given permission
- *
- * We generally assume so if the right is granted to '*' and isn't revoked
- * on any group. It doesn't attempt to take grants or other extension
- * limitations on rights into account in the general case, though, as that
- * would require it to always return false and defeat the purpose.
- * Specifically, session-based rights restrictions (such as OAuth or bot
- * passwords) are applied based on the current session.
- *
- * @param string $right Right to check
- *
- * @return bool
- * @since 1.34
- */
- public function isEveryoneAllowed( $right ) {
- // Use the cached results, except in unit tests which rely on
- // being able change the permission mid-request
- if ( isset( $this->cachedRights[$right] ) ) {
- return $this->cachedRights[$right];
- }
-
- if ( !isset( $this->groupPermissions['*'][$right] )
- || !$this->groupPermissions['*'][$right] ) {
- $this->cachedRights[$right] = false;
- return false;
- }
-
- // If it's revoked anywhere, then everyone doesn't have it
- foreach ( $this->revokePermissions as $rights ) {
- if ( isset( $rights[$right] ) && $rights[$right] ) {
- $this->cachedRights[$right] = false;
- return false;
- }
- }
-
- // Remove any rights that aren't allowed to the global-session user,
- // unless there are no sessions for this endpoint.
- if ( !defined( 'MW_NO_SESSION' ) ) {
-
- // XXX: think what could be done with the below
- $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
- if ( $allowedRights !== null && !in_array( $right, $allowedRights, true ) ) {
- $this->cachedRights[$right] = false;
- return false;
- }
- }
-
- // Allow extensions to say false
- if ( !Hooks::run( 'UserIsEveryoneAllowed', [ $right ] ) ) {
- $this->cachedRights[$right] = false;
- return false;
- }
-
- $this->cachedRights[$right] = true;
- return true;
- }
-
- /**
- * Get a list of all available permissions.
- *
- * @since 1.34
- *
- * @return string[] Array of permission names
- */
- public function getAllPermissions() {
- if ( $this->allRights === false ) {
- if ( count( $this->availableRights ) ) {
- $this->allRights = array_unique( array_merge(
- $this->coreRights,
- $this->availableRights
- ) );
- } else {
- $this->allRights = $this->coreRights;
- }
- Hooks::run( 'UserGetAllRights', [ &$this->allRights ] );
- }
- return $this->allRights;
- }
-
- /**
- * Overrides user permissions cache
- *
- * @since 1.34
- *
- * @param User $user
- * @param string[]|string $rights
- *
- * @throws Exception
- */
- public function overrideUserRightsForTesting( $user, $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 ];
- }
-