1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2026-10-23 06:49:01 +03:00
Files
bookstack/tests/Uploads/DrawioTest.php
Dan Brown fbe83a1895 Drawings: Validated drawing upload content as image data
Specifically check the mime type of Base64 drawing data to ensure
that it reads as image data rather than anything else which could be
potentially dangerous.

Thanks to Emanuele Cervelli (https://github.com/M4nu02) for reporting.
2026-08-19 16:53:47 +01:00

140 lines
5.3 KiB
PHP

<?php
namespace Tests\Uploads;
use BookStack\Uploads\Image;
use Tests\TestCase;
class DrawioTest extends TestCase
{
public function test_get_image_as_base64()
{
$page = $this->entities->page();
$this->asAdmin();
$imageName = 'first-image.png';
$this->files->uploadGalleryImage($this, $imageName, $page->id);
/** @var Image $image */
$image = Image::query()->first();
$image->type = 'drawio';
$image->save();
$imageGet = $this->getJson("/images/drawio/base64/{$image->id}");
$imageGet->assertJson([
'content' => 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=',
]);
}
public function test_non_accessible_image_returns_404_error_and_message()
{
$page = $this->entities->page();
$this->asEditor();
$imageName = 'non-accessible-image.png';
$this->files->uploadGalleryImage($this, $imageName, $page->id);
/** @var Image $image */
$image = Image::query()->first();
$image->type = 'drawio';
$image->save();
$this->permissions->disableEntityInheritedPermissions($page);
$imageGet = $this->getJson("/images/drawio/base64/{$image->id}");
$imageGet->assertNotFound();
$imageGet->assertJson([
'message' => 'Drawing data could not be loaded. The drawing file might no longer exist or you may not have permission to access it.',
]);
}
public function test_drawing_base64_upload()
{
$page = $this->entities->page();
$editor = $this->users->editor();
$this->actingAs($editor);
$upload = $this->postJson('images/drawio', [
'uploaded_to' => $page->id,
'image' => 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=',
]);
$upload->assertStatus(200);
$upload->assertJson([
'type' => 'drawio',
'uploaded_to' => $page->id,
'created_by' => $editor->id,
'updated_by' => $editor->id,
]);
$image = Image::where('type', '=', 'drawio')->first();
$this->assertTrue(file_exists(public_path($image->path)), 'Uploaded image not found at path: ' . public_path($image->path));
$testImageData = $this->files->pngImageData();
$uploadedImageData = file_get_contents(public_path($image->path));
$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_drawing_base64_upload_validates_data_as_image()
{
$page = $this->entities->page();
$editor = $this->users->editor();
$this->actingAs($editor);
$upload = $this->postJson('images/drawio', [
'uploaded_to' => $page->id,
'image' => 'image/png;base64,' . base64_encode('i like turtles'),
]);
$upload->assertStatus(422);
$upload->assertJsonValidationErrors([
'image' => 'The image must be a valid base64 URI containing data of image/png mime type.',
]);
}
public function test_drawio_url_can_be_configured()
{
config()->set('services.drawio', 'http://cats.com?dog=tree');
$page = $this->entities->page();
$editor = $this->users->editor();
$resp = $this->actingAs($editor)->get($page->getUrl('/edit'));
$resp->assertSee('drawio-url="http://cats.com?dog=tree"', false);
}
public function test_drawio_url_can_be_disabled()
{
config()->set('services.drawio', true);
$page = $this->entities->page();
$editor = $this->users->editor();
$resp = $this->actingAs($editor)->get($page->getUrl('/edit'));
$resp->assertSee('drawio-url="https://embed.diagrams.net/?embed=1&amp;proto=json&amp;spin=1&amp;configure=1"', false);
config()->set('services.drawio', false);
$resp = $this->actingAs($editor)->get($page->getUrl('/edit'));
$resp->assertDontSee('drawio-url', false);
}
}