in baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/UnzipFile.java [24:87]
public record UnzipFile(Path file, Path directory) implements Task {
private static final long THRESHOLD_ENTRIES = 10000;
private static final long THRESHOLD_SIZE = 10l << 30;
private static final double THRESHOLD_RATIO = 100;
private static final Logger logger = LoggerFactory.getLogger(UnzipFile.class);
@Override
public void execute(WorkflowContext context) throws Exception {
var filePath = file.toAbsolutePath();
var directoryPath = directory.toAbsolutePath();
try (var zipFile = new ZipFile(filePath.toFile())) {
var entries = zipFile.entries();
long totalSizeArchive = 0;
long totalEntryArchive = 0;
while (entries.hasMoreElements()) {
var ze = entries.nextElement();
var path = directoryPath.resolve(ze.getName());
var file = path.toFile().getCanonicalFile();
var directory = directoryPath.toFile().getCanonicalFile();
if (!file.toPath().startsWith(directory.toPath())) {
throw new IOException("Entry is outside of the target directory");
}
Files.createDirectories(path.getParent());
Files.write(path, new byte[] {}, StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
try (var input = new BufferedInputStream(zipFile.getInputStream(ze));
var output = new BufferedOutputStream(new FileOutputStream(path.toFile()))) {
totalEntryArchive++;
int nBytes = -1;
byte[] buffer = new byte[4096];
long totalSizeEntry = 0;
while ((nBytes = input.read(buffer)) > 0) {
output.write(buffer, 0, nBytes);
totalSizeEntry += nBytes;
totalSizeArchive += nBytes;
double compressionRatio = (double) totalSizeEntry / (double) ze.getCompressedSize();
if (compressionRatio > THRESHOLD_RATIO) {
throw new WorkflowException("Archive compression ratio is too high");
}
}
if (totalSizeArchive > THRESHOLD_SIZE) {
throw new IOException("Archive is too large");
}
if (totalEntryArchive > THRESHOLD_ENTRIES) {
throw new IOException("Archive contains too many entries");
}
}
}
}
}
}