diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index 5ec0baef..203a20a7 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -858,10 +858,6 @@ public class AppServices { deviceEnumerateService = createDeviceEnumerateService(); } - if(deviceEnumerateService.isRunning()) { - deviceEnumerateService.cancel(); - } - if(deviceEnumerateService.getState() == Worker.State.CANCELLED) { deviceEnumerateService.reset(); } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java index c00fa2ea..1e84cfcc 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletExportPane.java @@ -9,10 +9,7 @@ import com.sparrowwallet.sparrow.event.StorageEvent; import com.sparrowwallet.sparrow.event.TimedEvent; import com.sparrowwallet.sparrow.event.WalletExportEvent; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; -import com.sparrowwallet.sparrow.io.CoboVaultMultisig; -import com.sparrowwallet.sparrow.io.PassportMultisig; -import com.sparrowwallet.sparrow.io.Storage; -import com.sparrowwallet.sparrow.io.WalletExport; +import com.sparrowwallet.sparrow.io.*; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.Control; @@ -83,8 +80,8 @@ public class FileWalletExportPane extends TitledDescriptionPane { FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Export " + exporter.getWalletModel().toDisplayString() + " File"); String extension = exporter.getExportFileExtension(wallet); - fileChooser.setInitialFileName(wallet.getName() + "-" + - exporter.getWalletModel().toDisplayString().toLowerCase().replace(" ", "") + + fileChooser.setInitialFileName(wallet.getName() + + (exporter instanceof Sparrow ? "" : "-" + exporter.getWalletModel().toDisplayString().toLowerCase().replace(" ", "")) + (extension == null || extension.isEmpty() ? "" : "." + extension)); AppServices.moveToActiveWindowScreen(window, 800, 450); @@ -137,7 +134,7 @@ public class FileWalletExportPane extends TitledDescriptionPane { QRDisplayDialog qrDisplayDialog; if(exporter instanceof CoboVaultMultisig) { qrDisplayDialog = new QRDisplayDialog(RegistryType.BYTES.toString(), outputStream.toByteArray(), true); - } else if(exporter instanceof PassportMultisig) { + } else if(exporter instanceof PassportMultisig || exporter instanceof KeystoneMultisig) { qrDisplayDialog = new QRDisplayDialog(RegistryType.BYTES.toString(), outputStream.toByteArray(), false); } else { qrDisplayDialog = new QRDisplayDialog(outputStream.toString(StandardCharsets.UTF_8)); diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java index b00c002e..8e5a440e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java @@ -53,7 +53,7 @@ public class WalletImportDialog extends Dialog { importAccordion.getPanes().add(importPane); } - List walletImporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new KeystoneMultisig(), new SpecterDesktop(), new BlueWalletMultisig()); + List walletImporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new KeystoneMultisig(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow()); for(WalletImport importer : walletImporters) { FileWalletImportPane importPane = new FileWalletImportPane(importer); importAccordion.getPanes().add(importPane); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Sparrow.java b/src/main/java/com/sparrowwallet/sparrow/io/Sparrow.java index fde4fbe2..8ad0342c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Sparrow.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Sparrow.java @@ -1,15 +1,19 @@ package com.sparrowwallet.sparrow.io; +import com.google.common.io.Files; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.WalletModel; import com.sparrowwallet.sparrow.AppServices; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; -import java.nio.file.Files; +import java.nio.file.StandardCopyOption; -public class Sparrow implements WalletExport { +public class Sparrow implements WalletImport, WalletExport { private static final Logger log = LoggerFactory.getLogger(Sparrow.class); @Override @@ -26,8 +30,14 @@ public class Sparrow implements WalletExport { public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException { try { Storage storage = AppServices.get().getOpenWallets().get(wallet); - storage.copyWallet(outputStream); + File tempFile = File.createTempFile(wallet.getName(), null); + Storage tempStorage = new Storage(PersistenceType.JSON, tempFile); + tempStorage.setKeyDeriver(storage.getKeyDeriver()); + tempStorage.setEncryptionPubKey(storage.getEncryptionPubKey()); + tempStorage.saveWallet(wallet); + Files.copy(tempStorage.getWalletFile(), outputStream); outputStream.flush(); + tempStorage.getWalletFile().delete(); } catch(Exception e) { log.error("Error exporting Sparrow wallet file", e); throw new ExportException("Error exporting Sparrow wallet file", e); @@ -36,13 +46,19 @@ public class Sparrow implements WalletExport { @Override public String getWalletExportDescription() { - return "Exports a copy of your Sparrow wallet file, which can be loaded in another Sparrow instance running on any supported platform."; + return "Exports your Sparrow wallet file, which can be imported into another Sparrow instance running on any supported platform."; } @Override public String getExportFileExtension(Wallet wallet) { - Storage storage = AppServices.get().getOpenWallets().get(wallet); - return storage.getWalletFileExtension(); + try { + Storage storage = AppServices.get().getOpenWallets().get(wallet); + return storage.isEncrypted() ? "" : PersistenceType.JSON.getExtension(); + } catch(IOException e) { + //ignore + } + + return ""; } @Override @@ -54,4 +70,41 @@ public class Sparrow implements WalletExport { public boolean walletExportRequiresDecryption() { return false; } + + @Override + public boolean isEncrypted(File file) { + return Storage.isEncrypted(file); + } + + @Override + public String getWalletImportDescription() { + return "Imports an exported Sparrow wallet file into Sparrow's wallets folder."; + } + + @Override + public Wallet importWallet(InputStream inputStream, String password) throws ImportException { + File tempFile = null; + try { + tempFile = File.createTempFile("sparrow", null); + java.nio.file.Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + Storage storage = new Storage(PersistenceType.JSON, tempFile); + if(!isEncrypted(tempFile)) { + return storage.loadUnencryptedWallet().getWallet(); + } else { + return storage.loadEncryptedWallet(password).getWallet(); + } + } catch(IOException | StorageException e) { + log.error("Error importing Sparrow wallet", e); + throw new ImportException("Error importing Sparrow wallet", e); + } finally { + if(tempFile != null) { + tempFile.delete(); + } + } + } + + @Override + public boolean isWalletImportScannable() { + return false; + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java index 1900f148..79ad56fa 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Storage.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Storage.java @@ -37,6 +37,7 @@ public class Storage { public static final String WALLETS_BACKUP_DIR = "backup"; public static final String CERTS_DIR = "certs"; public static final String TEMP_BACKUP_PREFIX = "tmp"; + public static final List RESERVED_WALLET_NAMES = List.of("temp"); private Persistence persistence; private File walletFile; @@ -284,7 +285,7 @@ public class Storage { } } - return false; + return RESERVED_WALLET_NAMES.contains(walletName); } public static File getExistingWallet(String walletName) {