add change password button, delete backups option on changing password

This commit is contained in:
Craig Raw 2021-02-26 16:03:18 +02:00
parent 03ec0c9da1
commit 3bd2f69157
5 changed files with 82 additions and 19 deletions

View file

@ -22,17 +22,24 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
private final CustomPasswordField passwordConfirm; private final CustomPasswordField passwordConfirm;
private final CheckBox backupExisting; private final CheckBox backupExisting;
private final CheckBox changePassword; private final CheckBox changePassword;
private final CheckBox deleteBackups;
private boolean addingPassword;
public WalletPasswordDialog(PasswordRequirement requirement) { public WalletPasswordDialog(PasswordRequirement requirement) {
this(null, requirement); this(null, requirement);
} }
public WalletPasswordDialog(String walletName, PasswordRequirement requirement) { public WalletPasswordDialog(String walletName, PasswordRequirement requirement) {
this(null, requirement, false);
}
public WalletPasswordDialog(String walletName, PasswordRequirement requirement, boolean suggestChangePassword) {
this.requirement = requirement; this.requirement = requirement;
this.password = (CustomPasswordField)TextFields.createClearablePasswordField(); this.password = (CustomPasswordField)TextFields.createClearablePasswordField();
this.passwordConfirm = (CustomPasswordField)TextFields.createClearablePasswordField(); this.passwordConfirm = (CustomPasswordField)TextFields.createClearablePasswordField();
this.backupExisting = new CheckBox("Backup existing wallet first"); this.backupExisting = new CheckBox("Backup existing wallet first");
this.changePassword = new CheckBox("Change password"); this.changePassword = new CheckBox("Change password");
this.deleteBackups = new CheckBox("Delete any backups");
final DialogPane dialogPane = getDialogPane(); final DialogPane dialogPane = getDialogPane();
setTitle("Wallet Password" + (walletName != null ? " - " + walletName : "")); setTitle("Wallet Password" + (walletName != null ? " - " + walletName : ""));
@ -52,13 +59,21 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
content.getChildren().add(password); content.getChildren().add(password);
content.getChildren().add(passwordConfirm); content.getChildren().add(passwordConfirm);
if(requirement == PasswordRequirement.UPDATE_EMPTY || requirement == PasswordRequirement.UPDATE_SET) {
content.getChildren().add(backupExisting);
backupExisting.setSelected(true);
}
if(requirement == PasswordRequirement.UPDATE_SET) { if(requirement == PasswordRequirement.UPDATE_SET) {
content.getChildren().add(changePassword); content.getChildren().add(changePassword);
changePassword.selectedProperty().addListener((observable, oldValue, newValue) -> {
backupExisting.setVisible(!newValue);
});
changePassword.setSelected(suggestChangePassword);
}
if(requirement == PasswordRequirement.UPDATE_EMPTY || requirement == PasswordRequirement.UPDATE_SET) {
backupExisting.managedProperty().bind(backupExisting.visibleProperty());
deleteBackups.managedProperty().bind(deleteBackups.visibleProperty());
deleteBackups.visibleProperty().bind(backupExisting.visibleProperty().not());
content.getChildren().addAll(backupExisting, deleteBackups);
backupExisting.setSelected(true);
deleteBackups.setSelected(true);
} }
dialogPane.setContent(content); dialogPane.setContent(content);
@ -87,10 +102,14 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
okButton.setText("No Password"); okButton.setText("No Password");
passwordConfirm.setVisible(false); passwordConfirm.setVisible(false);
passwordConfirm.setManaged(false); passwordConfirm.setManaged(false);
backupExisting.setVisible(true);
addingPassword = false;
} else { } else {
okButton.setText("Set Password"); okButton.setText("Set Password");
passwordConfirm.setVisible(true); passwordConfirm.setVisible(true);
passwordConfirm.setManaged(true); passwordConfirm.setManaged(true);
backupExisting.setVisible(false);
addingPassword = true;
} }
}); });
} }
@ -103,13 +122,17 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
} }
public boolean isBackupExisting() { public boolean isBackupExisting() {
return backupExisting.isSelected(); return !(addingPassword || isChangePassword()) && backupExisting.isSelected();
} }
public boolean isChangePassword() { public boolean isChangePassword() {
return changePassword.isSelected(); return changePassword.isSelected();
} }
public boolean isDeleteBackups() {
return (addingPassword || isChangePassword()) && deleteBackups.isSelected();
}
public enum PasswordRequirement { public enum PasswordRequirement {
LOAD("Please enter the wallet password:", "Unlock"), LOAD("Please enter the wallet password:", "Unlock"),
UPDATE_NEW("Add a password to the wallet?\nLeave empty for none:", "No Password"), UPDATE_NEW("Add a password to the wallet?\nLeave empty for none:", "No Password"),

View file

@ -184,6 +184,18 @@ public class Storage {
Files.copy(walletFile, backupFile); Files.copy(walletFile, backupFile);
} }
public void deleteBackups() {
File backupDir = getWalletsBackupDir();
File[] unencryptedBackups = backupDir.listFiles((dir, name) -> {
int dotIndex = name.lastIndexOf('.');
return name.startsWith(walletFile.getName() + "-") && name.substring(walletFile.getName().length() + 1, dotIndex > -1 ? dotIndex : name.length()).matches("[0-9]+");
});
for(File unencryptedBackup : unencryptedBackups) {
unencryptedBackup.delete();
}
}
public ECKey getEncryptionPubKey() { public ECKey getEncryptionPubKey() {
return encryptionPubKey; return encryptionPubKey;
} }

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
@ -11,10 +12,11 @@ import org.controlsfx.tools.Borders;
import java.io.IOException; import java.io.IOException;
public class AdvancedDialog extends Dialog<Void> { public class AdvancedDialog extends Dialog<Boolean> {
public AdvancedDialog(Wallet wallet) { public AdvancedDialog(WalletForm walletForm) {
final DialogPane dialogPane = getDialogPane(); final DialogPane dialogPane = getDialogPane();
AppServices.setStageIcon(dialogPane.getScene().getWindow()); AppServices.setStageIcon(dialogPane.getScene().getWindow());
Wallet wallet = walletForm.getWallet();
try { try {
FXMLLoader advancedLoader = new FXMLLoader(AppServices.class.getResource("wallet/advanced.fxml")); FXMLLoader advancedLoader = new FXMLLoader(AppServices.class.getResource("wallet/advanced.fxml"));
@ -22,11 +24,18 @@ public class AdvancedDialog extends Dialog<Void> {
AdvancedController settingsAdvancedController = advancedLoader.getController(); AdvancedController settingsAdvancedController = advancedLoader.getController();
settingsAdvancedController.initializeView(wallet); settingsAdvancedController.initializeView(wallet);
boolean noPassword = Storage.NO_PASSWORD_KEY.equals(walletForm.getStorage().getEncryptionPubKey());
final ButtonType closeButtonType = new javafx.scene.control.ButtonType("Close", ButtonBar.ButtonData.CANCEL_CLOSE); final ButtonType closeButtonType = new javafx.scene.control.ButtonType("Close", ButtonBar.ButtonData.CANCEL_CLOSE);
dialogPane.getButtonTypes().addAll(closeButtonType); final ButtonType passwordButtonType = new javafx.scene.control.ButtonType(noPassword ? "Add Password..." : "Change Password...", ButtonBar.ButtonData.LEFT);
dialogPane.getButtonTypes().add(closeButtonType);
if(wallet.isValid()) {
dialogPane.getButtonTypes().add(passwordButtonType);
}
dialogPane.setPrefWidth(400); dialogPane.setPrefWidth(400);
dialogPane.setPrefHeight(300); dialogPane.setPrefHeight(300);
setResultConverter(dialogButton -> dialogButton == passwordButtonType);
} }
catch(IOException e) { catch(IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View file

@ -183,7 +183,7 @@ public class SettingsController extends WalletFormController implements Initiali
apply.setOnAction(event -> { apply.setOnAction(event -> {
revert.setDisable(true); revert.setDisable(true);
apply.setDisable(true); apply.setDisable(true);
saveWallet(false); saveWallet(false, false);
}); });
setFieldsFromWallet(walletForm.getWallet()); setFieldsFromWallet(walletForm.getWallet());
@ -303,8 +303,13 @@ public class SettingsController extends WalletFormController implements Initiali
} }
public void showAdvanced(ActionEvent event) { public void showAdvanced(ActionEvent event) {
AdvancedDialog advancedDialog = new AdvancedDialog(walletForm.getWallet()); AdvancedDialog advancedDialog = new AdvancedDialog(walletForm);
advancedDialog.showAndWait(); Optional<Boolean> optApply = advancedDialog.showAndWait();
if(optApply.isPresent() && optApply.get() && walletForm.getWallet().isValid()) {
revert.setDisable(true);
apply.setDisable(true);
saveWallet(false, true);
}
} }
@Override @Override
@ -355,7 +360,7 @@ public class SettingsController extends WalletFormController implements Initiali
} }
} }
private void saveWallet(boolean changePassword) { private void saveWallet(boolean changePassword, boolean suggestChangePassword) {
ECKey existingPubKey = walletForm.getStorage().getEncryptionPubKey(); ECKey existingPubKey = walletForm.getStorage().getEncryptionPubKey();
WalletPasswordDialog.PasswordRequirement requirement; WalletPasswordDialog.PasswordRequirement requirement;
@ -380,7 +385,7 @@ public class SettingsController extends WalletFormController implements Initiali
} }
} }
WalletPasswordDialog dlg = new WalletPasswordDialog(requirement); WalletPasswordDialog dlg = new WalletPasswordDialog(null, requirement, suggestChangePassword);
Optional<SecureString> password = dlg.showAndWait(); Optional<SecureString> password = dlg.showAndWait();
if(password.isPresent()) { if(password.isPresent()) {
if(dlg.isBackupExisting()) { if(dlg.isBackupExisting()) {
@ -399,7 +404,7 @@ public class SettingsController extends WalletFormController implements Initiali
try { try {
walletForm.getStorage().setEncryptionPubKey(Storage.NO_PASSWORD_KEY); walletForm.getStorage().setEncryptionPubKey(Storage.NO_PASSWORD_KEY);
walletForm.saveAndRefresh(); walletForm.saveAndRefresh();
if(requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_NEW) { if(requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_NEW || requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_CHANGE) {
EventManager.get().post(new RequestOpenWalletsEvent()); EventManager.get().post(new RequestOpenWalletsEvent());
} }
} catch (IOException e) { } catch (IOException e) {
@ -425,18 +430,28 @@ public class SettingsController extends WalletFormController implements Initiali
return; return;
} }
key = new Key(encryptionFullKey.getPrivKeyBytes(), walletForm.getStorage().getKeyDeriver().getSalt(), EncryptionType.Deriver.ARGON2);
if(dlg.isChangePassword()) { if(dlg.isChangePassword()) {
if(dlg.isDeleteBackups()) {
walletForm.deleteBackups();
}
walletForm.getStorage().setEncryptionPubKey(null); walletForm.getStorage().setEncryptionPubKey(null);
saveWallet(true); walletForm.getWallet().decrypt(key);
saveWallet(true, false);
return; return;
} }
key = new Key(encryptionFullKey.getPrivKeyBytes(), walletForm.getStorage().getKeyDeriver().getSalt(), EncryptionType.Deriver.ARGON2);
walletForm.getWallet().encrypt(key); walletForm.getWallet().encrypt(key);
walletForm.getStorage().setEncryptionPubKey(encryptionPubKey); walletForm.getStorage().setEncryptionPubKey(encryptionPubKey);
walletForm.saveAndRefresh(); walletForm.saveAndRefresh();
if(requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_NEW) {
if(dlg.isDeleteBackups()) {
walletForm.deleteBackups();
}
if(requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_NEW || requirement == WalletPasswordDialog.PasswordRequirement.UPDATE_EMPTY) {
EventManager.get().post(new RequestOpenWalletsEvent()); EventManager.get().post(new RequestOpenWalletsEvent());
} }
} catch (Exception e) { } catch (Exception e) {

View file

@ -75,6 +75,10 @@ public class WalletForm {
storage.backupWallet(); storage.backupWallet();
} }
public void deleteBackups() {
storage.deleteBackups();
}
public void refreshHistory(Integer blockHeight, Wallet pastWallet) { public void refreshHistory(Integer blockHeight, Wallet pastWallet) {
refreshHistory(blockHeight, pastWallet, null); refreshHistory(blockHeight, pastWallet, null);
} }