From c87abbd23f2dca8c733a8e010b42a089041fa2ae Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 14 May 2026 18:10:46 +0100 Subject: [PATCH] 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 --- app/Config/database.php | 1 - .../Controllers/DrawioImageController.php | 14 ++-- .../Controllers/GalleryImageController.php | 18 +++-- .../Controllers/ImageGalleryApiController.php | 1 + tests/Activity/CommentMentionTest.php | 2 +- tests/Api/ContentPermissionsApiTest.php | 4 +- tests/Api/ImageGalleryApiTest.php | 28 ++++++++ .../RegeneratePermissionsCommandTest.php | 2 +- tests/ErrorTest.php | 3 +- tests/Helpers/PermissionsProvider.php | 3 +- .../Scenarios/EntityRolePermissionsTest.php | 66 +++++++++---------- tests/PublicActionTest.php | 3 +- tests/Uploads/DrawioTest.php | 24 +++++++ tests/Uploads/ImageTest.php | 39 +++++++++++ 14 files changed, 155 insertions(+), 53 deletions(-) diff --git a/app/Config/database.php b/app/Config/database.php index 6fc861312..86bae5f5b 100644 --- a/app/Config/database.php +++ b/app/Config/database.php @@ -81,7 +81,6 @@ return [ 'strict' => false, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ - // @phpstan-ignore class.notFound (PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], diff --git a/app/Uploads/Controllers/DrawioImageController.php b/app/Uploads/Controllers/DrawioImageController.php index 8295febc1..53ae79004 100644 --- a/app/Uploads/Controllers/DrawioImageController.php +++ b/app/Uploads/Controllers/DrawioImageController.php @@ -2,6 +2,7 @@ namespace BookStack\Uploads\Controllers; +use BookStack\Entities\Queries\PageQueries; use BookStack\Exceptions\ImageUploadException; use BookStack\Http\Controller; use BookStack\Permissions\Permission; @@ -14,7 +15,8 @@ use Illuminate\Http\Request; class DrawioImageController extends Controller { public function __construct( - protected ImageRepo $imageRepo + protected ImageRepo $imageRepo, + protected PageQueries $pageQueries, ) { } @@ -53,16 +55,18 @@ class DrawioImageController extends Controller */ public function create(Request $request) { - $this->validate($request, [ + $this->checkPermission(Permission::ImageCreateAll); + $validated = $this->validate($request, [ 'image' => ['required', 'string'], 'uploaded_to' => ['required', 'integer'], ]); - $this->checkPermission(Permission::ImageCreateAll); - $imageBase64Data = $request->input('image'); + $imageBase64Data = $validated['image']; + $uploadedTo = $validated['uploaded_to']; + $targetPage = $this->pageQueries->findVisibleByIdOrFail($uploadedTo); + $this->checkOwnablePermission(Permission::PageUpdate, $targetPage); try { - $uploadedTo = $request->input('uploaded_to', 0); $image = $this->imageRepo->saveDrawing($imageBase64Data, $uploadedTo); } catch (ImageUploadException $e) { return response($e->getMessage(), 500); diff --git a/app/Uploads/Controllers/GalleryImageController.php b/app/Uploads/Controllers/GalleryImageController.php index 908322be0..ca60f9f8e 100644 --- a/app/Uploads/Controllers/GalleryImageController.php +++ b/app/Uploads/Controllers/GalleryImageController.php @@ -2,6 +2,7 @@ namespace BookStack\Uploads\Controllers; +use BookStack\Entities\Queries\PageQueries; use BookStack\Exceptions\ImageUploadException; use BookStack\Http\Controller; use BookStack\Permissions\Permission; @@ -14,7 +15,8 @@ use Illuminate\Validation\ValidationException; class GalleryImageController extends Controller { public function __construct( - protected ImageRepo $imageRepo + protected ImageRepo $imageRepo, + protected PageQueries $pageQueries, ) { } @@ -56,20 +58,26 @@ class GalleryImageController extends Controller $this->checkPermission(Permission::ImageCreateAll); try { - $this->validate($request, [ + $validated = $this->validate($request, [ 'file' => $this->getImageValidationRules(), + 'uploaded_to' => ['required', 'integer'], ]); } catch (ValidationException $exception) { - return $this->jsonError(implode("\n", $exception->errors()['file'])); + $errors = $exception->errors(); + $messages = array_merge($errors['file'] ?? [], $errors['uploaded_to'] ?? []); + return $this->jsonError(implode("\n", $messages)); } + $uploadedTo = intval($validated['uploaded_to']); + $targetPage = $this->pageQueries->findVisibleByIdOrFail($uploadedTo); + $this->checkOwnablePermission(Permission::PageUpdate, $targetPage); + new OutOfMemoryHandler(function () { return $this->jsonError(trans('errors.image_upload_memory_limit')); }); try { - $imageUpload = $request->file('file'); - $uploadedTo = $request->input('uploaded_to', 0); + $imageUpload = $validated['file']; $image = $this->imageRepo->saveNew($imageUpload, 'gallery', $uploadedTo); } catch (ImageUploadException $e) { return response($e->getMessage(), 500); diff --git a/app/Uploads/Controllers/ImageGalleryApiController.php b/app/Uploads/Controllers/ImageGalleryApiController.php index c4168a77e..6a72e4c30 100644 --- a/app/Uploads/Controllers/ImageGalleryApiController.php +++ b/app/Uploads/Controllers/ImageGalleryApiController.php @@ -75,6 +75,7 @@ class ImageGalleryApiController extends ApiController $this->checkPermission(Permission::ImageCreateAll); $data = $this->validate($request, $this->rules()['create']); $page = $this->pageQueries->findVisibleByIdOrFail($data['uploaded_to']); + $this->checkOwnablePermission(Permission::PageUpdate, $page); $image = $this->imageRepo->saveNew($data['image'], $data['type'], $page->id); diff --git a/tests/Activity/CommentMentionTest.php b/tests/Activity/CommentMentionTest.php index 7f26f8689..b9701b115 100644 --- a/tests/Activity/CommentMentionTest.php +++ b/tests/Activity/CommentMentionTest.php @@ -117,7 +117,7 @@ class CommentMentionTest extends TestCase $page = $this->entities->page(); $this->permissions->disableEntityInheritedPermissions($page); - $this->permissions->addEntityPermission($page, ['view'], $userA->roles()->first()); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $userA->roles()->first()); $this->asAdmin()->post("/comment/{$page->id}", [ 'html' => '

Hello and

' diff --git a/tests/Api/ContentPermissionsApiTest.php b/tests/Api/ContentPermissionsApiTest.php index 464d62683..6a26b4032 100644 --- a/tests/Api/ContentPermissionsApiTest.php +++ b/tests/Api/ContentPermissionsApiTest.php @@ -39,7 +39,7 @@ class ContentPermissionsApiTest extends TestCase $page = $this->entities->page(); $owner = $this->users->newUser(); $role = $this->users->createRole(); - $this->permissions->addEntityPermission($page, ['view', 'delete'], $role); + $this->permissions->setEntityPermissionsForRole($page, ['view', 'delete'], $role); $this->permissions->changeEntityOwner($page, $owner); $this->permissions->setFallbackPermissions($page, ['update', 'create']); @@ -209,7 +209,7 @@ class ContentPermissionsApiTest extends TestCase public function test_update_can_clear_roles_permissions() { $page = $this->entities->page(); - $this->permissions->addEntityPermission($page, ['view'], $this->users->createRole()); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $this->users->createRole()); $page->owned_by = null; $page->save(); diff --git a/tests/Api/ImageGalleryApiTest.php b/tests/Api/ImageGalleryApiTest.php index 07c20c834..09dba84f5 100644 --- a/tests/Api/ImageGalleryApiTest.php +++ b/tests/Api/ImageGalleryApiTest.php @@ -154,6 +154,34 @@ class ImageGalleryApiTest extends TestCase $resp->assertStatus(404); } + public function test_create_requires_update_permission_for_the_target_page() + { + $editor = $this->users->editor(); + $this->actingAsForApi($editor); + + $makeRequest = function (int $uploadedTo) { + return $this->call('POST', $this->baseEndpoint, [ + 'type' => 'gallery', + 'uploaded_to' => $uploadedTo, + 'name' => 'My awesome image!', + ], [], [ + 'image' => $this->files->uploadedImage('my-cool-image.png'), + ]); + }; + + $page = $this->entities->page(); + $this->permissions->disableEntityInheritedPermissions($page); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $editor->roles()->first()); + + $resp = $makeRequest($page->id); + $resp->assertStatus(403); + + $this->permissions->setEntityPermissionsForRole($page, ['view', 'update'], $editor->roles()->first()); + + $resp = $makeRequest($page->id); + $resp->assertStatus(200); + } + public function test_create_has_restricted_types() { $this->actingAsApiEditor(); diff --git a/tests/Commands/RegeneratePermissionsCommandTest.php b/tests/Commands/RegeneratePermissionsCommandTest.php index 75c6c1b38..27a339fbe 100644 --- a/tests/Commands/RegeneratePermissionsCommandTest.php +++ b/tests/Commands/RegeneratePermissionsCommandTest.php @@ -16,7 +16,7 @@ class RegeneratePermissionsCommandTest extends TestCase $page = $this->entities->page(); $editor = $this->users->editor(); $role = $editor->roles()->first(); - $this->permissions->addEntityPermission($page, ['view'], $role); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $role); JointPermission::query()->truncate(); $this->assertDatabaseMissing('joint_permissions', ['entity_id' => $page->id]); diff --git a/tests/ErrorTest.php b/tests/ErrorTest.php index 642945d43..27c83e212 100644 --- a/tests/ErrorTest.php +++ b/tests/ErrorTest.php @@ -2,7 +2,6 @@ namespace Tests; -use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use Illuminate\Support\Facades\Log; class ErrorTest extends TestCase @@ -44,7 +43,7 @@ class ErrorTest extends TestCase $this->actingAs($editor)->get($page->getUrl())->assertOk(); $this->permissions->disableEntityInheritedPermissions($book); - $this->permissions->addEntityPermission($page, ['view'], $editor->roles()->first()); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $editor->roles()->first()); $resp = $this->actingAs($editor)->get($book->getUrl()); $resp->assertNotFound(); diff --git a/tests/Helpers/PermissionsProvider.php b/tests/Helpers/PermissionsProvider.php index c9ae30919..9b12ee985 100644 --- a/tests/Helpers/PermissionsProvider.php +++ b/tests/Helpers/PermissionsProvider.php @@ -101,8 +101,9 @@ class PermissionsProvider $this->addEntityPermissionEntries($entity, $permissions); } - public function addEntityPermission(Entity $entity, array $actionList, Role $role) + 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]); } diff --git a/tests/Permissions/Scenarios/EntityRolePermissionsTest.php b/tests/Permissions/Scenarios/EntityRolePermissionsTest.php index 55761e08c..fa89d365c 100644 --- a/tests/Permissions/Scenarios/EntityRolePermissionsTest.php +++ b/tests/Permissions/Scenarios/EntityRolePermissionsTest.php @@ -29,8 +29,8 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->page(); $this->permissions->disableEntityInheritedPermissions($page); - $this->permissions->addEntityPermission($page, [], $roleA); - $this->permissions->addEntityPermission($page, ['view'], $roleB); + $this->permissions->setEntityPermissionsForRole($page, [], $roleA); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $roleB); $this->assertVisibleToUser($page, $user); } @@ -42,7 +42,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -54,7 +54,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -67,8 +67,8 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($chapter, [], $roleA); - $this->permissions->addEntityPermission($chapter, ['view'], $roleB); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleB); $this->assertVisibleToUser($page, $user); } @@ -80,8 +80,8 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($chapter, [], $roleA); - $this->permissions->addEntityPermission($page, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -93,8 +93,8 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($chapter, ['view'], $roleA); - $this->permissions->addEntityPermission($page, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($page, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -107,8 +107,8 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($page, [], $roleA); - $this->permissions->addEntityPermission($chapter, ['view'], $roleB); + $this->permissions->setEntityPermissionsForRole($page, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleB); $this->assertVisibleToUser($page, $user); } @@ -121,8 +121,8 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->disableEntityInheritedPermissions($chapter); - $this->permissions->addEntityPermission($page, ['view'], $roleA); - $this->permissions->addEntityPermission($chapter, [], $roleB); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleB); $this->assertVisibleToUser($page, $user); } @@ -131,7 +131,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase { [$user, $roleA] = $this->users->newUserWithRole(); $page = $this->entities->page(); - $this->permissions->addEntityPermission($page, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -140,7 +140,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase { [$user, $roleA] = $this->users->newUserWithRole([], ['page-view-all']); $page = $this->entities->page(); - $this->permissions->addEntityPermission($page, [], $roleA); + $this->permissions->setEntityPermissionsForRole($page, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -150,7 +150,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase [$user, $roleA] = $this->users->newUserWithRole([], []); $page = $this->entities->pageWithinChapter(); $chapter = $page->chapter; - $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -160,7 +160,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase [$user, $roleA] = $this->users->newUserWithRole([], ['page-view-all']); $page = $this->entities->pageWithinChapter(); $chapter = $page->chapter; - $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -170,7 +170,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase [$user, $roleA] = $this->users->newUserWithRole([], ['page-view-own']); $page = $this->entities->pageWithinChapter(); $chapter = $page->chapter; - $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); $this->permissions->changeEntityOwner($page, $user); $this->assertNotVisibleToUser($page, $user); @@ -182,7 +182,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $roleB = $this->users->attachNewRole($user); $page = $this->entities->page(); - $this->permissions->addEntityPermission($page, [], $roleB); + $this->permissions->setEntityPermissionsForRole($page, [], $roleB); $this->assertNotVisibleToUser($page, $user); } @@ -194,7 +194,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->page(); $this->permissions->changeEntityOwner($page, $user); - $this->permissions->addEntityPermission($page, [], $roleB); + $this->permissions->setEntityPermissionsForRole($page, [], $roleB); $this->assertNotVisibleToUser($page, $user); } @@ -207,7 +207,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->pageWithinChapter(); $chapter = $page->chapter; - $this->permissions->addEntityPermission($chapter, [], $roleB); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleB); $this->assertNotVisibleToUser($page, $user); } @@ -220,7 +220,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->changeEntityOwner($page, $user); - $this->permissions->addEntityPermission($chapter, [], $roleB); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleB); $this->assertNotVisibleToUser($page, $user); } @@ -231,7 +231,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->page(); $this->permissions->setFallbackPermissions($page, []); - $this->permissions->addEntityPermission($page, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -241,7 +241,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->page(); $this->permissions->setFallbackPermissions($page, ['view']); - $this->permissions->addEntityPermission($page, [], $roleA); + $this->permissions->setEntityPermissionsForRole($page, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -253,7 +253,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->page(); $this->permissions->setFallbackPermissions($page, []); - $this->permissions->addEntityPermission($page, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($page, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -265,7 +265,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $page = $this->entities->page(); $this->permissions->setFallbackPermissions($page, ['view']); - $this->permissions->addEntityPermission($page, [], $roleA); + $this->permissions->setEntityPermissionsForRole($page, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -277,7 +277,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->setFallbackPermissions($chapter, []); - $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -289,7 +289,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->setFallbackPermissions($chapter, ['view']); - $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -302,7 +302,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->setFallbackPermissions($chapter, []); - $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleA); $this->assertVisibleToUser($page, $user); } @@ -315,7 +315,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $chapter = $page->chapter; $this->permissions->setFallbackPermissions($chapter, ['view']); - $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, [], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -328,7 +328,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $this->permissions->setFallbackPermissions($chapter, []); $this->permissions->setFallbackPermissions($page, []); - $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($chapter, ['view'], $roleA); $this->assertNotVisibleToUser($page, $user); } @@ -342,7 +342,7 @@ class EntityRolePermissionsTest extends PermissionScenarioTestCase $this->permissions->setFallbackPermissions($book, []); $this->permissions->setFallbackPermissions($chapter, []); - $this->permissions->addEntityPermission($book, ['view'], $roleA); + $this->permissions->setEntityPermissionsForRole($book, ['view'], $roleA); $this->assertNotVisibleToUser($page, $user); } diff --git a/tests/PublicActionTest.php b/tests/PublicActionTest.php index e6fc7a6a3..5b0f5353a 100644 --- a/tests/PublicActionTest.php +++ b/tests/PublicActionTest.php @@ -6,7 +6,6 @@ use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Chapter; use BookStack\Permissions\Models\RolePermission; use BookStack\Users\Models\Role; -use BookStack\Users\Models\User; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\View; @@ -173,7 +172,7 @@ class PublicActionTest extends TestCase $newRole = $this->users->attachNewRole($this->users->guest(), []); $page = $this->entities->page(); $this->permissions->disableEntityInheritedPermissions($page); - $this->permissions->addEntityPermission($page, ['view', 'update'], $newRole); + $this->permissions->setEntityPermissionsForRole($page, ['view', 'update'], $newRole); $resp = $this->get($page->getUrl()); $resp->assertOk(); diff --git a/tests/Uploads/DrawioTest.php b/tests/Uploads/DrawioTest.php index d5b3f6088..faa2a0bfb 100644 --- a/tests/Uploads/DrawioTest.php +++ b/tests/Uploads/DrawioTest.php @@ -72,6 +72,30 @@ class DrawioTest extends TestCase $this->assertTrue($testImageData === $uploadedImageData, 'Uploaded image file data does not match our test image as expected'); } + public function test_base64_upload_requires_edit_permission_to_page() + { + $page = $this->entities->page(); + $editor = $this->users->editor(); + $this->actingAs($editor); + + $this->permissions->disableEntityInheritedPermissions($page); + + $upload = function () use ($page) { + return $this->postJson('images/drawio', [ + 'uploaded_to' => $page->id, + 'image' => 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=', + ]); + }; + + $upload()->assertStatus(404); + + $this->permissions->setEntityPermissionsForRole($page, ['view'], $editor->roles()->first()); + $upload()->assertStatus(403); + + $this->permissions->setEntityPermissionsForRole($page, ['view', 'update'], $editor->roles()->first()); + $upload()->assertStatus(200); + } + public function test_drawio_url_can_be_configured() { config()->set('services.drawio', 'http://cats.com?dog=tree'); diff --git a/tests/Uploads/ImageTest.php b/tests/Uploads/ImageTest.php index 1bccee2c3..ac7bf31e4 100644 --- a/tests/Uploads/ImageTest.php +++ b/tests/Uploads/ImageTest.php @@ -36,6 +36,45 @@ class ImageTest extends TestCase ]); } + public function test_image_upload_with_page_reference_requires_visibility_and_update_permissions_of_target_page() + { + $page = $this->entities->page(); + $editor = $this->users->editor(); + + $this->permissions->disableEntityInheritedPermissions($page); + $this->actingAs($editor); + + $resp = $this->files->uploadGalleryImage($this, 'test-image.png', $page->id); + $resp->assertStatus(404); + + $this->permissions->setEntityPermissionsForRole($page, ['view'], $editor->roles()->first()); + + $resp = $this->files->uploadGalleryImage($this, 'test-image.png', $page->id); + $this->assertPermissionError($resp); + + $this->permissions->setEntityPermissionsForRole($page, ['view', 'update'], $editor->roles()->first()); + + $resp = $this->files->uploadGalleryImage($this, 'test-image.png', $page->id); + $resp->assertStatus(200); + + $this->files->deleteAtRelativePath($resp->json('path')); + } + + public function test_image_upload_with_page_reference_requires_page_to_exist() + { + $page = $this->entities->page(); + $this->entities->destroy($page); + + $editor = $this->users->editor(); + $this->actingAs($editor); + + $resp = $this->files->uploadGalleryImage($this, 'test-image.png', $page->id); + $resp->assertStatus(404); + + $resp = $this->files->uploadGalleryImage($this, 'test-image.png', 0); + $resp->assertStatus(404); + } + public function test_image_display_thumbnail_generation_does_not_increase_image_size() { $page = $this->entities->page();