mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
add sparrow wallet file export, dont unnecessarily ask for password when exporting
This commit is contained in:
parent
b8739ace4f
commit
b74741bccb
16 changed files with 146 additions and 30 deletions
|
@ -115,7 +115,7 @@ run {
|
|||
"--add-opens=java.base/java.net=com.sparrowwallet.sparrow"]
|
||||
|
||||
if(os.macOsX) {
|
||||
applicationDefaultJvmArgs += ["-Xdock:name=Sparrow", "-Xdock:icon=/Users/scy/git/sparrow/src/main/resources/sparrow.png",
|
||||
applicationDefaultJvmArgs += ["-Xdock:name=Sparrow", "-Xdock:icon=/Users/scy/git/sparrow/src/main/resources/sparrow-large.png",
|
||||
"--add-opens=javafx.graphics/com.sun.glass.ui.mac=centerdevice.nsmenufx"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -334,7 +334,7 @@ public class AppServices {
|
|||
stage.setMinWidth(650);
|
||||
stage.setMinHeight(730);
|
||||
stage.setScene(scene);
|
||||
stage.getIcons().add(new Image(MainApp.class.getResourceAsStream("/image/sparrow.png")));
|
||||
stage.getIcons().add(new Image(MainApp.class.getResourceAsStream("/image/sparrow-large.png")));
|
||||
|
||||
appController.initializeView();
|
||||
stage.show();
|
||||
|
@ -453,7 +453,7 @@ public class AppServices {
|
|||
|
||||
public static void setStageIcon(Window window) {
|
||||
Stage stage = (Stage)window;
|
||||
stage.getIcons().add(new Image(AppServices.class.getResourceAsStream("/image/sparrow.png")));
|
||||
stage.getIcons().add(new Image(AppServices.class.getResourceAsStream("/image/sparrow-large.png")));
|
||||
|
||||
if(stage.getScene() != null && Config.get().getTheme() == Theme.DARK) {
|
||||
stage.getScene().getStylesheets().add(AppServices.class.getResource("darktheme.css").toExternalForm());
|
||||
|
|
|
@ -81,7 +81,10 @@ public class FileWalletExportPane extends TitledDescriptionPane {
|
|||
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Export " + exporter.getWalletModel().toDisplayString() + " File");
|
||||
fileChooser.setInitialFileName(wallet.getName() + "-" + exporter.getWalletModel().toDisplayString().toLowerCase() + "." + exporter.getExportFileExtension());
|
||||
String extension = exporter.getExportFileExtension(wallet);
|
||||
fileChooser.setInitialFileName(wallet.getName() + "-" +
|
||||
exporter.getWalletModel().toDisplayString().toLowerCase().replace(" ", "") +
|
||||
(extension == null || extension.isEmpty() ? "" : "." + extension));
|
||||
|
||||
File file = fileChooser.showSaveDialog(window);
|
||||
if(file != null) {
|
||||
|
@ -90,9 +93,8 @@ public class FileWalletExportPane extends TitledDescriptionPane {
|
|||
}
|
||||
|
||||
private void exportWallet(File file) {
|
||||
if(wallet.isEncrypted() && exporter.walletExportRequiresDecryption()) {
|
||||
Wallet copy = wallet.copy();
|
||||
|
||||
if(copy.isEncrypted()) {
|
||||
WalletPasswordDialog dlg = new WalletPasswordDialog(wallet.getName(), WalletPasswordDialog.PasswordRequirement.LOAD);
|
||||
Optional<SecureString> password = dlg.showAndWait();
|
||||
if(password.isPresent()) {
|
||||
|
@ -101,7 +103,12 @@ public class FileWalletExportPane extends TitledDescriptionPane {
|
|||
decryptWalletService.setOnSucceeded(workerStateEvent -> {
|
||||
EventManager.get().post(new StorageEvent(walletFile, TimedEvent.Action.END, "Done"));
|
||||
Wallet decryptedWallet = decryptWalletService.getValue();
|
||||
|
||||
try {
|
||||
exportWallet(file, decryptedWallet);
|
||||
} finally {
|
||||
decryptedWallet.clearPrivate();
|
||||
}
|
||||
});
|
||||
decryptWalletService.setOnFailed(workerStateEvent -> {
|
||||
EventManager.get().post(new StorageEvent(walletFile, TimedEvent.Action.END, "Failed"));
|
||||
|
@ -111,19 +118,19 @@ public class FileWalletExportPane extends TitledDescriptionPane {
|
|||
decryptWalletService.start();
|
||||
}
|
||||
} else {
|
||||
exportWallet(file, copy);
|
||||
exportWallet(file, wallet);
|
||||
}
|
||||
}
|
||||
|
||||
private void exportWallet(File file, Wallet decryptedWallet) {
|
||||
private void exportWallet(File file, Wallet exportWallet) {
|
||||
try {
|
||||
if(file != null) {
|
||||
OutputStream outputStream = new FileOutputStream(file);
|
||||
exporter.exportWallet(decryptedWallet, outputStream);
|
||||
EventManager.get().post(new WalletExportEvent(decryptedWallet));
|
||||
exporter.exportWallet(exportWallet, outputStream);
|
||||
EventManager.get().post(new WalletExportEvent(exportWallet));
|
||||
} else {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
exporter.exportWallet(decryptedWallet, outputStream);
|
||||
exporter.exportWallet(exportWallet, outputStream);
|
||||
QRDisplayDialog qrDisplayDialog;
|
||||
if(exporter instanceof CoboVaultMultisig) {
|
||||
qrDisplayDialog = new QRDisplayDialog(RegistryType.BYTES.toString(), outputStream.toByteArray(), true);
|
||||
|
@ -138,8 +145,6 @@ public class FileWalletExportPane extends TitledDescriptionPane {
|
|||
errorMessage = e.getCause().getMessage();
|
||||
}
|
||||
setError("Export Error", errorMessage);
|
||||
} finally {
|
||||
decryptedWallet.clearPrivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ public class WalletExportDialog extends Dialog<Wallet> {
|
|||
|
||||
List<WalletExport> exporters;
|
||||
if(wallet.getPolicyType() == PolicyType.SINGLE) {
|
||||
exporters = List.of(new Electrum(), new SpecterDesktop());
|
||||
exporters = List.of(new Electrum(), new SpecterDesktop(), new Sparrow());
|
||||
} else if(wallet.getPolicyType() == PolicyType.MULTI) {
|
||||
exporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new SpecterDesktop(), new BlueWalletMultisig());
|
||||
exporters = List.of(new ColdcardMultisig(), new CoboVaultMultisig(), new Electrum(), new SpecterDesktop(), new BlueWalletMultisig(), new Sparrow());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType());
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import com.sparrowwallet.drongo.policy.Policy;
|
|||
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
@ -14,6 +16,8 @@ import java.io.InputStreamReader;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class CoboVaultSinglesig implements KeystoreFileImport, WalletImport {
|
||||
private static final Logger log = LoggerFactory.getLogger(CoboVaultSinglesig.class);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Cobo Vault";
|
||||
|
@ -53,7 +57,8 @@ public class CoboVaultSinglesig implements KeystoreFileImport, WalletImport {
|
|||
|
||||
return keystore;
|
||||
} catch (Exception e) {
|
||||
throw new ImportException(e);
|
||||
log.error("Error getting Cobo Vault keystore", e);
|
||||
throw new ImportException("Error getting Cobo Vault keystore", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ import com.sparrowwallet.drongo.wallet.Keystore;
|
|||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -19,6 +21,8 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
public class ColdcardMultisig implements WalletImport, KeystoreFileImport, WalletExport {
|
||||
private static final Logger log = LoggerFactory.getLogger(ColdcardMultisig.class);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Coldcard Multisig";
|
||||
|
@ -81,7 +85,7 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileExtension() {
|
||||
public String getExportFileExtension(Wallet wallet) {
|
||||
return "txt";
|
||||
}
|
||||
|
||||
|
@ -146,7 +150,8 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
|||
|
||||
return wallet;
|
||||
} catch(Exception e) {
|
||||
throw new ImportException(e);
|
||||
log.error("Error importing Coldcard multisig wallet", e);
|
||||
throw new ImportException("Error importing Coldcard multisig wallet", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +204,8 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
|||
writer.flush();
|
||||
writer.close();
|
||||
} catch(Exception e) {
|
||||
throw new ExportException(e);
|
||||
log.error("Error exporting Coldcard multisig wallet", e);
|
||||
throw new ExportException("Error exporting Coldcard multisig wallet", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,4 +233,9 @@ public class ColdcardMultisig implements WalletImport, KeystoreFileImport, Walle
|
|||
public boolean isWalletExportScannable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean walletExportRequiresDecryption() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import com.sparrowwallet.drongo.policy.Policy;
|
|||
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
@ -18,6 +20,8 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.Map;
|
||||
|
||||
public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
|
||||
private static final Logger log = LoggerFactory.getLogger(ColdcardSinglesig.class);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Coldcard";
|
||||
|
@ -82,7 +86,8 @@ public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ImportException(e);
|
||||
log.error("Error getting Coldcard keystore", e);
|
||||
throw new ImportException("Error getting Coldcard keystore", e);
|
||||
}
|
||||
|
||||
throw new ImportException("Correct derivation not found for script type: " + scriptType);
|
||||
|
|
|
@ -14,6 +14,8 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
|
|||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.drongo.wallet.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -22,6 +24,8 @@ import java.util.*;
|
|||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
public class Electrum implements KeystoreFileImport, WalletImport, WalletExport {
|
||||
private static final Logger log = LoggerFactory.getLogger(Electrum.class);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Electrum";
|
||||
|
@ -246,7 +250,8 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
|
|||
|
||||
return wallet;
|
||||
} catch (Exception e) {
|
||||
throw new ImportException(e);
|
||||
log.error("Error importing Electrum Wallet", e);
|
||||
throw new ImportException("Error importing Electrum Wallet", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +278,7 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileExtension() {
|
||||
public String getExportFileExtension(Wallet wallet) {
|
||||
return "json";
|
||||
}
|
||||
|
||||
|
@ -350,7 +355,8 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
|
|||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
throw new ExportException(e);
|
||||
log.error("Error exporting Electrum Wallet", e);
|
||||
throw new ExportException("Error exporting Electrum Wallet", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,6 +385,11 @@ public class Electrum implements KeystoreFileImport, WalletImport, WalletExport
|
|||
return "Export this wallet as an Electrum wallet file.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean walletExportRequiresDecryption() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class ElectrumJsonWallet {
|
||||
public Map<String, ElectrumKeystore> keystores = new LinkedHashMap<>();
|
||||
public String wallet_type;
|
||||
|
|
62
src/main/java/com/sparrowwallet/sparrow/io/Sparrow.java
Normal file
62
src/main/java/com/sparrowwallet/sparrow/io/Sparrow.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package com.sparrowwallet.sparrow.io;
|
||||
|
||||
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.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class Sparrow implements WalletExport {
|
||||
private static final Logger log = LoggerFactory.getLogger(Sparrow.class);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Sparrow";
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletModel getWalletModel() {
|
||||
return WalletModel.SPARROW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException {
|
||||
try {
|
||||
Storage storage = AppServices.get().getOpenWallets().get(wallet);
|
||||
Files.copy(storage.getWalletFile().toPath(), outputStream);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch(Exception e) {
|
||||
log.error("Error exporting Sparrow wallet file", e);
|
||||
throw new ExportException("Error exporting Sparrow wallet file", e);
|
||||
}
|
||||
}
|
||||
|
||||
@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.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileExtension(Wallet wallet) {
|
||||
Storage storage = AppServices.get().getOpenWallets().get(wallet);
|
||||
if(storage != null && (storage.getEncryptionPubKey() == null || Storage.NO_PASSWORD_KEY.equals(storage.getEncryptionPubKey()))) {
|
||||
return "json";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWalletExportScannable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean walletExportRequiresDecryption() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ import com.sparrowwallet.drongo.wallet.Keystore;
|
|||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -15,6 +17,8 @@ import java.io.InputStreamReader;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class SpecterDIY implements KeystoreFileImport {
|
||||
private static final Logger log = LoggerFactory.getLogger(SpecterDIY.class);
|
||||
|
||||
@Override
|
||||
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||
try {
|
||||
|
@ -34,7 +38,8 @@ public class SpecterDIY implements KeystoreFileImport {
|
|||
|
||||
return keystore;
|
||||
} catch(IOException e) {
|
||||
throw new ImportException(e);
|
||||
log.error("Error getting Specter DIY keystore", e);
|
||||
throw new ImportException("Error getting Specter DIY keystore", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import com.sparrowwallet.drongo.wallet.BlockTransactionHash;
|
|||
import com.sparrowwallet.drongo.wallet.InvalidWalletException;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
@ -15,6 +17,8 @@ import java.io.OutputStream;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class SpecterDesktop implements WalletImport, WalletExport {
|
||||
private static final Logger log = LoggerFactory.getLogger(SpecterDesktop.class);
|
||||
|
||||
@Override
|
||||
public void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException {
|
||||
try {
|
||||
|
@ -29,7 +33,8 @@ public class SpecterDesktop implements WalletImport, WalletExport {
|
|||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch(Exception e) {
|
||||
throw new ExportException(e);
|
||||
log.error("Error exporting Specter Desktop wallet", e);
|
||||
throw new ExportException("Error exporting Specter Desktop wallet", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +44,7 @@ public class SpecterDesktop implements WalletImport, WalletExport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileExtension() {
|
||||
public String getExportFileExtension(Wallet wallet) {
|
||||
return "json";
|
||||
}
|
||||
|
||||
|
@ -68,7 +73,8 @@ public class SpecterDesktop implements WalletImport, WalletExport {
|
|||
return wallet;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
throw new ImportException(e);
|
||||
log.error("Error importing Specter Desktop wallet", e);
|
||||
throw new ImportException("Error importing Specter Desktop wallet", e);
|
||||
}
|
||||
|
||||
throw new ImportException("File was not a valid Specter Desktop wallet");
|
||||
|
@ -99,6 +105,11 @@ public class SpecterDesktop implements WalletImport, WalletExport {
|
|||
return WalletModel.SPECTER_DESKTOP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean walletExportRequiresDecryption() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class SpecterWallet {
|
||||
public String label;
|
||||
public Integer blockheight;
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.io.OutputStream;
|
|||
public interface WalletExport extends Export {
|
||||
void exportWallet(Wallet wallet, OutputStream outputStream) throws ExportException;
|
||||
String getWalletExportDescription();
|
||||
String getExportFileExtension();
|
||||
String getExportFileExtension(Wallet wallet);
|
||||
boolean isWalletExportScannable();
|
||||
boolean walletExportRequiresDecryption();
|
||||
}
|
||||
|
|
BIN
src/main/resources/image/sparrow-large.png
Normal file
BIN
src/main/resources/image/sparrow-large.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 4.7 KiB |
BIN
src/main/resources/image/sparrow@2x.png
Normal file
BIN
src/main/resources/image/sparrow@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
src/main/resources/image/sparrow@3x.png
Normal file
BIN
src/main/resources/image/sparrow@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Loading…
Reference in a new issue