archive encrytpion added
This commit is contained in:
parent
e191561e9c
commit
62162af00e
@ -157,6 +157,47 @@ public class FileOperationQueue {
|
||||
// For background queue, maybe skip on error?
|
||||
return FileOperations.ErrorResponse.SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestPassword(String archiveName) {
|
||||
final String[] result = {null};
|
||||
try {
|
||||
javax.swing.SwingUtilities.invokeAndWait(() -> {
|
||||
javax.swing.JPasswordField pf = new javax.swing.JPasswordField() {
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
requestFocusInWindow();
|
||||
}
|
||||
};
|
||||
|
||||
Object[] message = {
|
||||
"Enter password for " + archiveName,
|
||||
pf
|
||||
};
|
||||
|
||||
javax.swing.JOptionPane pane = new javax.swing.JOptionPane(message, javax.swing.JOptionPane.PLAIN_MESSAGE, javax.swing.JOptionPane.OK_CANCEL_OPTION);
|
||||
javax.swing.JDialog dialog = pane.createDialog(null, "Password Required");
|
||||
|
||||
dialog.addWindowFocusListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowGainedFocus(java.awt.event.WindowEvent e) {
|
||||
pf.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setVisible(true);
|
||||
Object selectedValue = pane.getValue();
|
||||
|
||||
if (selectedValue != null && (Integer) selectedValue == javax.swing.JOptionPane.OK_OPTION) {
|
||||
result[0] = new String(pf.getPassword());
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
});
|
||||
|
||||
if (task.status != OperationStatus.CANCELLED) {
|
||||
|
||||
@ -1045,78 +1045,52 @@ public class FileOperations {
|
||||
* Zip files/directories into a target zip file
|
||||
*/
|
||||
public static void zip(List<FileItem> items, File targetZipFile, ProgressCallback callback) throws IOException {
|
||||
zip(items, targetZipFile, null, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip files/directories into a target zip file with optional password
|
||||
*/
|
||||
public static void zip(List<FileItem> items, File targetZipFile, String password, ProgressCallback callback) throws IOException {
|
||||
List<FileItem> cleanedItems = cleanDuplicateItems(items);
|
||||
long totalItems = calculateTotalItems(cleanedItems);
|
||||
long[] currentItem = {0};
|
||||
|
||||
try (org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream zos = new org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream(targetZipFile)) {
|
||||
net.lingala.zip4j.model.ZipParameters zipParameters = new net.lingala.zip4j.model.ZipParameters();
|
||||
if (password != null && !password.isEmpty()) {
|
||||
zipParameters.setEncryptFiles(true);
|
||||
zipParameters.setEncryptionMethod(net.lingala.zip4j.model.enums.EncryptionMethod.AES);
|
||||
zipParameters.setAesKeyStrength(net.lingala.zip4j.model.enums.AesKeyStrength.KEY_STRENGTH_256);
|
||||
}
|
||||
|
||||
if (targetZipFile.exists()) {
|
||||
targetZipFile.delete();
|
||||
}
|
||||
|
||||
try (ZipFile zipFile = new ZipFile(targetZipFile)) {
|
||||
if (password != null && !password.isEmpty()) {
|
||||
zipFile.setPassword(password.toCharArray());
|
||||
}
|
||||
|
||||
for (FileItem item : cleanedItems) {
|
||||
if (callback != null && callback.isCancelled()) break;
|
||||
addToZip(item.getFile(), item.getName(), zos, totalItems, currentItem, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToZip(File fileToZip, String fileName, org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream zos, long totalItems, long[] currentItem, ProgressCallback callback) throws IOException {
|
||||
if (fileToZip.isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentItem[0]++;
|
||||
if (callback != null) {
|
||||
callback.onProgress(currentItem[0], totalItems, fileName);
|
||||
}
|
||||
|
||||
org.apache.commons.compress.archivers.zip.ZipArchiveEntry zipEntry = new org.apache.commons.compress.archivers.zip.ZipArchiveEntry(fileToZip, fileName);
|
||||
|
||||
// Try to set POSIX permissions
|
||||
if (cz.kamma.kfmanager.MainApp.CURRENT_OS == cz.kamma.kfmanager.MainApp.OS.LINUX ||
|
||||
cz.kamma.kfmanager.MainApp.CURRENT_OS == cz.kamma.kfmanager.MainApp.OS.MACOS) {
|
||||
try {
|
||||
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(fileToZip.toPath());
|
||||
int mode = 0;
|
||||
if (perms.contains(PosixFilePermission.OWNER_READ)) mode |= 0400;
|
||||
if (perms.contains(PosixFilePermission.OWNER_WRITE)) mode |= 0200;
|
||||
if (perms.contains(PosixFilePermission.OWNER_EXECUTE)) mode |= 0100;
|
||||
if (perms.contains(PosixFilePermission.GROUP_READ)) mode |= 0040;
|
||||
if (perms.contains(PosixFilePermission.GROUP_WRITE)) mode |= 0020;
|
||||
if (perms.contains(PosixFilePermission.GROUP_EXECUTE)) mode |= 0010;
|
||||
if (perms.contains(PosixFilePermission.OTHERS_READ)) mode |= 0004;
|
||||
if (perms.contains(PosixFilePermission.OTHERS_WRITE)) mode |= 0002;
|
||||
if (perms.contains(PosixFilePermission.OTHERS_EXECUTE)) mode |= 0001;
|
||||
zipEntry.setUnixMode(mode);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
if (fileToZip.isDirectory()) {
|
||||
zos.putArchiveEntry(zipEntry);
|
||||
zos.closeArchiveEntry();
|
||||
File[] children = fileToZip.listFiles();
|
||||
if (children != null) {
|
||||
for (File childFile : children) {
|
||||
addToZip(childFile, fileName + (fileName.endsWith("/") ? "" : "/") + childFile.getName(), zos, totalItems, currentItem, callback);
|
||||
|
||||
File file = item.getFile();
|
||||
net.lingala.zip4j.model.ZipParameters currentParams = new net.lingala.zip4j.model.ZipParameters(zipParameters);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
zipFile.addFolder(file, currentParams);
|
||||
// Update progress correctly for directories
|
||||
currentItem[0] += countItems(file.toPath());
|
||||
} else {
|
||||
zipFile.addFile(file, currentParams);
|
||||
currentItem[0]++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try (InputStream is = Files.newInputStream(fileToZip.toPath())) {
|
||||
zos.putArchiveEntry(zipEntry);
|
||||
long fileSize = fileToZip.length();
|
||||
long bytesCopied = 0;
|
||||
byte[] buffer = new byte[24576];
|
||||
int len;
|
||||
while ((len = is.read(buffer)) >= 0) {
|
||||
zos.write(buffer, 0, len);
|
||||
bytesCopied += len;
|
||||
|
||||
if (callback != null) {
|
||||
callback.onFileProgress(bytesCopied, fileSize);
|
||||
callback.onProgress(currentItem[0], totalItems, file.getName());
|
||||
}
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onFileProgress(fileSize, fileSize);
|
||||
}
|
||||
zos.closeArchiveEntry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ import cz.kamma.kfmanager.service.FileOperationQueue;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.event.AncestorListener;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
@ -1946,18 +1948,48 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
defaultName += ".zip";
|
||||
|
||||
String zipName = JOptionPane.showInputDialog(this, "Enter zip filename:", defaultName);
|
||||
if (zipName == null || zipName.trim().isEmpty()) {
|
||||
if (activePanel != null && activePanel.getFileTable() != null) {
|
||||
activePanel.getFileTable().requestFocusInWindow();
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.insets = new Insets(5, 5, 5, 5);
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
panel.add(new JLabel("Enter zip filename:"), gbc);
|
||||
|
||||
gbc.gridy = 1;
|
||||
JTextField zipNameField = new JTextField(defaultName, 20);
|
||||
panel.add(zipNameField, gbc);
|
||||
|
||||
gbc.gridy = 2;
|
||||
JCheckBox encryptCheckBox = new JCheckBox("Encrypt with password");
|
||||
encryptCheckBox.setMnemonic(KeyEvent.VK_E);
|
||||
panel.add(encryptCheckBox, gbc);
|
||||
|
||||
gbc.gridy = 3;
|
||||
JPasswordField passwordField = new JPasswordField(20);
|
||||
passwordField.setEnabled(false);
|
||||
panel.add(passwordField, gbc);
|
||||
|
||||
encryptCheckBox.addActionListener(e -> {
|
||||
passwordField.setEnabled(encryptCheckBox.isSelected());
|
||||
if (encryptCheckBox.isSelected()) {
|
||||
passwordField.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
|
||||
int option = JOptionPane.showConfirmDialog(this, panel, "Zip archive", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
if (option != JOptionPane.OK_OPTION || zipNameField.getText().trim().isEmpty()) {
|
||||
requestFocusInActivePanel();
|
||||
return;
|
||||
}
|
||||
|
||||
String zipName = zipNameField.getText().trim();
|
||||
if (!zipName.toLowerCase().endsWith(".zip")) {
|
||||
zipName += ".zip";
|
||||
}
|
||||
|
||||
String password = encryptCheckBox.isSelected() ? new String(passwordField.getPassword()) : null;
|
||||
|
||||
FilePanel targetPanel = (activePanel == leftPanel) ? rightPanel : leftPanel;
|
||||
File targetDir = targetPanel.getCurrentDirectory();
|
||||
File targetZip = new File(targetDir, zipName);
|
||||
@ -1974,6 +2006,7 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
|
||||
final File finalTargetZip = targetZip;
|
||||
final String finalPassword = password;
|
||||
final FilePanel sourcePanel = activePanel;
|
||||
int result = showConfirmWithBackground(
|
||||
"Zip %d items to:\n%s".formatted(selectedItems.size(), targetZip.getAbsolutePath()),
|
||||
@ -1983,10 +2016,10 @@ public class MainWindow extends JFrame {
|
||||
boolean background = (result == 1);
|
||||
if (background) {
|
||||
addOperationToQueue("Zip", "Zip %d items to %s".formatted(selectedItems.size(), finalTargetZip.getName()),
|
||||
(cb) -> FileOperations.zip(selectedItems, finalTargetZip, cb), () -> sourcePanel.unselectAll(), targetPanel);
|
||||
(cb) -> FileOperations.zip(selectedItems, finalTargetZip, finalPassword, cb), () -> sourcePanel.unselectAll(), targetPanel);
|
||||
} else {
|
||||
performFileOperation((callback) -> {
|
||||
FileOperations.zip(selectedItems, finalTargetZip, callback);
|
||||
FileOperations.zip(selectedItems, finalTargetZip, finalPassword, callback);
|
||||
}, "Zipped into " + zipName, false, true, () -> sourcePanel.unselectAll(), targetPanel);
|
||||
}
|
||||
} else {
|
||||
@ -3009,9 +3042,33 @@ public class MainWindow extends JFrame {
|
||||
final String[] result = new String[1];
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
JPasswordField pf = new JPasswordField();
|
||||
int ok = JOptionPane.showConfirmDialog(progressDialog, pf, "Enter password for " + archiveName, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
if (ok == JOptionPane.OK_OPTION) {
|
||||
JPasswordField pf = new JPasswordField() {
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
requestFocusInWindow();
|
||||
}
|
||||
};
|
||||
|
||||
Object[] message = {
|
||||
"Enter password for " + archiveName,
|
||||
pf
|
||||
};
|
||||
|
||||
JOptionPane pane = new JOptionPane(message, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
|
||||
JDialog dialog = pane.createDialog(progressDialog, "Password Required");
|
||||
|
||||
dialog.addWindowFocusListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowGainedFocus(WindowEvent e) {
|
||||
pf.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setVisible(true);
|
||||
Object selectedValue = pane.getValue();
|
||||
|
||||
if (selectedValue != null && (Integer) selectedValue == JOptionPane.OK_OPTION) {
|
||||
result[0] = new String(pf.getPassword());
|
||||
} else {
|
||||
result[0] = null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user