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;
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());
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");
* @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) {
@Override
public void close() throws IOException {
data = null;
+ if (encryptedTempData != null) {
+ encryptedTempData.dispose();
+ }
if (tempFile != null) {
tempFile.delete();
}
*/
public class ZipInputStreamZipEntrySource implements ZipEntrySource {
private static int thresholdForTempFiles = -1;
+ private static boolean encryptTempFiles = false;
private final Map<String, ZipArchiveFakeEntry> zipEntries = new HashMap<>();
private InputStream streamToClose;
* 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;
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.
}
}
+ @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()) {