7z encryption support

This commit is contained in:
Radek Davidek 2026-04-21 19:26:23 +02:00
parent 898416bea7
commit 65a996bc29
2 changed files with 98 additions and 34 deletions

View File

@ -15,7 +15,7 @@ import java.io.InputStreamReader;
*/ */
public class MainApp { public class MainApp {
public static final String APP_VERSION = "1.4.0"; public static final String APP_VERSION = "1.4.1";
public enum OS { public enum OS {
WINDOWS, LINUX, MACOS, UNKNOWN WINDOWS, LINUX, MACOS, UNKNOWN

View File

@ -18,6 +18,10 @@ import java.util.regex.Pattern;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; 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.FileItem;
import cz.kamma.kfmanager.model.FtpProfile; import cz.kamma.kfmanager.model.FtpProfile;
import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.ZipFile;
@ -751,8 +755,14 @@ public class FileOperations {
} }
} }
} else if (name.endsWith(".7z")) { } else if (name.endsWith(".7z")) {
try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) { SevenZFile szf;
org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry; try {
szf = new SevenZFile(archive);
} catch (PasswordRequiredException e) {
return null;
}
try (SevenZFile sevenZFile = szf) {
SevenZArchiveEntry entry;
while ((entry = sevenZFile.getNextEntry()) != null) { while ((entry = sevenZFile.getNextEntry()) != null) {
if (entry.getName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + entry.getName()).equals(entryPath)) { if (entry.getName().equals(entryPath) || (archive.getAbsolutePath() + File.separator + entry.getName()).equals(entryPath)) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
@ -764,6 +774,8 @@ public class FileOperations {
return baos.toByteArray(); return baos.toByteArray();
} }
} }
} catch (PasswordRequiredException e) {
return null;
} }
} else if (name.endsWith(".rar")) { } else if (name.endsWith(".rar")) {
try (com.github.junrar.Archive rar = new com.github.junrar.Archive(archive)) { try (com.github.junrar.Archive rar = new com.github.junrar.Archive(archive)) {
@ -842,32 +854,53 @@ public class FileOperations {
} }
} }
} else if (name.endsWith(".7z")) { } else if (name.endsWith(".7z")) {
try (org.apache.commons.compress.archivers.sevenz.SevenZFile sevenZFile = new org.apache.commons.compress.archivers.sevenz.SevenZFile(archive)) { SevenZFile szf;
org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry; try {
while ((entry = sevenZFile.getNextEntry()) != null) { szf = new SevenZFile(archive);
if (callback.isCancelled()) return; } catch (PasswordRequiredException e) {
if (!entry.isDirectory()) { szf = null;
boolean nameMatched = true; }
if (patternLower != null && !patternLower.isEmpty()) { if (szf != null) {
nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex, caseSensitive); try (SevenZFile sevenZFile = szf) {
} SevenZArchiveEntry entry;
boolean contentMatched = true; while ((entry = sevenZFile.getNextEntry()) != null) {
if (nameMatched && contentPattern != null) { if (callback.isCancelled()) return;
contentMatched = searchInStream(new InputStream() { if (!entry.isDirectory()) {
@Override boolean nameMatched = true;
public int read() throws IOException { if (patternLower != null && !patternLower.isEmpty()) {
return sevenZFile.read(); nameMatched = matchEntry(entry.getName(), patternLower, filenameRegex, caseSensitive);
} }
@Override boolean contentMatched = true;
public int read(byte[] b, int off, int len) throws IOException { if (nameMatched && contentPattern != null) {
return sevenZFile.read(b, off, len); final SevenZFile szfFinal = sevenZFile;
} InputStream is = new InputStream() {
}, contentPattern); @Override
} public int read() throws IOException {
if (nameMatched && contentMatched) { try {
callback.onFileFound(archive, archive.getAbsolutePath() + File.separator + entry.getName()); 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")) { } else if (name.endsWith(".rar")) {
@ -1041,17 +1074,44 @@ public class FileOperations {
} }
private static void extract7z(File archive, File targetDir, ProgressCallback callback) throws IOException { 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)) { String password = null;
Iterable<org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry> entries = sevenZFile.getEntries(); SevenZFile szf = null;
List<org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry> entryList = new ArrayList<>(); try {
for (org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry : entries) { szf = new SevenZFile(archive);
} catch (PasswordRequiredException e) {
password = callback.requestPassword(archive.getName());
if (password == null) return;
szf = new SevenZFile(archive, password.toCharArray());
}
try {
Iterable<SevenZArchiveEntry> entries = szf.getEntries();
List<SevenZArchiveEntry> entryList = new ArrayList<>();
for (SevenZArchiveEntry entry : entries) {
entryList.add(entry); entryList.add(entry);
} }
long total = entryList.size(); long total = entryList.size();
org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry entry; SevenZArchiveEntry entry;
int count = 0; 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; if (callback != null && callback.isCancelled()) break;
File targetFile = new File(targetDir, entry.getName()); File targetFile = new File(targetDir, entry.getName());
if (entry.isDirectory()) { if (entry.isDirectory()) {
@ -1061,7 +1121,7 @@ public class FileOperations {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(targetFile), 65536)) { try (OutputStream out = new BufferedOutputStream(new FileOutputStream(targetFile), 65536)) {
byte[] buffer = new byte[65536]; byte[] buffer = new byte[65536];
int len; int len;
while ((len = sevenZFile.read(buffer)) > 0) { while ((len = szf.read(buffer)) > 0) {
out.write(buffer, 0, len); out.write(buffer, 0, len);
} }
} }
@ -1071,6 +1131,10 @@ public class FileOperations {
callback.onProgress(count, total, entry.getName()); callback.onProgress(count, total, entry.getName());
} }
} }
} finally {
if (szf != null) {
szf.close();
}
} }
} }