mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-08-27 12:41:58 +00:00
![Dan Brown](/assets/img/avatar_default.png)
Had misalignment between query and usercan, The nuance between fallback and entity-role permissions was not taken into account by the query system. Now added with new test cases to cover.
82 lines
2.7 KiB
PHP
82 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace BookStack\Auth\Permissions;
|
|
|
|
class MassEntityPermissionEvaluator extends EntityPermissionEvaluator
|
|
{
|
|
/**
|
|
* @var SimpleEntityData[]
|
|
*/
|
|
protected array $entitiesInvolved;
|
|
protected array $permissionMapCache;
|
|
|
|
public function __construct(array $entitiesInvolved, string $action)
|
|
{
|
|
$this->entitiesInvolved = $entitiesInvolved;
|
|
parent::__construct($action);
|
|
}
|
|
|
|
public function evaluateEntityForRole(SimpleEntityData $entity, int $roleId): ?int
|
|
{
|
|
$typeIdChain = $this->gatherEntityChainTypeIds($entity);
|
|
$relevantPermissions = $this->getPermissionMapByTypeIdForChainAndRole($typeIdChain, $roleId);
|
|
$permitsByType = $this->collapseAndCategorisePermissions($typeIdChain, $relevantPermissions);
|
|
|
|
return $this->evaluatePermitsByType($permitsByType);
|
|
}
|
|
|
|
/**
|
|
* @param string[] $typeIdChain
|
|
* @return array<string, EntityPermission[]>
|
|
*/
|
|
protected function getPermissionMapByTypeIdForChainAndRole(array $typeIdChain, int $roleId): array
|
|
{
|
|
$allPermissions = $this->getPermissionMapByTypeIdAndRoleForAllInvolved();
|
|
$relevantPermissions = [];
|
|
|
|
// Filter down permissions to just those for current typeId
|
|
// and current roleID or fallback permissions.
|
|
foreach ($typeIdChain as $typeId) {
|
|
$relevantPermissions[$typeId] = [
|
|
...($allPermissions[$typeId][$roleId] ?? []),
|
|
...($allPermissions[$typeId][0] ?? [])
|
|
];
|
|
}
|
|
|
|
return $relevantPermissions;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, array<int, EntityPermission[]>>
|
|
*/
|
|
protected function getPermissionMapByTypeIdAndRoleForAllInvolved(): array
|
|
{
|
|
if (isset($this->permissionMapCache)) {
|
|
return $this->permissionMapCache;
|
|
}
|
|
|
|
$entityTypeIdChain = [];
|
|
foreach ($this->entitiesInvolved as $entity) {
|
|
$entityTypeIdChain[] = $entity->type . ':' . $entity->id;
|
|
}
|
|
|
|
$permissionMap = $this->getPermissionsMapByTypeId($entityTypeIdChain, []);
|
|
|
|
// Manipulate permission map to also be keyed by roleId.
|
|
foreach ($permissionMap as $typeId => $permissions) {
|
|
$permissionMap[$typeId] = [];
|
|
foreach ($permissions as $permission) {
|
|
$roleId = $permission->getRawAttribute('role_id');
|
|
if (!isset($permissionMap[$typeId][$roleId])) {
|
|
$permissionMap[$typeId][$roleId] = [];
|
|
}
|
|
$permissionMap[$typeId][$roleId][] = $permission;
|
|
}
|
|
}
|
|
|
|
$this->permissionMapCache = $permissionMap;
|
|
|
|
return $this->permissionMapCache;
|
|
}
|
|
}
|