diff --git a/app/common/src/main/java/stirling/software/common/util/FileMonitor.java b/app/common/src/main/java/stirling/software/common/util/FileMonitor.java index 5bdda6b5e2..dc0362b356 100644 --- a/app/common/src/main/java/stirling/software/common/util/FileMonitor.java +++ b/app/common/src/main/java/stirling/software/common/util/FileMonitor.java @@ -129,7 +129,9 @@ public class FileMonitor { // Skip expensive collection work when there is nothing to track WatchKey firstKey = watchService.poll(); - if (firstKey == null && newlyDiscoveredFiles.isEmpty() && readyForProcessingFiles.isEmpty()) { + if (firstKey == null + && newlyDiscoveredFiles.isEmpty() + && readyForProcessingFiles.isEmpty()) { return; } diff --git a/app/core/src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java b/app/core/src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java index 1a75c60f31..c08e53e1ab 100644 --- a/app/core/src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java +++ b/app/core/src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java @@ -73,7 +73,8 @@ public class ExternalAppDepConfig { tmp.put("tesseract", List.of("tesseract")); tmp.put("rar", List.of("rar")); // Required for real CBR output tmp.put(calibrePath, List.of("Calibre")); - tmp.put("ffmpeg", List.of("FFmpeg")); + // ffmpeg disabled due to raised CVEs + // tmp.put("ffmpeg", List.of("FFmpeg")); tmp.put("magick", List.of("ImageMagick")); this.commandToGroupMapping = Collections.unmodifiableMap(tmp); } diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoController.java index 56780fa901..001e09305e 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoController.java @@ -8,10 +8,7 @@ import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -23,31 +20,17 @@ import javax.imageio.ImageIO; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.multipart.MultipartFile; - -import io.github.pixee.security.Filenames; -import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; -import stirling.software.SPDF.model.api.converters.PdfToVideoRequest; -import stirling.software.common.annotations.AutoJobPostMapping; import stirling.software.common.annotations.api.ConvertApi; import stirling.software.common.model.ApplicationProperties; import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.util.ApplicationContextProvider; -import stirling.software.common.util.CheckProgramInstall; import stirling.software.common.util.ExceptionUtils; -import stirling.software.common.util.ProcessExecutor; -import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult; -import stirling.software.common.util.TempDirectory; import stirling.software.common.util.TempFile; import stirling.software.common.util.TempFileManager; -import stirling.software.common.util.WebResponseUtils; @ConvertApi @RequiredArgsConstructor @@ -64,6 +47,8 @@ public class ConvertPdfToVideoController { private final CustomPDFDocumentFactory pdfDocumentFactory; private final TempFileManager tempFileManager; + // ffmpeg disabled due to raised CVEs + /* @AutoJobPostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/pdf/video") @Operation( summary = "Convert PDF to Video Slideshow", @@ -163,6 +148,7 @@ public class ConvertPdfToVideoController { return WebResponseUtils.bytesToWebResponse(videoBytes, outputName, mediaType); } } + */ private void generateFrames( Path inputPdf, diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoControllerTest.java deleted file mode 100644 index 0b8de27f9b..0000000000 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoControllerTest.java +++ /dev/null @@ -1,164 +0,0 @@ -package stirling.software.SPDF.controller.api.converters; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.mock.web.MockMultipartFile; - -import stirling.software.SPDF.model.api.converters.PdfToVideoRequest; -import stirling.software.common.service.CustomPDFDocumentFactory; -import stirling.software.common.util.CheckProgramInstall; -import stirling.software.common.util.TempFileManager; - -@ExtendWith(MockitoExtension.class) -class ConvertPdfToVideoControllerTest { - - @Mock private CustomPDFDocumentFactory pdfDocumentFactory; - @Mock private TempFileManager tempFileManager; - - @InjectMocks private ConvertPdfToVideoController controller; - - @Test - void convertPdfToVideo_ffmpegNotAvailableThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile pdfFile = - new MockMultipartFile( - "fileInput", "doc.pdf", "application/pdf", "content".getBytes()); - request.setFileInput(pdfFile); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(false); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void convertPdfToVideo_nullFileThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - request.setFileInput(null); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void convertPdfToVideo_emptyFileThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile emptyFile = - new MockMultipartFile("fileInput", "doc.pdf", "application/pdf", new byte[0]); - request.setFileInput(emptyFile); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void convertPdfToVideo_nonPdfContentTypeReturnsBadRequest() throws Exception { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile txtFile = - new MockMultipartFile("fileInput", "doc.txt", "text/plain", "content".getBytes()); - request.setFileInput(txtFile); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - ResponseEntity response = controller.convertPdfToVideo(request); - - assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); - } - } - - @Test - void convertPdfToVideo_invalidOpacityThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile pdfFile = - new MockMultipartFile( - "fileInput", "doc.pdf", "application/pdf", "content".getBytes()); - request.setFileInput(pdfFile); - request.setOpacity(1.5f); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void convertPdfToVideo_negativeOpacityThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile pdfFile = - new MockMultipartFile( - "fileInput", "doc.pdf", "application/pdf", "content".getBytes()); - request.setFileInput(pdfFile); - request.setOpacity(-0.1f); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void convertPdfToVideo_negativeSecondsPerPageThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile pdfFile = - new MockMultipartFile( - "fileInput", "doc.pdf", "application/pdf", "content".getBytes()); - request.setFileInput(pdfFile); - request.setSecondsPerPage(-1); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void convertPdfToVideo_zeroSecondsPerPageThrows() { - PdfToVideoRequest request = new PdfToVideoRequest(); - MockMultipartFile pdfFile = - new MockMultipartFile( - "fileInput", "doc.pdf", "application/pdf", "content".getBytes()); - request.setFileInput(pdfFile); - request.setSecondsPerPage(0); - - try (MockedStatic mock = - Mockito.mockStatic(CheckProgramInstall.class)) { - mock.when(CheckProgramInstall::isFfmpegAvailable).thenReturn(true); - - assertThrows(Exception.class, () -> controller.convertPdfToVideo(request)); - } - } - - @Test - void controllerIsConstructed() { - assertNotNull(controller); - } -} diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java index bce3bf63e8..69c9d261b2 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/configuration/SecurityConfiguration.java @@ -159,9 +159,8 @@ public class SecurityConfiguration { firewall.setAllowedHeaderValues( headerValue -> headerValue != null && allowedChars.matcher(headerValue).matches()); - // Allow non-ASCII characters and newlines in parameter values. - Pattern allowedParamChars = - Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]\\r\\n]*"); + // Allow non-ASCII characters and newlines in parameter values. + Pattern allowedParamChars = Pattern.compile("[\\p{IsAssigned}&&[^\\p{IsControl}]\\r\\n]*"); firewall.setAllowedParameterValues( parameterValue -> parameterValue != null diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index b2e8266851..acb6d5a9f5 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -385,7 +385,9 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ apt-get install -y --no-install-recommends \ # Core tools ca-certificates tzdata tini bash fontconfig curl \ - ffmpeg poppler-utils fontforge \ + # ffmpeg disabled due to raised CVEs + # ffmpeg \ + poppler-utils fontforge \ unpaper pngquant \ # Fonts: full coverage for standard + fat variants fonts-dejavu \ diff --git a/docker/embedded/Dockerfile b/docker/embedded/Dockerfile index 548294a315..d44e616f59 100644 --- a/docker/embedded/Dockerfile +++ b/docker/embedded/Dockerfile @@ -1,7 +1,7 @@ # Stirling-PDF - Full version (embedded frontend) # Uses pre-built base image for fast builds -ARG BASE_VERSION=1.0.1 +ARG BASE_VERSION=1.0.2 ARG BASE_IMAGE=stirlingtools/stirling-pdf-base:${BASE_VERSION} # Stage 1: Build the Java application and frontend diff --git a/docker/embedded/Dockerfile.fat b/docker/embedded/Dockerfile.fat index 766fede0f2..6ad392d341 100644 --- a/docker/embedded/Dockerfile.fat +++ b/docker/embedded/Dockerfile.fat @@ -2,7 +2,7 @@ # Extra fonts for air-gapped environments # Uses pre-built base image for fast builds -ARG BASE_VERSION=1.0.1 +ARG BASE_VERSION=1.0.2 ARG BASE_IMAGE=stirlingtools/stirling-pdf-base:${BASE_VERSION} # Stage 1: Build the Java application and frontend diff --git a/scripts/init-without-ocr.sh b/scripts/init-without-ocr.sh index f7707fcc36..f48955f780 100755 --- a/scripts/init-without-ocr.sh +++ b/scripts/init-without-ocr.sh @@ -41,7 +41,8 @@ print_versions() { command_exists unoserver && unoserver --version 2>&1 | head -n 1 | log command_exists tesseract && tesseract --version | head -n 1 | log command_exists gs && gs --version | printf "Ghostscript %s\n" "$(cat)" | log - command_exists ffmpeg && ffmpeg -version | head -n 1 | log + # ffmpeg disabled due to raised CVEs + # command_exists ffmpeg && ffmpeg -version | head -n 1 | log command_exists pdfinfo && pdfinfo -v 2>&1 | head -n 1 | log command_exists fontforge && fontforge --version 2>&1 | head -n 1 | log command_exists unpaper && unpaper --version 2>&1 | head -n 1 | log