From c78a4ae0748c27e3041e996d1637e3e0fc8ccaee Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 28 Oct 2025 14:07:19 -0400 Subject: [PATCH 1/2] fix(preview/bundled): copy content not resource id and improve error handling Signed-off-by: Josh --- lib/private/Preview/Bundled.php | 69 ++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/lib/private/Preview/Bundled.php b/lib/private/Preview/Bundled.php index 6100e8262a4ba..cf241d22075c6 100644 --- a/lib/private/Preview/Bundled.php +++ b/lib/private/Preview/Bundled.php @@ -8,28 +8,73 @@ use OC\Archive\ZIP; use OCP\Files\File; +use OCP\IConfig; use OCP\IImage; +use OCP\ITempManager; +use OCP\Server; +use Psr\Log\LoggerInterface; /** * Extracts a preview from files that embed them in an ZIP archive */ abstract class Bundled extends ProviderV2 { protected function extractThumbnail(File $file, string $path): ?IImage { - if ($file->getSize() === 0) { + $previewMaxFilesize = Server::get(IConfig::class)->getSystemValueInt('preview_max_filesize_image', 50); + $size = $file->getSize(); + if ($size === 0) { + return null; + } + if ($previewMaxFilesize !== -1 && $size > ($previewMaxFilesize * 1024 * 1024)) { return null; } - $sourceTmp = \OC::$server->getTempManager()->getTemporaryFile(); - $targetTmp = \OC::$server->getTempManager()->getTemporaryFile(); + $sourceTmp = Server::get(ITempManager::class)->getTemporaryFile(); + $targetTmp = Server::get(ITempManager::class)->getTemporaryFile(); $this->tmpFiles[] = $sourceTmp; $this->tmpFiles[] = $targetTmp; try { - $content = $file->fopen('r'); - file_put_contents($sourceTmp, $content); + $src = $file->fopen('r'); + if ($src === false) { + Server::get(LoggerInterface::class)->debug( + 'Unable to extract thumbnail - fopen source failed', + ['path' => $path] + ); + return null; + } + + $dst = fopen($sourceTmp, 'wb'); + if ($dst === false) { + Server::get(LoggerInterface::class)->debug( + 'Unable to extract thumbnail - fopen destination failed', + ['path' => $path] + ); + return null; + } + + $bytes = stream_copy_to_stream($src, $dst); + if ($bytes === false || $bytes === 0) { + Server::get(LoggerInterface::class)->debug( + 'Unable to extract thumbnail - copy returned 0 bytes', + ['path' => $path] + ); + return null; + } + + fclose($dst); + $dst = null; + fclose($src); + $src = null; $zip = new ZIP($sourceTmp); - $zip->extractFile($path, $targetTmp); + $result = $zip->extractFile($path, $targetTmp); + if ($result === false || !file_exists($targetTmp) || filesize($targetTmp) === 0) { + Server::get(LoggerInterface::class)->debug( + 'Unable to extract thumbnail - extractFile failed or target missing/empty', + ['path' => $path] + ); + return null; + } $image = new \OCP\Image(); $image->loadFromFile($targetTmp); @@ -37,7 +82,19 @@ protected function extractThumbnail(File $file, string $path): ?IImage { return $image; } catch (\Throwable $e) { + Server::get(LoggerInterface::class)->debug( + 'Unable to extract thumbnail - exception while extracting', + ['message' => $e->getMessage(), 'path' => $path] + ); return null; + } finally { + if (isset($dst) && is_resource($dst)) { + fclose($dst); + } + if (isset($src) && is_resource($src)) { + fclose($src); + } + $this->cleanTmpFiles(); } } } From d73a1cc7471d1cfbec73857e33b56d1f0b494c06 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 28 Oct 2025 14:25:08 -0400 Subject: [PATCH 2/2] fix: lint and psalm Signed-off-by: Josh --- lib/private/Preview/Bundled.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/private/Preview/Bundled.php b/lib/private/Preview/Bundled.php index cf241d22075c6..277962d49f24d 100644 --- a/lib/private/Preview/Bundled.php +++ b/lib/private/Preview/Bundled.php @@ -34,6 +34,7 @@ protected function extractThumbnail(File $file, string $path): ?IImage { $this->tmpFiles[] = $targetTmp; try { + /** @var resource|false|null */ $src = $file->fopen('r'); if ($src === false) { Server::get(LoggerInterface::class)->debug( @@ -42,7 +43,8 @@ protected function extractThumbnail(File $file, string $path): ?IImage { ); return null; } - + + /** @var resource|false|null */ $dst = fopen($sourceTmp, 'wb'); if ($dst === false) { Server::get(LoggerInterface::class)->debug( @@ -51,7 +53,7 @@ protected function extractThumbnail(File $file, string $path): ?IImage { ); return null; } - + $bytes = stream_copy_to_stream($src, $dst); if ($bytes === false || $bytes === 0) { Server::get(LoggerInterface::class)->debug( @@ -82,10 +84,10 @@ protected function extractThumbnail(File $file, string $path): ?IImage { return $image; } catch (\Throwable $e) { - Server::get(LoggerInterface::class)->debug( - 'Unable to extract thumbnail - exception while extracting', - ['message' => $e->getMessage(), 'path' => $path] - ); + Server::get(LoggerInterface::class)->debug( + 'Unable to extract thumbnail - exception while extracting', + ['message' => $e->getMessage(), 'path' => $path] + ); return null; } finally { if (isset($dst) && is_resource($dst)) {