wiki.techinc.nl/includes/Permissions/GroupPermissionsLookup.php
thiemowmde b1c9ec74fa Remove meaningless @var documentation from constants
A constant is not a variable. The type is hard-coded via the value
and can never change. While the extra @var probably doesn't hurt much,
it's redundant and error-prone and can't provide any additional
information.

Change-Id: Iee1f36a1905d9b9c6b26d0684b7848571f0c1733
2024-10-09 09:33:12 +02:00

215 lines
6.7 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Permissions;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\MainConfigNames;
/**
* A service class for looking up permissions bestowed to groups, groups bestowed with
* permissions, and permissions bestowed by membership in a combination of groups, solely
* according to site configuration for group permissions and inheritence thereof.
*
* This class does *not* account for implicit rights (which are not associated with groups).
* Callers might want to use {@see PermissionManager} if this is an issue.
*
* This class does *not* infer membership in one group (e.g. '*') from membership in another
* (e.g. 'user'). Callers must account for this when using {@see self::getGroupPermissions()}.
*
* @since 1.36
* @package MediaWiki\Permissions
*/
class GroupPermissionsLookup {
/**
* @internal
*/
public const CONSTRUCTOR_OPTIONS = [
MainConfigNames::GroupInheritsPermissions,
MainConfigNames::GroupPermissions,
MainConfigNames::RevokePermissions,
];
/** @var array[] */
private $groupPermissions;
/** @var array[] */
private $revokePermissions;
/** @var string[] */
private $groupInheritance;
/**
* @param ServiceOptions $options
*/
public function __construct( ServiceOptions $options ) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
$this->groupPermissions = $options->get( MainConfigNames::GroupPermissions );
$this->revokePermissions = $options->get( MainConfigNames::RevokePermissions );
$this->groupInheritance = $options->get( MainConfigNames::GroupInheritsPermissions );
}
/**
* 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.
*
* @param string $group Group to check
* @param string $permission Role to check
*
* @return bool
*/
public function groupHasPermission( string $group, string $permission ): bool {
$inheritsFrom = $this->groupInheritance[$group] ?? false;
$has = isset( $this->groupPermissions[$group][$permission] ) &&
$this->groupPermissions[$group][$permission];
// If the group doesn't have the permission and inherits from somewhere,
// check that group too
if ( !$has && $inheritsFrom !== false ) {
$has = isset( $this->groupPermissions[$inheritsFrom][$permission] ) &&
$this->groupPermissions[$inheritsFrom][$permission];
}
if ( !$has ) {
// If they don't have the permission, exit early
return false;
}
// Check if the permission has been revoked
$revoked = isset( $this->revokePermissions[$group][$permission] ) &&
$this->revokePermissions[$group][$permission];
if ( !$revoked && $inheritsFrom !== false ) {
$revoked = isset( $this->revokePermissions[$inheritsFrom][$permission] ) &&
$this->revokePermissions[$inheritsFrom][$permission];
}
return !$revoked;
}
/**
* Get a list of permissions granted to this group. This
* must *NOT* be used for permissions checking as it
* does not check whether a permission has been revoked
* from this group.
*
* @param string $group Group to get permissions of
* @return string[]
* @since 1.38
*/
public function getGrantedPermissions( string $group ): array {
$rights = array_keys( array_filter( $this->groupPermissions[$group] ?? [] ) );
$inheritsFrom = $this->groupInheritance[$group] ?? false;
if ( $inheritsFrom !== false ) {
$rights = array_merge(
$rights,
// array_filter removes empty items
array_keys( array_filter( $this->groupPermissions[$inheritsFrom] ?? [] ) )
);
}
return array_unique( $rights );
}
/**
* Get a list of permissions revoked from this group
*
* @param string $group Group to get revoked permissions of
* @return string[]
* @since 1.38
*/
public function getRevokedPermissions( string $group ): array {
$rights = array_keys( array_filter( $this->revokePermissions[$group] ?? [] ) );
$inheritsFrom = $this->groupInheritance[$group] ?? false;
if ( $inheritsFrom !== false ) {
$rights = array_merge(
$rights,
// array_filter removes empty items
array_keys( array_filter( $this->revokePermissions[$inheritsFrom] ?? [] ) )
);
}
return array_unique( $rights );
}
/**
* Get the permissions associated with membership in a combination of groups
*
* Group-based revocation of a permission negates all group-based assignments of that
* permission.
*
* @param string[] $groups internal group names
* @return string[] permission key names for given groups combined
*/
public function getGroupPermissions( array $groups ): array {
$rights = [];
$checkGroups = [];
// Add inherited groups to the list of groups to check
foreach ( $groups as $group ) {
$checkGroups[] = $group;
if ( isset( $this->groupInheritance[$group] ) ) {
$checkGroups[] = $this->groupInheritance[$group];
}
}
// grant every granted permission first
foreach ( $checkGroups 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 ( $checkGroups 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
*
* @param string $permission
* @return string[] internal group names with the given permission
*/
public function getGroupsWithPermission( string $permission ): array {
$allowedGroups = [];
$groups = array_unique( array_merge(
array_keys( $this->groupPermissions ),
array_keys( $this->groupInheritance )
) );
foreach ( $groups as $group ) {
if ( $this->groupHasPermission( $group, $permission ) ) {
$allowedGroups[] = $group;
}
}
return $allowedGroups;
}
}