From 65a996bc29541be0d685b74cc7cffdf959ea09bc Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Tue, 21 Apr 2026 19:26:23 +0200 Subject: [PATCH] 7z encryption support --- src/main/java/cz/kamma/kfmanager/MainApp.java | 2 +- .../kfmanager/service/FileOperations.java | 130 +++++++++++++----- 2 files changed, 98 insertions(+), 34 deletions(-) diff --git a/src/main/java/cz/kamma/kfmanager/MainApp.java b/src/main/java/cz/kamma/kfmanager/MainApp.java index 1b1a761..c6aaa0b 100644 --- a/src/main/java/cz/kamma/kfmanager/MainApp.java +++ b/src/main/java/cz/kamma/kfmanager/MainApp.java @@ -15,7 +15,7 @@ import java.io.InputStreamReader; */ public class MainApp { - public static final String APP_VERSION = "1.4.0"; + public static final String APP_VERSION = "1.4.1"; public enum OS { WINDOWS, LINUX, MACOS, UNKNOWN diff --git a/src/main/java/cz/kamma/kfmanager/service/FileOperations.java b/src/main/java/cz/kamma/kfmanager/service/FileOperations.java index e7b570e..b379087 100644 --- a/src/main/java/cz/kamma/kfmanager/service/FileOperations.java +++ b/src/main/java/cz/kamma/kfmanager/service/FileOperations.java @@ -18,6 +18,10 @@ import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import org.apache.commons.compress.PasswordRequiredException; +import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; +import org.apache.commons.compress.archivers.sevenz.SevenZFile; + import cz.kamma.kfmanager.model.FileItem; import cz.kamma.kfmanager.model.FtpProfile; import net.lingala.zip4j.ZipFile; @@ -751,8 +755,14 @@ public class FileOperations { } } } else if (name.endsWith(".7z")) { - try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) { - org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry; + SevenZFile szf; + try { + szf = new SevenZFile(archive); + } catch (PasswordRequiredException e) { + return null; + } + try (SevenZFile sevenZFile = szf) { + SevenZArchiveEntry entry; while ((entry = sevenZFile.getNextEntry()) != null) { if (entry.getName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + entry.getName()).equals(entryPath)) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -764,6 +774,8 @@ public class FileOperations { return baos.toByteArray(); } } + } catch (PasswordRequiredException e) { + return null; } } else if (name.endsWith(".rar")) { try (com.github.junrar.Archive rar = new com.github.junrar.Archive(archive)) { @@ -842,32 +854,53 @@ public class FileOperations { } } } else if (name.endsWith(".7z")) { - try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) { - org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry; - while ((entry = sevenZFile.getNextEntry()) != null) { - if (callback.isCancelled()) return; - if (!entry.isDirectory()) { - boolean nameMatched = true; - if (patternLower != null && !patternLower.isEmpty()) { - nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex, caseSensitive); - } - boolean contentMatched = true; - if (nameMatched && contentPattern != null) { - contentMatched = searchInStream(new InputStream() { - @Override - public int read() throws IOException { - return sevenZFile.read(); - } - @Override - public int read(byte[] b, int off, int len) throws IOException { - return sevenZFile.read(b, off, len); - } - }, contentPattern); - } - if (nameMatched && contentMatched) { - callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName()); + SevenZFile szf; + try { + szf = new SevenZFile(archive); + } catch (PasswordRequiredException e) { + szf = null; + } + if (szf != null) { + try (SevenZFile sevenZFile = szf) { + SevenZArchiveEntry entry; + while ((entry = sevenZFile.getNextEntry()) != null) { + if (callback.isCancelled()) return; + if (!entry.isDirectory()) { + boolean nameMatched = true; + if (patternLower != null && !patternLower.isEmpty()) { + nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex, caseSensitive); + } + boolean contentMatched = true; + if (nameMatched && contentPattern != null) { + final SevenZFile szfFinal = sevenZFile; + InputStream is = new InputStream() { + @Override + public int read() throws IOException { + try { + return szfFinal.read(); + } catch (PasswordRequiredException e) { + throw new IOException("Password required", e); + } + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + try { + return szfFinal.read(b, off, len); + } catch (PasswordRequiredException e) { + throw new IOException("Password required", e); + } + } + }; + contentMatched = searchInStream(is, contentPattern); + } + if (nameMatched && contentMatched) { + callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName()); + } } } + } catch (PasswordRequiredException e) { + // Handle cases where data is encrypted but headers were not } } } else if (name.endsWith(".rar")) { @@ -1041,17 +1074,44 @@ public class FileOperations { } private static void extract7z(File archive, File targetDir, ProgressCallback callback) throws IOException { - try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) { - Iterable entries = sevenZFile.getEntries(); - List entryList = new ArrayList<>(); - for (org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry : entries) { + String password = null; + SevenZFile szf = null; + try { + szf = new SevenZFile(archive); + } catch (PasswordRequiredException e) { + password = callback.requestPassword(archive.getName()); + if (password == null) return; + szf = new SevenZFile(archive, password.toCharArray()); + } + + try { + Iterable entries = szf.getEntries(); + List entryList = new ArrayList<>(); + for (SevenZArchiveEntry entry : entries) { entryList.add(entry); } long total = entryList.size(); - org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry; + SevenZArchiveEntry entry; int count = 0; - while ((entry = sevenZFile.getNextEntry()) != null) { + while (true) { + try { + entry = szf.getNextEntry(); + } catch (PasswordRequiredException e) { + if (password == null) { + password = callback.requestPassword(archive.getName()); + if (password == null) { + szf.close(); + return; + } + } + szf.close(); + szf = new SevenZFile(archive, password.toCharArray()); + count = 0; + entry = szf.getNextEntry(); + } + if (entry == null) break; + if (callback != null && callback.isCancelled()) break; File targetFile = new File(targetDir, entry.getName()); if (entry.isDirectory()) { @@ -1061,7 +1121,7 @@ public class FileOperations { try (OutputStream out = new BufferedOutputStream(new FileOutputStream(targetFile), 65536)) { byte[] buffer = new byte[65536]; int len; - while ((len = sevenZFile.read(buffer)) > 0) { + while ((len = szf.read(buffer)) > 0) { out.write(buffer, 0, len); } } @@ -1071,6 +1131,10 @@ public class FileOperations { callback.onProgress(count, total, entry.getName()); } } + } finally { + if (szf != null) { + szf.close(); + } } }