mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-30 04:23:11 +03:00
ZIP Imports: Added image type validation/handling
Images were missing their extension after import since it was (potentially) not part of the import data. This adds validation via mime sniffing (to match normal image upload checks) and also uses the same logic to sniff out a correct extension. Added tests to cover. Also fixed some existing tests around zip functionality.
This commit is contained in:
@ -32,10 +32,11 @@ class ZipExportImage extends ZipExportModel
|
||||
|
||||
public static function validate(ZipValidationHelper $context, array $data): array
|
||||
{
|
||||
$acceptedImageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
|
||||
$rules = [
|
||||
'id' => ['nullable', 'int', $context->uniqueIdRule('image')],
|
||||
'name' => ['required', 'string', 'min:1'],
|
||||
'file' => ['required', 'string', $context->fileReferenceRule()],
|
||||
'file' => ['required', 'string', $context->fileReferenceRule($acceptedImageTypes)],
|
||||
'type' => ['required', 'string', Rule::in(['gallery', 'drawio'])],
|
||||
];
|
||||
|
||||
|
@ -7,6 +7,7 @@ use BookStack\Exports\ZipExports\Models\ZipExportBook;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportChapter;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportModel;
|
||||
use BookStack\Exports\ZipExports\Models\ZipExportPage;
|
||||
use BookStack\Util\WebSafeMimeSniffer;
|
||||
use ZipArchive;
|
||||
|
||||
class ZipExportReader
|
||||
@ -81,6 +82,17 @@ class ZipExportReader
|
||||
return $this->zip->getStream("files/{$fileName}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sniff the mime type from the file of given name.
|
||||
*/
|
||||
public function sniffFileMime(string $fileName): string
|
||||
{
|
||||
$stream = $this->streamFile($fileName);
|
||||
$sniffContent = fread($stream, 2000);
|
||||
|
||||
return (new WebSafeMimeSniffer())->sniff($sniffContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ZipExportException
|
||||
*/
|
||||
|
@ -9,6 +9,7 @@ class ZipFileReferenceRule implements ValidationRule
|
||||
{
|
||||
public function __construct(
|
||||
protected ZipValidationHelper $context,
|
||||
protected array $acceptedMimes,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -21,5 +22,16 @@ class ZipFileReferenceRule implements ValidationRule
|
||||
if (!$this->context->zipReader->fileExists($value)) {
|
||||
$fail('validation.zip_file')->translate();
|
||||
}
|
||||
|
||||
if (!empty($this->acceptedMimes)) {
|
||||
$fileMime = $this->context->zipReader->sniffFileMime($value);
|
||||
if (!in_array($fileMime, $this->acceptedMimes)) {
|
||||
$fail('validation.zip_file_mime')->translate([
|
||||
'attribute' => $attribute,
|
||||
'validTypes' => implode(',', $this->acceptedMimes),
|
||||
'foundType' => $fileMime
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +228,9 @@ class ZipImportRunner
|
||||
|
||||
protected function importImage(ZipExportImage $exportImage, Page $page, ZipExportReader $reader): Image
|
||||
{
|
||||
$mime = $reader->sniffFileMime($exportImage->file);
|
||||
$extension = explode('/', $mime)[1];
|
||||
|
||||
$file = $this->zipFileToUploadedFile($exportImage->file, $reader);
|
||||
$image = $this->imageService->saveNewFromUpload(
|
||||
$file,
|
||||
@ -236,9 +239,12 @@ class ZipImportRunner
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
$exportImage->name,
|
||||
$exportImage->name . '.' . $extension,
|
||||
);
|
||||
|
||||
$image->name = $exportImage->name;
|
||||
$image->save();
|
||||
|
||||
$this->references->addImage($image, $exportImage->id);
|
||||
|
||||
return $image;
|
||||
|
@ -33,9 +33,9 @@ class ZipValidationHelper
|
||||
return $messages;
|
||||
}
|
||||
|
||||
public function fileReferenceRule(): ZipFileReferenceRule
|
||||
public function fileReferenceRule(array $acceptedMimes = []): ZipFileReferenceRule
|
||||
{
|
||||
return new ZipFileReferenceRule($this);
|
||||
return new ZipFileReferenceRule($this, $acceptedMimes);
|
||||
}
|
||||
|
||||
public function uniqueIdRule(string $type): ZipUniqueIdRule
|
||||
@ -43,7 +43,7 @@ class ZipValidationHelper
|
||||
return new ZipUniqueIdRule($this, $type);
|
||||
}
|
||||
|
||||
public function hasIdBeenUsed(string $type, int $id): bool
|
||||
public function hasIdBeenUsed(string $type, mixed $id): bool
|
||||
{
|
||||
$key = $type . ':' . $id;
|
||||
if (isset($this->validatedIds[$key])) {
|
||||
|
Reference in New Issue
Block a user