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?
|
// For background queue, maybe skip on error?
|
||||||
return FileOperations.ErrorResponse.SKIP;
|
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) {
|
if (task.status != OperationStatus.CANCELLED) {
|
||||||
|
|||||||
@ -1045,78 +1045,52 @@ public class FileOperations {
|
|||||||
* Zip files/directories into a target zip file
|
* Zip files/directories into a target zip file
|
||||||
*/
|
*/
|
||||||
public static void zip(List<FileItem> items, File targetZipFile, ProgressCallback callback) throws IOException {
|
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);
|
List<FileItem> cleanedItems = cleanDuplicateItems(items);
|
||||||
long totalItems = calculateTotalItems(cleanedItems);
|
long totalItems = calculateTotalItems(cleanedItems);
|
||||||
long[] currentItem = {0};
|
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) {
|
for (FileItem item : cleanedItems) {
|
||||||
if (callback != null && callback.isCancelled()) break;
|
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 {
|
File file = item.getFile();
|
||||||
if (fileToZip.isHidden()) {
|
net.lingala.zip4j.model.ZipParameters currentParams = new net.lingala.zip4j.model.ZipParameters(zipParameters);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
zipFile.addFolder(file, currentParams);
|
||||||
|
// Update progress correctly for directories
|
||||||
|
currentItem[0] += countItems(file.toPath());
|
||||||
|
} else {
|
||||||
|
zipFile.addFile(file, currentParams);
|
||||||
currentItem[0]++;
|
currentItem[0]++;
|
||||||
|
}
|
||||||
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onProgress(currentItem[0], totalItems, fileName);
|
callback.onProgress(currentItem[0], totalItems, file.getName());
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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.*;
|
||||||
import javax.swing.filechooser.FileSystemView;
|
import javax.swing.filechooser.FileSystemView;
|
||||||
|
import javax.swing.event.AncestorListener;
|
||||||
|
import javax.swing.event.AncestorEvent;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.datatransfer.DataFlavor;
|
import java.awt.datatransfer.DataFlavor;
|
||||||
@ -1946,18 +1948,48 @@ public class MainWindow extends JFrame {
|
|||||||
}
|
}
|
||||||
defaultName += ".zip";
|
defaultName += ".zip";
|
||||||
|
|
||||||
String zipName = JOptionPane.showInputDialog(this, "Enter zip filename:", defaultName);
|
JPanel panel = new JPanel(new GridBagLayout());
|
||||||
if (zipName == null || zipName.trim().isEmpty()) {
|
GridBagConstraints gbc = new GridBagConstraints();
|
||||||
if (activePanel != null && activePanel.getFileTable() != null) {
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||||
activePanel.getFileTable().requestFocusInWindow();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String zipName = zipNameField.getText().trim();
|
||||||
if (!zipName.toLowerCase().endsWith(".zip")) {
|
if (!zipName.toLowerCase().endsWith(".zip")) {
|
||||||
zipName += ".zip";
|
zipName += ".zip";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String password = encryptCheckBox.isSelected() ? new String(passwordField.getPassword()) : null;
|
||||||
|
|
||||||
FilePanel targetPanel = (activePanel == leftPanel) ? rightPanel : leftPanel;
|
FilePanel targetPanel = (activePanel == leftPanel) ? rightPanel : leftPanel;
|
||||||
File targetDir = targetPanel.getCurrentDirectory();
|
File targetDir = targetPanel.getCurrentDirectory();
|
||||||
File targetZip = new File(targetDir, zipName);
|
File targetZip = new File(targetDir, zipName);
|
||||||
@ -1974,6 +2006,7 @@ public class MainWindow extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final File finalTargetZip = targetZip;
|
final File finalTargetZip = targetZip;
|
||||||
|
final String finalPassword = password;
|
||||||
final FilePanel sourcePanel = activePanel;
|
final FilePanel sourcePanel = activePanel;
|
||||||
int result = showConfirmWithBackground(
|
int result = showConfirmWithBackground(
|
||||||
"Zip %d items to:\n%s".formatted(selectedItems.size(), targetZip.getAbsolutePath()),
|
"Zip %d items to:\n%s".formatted(selectedItems.size(), targetZip.getAbsolutePath()),
|
||||||
@ -1983,10 +2016,10 @@ public class MainWindow extends JFrame {
|
|||||||
boolean background = (result == 1);
|
boolean background = (result == 1);
|
||||||
if (background) {
|
if (background) {
|
||||||
addOperationToQueue("Zip", "Zip %d items to %s".formatted(selectedItems.size(), finalTargetZip.getName()),
|
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 {
|
} else {
|
||||||
performFileOperation((callback) -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.zip(selectedItems, finalTargetZip, callback);
|
FileOperations.zip(selectedItems, finalTargetZip, finalPassword, callback);
|
||||||
}, "Zipped into " + zipName, false, true, () -> sourcePanel.unselectAll(), targetPanel);
|
}, "Zipped into " + zipName, false, true, () -> sourcePanel.unselectAll(), targetPanel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3009,9 +3042,33 @@ public class MainWindow extends JFrame {
|
|||||||
final String[] result = new String[1];
|
final String[] result = new String[1];
|
||||||
try {
|
try {
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
JPasswordField pf = new JPasswordField();
|
JPasswordField pf = new JPasswordField() {
|
||||||
int ok = JOptionPane.showConfirmDialog(progressDialog, pf, "Enter password for " + archiveName, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
@Override
|
||||||
if (ok == JOptionPane.OK_OPTION) {
|
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());
|
result[0] = new String(pf.getPassword());
|
||||||
} else {
|
} else {
|
||||||
result[0] = null;
|
result[0] = null;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user