diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java b/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java index ca967195..a442971b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java @@ -5,8 +5,13 @@ import com.googlecode.lanterna.gui2.ActionListBox; import com.googlecode.lanterna.gui2.dialogs.ActionListDialogBuilder; import com.googlecode.lanterna.gui2.dialogs.FileDialogBuilder; import com.googlecode.lanterna.gui2.dialogs.TextInputDialogBuilder; +import com.sparrowwallet.drongo.SecureString; +import com.sparrowwallet.drongo.crypto.InvalidPasswordException; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.AppServices; +import com.sparrowwallet.sparrow.EventManager; +import com.sparrowwallet.sparrow.event.StorageEvent; +import com.sparrowwallet.sparrow.event.TimedEvent; import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Storage; import com.sparrowwallet.sparrow.terminal.preferences.GeneralDialog; @@ -15,12 +20,19 @@ import com.sparrowwallet.sparrow.terminal.preferences.ServerTypeDialog; import com.sparrowwallet.sparrow.terminal.wallet.Bip39Dialog; import com.sparrowwallet.sparrow.terminal.wallet.LoadWallet; import com.sparrowwallet.sparrow.terminal.wallet.WatchOnlyDialog; +import javafx.application.Platform; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.util.Map; import java.util.Optional; +import static com.sparrowwallet.sparrow.AppServices.showErrorDialog; + public class MasterActionListBox extends ActionListBox { + private static final Logger log = LoggerFactory.getLogger(MasterActionListBox.class); + public static final int MAX_RECENT_WALLETS = 6; public MasterActionListBox(SparrowTerminal sparrowTerminal) { @@ -42,9 +54,9 @@ public class MasterActionListBox extends ActionListBox { .filter(entry -> entry.getValue().getWalletFile().equals(recentWalletFile)).map(Map.Entry::getKey) .map(wallet -> wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()).findFirst(); if(optWallet.isPresent()) { - builder.addAction(storage.getWalletName(null) + "*", () -> { - SparrowTerminal.get().getGuiThread().invokeLater(() -> LoadWallet.getOpeningDialog(storage, optWallet.get()).showDialog(SparrowTerminal.get().getGui())); - }); + Wallet wallet = optWallet.get(); + Storage existingStorage = AppServices.get().getOpenWallets().get(wallet); + builder.addAction(storage.getWalletName(null) + "*", () -> openLoadedWallet(existingStorage, optWallet.get())); } else { builder.addAction(storage.getWalletName(null), new LoadWallet(storage)); } @@ -82,6 +94,41 @@ public class MasterActionListBox extends ActionListBox { addItem("Quit", () -> sparrowTerminal.getGui().getMainWindow().close()); } + private static void openLoadedWallet(Storage storage, Wallet wallet) { + if(SparrowTerminal.get().isLocked(storage)) { + String walletId = storage.getWalletId(wallet); + + TextInputDialogBuilder builder = new TextInputDialogBuilder().setTitle("Wallet Password"); + builder.setDescription("Enter the wallet password:"); + builder.setPasswordInput(true); + + String password = builder.build().showDialog(SparrowTerminal.get().getGui()); + if(password != null) { + Platform.runLater(() -> { + Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(storage, new SecureString(password), true); + keyDerivationService.setOnSucceeded(workerStateEvent -> { + EventManager.get().post(new StorageEvent(walletId, TimedEvent.Action.END, "Done")); + keyDerivationService.getValue().clear(); + SparrowTerminal.get().unlockWallet(storage); + SparrowTerminal.get().getGuiThread().invokeLater(() -> LoadWallet.getOpeningDialog(storage, wallet).showDialog(SparrowTerminal.get().getGui())); + }); + keyDerivationService.setOnFailed(workerStateEvent -> { + EventManager.get().post(new StorageEvent(walletId, TimedEvent.Action.END, "Failed")); + if(keyDerivationService.getException() instanceof InvalidPasswordException) { + showErrorDialog("Invalid Password", "The wallet password was invalid."); + } else { + log.error("Error deriving wallet key", keyDerivationService.getException()); + } + }); + EventManager.get().post(new StorageEvent(walletId, TimedEvent.Action.START, "Decrypting wallet...")); + keyDerivationService.start(); + }); + } + } else { + SparrowTerminal.get().getGuiThread().invokeLater(() -> LoadWallet.getOpeningDialog(storage, wallet).showDialog(SparrowTerminal.get().getGui())); + } + } + private static void openWallet() { FileDialogBuilder openBuilder = new FileDialogBuilder().setTitle("Open Wallet"); openBuilder.setShowHiddenDirectories(true); diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java b/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java index a7fc4739..f01a3eef 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java @@ -40,6 +40,7 @@ public class SparrowTerminal extends Application { private SparrowTextGui gui; private final Map walletData = new HashMap<>(); + private final Set lockedWallets = new HashSet<>(); private static final javafx.stage.Window DEFAULT_WINDOW = new Window() { }; @@ -147,4 +148,16 @@ public class SparrowTerminal extends Application { EventManager.get().post(new WalletOpenedEvent(storage, wallet)); } + + public boolean isLocked(Storage storage) { + return lockedWallets.contains(storage.getWalletFile()); + } + + public void lockWallet(Storage storage) { + lockedWallets.add(storage.getWalletFile()); + } + + public void unlockWallet(Storage storage) { + lockedWallets.remove(storage.getWalletFile()); + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java index 615940e7..49acbc8a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java @@ -48,6 +48,12 @@ public class WalletActionsDialog extends DialogWindow { SettingsDialog settingsDialog = getWalletData().getSettingsDialog(); settingsDialog.showDialog(SparrowTerminal.get().getGui()); }); + if(getWalletData().getWalletForm().getWallet().isEncrypted()) { + actions.addItem("Lock", () -> { + close(); + SparrowTerminal.get().lockWallet(getWalletData().getWalletForm().getStorage()); + }); + } Panel mainPanel = new Panel(); mainPanel.setLayoutManager(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1));