]> BookStack Code Mirror - bookstack/blobdiff - tests/Uploads/ImageTest.php
Fixed local_secure_restricted preventing attachment uploads
[bookstack] / tests / Uploads / ImageTest.php
index 296e4d1878ae85680e8553e5f0152ea214273dea..2a3023a9eafe470418d3354aaed614d506002afd 100644 (file)
@@ -61,6 +61,19 @@ class ImageTest extends TestCase
         $this->assertEquals($originalFileSize, $displayFileSize, 'Display thumbnail generation should not increase image size');
     }
 
+    public function test_image_display_thumbnail_generation_for_apng_images_uses_original_file()
+    {
+        $page = Page::query()->first();
+        $admin = $this->getAdmin();
+        $this->actingAs($admin);
+
+        $imgDetails = $this->uploadGalleryImage($page, 'animated.png');
+        $this->deleteImage($imgDetails['path']);
+
+        $this->assertStringContainsString('thumbs-', $imgDetails['response']->thumbs->gallery);
+        $this->assertStringNotContainsString('thumbs-', $imgDetails['response']->thumbs->display);
+    }
+
     public function test_image_edit()
     {
         $editor = $this->getEditor();
@@ -91,11 +104,13 @@ class ImageTest extends TestCase
 
         $pageId = $imgDetails['page']->id;
         $firstPageRequest = $this->get("/images/gallery?page=1&uploaded_to={$pageId}");
-        $firstPageRequest->assertSuccessful()->assertElementExists('div');
+        $firstPageRequest->assertSuccessful();
+        $this->withHtml($firstPageRequest)->assertElementExists('div');
         $firstPageRequest->assertSuccessful()->assertSeeText($image->name);
 
         $secondPageRequest = $this->get("/images/gallery?page=2&uploaded_to={$pageId}");
-        $secondPageRequest->assertSuccessful()->assertElementNotExists('div');
+        $secondPageRequest->assertSuccessful();
+        $this->withHtml($secondPageRequest)->assertElementNotExists('div');
 
         $namePartial = substr($imgDetails['name'], 0, 3);
         $searchHitRequest = $this->get("/images/gallery?page=1&uploaded_to={$pageId}&search={$namePartial}");
@@ -104,7 +119,8 @@ class ImageTest extends TestCase
         $namePartial = Str::random(16);
         $searchFailRequest = $this->get("/images/gallery?page=1&uploaded_to={$pageId}&search={$namePartial}");
         $searchFailRequest->assertSuccessful()->assertDontSee($imgDetails['name']);
-        $searchFailRequest->assertSuccessful()->assertElementNotExists('div');
+        $searchFailRequest->assertSuccessful();
+        $this->withHtml($searchFailRequest)->assertElementNotExists('div');
     }
 
     public function test_image_usage()
@@ -301,8 +317,8 @@ class ImageTest extends TestCase
         $galleryFile = $this->getTestImage('my-system-test-upload.png');
         $expectedPath = public_path('uploads/images/system/' . date('Y-m') . '/my-system-test-upload.png');
 
-        $upload = $this->call('POST', '/settings', [], [], ['app_logo' => $galleryFile], []);
-        $upload->assertRedirect('/settings');
+        $upload = $this->call('POST', '/settings/customization', [], [], ['app_logo' => $galleryFile], []);
+        $upload->assertRedirect('/settings/customization');
 
         $this->assertTrue(file_exists($expectedPath), 'Uploaded image not found at path: ' . $expectedPath);
 
@@ -311,6 +327,89 @@ class ImageTest extends TestCase
         }
     }
 
+    public function test_secure_restricted_images_inaccessible_without_relation_permission()
+    {
+        config()->set('filesystems.images', 'local_secure_restricted');
+        $this->asEditor();
+        $galleryFile = $this->getTestImage('my-secure-restricted-test-upload.png');
+        /** @var Page $page */
+        $page = Page::query()->first();
+
+        $upload = $this->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $galleryFile], []);
+        $upload->assertStatus(200);
+        $expectedUrl = url('uploads/images/gallery/' . date('Y-m') . '/my-secure-restricted-test-upload.png');
+        $expectedPath = storage_path('uploads/images/gallery/' . date('Y-m') . '/my-secure-restricted-test-upload.png');
+
+        $this->get($expectedUrl)->assertOk();
+
+        $this->setEntityRestrictions($page, [], []);
+
+        $resp = $this->get($expectedUrl);
+        $resp->assertNotFound();
+
+        if (file_exists($expectedPath)) {
+            unlink($expectedPath);
+        }
+    }
+
+    public function test_thumbnail_path_handled_by_secure_restricted_images()
+    {
+        config()->set('filesystems.images', 'local_secure_restricted');
+        $this->asEditor();
+        $galleryFile = $this->getTestImage('my-secure-restricted-thumb-test-test.png');
+        /** @var Page $page */
+        $page = Page::query()->first();
+
+        $upload = $this->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $galleryFile], []);
+        $upload->assertStatus(200);
+        $expectedUrl = url('uploads/images/gallery/' . date('Y-m') . '/thumbs-150-150/my-secure-restricted-thumb-test-test.png');
+        $expectedPath = storage_path('uploads/images/gallery/' . date('Y-m') . '/my-secure-restricted-thumb-test-test.png');
+
+        $this->get($expectedUrl)->assertOk();
+
+        $this->setEntityRestrictions($page, [], []);
+
+        $resp = $this->get($expectedUrl);
+        $resp->assertNotFound();
+
+        if (file_exists($expectedPath)) {
+            unlink($expectedPath);
+        }
+    }
+
+    public function test_secure_restricted_image_access_controlled_in_exports()
+    {
+        config()->set('filesystems.images', 'local_secure_restricted');
+        $this->asEditor();
+        $galleryFile = $this->getTestImage('my-secure-restricted-export-test.png');
+
+        /** @var Page $pageA */
+        /** @var Page $pageB */
+        $pageA = Page::query()->first();
+        $pageB = Page::query()->where('id', '!=', $pageA->id)->first();
+        $expectedPath = storage_path('uploads/images/gallery/' . date('Y-m') . '/my-secure-restricted-export-test.png');
+
+        $upload = $this->asEditor()->call('POST', '/images/gallery', ['uploaded_to' => $pageA->id], [], ['file' => $galleryFile], []);
+        $upload->assertOk();
+
+        $imageUrl = json_decode($upload->getContent(), true)['url'];
+        $pageB->html .= "<img src=\"{$imageUrl}\">";
+        $pageB->save();
+
+        $encodedImageContent = base64_encode(file_get_contents($expectedPath));
+        $export = $this->get($pageB->getUrl('/export/html'));
+        $this->assertStringContainsString($encodedImageContent, $export->getContent());
+
+        $this->setEntityRestrictions($pageA, [], []);
+
+        $export = $this->get($pageB->getUrl('/export/html'));
+        $this->assertStringNotContainsString($encodedImageContent, $export->getContent());
+
+        if (file_exists($expectedPath)) {
+            unlink($expectedPath);
+        }
+    }
+
     public function test_image_delete()
     {
         $page = Page::query()->first();