mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-10-12 10:09:58 +00:00
Images: Added content checking and app range support to streaming
Mainly to prevent non-image files being streamed in scenarios where the underlying image data is somehow a non-image. Thanks to Emanuele Cervelli (https://github.com/M4nu02) for reporting.
This commit is contained in:
@@ -4,6 +4,8 @@ namespace BookStack\Uploads;
|
||||
|
||||
use BookStack\Entities\Queries\EntityQueries;
|
||||
use BookStack\Exceptions\ImageUploadException;
|
||||
use BookStack\Exceptions\PrettyException;
|
||||
use BookStack\Http\DownloadResponseFactory;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -368,7 +370,18 @@ class ImageService
|
||||
{
|
||||
$disk = $this->storage->getDisk($imageType);
|
||||
|
||||
return $disk->response($path);
|
||||
$stream = $disk->stream($path);
|
||||
$fileSize = $disk->size($path);
|
||||
$imageName = basename($path);
|
||||
$downloadResponseFactory = new DownloadResponseFactory(request());
|
||||
$response = $downloadResponseFactory->streamedInline($stream, $imageName, $fileSize);
|
||||
|
||||
$contentType = $response->headers->get('Content-Type');
|
||||
if (!str_starts_with($contentType, 'image/')) {
|
||||
throw new PrettyException('Invalid non-image file type when streaming from storage', 415);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -68,6 +68,14 @@ class ImageStorageDisk
|
||||
return $this->filesystem->readStream($this->adjustPathForDisk($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the file at the given path.
|
||||
*/
|
||||
public function size(string $path): int
|
||||
{
|
||||
return $this->filesystem->size($this->adjustPathForDisk($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the given image data at the given path. Can choose to set
|
||||
* the image as public which will update its visibility after saving.
|
||||
|
||||
@@ -333,6 +333,22 @@ class ImageGalleryApiTest extends TestCase
|
||||
$resp->assertStatus(404);
|
||||
}
|
||||
|
||||
public function test_read_data_endpoint_does_not_serve_non_image_files()
|
||||
{
|
||||
$this->actingAsApiAdmin();
|
||||
$imagePage = $this->entities->page();
|
||||
$data = $this->files->uploadGalleryImageToPage($this, $imagePage, 'test-image.png');
|
||||
|
||||
$image = Image::findOrFail($data['response']->id);
|
||||
$storagePath = public_path($image->path);
|
||||
file_put_contents($storagePath, '<html><body><p>This is totally not an image file!</p></body></html>');
|
||||
|
||||
$resp = $this->get("{$this->baseEndpoint}/{$image->id}/data");
|
||||
$resp->assertStatus(415);
|
||||
|
||||
$resp->assertJson($this->errorResponse('Invalid non-image file type when streaming from storage.', 415));
|
||||
}
|
||||
|
||||
public function test_read_url_data_endpoint()
|
||||
{
|
||||
$this->actingAsApiAdmin();
|
||||
|
||||
Reference in New Issue
Block a user