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 CheckBox backupExisting;
private final CheckBox changePassword;
private final CheckBox deleteBackups;
private boolean addingPassword;
public WalletPasswordDialog(PasswordRequirement requirement) {
this(null, requirement);
}
public WalletPasswordDialog(String walletName, PasswordRequirement requirement) {
this(null, requirement, false);
}
public WalletPasswordDialog(String walletName, PasswordRequirement requirement, boolean suggestChangePassword) {
this.requirement = requirement;
this.password = (CustomPasswordField)TextFields.createClearablePasswordField();
this.passwordConfirm = (CustomPasswordField)TextFields.createClearablePasswordField();
this.backupExisting = new CheckBox("Backup existing wallet first");
this.changePassword = new CheckBox("Change password");
this.deleteBackups = new CheckBox("Delete any backups");
final DialogPane dialogPane = getDialogPane();
setTitle("Wallet Password" + (walletName != null ? " - " + walletName : ""));
@ -52,13 +59,21 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
content.getChildren().add(password);
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) {
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);
@ -87,10 +102,14 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
okButton.setText("No Password");
passwordConfirm.setVisible(false);
passwordConfirm.setManaged(false);
backupExisting.setVisible(true);
addingPassword = false;
} else {
okButton.setText("Set Password");
passwordConfirm.setVisible(true);
passwordConfirm.setManaged(true);
backupExisting.setVisible(false);
addingPassword = true;
}
});
}
@ -103,13 +122,17 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
}
public boolean isBackupExisting() {
return backupExisting.isSelected();
return !(addingPassword || isChangePassword()) && backupExisting.isSelected();
}
public boolean isChangePassword() {
return changePassword.isSelected();
}
public boolean isDeleteBackups() {
return (addingPassword || isChangePassword()) && deleteBackups.isSelected();
}
public enum PasswordRequirement {
LOAD("Please enter the wallet password:", "Unlock"),
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);
}
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() {
return encryptionPubKey;
}

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
@ -11,10 +12,11 @@ import org.controlsfx.tools.Borders;
import java.io.IOException;
public class AdvancedDialog extends Dialog<Void> {
public AdvancedDialog(Wallet wallet) {
public class AdvancedDialog extends Dialog<Boolean> {
public AdvancedDialog(WalletForm walletForm) {
final DialogPane dialogPane = getDialogPane();
AppServices.setStageIcon(dialogPane.getScene().getWindow());
Wallet wallet = walletForm.getWallet();
try {
FXMLLoader advancedLoader = new FXMLLoader(AppServices.class.getResource("wallet/advanced.fxml"));
@ -22,11 +24,18 @@ public class AdvancedDialog extends Dialog<Void> {
AdvancedController settingsAdvancedController = advancedLoader.getController();
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);
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.setPrefHeight(300);
setResultConverter(dialogButton -> dialogButton == passwordButtonType);
}
catch(IOException e) {
throw new RuntimeException(e);

View file

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

View file

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