1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2024-10-30 07:32:39 +01:00

Merge pull request #3632 from BookStackApp/ownable_permission_fix

Fixed failed permission checks due to non-loaded fields
This commit is contained in:
Dan Brown 2022-08-10 17:59:46 +01:00 committed by GitHub
commit 375abca1ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 6 deletions

View File

@ -34,7 +34,13 @@ class PermissionApplicator
$ownRolePermission = $user->can($fullPermission . '-own'); $ownRolePermission = $user->can($fullPermission . '-own');
$nonJointPermissions = ['restrictions', 'image', 'attachment', 'comment']; $nonJointPermissions = ['restrictions', 'image', 'attachment', 'comment'];
$ownerField = ($ownable instanceof Entity) ? 'owned_by' : 'created_by'; $ownerField = ($ownable instanceof Entity) ? 'owned_by' : 'created_by';
$isOwner = $user->id === $ownable->getAttribute($ownerField); $ownableFieldVal = $ownable->getAttribute($ownerField);
if (is_null($ownableFieldVal)) {
throw new InvalidArgumentException("{$ownerField} field used but has not been loaded");
}
$isOwner = $user->id === $ownableFieldVal;
$hasRolePermission = $allRolePermission || ($isOwner && $ownRolePermission); $hasRolePermission = $allRolePermission || ($isOwner && $ownRolePermission);
// Handle non entity specific jointPermissions // Handle non entity specific jointPermissions
@ -68,6 +74,11 @@ class PermissionApplicator
} }
foreach ($chain as $currentEntity) { foreach ($chain as $currentEntity) {
if (is_null($currentEntity->restricted)) {
throw new InvalidArgumentException("Entity restricted field used but has not been loaded");
}
if ($currentEntity->restricted) { if ($currentEntity->restricted) {
return $currentEntity->permissions() return $currentEntity->permissions()
->whereIn('role_id', $userRoleIds) ->whereIn('role_id', $userRoleIds)

View File

@ -38,6 +38,7 @@ class BaseRepo
$this->tagRepo->saveTagsToEntity($entity, $input['tags']); $this->tagRepo->saveTagsToEntity($entity, $input['tags']);
} }
$entity->refresh();
$entity->rebuildPermissions(); $entity->rebuildPermissions();
$entity->indexForSearch(); $entity->indexForSearch();
} }

View File

@ -140,7 +140,7 @@ class BookshelfRepo
public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int
{ {
$shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray(); $shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray();
$shelfBooks = $shelf->books()->get(['id', 'restricted']); $shelfBooks = $shelf->books()->get(['id', 'restricted', 'owned_by']);
$updatedBookCount = 0; $updatedBookCount = 0;
/** @var Book $book */ /** @var Book $book */

View File

@ -163,7 +163,7 @@ class SearchRunner
$entityQuery = $entityModelInstance->newQuery()->scopes('visible'); $entityQuery = $entityModelInstance->newQuery()->scopes('visible');
if ($entityModelInstance instanceof Page) { if ($entityModelInstance instanceof Page) {
$entityQuery->select($entityModelInstance::$listAttributes); $entityQuery->select(array_merge($entityModelInstance::$listAttributes, ['restricted', 'owned_by']));
} else { } else {
$entityQuery->select(['*']); $entityQuery->select(['*']);
} }

View File

@ -87,7 +87,7 @@ class FavouriteController extends Controller
$modelInstance = $model->newQuery() $modelInstance = $model->newQuery()
->where('id', '=', $modelInfo['id']) ->where('id', '=', $modelInfo['id'])
->first(['id', 'name']); ->first(['id', 'name', 'restricted', 'owned_by']);
$inaccessibleEntity = ($modelInstance instanceof Entity && !userCan('view', $modelInstance)); $inaccessibleEntity = ($modelInstance instanceof Entity && !userCan('view', $modelInstance));
if (is_null($modelInstance) || $inaccessibleEntity) { if (is_null($modelInstance) || $inaccessibleEntity) {

View File

@ -1,11 +1,11 @@
<?php <?php namespace Tests;
use BookStack\Actions\Favourite; use BookStack\Actions\Favourite;
use BookStack\Auth\User;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use Tests\TestCase;
class FavouriteTest extends TestCase class FavouriteTest extends TestCase
{ {
@ -58,6 +58,30 @@ class FavouriteTest extends TestCase
]); ]);
} }
public function test_favourite_flow_with_own_permissions()
{
/** @var Book $book */
$book = Book::query()->first();
$user = User::factory()->create();
$book->owned_by = $user->id;
$book->save();
$this->giveUserPermissions($user, ['book-view-own']);
$this->actingAs($user)->get($book->getUrl());
$resp = $this->post('/favourites/add', [
'type' => get_class($book),
'id' => $book->id,
]);
$resp->assertRedirect($book->getUrl());
$this->assertDatabaseHas('favourites', [
'user_id' => $user->id,
'favouritable_type' => $book->getMorphClass(),
'favouritable_id' => $book->id,
]);
}
public function test_book_chapter_shelf_pages_contain_favourite_button() public function test_book_chapter_shelf_pages_contain_favourite_button()
{ {
$entities = [ $entities = [