Skip to content

Commit

Permalink
fix(preview): check mime type before processing with Imagick
Browse files Browse the repository at this point in the history
Signed-off-by: Varun Patil <varunpatil@ucla.edu>
  • Loading branch information
pulsejet committed Apr 8, 2024
1 parent 1fb5486 commit 5d4d84b
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 13 deletions.
23 changes: 23 additions & 0 deletions lib/private/Preview/Bitmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@
* @package OC\Preview
*/
abstract class Bitmap extends ProviderV2 {
/**
* List of MIME types that this preview provider is allowed to process.
*
* These should correspond to the MIME types *identified* by Imagemagick
* for files to be processed by this provider. These do / will not
* necessarily need to match the MIME types stored in the database
* (which are identified by IMimeTypeDetector).
*
* @return string Regular expression
*/
protected function getAllowedMimeTypes(): string {
return '/invalid\/invalid/';
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -86,10 +100,19 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
* @param int $maxY
*
* @return \Imagick
*
* @throws \Exception
*/
private function getResizedPreview($tmpPath, $maxX, $maxY) {
$bp = new Imagick();

// Validate mime type
$bp->pingImage($tmpPath . '[0]');
$mimeType = $bp->getImageMimeType();
if (!preg_match($this->getAllowedMimeTypes(), $mimeType)) {
throw new \Exception('File mime type does not match the preview provider: ' . $mimeType);
}

// Layer 0 contains either the bitmap or a flat representation of all vector layers
$bp->readImage($tmpPath . '[0]');

Expand Down
7 changes: 7 additions & 0 deletions lib/private/Preview/Font.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,11 @@ class Font extends Bitmap {
public function getMimeType(): string {
return '/application\/(?:font-sfnt|x-font$)/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/(application|image)\/(?:font-sfnt|x-font|x-otf|x-ttf|x-pfb$)/';
}
}
12 changes: 11 additions & 1 deletion lib/private/Preview/HEIC.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class HEIC extends ProviderV2 {
* {@inheritDoc}
*/
public function getMimeType(): string {
return '/image\/hei(f|c)/';
return '/image\/(x-)?hei(f|c)/';
}

/**
Expand Down Expand Up @@ -108,10 +108,20 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
* @param int $maxY
*
* @return \Imagick
*
* @throws \Exception
*/
private function getResizedPreview($tmpPath, $maxX, $maxY) {
$bp = new \Imagick();

// Some HEIC files just contain (or at least are identified as) other formats
// like JPEG. We just need to check if the image is safe to process.
$bp->pingImage($tmpPath . '[0]');
$mimeType = $bp->getImageMimeType();
if (!preg_match('/^image\/(x-)?(png|jpeg|gif|bmp|tiff|webp|hei(f|c)|avif)$/', $mimeType)) {
throw new \Exception('File mime type does not match the preview provider: ' . $mimeType);
}

// Layer 0 contains either the bitmap or a flat representation of all vector layers
$bp->readImage($tmpPath . '[0]');

Expand Down
7 changes: 7 additions & 0 deletions lib/private/Preview/Illustrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ class Illustrator extends Bitmap {
public function getMimeType(): string {
return '/application\/illustrator/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/application\/(illustrator|pdf)/';
}
}
7 changes: 7 additions & 0 deletions lib/private/Preview/PDF.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ class PDF extends Bitmap {
public function getMimeType(): string {
return '/application\/pdf/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/application\/pdf/';
}
}
7 changes: 7 additions & 0 deletions lib/private/Preview/Photoshop.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ class Photoshop extends Bitmap {
public function getMimeType(): string {
return '/application\/x-photoshop/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/(application|image)\/(x-photoshop|x-psd)/';
}
}
7 changes: 7 additions & 0 deletions lib/private/Preview/Postscript.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ class Postscript extends Bitmap {
public function getMimeType(): string {
return '/application\/postscript/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/application\/postscript/';
}
}
9 changes: 8 additions & 1 deletion lib/private/Preview/SGI.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class SGI extends Bitmap {
* {@inheritDoc}
*/
public function getMimeType(): string {
return '/image\/sgi/';
return '/image\/(x-)?sgi/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/image\/(x-)?sgi/';
}
}
23 changes: 16 additions & 7 deletions lib/private/Preview/SVG.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ public function getMimeType(): string {
*/
public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
try {
$svg = new \Imagick();
$svg->setBackgroundColor(new \ImagickPixel('transparent'));

$content = stream_get_contents($file->fopen('r'));
if (substr($content, 0, 5) !== '<?xml') {
$content = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $content;
Expand All @@ -57,13 +54,25 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
return null;
}

$svg = new \Imagick();

$svg->pingImageBlob($content);
$mimeType = $svg->getImageMimeType();
if (!preg_match($this->getMimeType(), $mimeType)) {
throw new \Exception('File mime type does not match the preview provider: ' . $mimeType);
}

$svg->setBackgroundColor(new \ImagickPixel('transparent'));
$svg->readImageBlob($content);
$svg->setImageFormat('png32');
} catch (\Exception $e) {
\OC::$server->get(LoggerInterface::class)->error($e->getMessage(), [
'exception' => $e,
'app' => 'core',
]);
\OC::$server->get(LoggerInterface::class)->error(
'File: ' . $file->getPath() . ' Imagick says:',
[
'exception' => $e,
'app' => 'core',
]
);
return null;
}

Expand Down
9 changes: 8 additions & 1 deletion lib/private/Preview/TGA.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class TGA extends Bitmap {
* {@inheritDoc}
*/
public function getMimeType(): string {
return '/image\/t(ar)?ga/';
return '/image\/(x-)?t(ar)?ga/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/image\/(x-)?t(ar)?ga/';
}
}
7 changes: 7 additions & 0 deletions lib/private/Preview/TIFF.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ class TIFF extends Bitmap {
public function getMimeType(): string {
return '/image\/tiff/';
}

/**
* {@inheritDoc}
*/
protected function getAllowedMimeTypes(): string {
return '/image\/tiff/';
}
}
6 changes: 3 additions & 3 deletions lib/private/PreviewManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,9 @@ protected function registerCoreProviders() {
'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
'HEIC' => ['mimetype' => '/image\/hei(f|c)/', 'class' => Preview\HEIC::class],
'TGA' => ['mimetype' => '/image\/t(ar)?ga/', 'class' => Preview\TGA::class],
'SGI' => ['mimetype' => '/image\/sgi/', 'class' => Preview\SGI::class],
'HEIC' => ['mimetype' => '/image\/(x-)?hei(f|c)/', 'class' => Preview\HEIC::class],
'TGA' => ['mimetype' => '/image\/(x-)?t(ar)?ga/', 'class' => Preview\TGA::class],
'SGI' => ['mimetype' => '/image\/(x-)?sgi/', 'class' => Preview\SGI::class],
];

foreach ($imagickProviders as $queryFormat => $provider) {
Expand Down

0 comments on commit 5d4d84b

Please sign in to comment.