Files
BookStack/tests/Helpers/PermissionsProvider.php
Dan Brown c87abbd23f Images: Increased validation against related page on upload
Adds validation that the related page exists, is visible, and that the
user has page edit permissions for the page.
Aligns with attachment permission model, and aligns across different
image endpoints.

Added tests to cover.
Closes #6126
2026-05-14 18:10:46 +01:00

151 lines
5.0 KiB
PHP

<?php
namespace Tests\Helpers;
use BookStack\Entities\Models\Entity;
use BookStack\Permissions\Models\EntityPermission;
use BookStack\Permissions\Models\RolePermission;
use BookStack\Permissions\Permission;
use BookStack\Settings\SettingService;
use BookStack\Users\Models\Role;
use BookStack\Users\Models\User;
class PermissionsProvider
{
public function __construct(
protected UserRoleProvider $userRoleProvider
) {
}
public function makeAppPublic(): void
{
$settings = app(SettingService::class);
$settings->put('app-public', 'true');
}
/**
* Grant role permissions to the provided user.
*/
public function grantUserRolePermissions(User $user, array $permissions): void
{
$newRole = $this->userRoleProvider->createRole($permissions);
$user->attachRole($newRole);
$user->load('roles');
$user->clearPermissionCache();
}
/**
* Completely remove specific role permissions from the provided user.
*/
public function removeUserRolePermissions(User $user, array $permissions): void
{
foreach ($permissions as $permissionName) {
/** @var RolePermission $permission */
$permission = RolePermission::query()
->where('name', '=', $permissionName)
->firstOrFail();
$roles = $user->roles()->whereHas('permissions', function ($query) use ($permission) {
$query->where('id', '=', $permission->id);
})->get();
/** @var Role $role */
foreach ($roles as $role) {
$role->detachPermission($permission);
}
$user->clearPermissionCache();
}
}
/**
* Change the owner of the given entity to the given user.
*/
public function changeEntityOwner(Entity $entity, User $newOwner): void
{
$entity->owned_by = $newOwner->id;
$entity->save();
$entity->rebuildPermissions();
}
/**
* Regenerate the permission for an entity.
* Centralised to manage clearing of cached elements between requests.
*/
public function regenerateForEntity(Entity $entity): void
{
$entity->rebuildPermissions();
}
/**
* Set the given entity as having restricted permissions, and apply the given
* permissions for the given roles.
* @param string[] $actions
* @param Role[] $roles
*/
public function setEntityPermissions(Entity $entity, array $actions = [], array $roles = [], $inherit = false): void
{
$entity->permissions()->delete();
$permissions = [];
if (!$inherit) {
// Set default permissions to not allow actions so that only the provided role permissions are at play.
$permissions[] = ['role_id' => 0, 'view' => false, 'create' => false, 'update' => false, 'delete' => false];
}
foreach ($roles as $role) {
$permissions[] = $this->actionListToEntityPermissionData($actions, $role->id);
}
$this->addEntityPermissionEntries($entity, $permissions);
}
public function setEntityPermissionsForRole(Entity $entity, array $actionList, Role $role)
{
$entity->permissions()->where('role_id', '=', $role->id)->delete();
$permissionData = $this->actionListToEntityPermissionData($actionList, $role->id);
$this->addEntityPermissionEntries($entity, [$permissionData]);
}
public function setFallbackPermissions(Entity $entity, array $actionList)
{
$entity->permissions()->where('role_id', '=', 0)->delete();
$permissionData = $this->actionListToEntityPermissionData($actionList, 0);
$this->addEntityPermissionEntries($entity, [$permissionData]);
}
/**
* Disable inherited permissions on the given entity.
* Effectively sets the "Other Users" UI permission option to not inherit, with no permissions.
*/
public function disableEntityInheritedPermissions(Entity $entity): void
{
$entity->permissions()->where('role_id', '=', 0)->delete();
$fallback = $this->actionListToEntityPermissionData([]);
$this->addEntityPermissionEntries($entity, [$fallback]);
}
protected function addEntityPermissionEntries(Entity $entity, array $entityPermissionData): void
{
$entity->permissions()->createMany($entityPermissionData);
$entity->load('permissions');
$this->regenerateForEntity($entity);
}
/**
* For the given simple array of string actions (view, create, update, delete), convert
* the format to entity permission data, where permission is granted if the action is in the
* given actionList array.
*/
protected function actionListToEntityPermissionData(array $actionList, int $roleId = 0): array
{
$permissionData = ['role_id' => $roleId];
foreach (Permission::genericForEntity() as $permission) {
$permissionData[$permission->value] = in_array($permission->value, $actionList);
}
return $permissionData;
}
}