From 75edc3e17e4ead3d8e9811c85a3ac64d10d93fc2 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Thu, 31 Mar 2016 17:47:57 +0200 Subject: [PATCH] Add restore from seed words section --- .../content/seedwords/SeedWordsView.java | 226 +++++++++--------- .../overlays/windows/EmptyWalletWindow.java | 17 +- 2 files changed, 123 insertions(+), 120 deletions(-) diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java index 66e996a50d..7ddde254da 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/seedwords/SeedWordsView.java @@ -59,17 +59,20 @@ public class SeedWordsView extends ActivatableView { private Preferences preferences; private Button restoreButton; - private TextArea seedWordsTextArea; - private DatePicker datePicker; + private TextArea displaySeedWordsTextArea, restorSeedWordsTextArea; + private DatePicker datePicker, restoreDatePicker; private int gridRow = 0; private DeterministicSeed keyChainSeed; private ChangeListener seedWordsValidChangeListener; - private SimpleBooleanProperty seedWordsValid; - private SimpleBooleanProperty dateValid; + private SimpleBooleanProperty seedWordsValid = new SimpleBooleanProperty(false); + private SimpleBooleanProperty dateValid = new SimpleBooleanProperty(false); private ChangeListener seedWordsTextAreaChangeListener; private ChangeListener datePickerChangeListener; private ChangeListener dateChangeListener; + BooleanProperty seedWordsEdited = new SimpleBooleanProperty(); + private String seedWordText; + private LocalDate walletCreationDate; /////////////////////////////////////////////////////////////////////////////////////////// @@ -85,105 +88,31 @@ public class SeedWordsView extends ActivatableView { @Override protected void initialize() { - addTitledGroupBg(root, gridRow, 3, "Backup or restore your wallet seed words"); - seedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second; - seedWordsTextArea.setPrefHeight(60); + addTitledGroupBg(root, gridRow, 2, "Backup your wallet seed words"); + displaySeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_DISTANCE).second; + displaySeedWordsTextArea.setPrefHeight(60); datePicker = addLabelDatePicker(root, ++gridRow, "Creation Date:").second; + datePicker.setMouseTransparent(true); + + addTitledGroupBg(root, ++gridRow, 3, "Restore your wallet seed words", Layout.GROUP_DISTANCE); + restorSeedWordsTextArea = addLabelTextArea(root, gridRow, "Wallet seed words:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; + restorSeedWordsTextArea.setPrefHeight(60); + restoreDatePicker = addLabelDatePicker(root, ++gridRow, "Creation Date:").second; restoreButton = addButton(root, ++gridRow, "Restore wallet"); addTitledGroupBg(root, ++gridRow, 1, "Information", Layout.GROUP_DISTANCE); addMultilineLabel(root, gridRow, "Please write down you wallet seed words and the creation date.\n" + - "You can recover your wallet with those words and the date in emergency case.", + "You can recover your wallet with those seed words and the creation date.", Layout.FIRST_ROW_AND_GROUP_DISTANCE); - } - @Override - public void activate() { - seedWordsTextArea.getStyleClass().remove("validation_error"); - datePicker.getStyleClass().remove("validation_error"); - DeterministicSeed keyChainSeed = walletService.getWallet().getKeyChainSeed(); - if (keyChainSeed.isEncrypted()) { - restoreButton.setDisable(true); - seedWordsTextArea.setDisable(true); - datePicker.setDisable(true); - askForPassword(); - } else { - String key = "showSeedWordsWarning"; - if (preferences.showAgain(key)) { - new Popup().warning("You have not setup a wallet password which would protect the display of the seed words.\n\n" + - "Do you want to display the seed words?") - .actionButtonText("Yes, and don't ask me again") - .onAction(() -> { - preferences.dontShowAgain(key, true); - showSeedScreen(keyChainSeed); - }) - .closeButtonText("No") - .show(); - } else { - showSeedScreen(keyChainSeed); - } - } - } - - @Override - protected void deactivate() { - if (seedWordsTextAreaChangeListener != null) - seedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener); - - seedWordsTextArea.setText(""); - seedWordsTextArea.getStyleClass().remove("validation_error"); - - if (dateChangeListener != null) - datePicker.valueProperty().removeListener(dateChangeListener); - - datePicker.setValue(null); - datePicker.getStyleClass().remove("validation_error"); - - restoreButton.disableProperty().unbind(); - - if (seedWordsValid != null && seedWordsValidChangeListener != null) - seedWordsValid.removeListener(seedWordsValidChangeListener); - - if (dateValid != null && datePickerChangeListener != null) - dateValid.removeListener(datePickerChangeListener); - } - - private void askForPassword() { - walletPasswordWindow.onAesKey(aesKey -> { - Wallet wallet = walletService.getWallet(); - KeyCrypter keyCrypter = wallet.getKeyCrypter(); - keyChainSeed = wallet.getKeyChainSeed(); - if (keyCrypter != null) { - DeterministicSeed decryptedSeed = keyChainSeed.decrypt(keyCrypter, "", aesKey); - showSeedScreen(decryptedSeed); - } else { - log.warn("keyCrypter is null"); - } - }).show(); - } - - private void showSeedScreen(DeterministicSeed seed) { - seedWordsTextArea.setDisable(false); - datePicker.setDisable(false); - List mnemonicCode = seed.getMnemonicCode(); - if (mnemonicCode != null) - seedWordsTextArea.setText(Joiner.on(" ").join(mnemonicCode)); - LocalDate creationDate = Instant.ofEpochSecond(seed.getCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate(); - datePicker.setValue(creationDate); - restoreButton.setOnAction(e -> onRestore()); - - BooleanProperty seedWordsEdited = new SimpleBooleanProperty(); - - seedWordsValid = new SimpleBooleanProperty(true); seedWordsValidChangeListener = (observable, oldValue, newValue) -> { if (newValue) { - seedWordsTextArea.getStyleClass().remove("validation_error"); + restorSeedWordsTextArea.getStyleClass().remove("validation_error"); } else { - seedWordsTextArea.getStyleClass().add("validation_error"); + restorSeedWordsTextArea.getStyleClass().add("validation_error"); } }; - seedWordsValid.addListener(seedWordsValidChangeListener); seedWordsTextAreaChangeListener = (observable, oldValue, newValue) -> { seedWordsEdited.set(true); @@ -194,28 +123,108 @@ public class SeedWordsView extends ActivatableView { } catch (IOException | MnemonicException e) { seedWordsValid.set(false); } - - if (creationDate.equals(datePicker.getValue())) - datePicker.setValue(null); }; - seedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener); - dateValid = new SimpleBooleanProperty(true); + datePickerChangeListener = (observable, oldValue, newValue) -> { if (newValue) - datePicker.getStyleClass().remove("validation_error"); + restoreDatePicker.getStyleClass().remove("validation_error"); else - datePicker.getStyleClass().add("validation_error"); + restoreDatePicker.getStyleClass().add("validation_error"); }; - dateValid.addListener(datePickerChangeListener); dateChangeListener = (observable, oldValue, newValue) -> { - dateValid.set(newValue != null && !newValue.isAfter(LocalDate.now())); + dateValid.set(walletCreationDate.equals(newValue)); }; - datePicker.valueProperty().addListener(dateChangeListener); + } + @Override + public void activate() { + seedWordsValid.addListener(seedWordsValidChangeListener); + dateValid.addListener(datePickerChangeListener); + restorSeedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener); + restoreDatePicker.valueProperty().addListener(dateChangeListener); restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !dateValid.get() || !seedWordsEdited.get(), seedWordsValid, dateValid, seedWordsEdited)); + + restoreButton.setOnAction(e -> onRestore()); + + restorSeedWordsTextArea.getStyleClass().remove("validation_error"); + restoreDatePicker.getStyleClass().remove("validation_error"); + + + DeterministicSeed keyChainSeed = walletService.getWallet().getKeyChainSeed(); + // wallet creation date is not encrypted + walletCreationDate = Instant.ofEpochSecond(keyChainSeed.getCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate(); + log.error("walletCreationDate " + walletCreationDate); + if (keyChainSeed.isEncrypted()) { + askForPassword(); + } else { + String key = "showSeedWordsWarning"; + if (preferences.showAgain(key)) { + new Popup().warning("You have not setup a wallet password which would protect the display of the seed words.\n\n" + + "Do you want to display the seed words?") + .actionButtonText("Yes, and don't ask me again") + .onAction(() -> { + preferences.dontShowAgain(key, true); + initSeedWords(keyChainSeed); + showSeedScreen(); + }) + .closeButtonText("No") + .show(); + } else { + initSeedWords(keyChainSeed); + showSeedScreen(); + } + } + } + + @Override + protected void deactivate() { + seedWordsValid.removeListener(seedWordsValidChangeListener); + dateValid.removeListener(datePickerChangeListener); + restorSeedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener); + restoreDatePicker.valueProperty().removeListener(dateChangeListener); + restoreButton.disableProperty().unbind(); + + restoreButton.setOnAction(null); + + + displaySeedWordsTextArea.setText(""); + restorSeedWordsTextArea.setText(""); + + restoreDatePicker.setValue(null); + datePicker.setValue(null); + + restorSeedWordsTextArea.getStyleClass().remove("validation_error"); + restoreDatePicker.getStyleClass().remove("validation_error"); + } + + private void askForPassword() { + walletPasswordWindow.headLine("Enter password to view seed words").onAesKey(aesKey -> { + Wallet wallet = walletService.getWallet(); + KeyCrypter keyCrypter = wallet.getKeyCrypter(); + keyChainSeed = wallet.getKeyChainSeed(); + if (keyCrypter != null) { + DeterministicSeed decryptedSeed = keyChainSeed.decrypt(keyCrypter, "", aesKey); + initSeedWords(decryptedSeed); + showSeedScreen(); + } else { + log.warn("keyCrypter is null"); + } + }).show(); + } + + private void initSeedWords(DeterministicSeed seed) { + List mnemonicCode = seed.getMnemonicCode(); + if (mnemonicCode != null) { + seedWordText = Joiner.on(" ").join(mnemonicCode); + } + } + + private void showSeedScreen() { + displaySeedWordsTextArea.setText(seedWordText); + datePicker.setValue(walletCreationDate); } private void onRestore() { @@ -241,9 +250,9 @@ public class SeedWordsView extends ActivatableView { } private void doRestore() { - log.info("Attempting wallet restore using seed '{}' from date {}", seedWordsTextArea.getText(), datePicker.getValue()); - long date = datePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC); - DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(seedWordsTextArea.getText()), null, "", date); + log.info("Attempting wallet restore using seed '{}' from date {}", restorSeedWordsTextArea.getText(), restoreDatePicker.getValue()); + long date = restoreDatePicker.getValue().atStartOfDay().toEpochSecond(ZoneOffset.UTC); + DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(restorSeedWordsTextArea.getText()), null, "", date); walletService.restoreSeedWords(seed, () -> UserThread.execute(() -> { log.debug("Wallet restored with seed words"); @@ -253,20 +262,9 @@ public class SeedWordsView extends ActivatableView { "You need to shut down and restart the application.") .closeButtonText("Shut down") .onClose(() -> BitsquareApp.shutDownHandler.run()).show(); - //TODO - /* new Popup() - .information("Wallet restored successfully with the new seed words.\n\n" + - "You need to restart now the application.") - .closeButtonText("Restart") - .onClose(() -> BitsquareApp.restartDownHandler.run()).show();*/ }), throwable -> UserThread.execute(() -> { log.error(throwable.getMessage()); - new Popup() - .warning("You entered the wrong password.\n\n" + - "Please try entering your password again, carefully checking for typos or spelling errors.") - .show(); - new Popup() .error("An error occurred when restoring the wallet with seed words.\n" + "Error message: " + throwable.getMessage()) diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java index fb42fe61ce..30e51c9904 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java @@ -17,6 +17,7 @@ package io.bitsquare.gui.main.overlays.windows; +import io.bitsquare.app.BitsquareApp; import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.WalletService; import io.bitsquare.common.UserThread; @@ -53,7 +54,7 @@ public class EmptyWalletWindow extends Overlay { private final BSFormatter formatter; private Button emptyWalletButton; private InputTextField addressInputTextField; - private TextField addressTextField; + private TextField balanceTextField; /////////////////////////////////////////////////////////////////////////////////////////// @@ -97,10 +98,14 @@ public class EmptyWalletWindow extends Overlay { 10); Coin totalBalance = walletService.getAvailableBalance(); - addressTextField = addLabelTextField(gridPane, ++rowIndex, "Your available wallet balance:", + balanceTextField = addLabelTextField(gridPane, ++rowIndex, "Your available wallet balance:", formatter.formatCoinWithCode(totalBalance), 10).second; + Tuple2 tuple = addLabelInputTextField(gridPane, ++rowIndex, "Your destination address:"); addressInputTextField = tuple.second; + if (BitsquareApp.DEV_MODE) + addressInputTextField.setText("mo6y756TnpdZQCeHStraavjqrndeXzVkxi"); + emptyWalletButton = new Button("Empty wallet"); boolean isBalanceSufficient = Restrictions.isAboveDust(totalBalance); emptyWalletButton.setDefaultButton(isBalanceSufficient); @@ -142,13 +147,13 @@ public class EmptyWalletWindow extends Overlay { aesKey, () -> { closeButton.setText("Close"); - addressTextField.setText(formatter.formatCoinWithCode(walletService.getAvailableBalance())); + balanceTextField.setText(formatter.formatCoinWithCode(walletService.getAvailableBalance())); emptyWalletButton.setDisable(true); log.debug("wallet empty successful"); - UserThread.runAfter(() -> new Popup() + onClose(() -> UserThread.runAfter(() -> new Popup() .feedback("The balance of your wallet was successfully transferred.") - .onClose(this::hide) - .show(), Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS); + .show(), Transitions.DEFAULT_DURATION, TimeUnit.MILLISECONDS)); + doClose(); }, (errorMessage) -> { emptyWalletButton.setDisable(false);