From 181f4ba49a619fbda6405339522d5c741901a42a Mon Sep 17 00:00:00 2001 From: Zankaria Date: Mon, 21 Apr 2025 14:53:09 +0200 Subject: [PATCH 1/6] config.php: add generic invalidfile error --- inc/config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/config.php b/inc/config.php index 71b0fbf4..5fc38c8d 100644 --- a/inc/config.php +++ b/inc/config.php @@ -1298,6 +1298,7 @@ $config['error']['pendingappeal'] = _('There is already a pending appeal for this ban.'); $config['error']['invalidpassword'] = _('Wrong password…'); $config['error']['invalidimg'] = _('Invalid image.'); + $config['error']['invalidfile'] = _('Invalid file.'); $config['error']['unknownext'] = _('Unknown file extension.'); $config['error']['filesize'] = _('Maximum file size: %maxsz% bytes
Your file\'s size: %filesz% bytes'); $config['error']['maxsize'] = _('The file was too big.'); From ff94e58f2e7c14868848143f6ee42ecf4f92f90a Mon Sep 17 00:00:00 2001 From: Zankaria Date: Mon, 21 Apr 2025 15:19:34 +0200 Subject: [PATCH 2/6] config.php: update pdf_file_thumbnail documentation --- inc/config.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/inc/config.php b/inc/config.php index 5fc38c8d..9a9de46c 100644 --- a/inc/config.php +++ b/inc/config.php @@ -2069,7 +2069,9 @@ // Enable auto IP note generation of moderator deleted posts $config['autotagging'] = false; - // Enable PDF file thumbnail generation + // Enable PDF thumbnail generation. + // Requires a working installation of ghostscript and imagemagick. + // Imagemagick support of PDF files is not required. $config['pdf_file_thumbnail'] = false; // Enable TXT file thumbnail From 28f75c8aed7d12bb783ffb06e6430420fa6f3b64 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Mon, 21 Apr 2025 15:21:13 +0200 Subject: [PATCH 3/6] config.php: add missing djvu_file_thumbnail option --- inc/config.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/inc/config.php b/inc/config.php index 9a9de46c..55580cec 100644 --- a/inc/config.php +++ b/inc/config.php @@ -2074,6 +2074,11 @@ // Imagemagick support of PDF files is not required. $config['pdf_file_thumbnail'] = false; + // Enable djvu thumbnail generation. + // Requires djvulibre's tools and imagemagick. + // Imagemagick support of djvu files is not required. + $config['djvu_file_thumbnail'] = false; + // Enable TXT file thumbnail $config['txt_file_thumbnail'] = false; From 8282d5cd6361914660f83334ea166d13d76c27ee Mon Sep 17 00:00:00 2001 From: Zankaria Date: Mon, 21 Apr 2025 15:11:32 +0200 Subject: [PATCH 4/6] post.php: implement safe PDF thumbnailing --- post.php | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/post.php b/post.php index 5483600d..e4560bb8 100644 --- a/post.php +++ b/post.php @@ -1447,10 +1447,36 @@ function handle_post(Context $ctx) } $image->destroy(); } else { - if ( - ($file['extension'] == "pdf" && $config['pdf_file_thumbnail']) || - ($file['extension'] == "djvu" && $config['djvu_file_thumbnail']) - ) { + $mime = \mime_content_type($file['tmp_name']); + if ($file['extension'] === "pdf" && $config['pdf_file_thumbnail']) { + if ($mime !== 'application/pdf' && $mime !== 'application/x-pdf') { + error($config['error']['invalidfile']); + } + + $e_thumb_path = \escapeshellarg($file['thumb']); + $e_file_path = \escapeshellarg($file['tmp_name']); + $thumb_width = $config['thumb_width']; + $thumb_height = $config['thumb_height']; + + // Generates a PPM image and pipes it directly into convert for resizing + type conversion. + $error = shell_exec_error("gs -dSAFER -dBATCH -dNOPAUSE -dQUIET + -sDEVICE=ppmraw -r100 -dFirstPage=1 -dLastPage=1 -sOutputFile=- $e_file_path + | convert -thumbnail {$thumb_width}x{$thumb_height} ppm:- $e_thumb_path"); + + if ($error) { + $log = $ctx->get(LogDriver::class); + $log->log(LogDriver::ERROR, 'Could not render thumbnail for PDF file, using static fallback.'); + $path = sprintf($config['file_thumb'], isset($config['file_icons'][$file['extension']]) ? $config['file_icons'][$file['extension']] : $config['file_icons']['default']); + } + + $file['thumb'] = basename($file['thumb']); + $size = @getimagesize($path); + $file['thumbwidth'] = $size[0]; + $file['thumbheight'] = $size[1]; + $file['width'] = $size[0]; + $file['height'] = $size[1]; + } + if ($file['extension'] == "djvu" && $config['djvu_file_thumbnail']) { $path = $file['thumb']; $error = shell_exec_error('convert -size ' . $config['thumb_width'] . 'x' . $config['thumb_height'] . ' -thumbnail ' . $config['thumb_width'] . 'x' . $config['thumb_height'] . ' -background white -alpha remove ' . escapeshellarg($file['tmp_name'] . '[0]') . ' ' . From 8cb6a76f0a92740312ccbfeff61fa5d823f7ad0f Mon Sep 17 00:00:00 2001 From: Zankaria Date: Mon, 21 Apr 2025 15:58:11 +0200 Subject: [PATCH 5/6] post.php: add safe djvu thumbnail generation --- post.php | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/post.php b/post.php index e4560bb8..e6afe5b6 100644 --- a/post.php +++ b/post.php @@ -1448,42 +1448,34 @@ function handle_post(Context $ctx) $image->destroy(); } else { $mime = \mime_content_type($file['tmp_name']); - if ($file['extension'] === "pdf" && $config['pdf_file_thumbnail']) { - if ($mime !== 'application/pdf' && $mime !== 'application/x-pdf') { - error($config['error']['invalidfile']); - } + $pdf = $file['extension'] === "pdf" && $config['pdf_file_thumbnail']; + $djvu = $file['extension'] === "djvu" && $config['djvu_file_thumbnail']; + if ($pdf || $djvu) { $e_thumb_path = \escapeshellarg($file['thumb']); $e_file_path = \escapeshellarg($file['tmp_name']); $thumb_width = $config['thumb_width']; $thumb_height = $config['thumb_height']; // Generates a PPM image and pipes it directly into convert for resizing + type conversion. - $error = shell_exec_error("gs -dSAFER -dBATCH -dNOPAUSE -dQUIET - -sDEVICE=ppmraw -r100 -dFirstPage=1 -dLastPage=1 -sOutputFile=- $e_file_path - | convert -thumbnail {$thumb_width}x{$thumb_height} ppm:- $e_thumb_path"); + if ($pdf && $mime === 'application/pdf') { + $error = shell_exec_error("gs -dSAFER -dBATCH -dNOPAUSE -dQUIET \ + -sDEVICE=ppmraw -r100 -dFirstPage=1 -dLastPage=1 -sOutputFile=- $e_file_path \ + | convert -thumbnail {$thumb_width}x{$thumb_height} ppm:- $e_thumb_path"); + } elseif ($djvu && $mime === 'image/vnd.djvu') { + $error = shell_exec_error("ddjvu -format=ppm -page 1 $e_file_path \ + | convert -thumbnail {$thumb_width}x{$thumb_height} ppm:- $e_thumb_path"); + } else { + // Mime check failed. + error($config['error']['invalidfile']); + } if ($error) { $log = $ctx->get(LogDriver::class); - $log->log(LogDriver::ERROR, 'Could not render thumbnail for PDF file, using static fallback.'); - $path = sprintf($config['file_thumb'], isset($config['file_icons'][$file['extension']]) ? $config['file_icons'][$file['extension']] : $config['file_icons']['default']); - } - - $file['thumb'] = basename($file['thumb']); - $size = @getimagesize($path); - $file['thumbwidth'] = $size[0]; - $file['thumbheight'] = $size[1]; - $file['width'] = $size[0]; - $file['height'] = $size[1]; - } - if ($file['extension'] == "djvu" && $config['djvu_file_thumbnail']) { - $path = $file['thumb']; - $error = shell_exec_error('convert -size ' . $config['thumb_width'] . 'x' . $config['thumb_height'] . ' -thumbnail ' . $config['thumb_width'] . 'x' . $config['thumb_height'] . ' -background white -alpha remove ' . - escapeshellarg($file['tmp_name'] . '[0]') . ' ' . - escapeshellarg($file['thumb'])); - - if ($error) { - $path = sprintf($config['file_thumb'], isset($config['file_icons'][$file['extension']]) ? $config['file_icons'][$file['extension']] : $config['file_icons']['default']); + $log->log(LogDriver::ERROR, 'Could not render thumbnail for PDF/DJVU file, using static fallback.'); + $path = \sprintf($config['file_thumb'], isset($config['file_icons'][$file['extension']]) ? $config['file_icons'][$file['extension']] : $config['file_icons']['default']); + } else { + $path = $file['thumb']; } $file['thumb'] = basename($file['thumb']); From 19c08683207835e95b1b6844f4655f9239209f1f Mon Sep 17 00:00:00 2001 From: Zankaria Date: Mon, 21 Apr 2025 16:37:17 +0200 Subject: [PATCH 6/6] docker: add djvulibre and ghostscript tools --- docker/php/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index a884650c..fffd868d 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -18,6 +18,8 @@ RUN apk add --no-cache \ graphicsmagick \ gifsicle \ ffmpeg \ + djvulibre \ + ghostscript \ bind-tools \ gettext \ gettext-dev \