1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-08-07 23:03:00 +03:00

Created big scary query to apply permissions via new format

This commit is contained in:
Dan Brown
2022-12-22 20:32:06 +00:00
parent 39acbeac68
commit 7330139555
4 changed files with 72 additions and 14 deletions

View File

@@ -2,7 +2,6 @@
namespace BookStack\Auth\Permissions; namespace BookStack\Auth\Permissions;
use BookStack\Auth\Role;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\BookChild; use BookStack\Entities\Models\BookChild;
use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Bookshelf;

View File

@@ -183,20 +183,70 @@ class PermissionApplicator
* Limit the given entity query so that the query will only * Limit the given entity query so that the query will only
* return items that the user has view permission for. * return items that the user has view permission for.
*/ */
public function restrictEntityQuery(Builder $query): Builder public function restrictEntityQuery(Builder $query, string $morphClass): Builder
{ {
return $query->where(function (Builder $parentQuery) { $this->getCurrentUserRoleIds();
$parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) { $this->currentUser()->id;
$permissionQuery->whereIn('role_id', $this->getCurrentUserRoleIds())
->where(function (Builder $query) { $userViewAll = userCan($morphClass . '-view-all');
$this->addJointHasPermissionCheck($query, $this->currentUser()->id); $userViewOwn = userCan($morphClass . '-view-own');
});
})->orWhereHas('jointUserPermissions', function (Builder $query) { // TODO - Leave this as the new admin workaround?
$query->where('user_id', '=', $this->currentUser()->id)->where('has_permission', '=', true); // Or auto generate collapsed role permissions for admins?
}); if (\user()->hasSystemRole('admin')) {
})->whereDoesntHave('jointUserPermissions', function (Builder $query) { return $query;
$query->where('user_id', '=', $this->currentUser()->id)->where('has_permission', '=', false); }
// Fallback permission join
$query->joinSub(function (QueryBuilder $joinQuery) use ($morphClass) {
$joinQuery->select(['entity_id'])->selectRaw('max(view) as perms_fallback')
->from('entity_permissions_collapsed')
->where('entity_type', '=', $morphClass)
->whereNull(['role_id', 'user_id'])
->groupBy('entity_id');
}, 'p_f', 'id', '=', 'p_f.entity_id', 'left');
// Role permission join
$query->joinSub(function (QueryBuilder $joinQuery) use ($morphClass) {
$joinQuery->select(['entity_id'])->selectRaw('max(view) as perms_role')
->from('entity_permissions_collapsed')
->where('entity_type', '=', $morphClass)
->whereIn('role_id', $this->getCurrentUserRoleIds())
->groupBy('entity_id');
}, 'p_r', 'id', '=', 'p_r.entity_id', 'left');
// User permission join
$query->joinSub(function (QueryBuilder $joinQuery) use ($morphClass) {
$joinQuery->select(['entity_id'])->selectRaw('max(view) as perms_user')
->from('entity_permissions_collapsed')
->where('entity_type', '=', $morphClass)
->where('user_id', '=', $this->currentUser()->id)
->groupBy('entity_id');
}, 'p_u', 'id', '=', 'p_u.entity_id', 'left');
// Where permissions apply
$query->where(function (Builder $query) use ($userViewOwn, $userViewAll) {
$query->where('perms_user', '=', 1)
->orWhere(function (Builder $query) {
$query->whereNull('perms_user')->where('perms_role', '=', 1);
})->orWhere(function (Builder $query) {
$query->whereNull(['perms_user', 'perms_role'])
->where('perms_fallback', '=', 1);
});
if ($userViewAll) {
$query->orWhere(function (Builder $query) {
$query->whereNull(['perms_user', 'perms_role', 'perms_fallback']);
});
} else if ($userViewOwn) {
$query->orWhere(function (Builder $query) {
$query->whereNull(['perms_user', 'perms_role', 'perms_fallback'])
->where('created_by', '=', $this->currentUser()->id);
});
}
}); });
return $query;
} }
/** /**
@@ -226,6 +276,9 @@ class PermissionApplicator
$tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn]; $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
$pageMorphClass = (new Page())->getMorphClass(); $pageMorphClass = (new Page())->getMorphClass();
// TODO;
return $query;
$q = $query->where(function ($query) use ($tableDetails) { $q = $query->where(function ($query) use ($tableDetails) {
$query->whereExists(function ($permissionQuery) use ($tableDetails) { $query->whereExists(function ($permissionQuery) use ($tableDetails) {
/** @var Builder $permissionQuery */ /** @var Builder $permissionQuery */
@@ -275,6 +328,9 @@ class PermissionApplicator
$fullPageIdColumn = $tableName . '.' . $pageIdColumn; $fullPageIdColumn = $tableName . '.' . $pageIdColumn;
$morphClass = (new Page())->getMorphClass(); $morphClass = (new Page())->getMorphClass();
// TODO
return $query;
$existsQuery = function ($permissionQuery) use ($fullPageIdColumn, $morphClass) { $existsQuery = function ($permissionQuery) use ($fullPageIdColumn, $morphClass) {
/** @var Builder $permissionQuery */ /** @var Builder $permissionQuery */
$permissionQuery->select('joint_permissions.role_id')->from('joint_permissions') $permissionQuery->select('joint_permissions.role_id')->from('joint_permissions')

View File

@@ -70,7 +70,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
*/ */
public function scopeVisible(Builder $query): Builder public function scopeVisible(Builder $query): Builder
{ {
return app()->make(PermissionApplicator::class)->restrictEntityQuery($query); return app()->make(PermissionApplicator::class)->restrictEntityQuery($query, $this->getMorphClass());
} }
/** /**

View File

@@ -8,8 +8,11 @@ Tests are categorised by the most specific element involved in the scenario, whe
- User entity permissions. - User entity permissions.
- Role entity permissions. - Role entity permissions.
- Fallback entity permissions.
- Role permissions. - Role permissions.
- TODO - Test fallback in the context of the above.
## General Permission Logical Rules ## General Permission Logical Rules
The below are some general rules we follow to standardise the behaviour of permissions in the platform: The below are some general rules we follow to standardise the behaviour of permissions in the platform: