From 803403bc86835c08bfc0f70717ea3f6c3461579e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sun, 19 Sep 2021 10:59:52 +0000 Subject: [PATCH] add support for encrypting temp files git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1893435 13f79535-47bb-0310-9956-ffa450edef68 --- poi-ooxml/build.gradle | 1 + .../openxml4j/util/ZipArchiveFakeEntry.java | 35 +++++++++++++------ .../util/ZipInputStreamZipEntrySource.java | 20 +++++++++++ .../poifs/crypt/temp/EncryptedTempData.java | 2 +- .../poi/xssf/usermodel/TestXSSFWorkbook.java | 23 ++++++++++++ 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/poi-ooxml/build.gradle b/poi-ooxml/build.gradle index f8ac5a93ae..87cf391d53 100644 --- a/poi-ooxml/build.gradle +++ b/poi-ooxml/build.gradle @@ -64,6 +64,7 @@ java { dependencies { api project(':poi') + //implementation files('/Users/pj.fanning/Downloads/poi-bin-5.1.1-SNAPSHOT/poi-ooxml-lite-5.1.1-SNAPSHOT.jar') api project(':poi-ooxml-full') api project(path: ':poi-ooxml-full', configuration: 'archives') diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java index 6c62e5c74d..36dc170be0 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipArchiveFakeEntry.java @@ -17,17 +17,13 @@ package org.apache.poi.openxml4j.util; -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.IOException; +import java.io.*; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.poi.poifs.crypt.temp.EncryptedTempData; import org.apache.poi.util.IOUtils; import org.apache.poi.util.TempFile; @@ -42,6 +38,7 @@ import org.apache.poi.util.TempFile; private static Logger LOG = LogManager.getLogger(ZipArchiveFakeEntry.class); private byte[] data; private File tempFile; + private EncryptedTempData encryptedTempData; ZipArchiveFakeEntry(ZipArchiveEntry entry, InputStream inp) throws IOException { super(entry.getName()); @@ -50,10 +47,17 @@ import org.apache.poi.util.TempFile; final int threshold = ZipInputStreamZipEntrySource.getThresholdBytesForTempFiles(); if (threshold >= 0 && entrySize >= threshold) { - tempFile = TempFile.createTempFile("poi-zip-entry", ".tmp"); - LOG.atInfo().log("created for temp file {} for zip entry {} of size {} bytes", - () -> tempFile.getAbsolutePath(), () -> entry.getName(), () -> entrySize); - IOUtils.copy(inp, tempFile); + if (ZipInputStreamZipEntrySource.shouldEncryptTempFiles()) { + encryptedTempData = new EncryptedTempData(); + try (OutputStream os = encryptedTempData.getOutputStream()) { + IOUtils.copy(inp, os); + } + } else { + tempFile = TempFile.createTempFile("poi-zip-entry", ".tmp"); + LOG.atInfo().log("created for temp file {} for zip entry {} of size {} bytes", + () -> tempFile.getAbsolutePath(), () -> entry.getName(), () -> entrySize); + IOUtils.copy(inp, tempFile); + } } else { if (entrySize < -1 || entrySize >= Integer.MAX_VALUE) { throw new IOException("ZIP entry size is too large or invalid"); @@ -72,7 +76,13 @@ import org.apache.poi.util.TempFile; * @see ZipInputStreamZipEntrySource#setThresholdBytesForTempFiles(int) */ public InputStream getInputStream() { - if (tempFile != null) { + if (encryptedTempData != null) { + try { + return encryptedTempData.getInputStream(); + } catch (IOException e) { + throw new RuntimeException("failed to read from encryped temp data", e); + } + } else if (tempFile != null) { try { return new FileInputStream(tempFile); } catch (FileNotFoundException e) { @@ -91,6 +101,9 @@ import org.apache.poi.util.TempFile; @Override public void close() throws IOException { data = null; + if (encryptedTempData != null) { + encryptedTempData.dispose(); + } if (tempFile != null) { tempFile.delete(); } diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java index fedaff1990..cea12db5fd 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/util/ZipInputStreamZipEntrySource.java @@ -35,6 +35,7 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; */ public class ZipInputStreamZipEntrySource implements ZipEntrySource { private static int thresholdForTempFiles = -1; + private static boolean encryptTempFiles = false; private final Map zipEntries = new HashMap<>(); private InputStream streamToClose; @@ -47,6 +48,7 @@ public class ZipInputStreamZipEntrySource implements ZipEntrySource { * and that zip entries with more than 2GB of data after decompressing will fail, 0 means all * zip entries are stored in temp files. A threshold like 50000000 (approx 50Mb is recommended) * @since POI 5.1.0 + * @see #setEncryptTempFiles(boolean) */ public static void setThresholdBytesForTempFiles(int thresholdBytes) { thresholdForTempFiles = thresholdBytes; @@ -62,6 +64,24 @@ public class ZipInputStreamZipEntrySource implements ZipEntrySource { return thresholdForTempFiles; } + /** + * Encrypt temp files when they are used. Only affects temp files related to zip entries. + * @param encrypt whether temp files should be encrypted + * @since POI 5.1.0 + * @see #setThresholdBytesForTempFiles(int) + */ + public static void setEncryptTempFiles(boolean encrypt) { + encryptTempFiles = encrypt; + } + + /** + * Whether temp files should be encrypted. Only affects temp files related to zip entries. + * @since POI 5.1.0 + */ + public static boolean shouldEncryptTempFiles() { + return encryptTempFiles; + } + /** * Reads all the entries from the ZipInputStream * into memory, and don't close (since POI 4.0.1) the source stream. diff --git a/poi-ooxml/src/main/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java b/poi-ooxml/src/main/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java index e1ea120e09..9f219f1a80 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java +++ b/poi-ooxml/src/main/java/org/apache/poi/poifs/crypt/temp/EncryptedTempData.java @@ -91,7 +91,7 @@ public class EncryptedTempData { */ public void dispose() { if (!tempFile.delete()) { - LOG.atWarn().log("{} can't be removed (or was already removed).", tempFile.getAbsolutePath()); + LOG.atWarn().log("{} can't be removed (or was already removed).", () -> tempFile.getAbsolutePath()); } } } diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java index 9845af910d..04ecbbfb6e 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java @@ -188,6 +188,29 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook { } } + @Test + void existingWithZipEntryEncryptedTempFiles() throws Exception { + int defaultThreshold = ZipInputStreamZipEntrySource.getThresholdBytesForTempFiles(); + boolean defaultEncryptFlag = ZipInputStreamZipEntrySource.shouldEncryptTempFiles(); + ZipInputStreamZipEntrySource.setEncryptTempFiles(true); + ZipInputStreamZipEntrySource.setThresholdBytesForTempFiles(100); + try (XSSFWorkbook workbook = openSampleWorkbook("Formatting.xlsx"); + OPCPackage pkg = OPCPackage.open(openSampleFileStream("Formatting.xlsx"))) { + assertNotNull(workbook.getSharedStringSource()); + assertNotNull(workbook.getStylesSource()); + + // And check a few low level bits too + PackagePart wbPart = pkg.getPart(PackagingURIHelper.createPartName("/xl/workbook.xml")); + + // Links to the three sheets, shared, styles and themes + assertTrue(wbPart.hasRelationships()); + assertEquals(6, wbPart.getRelationships().size()); + } finally { + ZipInputStreamZipEntrySource.setThresholdBytesForTempFiles(defaultThreshold); + ZipInputStreamZipEntrySource.setEncryptTempFiles(defaultEncryptFlag); + } + } + @Test void getCellStyleAt() throws IOException{ try (XSSFWorkbook workbook = new XSSFWorkbook()) { -- 2.39.5