This commit is contained in:
Anthony Stirling
2026-01-14 11:03:21 +00:00
parent db049a3467
commit 0b5c885750
6 changed files with 79 additions and 7 deletions
@@ -242,6 +242,42 @@ public class GeneralUtils {
return safeName;
}
/**
* Sanitizes a filename to ASCII-safe characters for use with external processes. Replaces
* non-ASCII characters and special characters with underscores to prevent InvalidPathException
* and encoding issues when filenames are passed to external programs like LibreOffice,
* Ghostscript, etc.
*
* <p>This method is specifically designed for temporary filenames used in ProcessExecutor calls
* where non-ASCII characters (e.g., Polish "ł", Chinese characters, etc.) can cause path
* encoding issues.
*
* @param filename the filename to sanitize, may be null
* @return ASCII-safe filename with only alphanumeric, dot, dash, and underscore characters, or
* "file" if input is null/empty
*/
public String sanitizeFilenameForProcess(String filename) {
if (filename == null || filename.isBlank()) {
return "file";
}
// Replace non-ASCII and non-alphanumeric characters (except dot, dash, underscore) with
// underscore
String sanitized = filename.replaceAll("[^a-zA-Z0-9._-]", "_");
// Handle cases where the entire filename became underscores
if (sanitized.isBlank() || sanitized.matches("^[._-]+$")) {
return "file";
}
// Limit length to prevent excessively long filenames
if (sanitized.length() > 200) {
sanitized = sanitized.substring(0, 200);
}
return sanitized;
}
// Get resources from a location pattern
public Resource[] getResourcesFromLocationPattern(
String locationPattern, ResourceLoader resourceLoader) throws Exception {
@@ -81,6 +81,8 @@ public class PDFToFile {
if (originalPdfFileName.contains(".")) {
pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
}
// Sanitize to ASCII-safe characters for external process compatibility
String sanitizedBaseName = GeneralUtils.sanitizeFilenameForProcess(pdfBaseName);
byte[] fileBytes;
String fileName;
@@ -97,7 +99,7 @@ public class PDFToFile {
"-noframes",
"-c",
tempInputFile.getAbsolutePath(),
pdfBaseName));
sanitizedBaseName));
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.PDFTOHTML)
@@ -169,6 +171,8 @@ public class PDFToFile {
if (originalPdfFileName.contains(".")) {
pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
}
// Sanitize to ASCII-safe characters for external process compatibility
String sanitizedBaseName = GeneralUtils.sanitizeFilenameForProcess(pdfBaseName);
byte[] fileBytes;
String fileName;
@@ -186,7 +190,7 @@ public class PDFToFile {
List<String> command =
new ArrayList<>(
Arrays.asList(
"pdftohtml", "-c", tempInputFile.toString(), pdfBaseName));
"pdftohtml", "-c", tempInputFile.toString(), sanitizedBaseName));
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.PDFTOHTML)
@@ -238,6 +242,8 @@ public class PDFToFile {
if (originalPdfFileName.contains(".")) {
pdfBaseName = originalPdfFileName.substring(0, originalPdfFileName.lastIndexOf('.'));
}
// Sanitize to ASCII-safe characters for external process compatibility
String sanitizedBaseName = GeneralUtils.sanitizeFilenameForProcess(pdfBaseName);
// Validate output format
List<String> allowedFormats =
Arrays.asList("doc", "docx", "odt", "ppt", "pptx", "odp", "rtf", "xml", "txt:Text");
@@ -256,7 +262,7 @@ public class PDFToFile {
Path tempOutputDir = outputDirTemp.getPath();
Path unoOutputFile =
tempOutputDir.resolve(
pdfBaseName + "." + resolvePrimaryExtension(outputFormat));
sanitizedBaseName + "." + resolvePrimaryExtension(outputFormat));
// Save the uploaded file to a temporary location
inputFile.transferTo(tempInputFile);
@@ -73,10 +73,14 @@ public class ConvertOfficeController {
baseName = "input";
}
// Sanitize baseName to ASCII-safe characters to prevent InvalidPathException
// with non-ASCII characters (e.g., Polish, Chinese, etc.) when creating temp file paths
String sanitizedBaseName = GeneralUtils.sanitizeFilenameForProcess(baseName);
// create temporary working directory
Path workDir = Files.createTempDirectory("office2pdf_");
Path inputPath = workDir.resolve(baseName + "." + extensionLower);
Path outputPath = workDir.resolve(baseName + ".pdf");
Path inputPath = workDir.resolve(sanitizedBaseName + "." + extensionLower);
Path outputPath = workDir.resolve(sanitizedBaseName + ".pdf");
// Check if the file is HTML and apply sanitization if needed
if ("html".equals(extensionLower) || "htm".equals(extensionLower)) {
+11
View File
@@ -66,6 +66,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
xvfb x11-utils coreutils \
# Temporary packages only needed for Calibre installer
xz-utils gpgv curl xdg-utils \
# UTF-8 locale support for handling international filenames
locales \
\
# Install Calibre from official installer script
&& curl -fsSL https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin \
@@ -79,6 +81,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \
&& /opt/calibre/ebook-convert --version
# Configure UTF-8 locale to support international characters in filenames
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \
&& locale-gen en_US.UTF-8
# Set UTF-8 locale environment variables
ENV LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
LANGUAGE=en_US:en
# ==============================================================================
# Create non-root user (stirlingpdfuser) with configurable UID/GID
# ==============================================================================
+11
View File
@@ -69,6 +69,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
xvfb x11-utils coreutils \
# Temporary packages only needed for Calibre installer
xz-utils gpgv curl xdg-utils \
# UTF-8 locale support for handling international filenames
locales \
\
# Install Calibre from official installer script
&& curl -fsSL https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin \
@@ -82,6 +84,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \
&& /opt/calibre/ebook-convert --version
# Configure UTF-8 locale to support international characters in filenames
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \
&& locale-gen en_US.UTF-8
# Set UTF-8 locale environment variables
ENV LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
LANGUAGE=en_US:en
# ==============================================================================
# Create non-root user (stirlingpdfuser) with configurable UID/GID
# ==============================================================================
+6 -2
View File
@@ -73,7 +73,10 @@ ENV VERSION_TAG=$VERSION_TAG \
TMPDIR=/tmp/stirling-pdf \
TEMP=/tmp/stirling-pdf \
TMP=/tmp/stirling-pdf \
ENDPOINTS_GROUPS_TO_REMOVE=CLI
ENDPOINTS_GROUPS_TO_REMOVE=CLI \
LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
LANGUAGE=en_US:en
# Install minimal dependencies
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
@@ -88,7 +91,8 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a
curl \
shadow \
su-exec \
openjdk21-jre && \
openjdk21-jre \
musl-locales musl-locales-lang && \
mkdir -p $HOME /configs /configs/heap_dumps /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf && \
mkdir -p /usr/share/fonts/opentype/noto && \
chmod +x /scripts/*.sh && \