mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-04 21:36:45 +00:00
extra logging, backup existing wallet first functionality
This commit is contained in:
parent
03abc59ed3
commit
ce60fe3dc6
7 changed files with 75 additions and 3 deletions
|
@ -430,6 +430,7 @@ public class AppController implements Initializable {
|
||||||
showErrorDialog("Invalid QR Code", result.error);
|
showErrorDialog("Invalid QR Code", result.error);
|
||||||
}
|
}
|
||||||
if(result.exception != null) {
|
if(result.exception != null) {
|
||||||
|
log.error("Error opening webcam", result.exception);
|
||||||
showErrorDialog("Error opening webcam", result.exception.getMessage());
|
showErrorDialog("Error opening webcam", result.exception.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,6 +475,7 @@ public class AppController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
|
log.error("Error saving transaction", e);
|
||||||
AppController.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
|
AppController.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,6 +612,7 @@ public class AppController implements Initializable {
|
||||||
if(exception instanceof InvalidPasswordException) {
|
if(exception instanceof InvalidPasswordException) {
|
||||||
showErrorDialog("Invalid Password", "The wallet password was invalid.");
|
showErrorDialog("Invalid Password", "The wallet password was invalid.");
|
||||||
} else {
|
} else {
|
||||||
|
log.error("Error Opening Wallet", exception);
|
||||||
showErrorDialog("Error Opening Wallet", exception.getMessage());
|
showErrorDialog("Error Opening Wallet", exception.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,11 +20,13 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
|
||||||
private final PasswordRequirement requirement;
|
private final PasswordRequirement requirement;
|
||||||
private final CustomPasswordField password;
|
private final CustomPasswordField password;
|
||||||
private final CustomPasswordField passwordConfirm;
|
private final CustomPasswordField passwordConfirm;
|
||||||
|
private final CheckBox backupExisting;
|
||||||
|
|
||||||
public WalletPasswordDialog(PasswordRequirement requirement) {
|
public WalletPasswordDialog(PasswordRequirement requirement) {
|
||||||
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");
|
||||||
|
|
||||||
final DialogPane dialogPane = getDialogPane();
|
final DialogPane dialogPane = getDialogPane();
|
||||||
setTitle("Wallet Password");
|
setTitle("Wallet Password");
|
||||||
|
@ -32,7 +34,7 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
|
||||||
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
|
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
|
||||||
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
|
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
|
||||||
dialogPane.setPrefWidth(380);
|
dialogPane.setPrefWidth(380);
|
||||||
dialogPane.setPrefHeight(250);
|
dialogPane.setPrefHeight(260);
|
||||||
|
|
||||||
Glyph lock = new Glyph("FontAwesome", FontAwesome.Glyph.LOCK);
|
Glyph lock = new Glyph("FontAwesome", FontAwesome.Glyph.LOCK);
|
||||||
lock.setFontSize(50);
|
lock.setFontSize(50);
|
||||||
|
@ -43,6 +45,11 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
dialogPane.setContent(content);
|
dialogPane.setContent(content);
|
||||||
|
|
||||||
ValidationSupport validationSupport = new ValidationSupport();
|
ValidationSupport validationSupport = new ValidationSupport();
|
||||||
|
@ -84,6 +91,10 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
|
||||||
setResultConverter(dialogButton -> dialogButton == okButtonType ? new SecureString(password.getText()) : null);
|
setResultConverter(dialogButton -> dialogButton == okButtonType ? new SecureString(password.getText()) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBackupExisting() {
|
||||||
|
return backupExisting.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"),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.sparrowwallet.sparrow.io;
|
package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import com.sparrowwallet.drongo.ExtendedKey;
|
import com.sparrowwallet.drongo.ExtendedKey;
|
||||||
import com.sparrowwallet.drongo.SecureString;
|
import com.sparrowwallet.drongo.SecureString;
|
||||||
|
@ -19,6 +20,8 @@ import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
|
|
||||||
|
@ -27,8 +30,11 @@ import static com.sparrowwallet.drongo.crypto.Argon2KeyDeriver.SPRW1_PARAMETERS;
|
||||||
public class Storage {
|
public class Storage {
|
||||||
public static final ECKey NO_PASSWORD_KEY = ECKey.fromPublicOnly(ECKey.fromPrivate(Utils.hexToBytes("885e5a09708a167ea356a252387aa7c4893d138d632e296df8fbf5c12798bd28")));
|
public static final ECKey NO_PASSWORD_KEY = ECKey.fromPublicOnly(ECKey.fromPrivate(Utils.hexToBytes("885e5a09708a167ea356a252387aa7c4893d138d632e296df8fbf5c12798bd28")));
|
||||||
|
|
||||||
|
private static final DateFormat BACKUP_DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||||
|
|
||||||
public static final String SPARROW_DIR = ".sparrow";
|
public static final String SPARROW_DIR = ".sparrow";
|
||||||
public static final String WALLETS_DIR = "wallets";
|
public static final String WALLETS_DIR = "wallets";
|
||||||
|
public static final String WALLETS_BACKUP_DIR = "backup";
|
||||||
public static final String HEADER_MAGIC_1 = "SPRW1";
|
public static final String HEADER_MAGIC_1 = "SPRW1";
|
||||||
private static final int BINARY_HEADER_LENGTH = 28;
|
private static final int BINARY_HEADER_LENGTH = 28;
|
||||||
|
|
||||||
|
@ -157,6 +163,23 @@ public class Storage {
|
||||||
outputStream.write(encoded);
|
outputStream.write(encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void backupWallet() throws IOException {
|
||||||
|
File backupDir = getWalletsBackupDir();
|
||||||
|
|
||||||
|
Date backupDate = new Date();
|
||||||
|
String backupName = walletFile.getName();
|
||||||
|
String dateSuffix = "-" + BACKUP_DATE_FORMAT.format(backupDate);
|
||||||
|
int lastDot = backupName.lastIndexOf('.');
|
||||||
|
if(lastDot > 0) {
|
||||||
|
backupName = backupName.substring(0, lastDot) + dateSuffix + backupName.substring(lastDot);
|
||||||
|
} else {
|
||||||
|
backupName += dateSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
File backupFile = new File(backupDir, backupName);
|
||||||
|
Files.copy(walletFile, backupFile);
|
||||||
|
}
|
||||||
|
|
||||||
public ECKey getEncryptionPubKey() {
|
public ECKey getEncryptionPubKey() {
|
||||||
return encryptionPubKey;
|
return encryptionPubKey;
|
||||||
}
|
}
|
||||||
|
@ -228,6 +251,15 @@ public class Storage {
|
||||||
return new File(getWalletsDir(), walletName);
|
return new File(getWalletsDir(), walletName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File getWalletsBackupDir() {
|
||||||
|
File walletsBackupDir = new File(getWalletsDir(), WALLETS_BACKUP_DIR);
|
||||||
|
if(!walletsBackupDir.exists()) {
|
||||||
|
walletsBackupDir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
return walletsBackupDir;
|
||||||
|
}
|
||||||
|
|
||||||
public static File getWalletsDir() {
|
public static File getWalletsDir() {
|
||||||
File walletsDir = new File(getSparrowDir(), WALLETS_DIR);
|
File walletsDir = new File(getSparrowDir(), WALLETS_DIR);
|
||||||
if(!walletsDir.exists()) {
|
if(!walletsDir.exists()) {
|
||||||
|
|
|
@ -26,6 +26,8 @@ import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import tornadofx.control.DateTimePicker;
|
import tornadofx.control.DateTimePicker;
|
||||||
import tornadofx.control.Field;
|
import tornadofx.control.Field;
|
||||||
import tornadofx.control.Fieldset;
|
import tornadofx.control.Fieldset;
|
||||||
|
@ -43,6 +45,7 @@ import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class HeadersController extends TransactionFormController implements Initializable {
|
public class HeadersController extends TransactionFormController implements Initializable {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HeadersController.class);
|
||||||
public static final String LOCKTIME_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
public static final String LOCKTIME_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||||
public static final String BLOCK_TIMESTAMP_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss ZZZ";
|
public static final String BLOCK_TIMESTAMP_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss ZZZ";
|
||||||
public static final String UNFINALIZED_TXID_CLASS = "unfinalized-txid";
|
public static final String UNFINALIZED_TXID_CLASS = "unfinalized-txid";
|
||||||
|
@ -561,6 +564,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
writer.print(headersForm.getPsbt().toBase64String());
|
writer.print(headersForm.getPsbt().toBase64String());
|
||||||
}
|
}
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
|
log.error("Error saving PSBT", e);
|
||||||
AppController.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
|
AppController.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -617,6 +621,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
unencryptedWallet.sign(headersForm.getPsbt());
|
unencryptedWallet.sign(headersForm.getPsbt());
|
||||||
updateSignedKeystores(headersForm.getSigningWallet());
|
updateSignedKeystores(headersForm.getSigningWallet());
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
log.warn("Failed to Sign", e);
|
||||||
AppController.showErrorDialog("Failed to Sign", e.getMessage());
|
AppController.showErrorDialog("Failed to Sign", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -707,6 +712,7 @@ public class HeadersController extends TransactionFormController implements Init
|
||||||
writer.print(Utils.bytesToHex(finalTx.bitcoinSerialize()));
|
writer.print(Utils.bytesToHex(finalTx.bitcoinSerialize()));
|
||||||
}
|
}
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
|
log.error("Error saving transaction", e);
|
||||||
AppController.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
|
AppController.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import com.sparrowwallet.sparrow.control.WalletPasswordDialog;
|
||||||
import com.sparrowwallet.sparrow.event.SettingsChangedEvent;
|
import com.sparrowwallet.sparrow.event.SettingsChangedEvent;
|
||||||
import com.sparrowwallet.sparrow.event.StorageEvent;
|
import com.sparrowwallet.sparrow.event.StorageEvent;
|
||||||
import com.sparrowwallet.sparrow.event.TimedEvent;
|
import com.sparrowwallet.sparrow.event.TimedEvent;
|
||||||
import com.sparrowwallet.sparrow.event.WalletSettingsChangedEvent;
|
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -28,6 +27,8 @@ import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import org.controlsfx.control.RangeSlider;
|
import org.controlsfx.control.RangeSlider;
|
||||||
import org.controlsfx.tools.Borders;
|
import org.controlsfx.tools.Borders;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import tornadofx.control.Fieldset;
|
import tornadofx.control.Fieldset;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -39,6 +40,7 @@ import java.util.ResourceBundle;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SettingsController extends WalletFormController implements Initializable {
|
public class SettingsController extends WalletFormController implements Initializable {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SettingsController.class);
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<PolicyType> policyType;
|
private ComboBox<PolicyType> policyType;
|
||||||
|
@ -272,11 +274,24 @@ public class SettingsController extends WalletFormController implements Initiali
|
||||||
WalletPasswordDialog dlg = new WalletPasswordDialog(requirement);
|
WalletPasswordDialog dlg = new WalletPasswordDialog(requirement);
|
||||||
Optional<SecureString> password = dlg.showAndWait();
|
Optional<SecureString> password = dlg.showAndWait();
|
||||||
if(password.isPresent()) {
|
if(password.isPresent()) {
|
||||||
|
if(dlg.isBackupExisting()) {
|
||||||
|
try {
|
||||||
|
walletForm.saveBackup();
|
||||||
|
} catch(IOException e) {
|
||||||
|
log.error("Error saving wallet backup", e);
|
||||||
|
AppController.showErrorDialog("Error saving wallet backup", e.getMessage());
|
||||||
|
revert.setDisable(false);
|
||||||
|
apply.setDisable(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(password.get().length() == 0) {
|
if(password.get().length() == 0) {
|
||||||
try {
|
try {
|
||||||
walletForm.getStorage().setEncryptionPubKey(Storage.NO_PASSWORD_KEY);
|
walletForm.getStorage().setEncryptionPubKey(Storage.NO_PASSWORD_KEY);
|
||||||
walletForm.saveAndRefresh();
|
walletForm.saveAndRefresh();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
log.error("Error saving wallet", e);
|
||||||
AppController.showErrorDialog("Error saving wallet", e.getMessage());
|
AppController.showErrorDialog("Error saving wallet", e.getMessage());
|
||||||
revert.setDisable(false);
|
revert.setDisable(false);
|
||||||
apply.setDisable(false);
|
apply.setDisable(false);
|
||||||
|
@ -304,6 +319,7 @@ public class SettingsController extends WalletFormController implements Initiali
|
||||||
walletForm.getStorage().setEncryptionPubKey(encryptionPubKey);
|
walletForm.getStorage().setEncryptionPubKey(encryptionPubKey);
|
||||||
walletForm.saveAndRefresh();
|
walletForm.saveAndRefresh();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
log.error("Error saving wallet", e);
|
||||||
AppController.showErrorDialog("Error saving wallet", e.getMessage());
|
AppController.showErrorDialog("Error saving wallet", e.getMessage());
|
||||||
revert.setDisable(false);
|
revert.setDisable(false);
|
||||||
apply.setDisable(false);
|
apply.setDisable(false);
|
||||||
|
|
|
@ -59,6 +59,10 @@ public class WalletForm {
|
||||||
refreshHistory(AppController.getCurrentBlockHeight());
|
refreshHistory(AppController.getCurrentBlockHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void saveBackup() throws IOException {
|
||||||
|
storage.backupWallet();
|
||||||
|
}
|
||||||
|
|
||||||
public void refreshHistory(Integer blockHeight) {
|
public void refreshHistory(Integer blockHeight) {
|
||||||
Wallet previousWallet = wallet.copy();
|
Wallet previousWallet = wallet.copy();
|
||||||
if(wallet.isValid() && AppController.isOnline()) {
|
if(wallet.isValid() && AppController.isOnline()) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form .wideLabelFieldSet.fieldset:horizontal .label-container {
|
.form .wideLabelFieldSet.fieldset:horizontal .label-container {
|
||||||
-fx-pref-width: 160px;
|
-fx-pref-width: 170px;
|
||||||
-fx-pref-height: 25px;
|
-fx-pref-height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue