mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
encrypted wallet and keystore import
This commit is contained in:
parent
60c1c17d26
commit
2ee9f3d10a
13 changed files with 181 additions and 37 deletions
|
@ -17,6 +17,8 @@ import com.sparrowwallet.sparrow.control.WalletNameDialog;
|
||||||
import com.sparrowwallet.sparrow.event.TabEvent;
|
import com.sparrowwallet.sparrow.event.TabEvent;
|
||||||
import com.sparrowwallet.sparrow.event.TransactionTabChangedEvent;
|
import com.sparrowwallet.sparrow.event.TransactionTabChangedEvent;
|
||||||
import com.sparrowwallet.sparrow.event.TransactionTabSelectedEvent;
|
import com.sparrowwallet.sparrow.event.TransactionTabSelectedEvent;
|
||||||
|
import com.sparrowwallet.sparrow.io.FileType;
|
||||||
|
import com.sparrowwallet.sparrow.io.IOUtils;
|
||||||
import com.sparrowwallet.sparrow.io.Storage;
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import com.sparrowwallet.sparrow.transaction.TransactionController;
|
import com.sparrowwallet.sparrow.transaction.TransactionController;
|
||||||
import com.sparrowwallet.sparrow.wallet.SettingsController;
|
import com.sparrowwallet.sparrow.wallet.SettingsController;
|
||||||
|
@ -227,9 +229,10 @@ public class AppController implements Initializable {
|
||||||
try {
|
try {
|
||||||
Wallet wallet;
|
Wallet wallet;
|
||||||
ECKey encryptionPubKey = WalletForm.NO_PASSWORD_KEY;
|
ECKey encryptionPubKey = WalletForm.NO_PASSWORD_KEY;
|
||||||
try {
|
FileType fileType = IOUtils.getFileType(file);
|
||||||
|
if(FileType.JSON.equals(fileType)) {
|
||||||
wallet = Storage.getStorage().loadWallet(file);
|
wallet = Storage.getStorage().loadWallet(file);
|
||||||
} catch(JsonSyntaxException e) {
|
} else if(FileType.BINARY.equals(fileType)) {
|
||||||
Optional<ECKey> optionalFullKey = SettingsController.askForWalletPassword(null, true);
|
Optional<ECKey> optionalFullKey = SettingsController.askForWalletPassword(null, true);
|
||||||
if(!optionalFullKey.isPresent()) {
|
if(!optionalFullKey.isPresent()) {
|
||||||
return;
|
return;
|
||||||
|
@ -238,6 +241,8 @@ public class AppController implements Initializable {
|
||||||
ECKey encryptionFullKey = optionalFullKey.get();
|
ECKey encryptionFullKey = optionalFullKey.get();
|
||||||
wallet = Storage.getStorage().loadWallet(file, encryptionFullKey);
|
wallet = Storage.getStorage().loadWallet(file, encryptionFullKey);
|
||||||
encryptionPubKey = ECKey.fromPublicOnly(encryptionFullKey);
|
encryptionPubKey = ECKey.fromPublicOnly(encryptionFullKey);
|
||||||
|
} else {
|
||||||
|
throw new IOException("Unsupported file type");
|
||||||
}
|
}
|
||||||
|
|
||||||
Tab tab = addWalletTab(file, encryptionPubKey, wallet);
|
Tab tab = addWalletTab(file, encryptionPubKey, wallet);
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class MainApp extends Application {
|
||||||
|
|
||||||
Wallet wallet = new Wallet();
|
Wallet wallet = new Wallet();
|
||||||
wallet.setPolicyType(PolicyType.MULTI);
|
wallet.setPolicyType(PolicyType.MULTI);
|
||||||
wallet.setScriptType(ScriptType.P2SH);
|
wallet.setScriptType(ScriptType.P2WPKH);
|
||||||
|
|
||||||
KeystoreImportDialog dlg = new KeystoreImportDialog(wallet);
|
KeystoreImportDialog dlg = new KeystoreImportDialog(wallet);
|
||||||
//dlg.showAndWait();
|
//dlg.showAndWait();
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.event.KeystoreImportEvent;
|
import com.sparrowwallet.sparrow.event.KeystoreImportEvent;
|
||||||
import com.sparrowwallet.sparrow.io.KeystoreFileImport;
|
import com.sparrowwallet.sparrow.io.KeystoreFileImport;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Hyperlink;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TitledPane;
|
import javafx.scene.control.TitledPane;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
|
@ -20,7 +23,8 @@ import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.controlsfx.control.HyperlinkLabel;
|
import org.controlsfx.control.textfield.CustomPasswordField;
|
||||||
|
import org.controlsfx.control.textfield.TextFields;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
|
@ -30,7 +34,11 @@ public class KeystoreFileImportPane extends TitledPane {
|
||||||
private final KeystoreFileImport importer;
|
private final KeystoreFileImport importer;
|
||||||
|
|
||||||
private Label mainLabel;
|
private Label mainLabel;
|
||||||
private HyperlinkLabel descriptionLabel;
|
private Label descriptionLabel;
|
||||||
|
private Hyperlink showHideLink;
|
||||||
|
private Button importButton;
|
||||||
|
|
||||||
|
private final SimpleStringProperty password = new SimpleStringProperty("");
|
||||||
|
|
||||||
public KeystoreFileImportPane(KeystoreImportAccordion importAccordion, Wallet wallet, KeystoreFileImport importer) {
|
public KeystoreFileImportPane(KeystoreImportAccordion importAccordion, Wallet wallet, KeystoreFileImport importer) {
|
||||||
this.importAccordion = importAccordion;
|
this.importAccordion = importAccordion;
|
||||||
|
@ -83,21 +91,32 @@ public class KeystoreFileImportPane extends TitledPane {
|
||||||
mainLabel.getStyleClass().add("main-label");
|
mainLabel.getStyleClass().add("main-label");
|
||||||
labelsBox.getChildren().add(mainLabel);
|
labelsBox.getChildren().add(mainLabel);
|
||||||
|
|
||||||
this.descriptionLabel = new HyperlinkLabel();
|
HBox descriptionBox = new HBox();
|
||||||
|
descriptionBox.setSpacing(7);
|
||||||
|
labelsBox.getChildren().add(descriptionBox);
|
||||||
|
|
||||||
labelsBox.getChildren().add(descriptionLabel);
|
descriptionLabel = new Label("Keystore file import");
|
||||||
descriptionLabel.getStyleClass().add("description-label");
|
descriptionLabel.getStyleClass().add("description-label");
|
||||||
descriptionLabel.setText("Keystore file import [View Details...]");
|
showHideLink = new Hyperlink("View Details...");
|
||||||
descriptionLabel.setOnAction(event -> {
|
showHideLink.managedProperty().bind(showHideLink.visibleProperty());
|
||||||
setExpanded(true);
|
showHideLink.setOnAction(event -> {
|
||||||
|
if(showHideLink.getText().contains("View")) {
|
||||||
|
setExpanded(true);
|
||||||
|
showHideLink.setText("Hide Details...");
|
||||||
|
} else {
|
||||||
|
setExpanded(false);
|
||||||
|
showHideLink.setText("View Details...");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
descriptionBox.getChildren().addAll(descriptionLabel, showHideLink);
|
||||||
|
|
||||||
listItem.getChildren().add(labelsBox);
|
listItem.getChildren().add(labelsBox);
|
||||||
HBox.setHgrow(labelsBox, Priority.ALWAYS);
|
HBox.setHgrow(labelsBox, Priority.ALWAYS);
|
||||||
|
|
||||||
HBox buttonBox = new HBox();
|
HBox buttonBox = new HBox();
|
||||||
buttonBox.setAlignment(Pos.CENTER_RIGHT);
|
buttonBox.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
|
||||||
Button importButton = new Button("Import File...");
|
importButton = new Button("Import File...");
|
||||||
importButton.setAlignment(Pos.CENTER_RIGHT);
|
importButton.setAlignment(Pos.CENTER_RIGHT);
|
||||||
importButton.setOnAction(event -> {
|
importButton.setOnAction(event -> {
|
||||||
importFile();
|
importFile();
|
||||||
|
@ -125,29 +144,44 @@ public class KeystoreFileImportPane extends TitledPane {
|
||||||
|
|
||||||
File file = fileChooser.showOpenDialog(window);
|
File file = fileChooser.showOpenDialog(window);
|
||||||
if(file != null) {
|
if(file != null) {
|
||||||
importFile(file);
|
importFile(file, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void importFile(File file) {
|
private void importFile(File file, String password) {
|
||||||
if(file.exists()) {
|
if(file.exists()) {
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
|
if(importer.isEncrypted(file) && password == null) {
|
||||||
Keystore keystore = importer.getKeystore(wallet.getScriptType(), inputStream);
|
descriptionLabel.getStyleClass().remove("description-error");
|
||||||
EventManager.get().post(new KeystoreImportEvent(keystore));
|
descriptionLabel.getStyleClass().add("description-label");
|
||||||
|
descriptionLabel.setText("Password Required");
|
||||||
|
showHideLink.setVisible(false);
|
||||||
|
setContent(getPasswordEntry(file));
|
||||||
|
importButton.setDisable(true);
|
||||||
|
setExpanded(true);
|
||||||
|
} else {
|
||||||
|
InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
Keystore keystore = importer.getKeystore(wallet.getScriptType(), inputStream, password);
|
||||||
|
EventManager.get().post(new KeystoreImportEvent(keystore));
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
setExpanded(false);
|
|
||||||
descriptionLabel.getStyleClass().remove("description-label");
|
descriptionLabel.getStyleClass().remove("description-label");
|
||||||
descriptionLabel.getStyleClass().add("description-error");
|
descriptionLabel.getStyleClass().add("description-error");
|
||||||
descriptionLabel.setText("Error Importing [View Details...]");
|
descriptionLabel.setText("Import Error");
|
||||||
String errorMessage = e.getMessage();
|
String errorMessage = e.getMessage();
|
||||||
if(e.getCause() != null) {
|
if(e.getCause() != null && e.getCause().getMessage() != null && !e.getCause().getMessage().isEmpty()) {
|
||||||
errorMessage = e.getCause().getMessage();
|
errorMessage = e.getCause().getMessage();
|
||||||
}
|
}
|
||||||
|
if(e instanceof ECKey.InvalidPasswordException || e.getCause() instanceof ECKey.InvalidPasswordException) {
|
||||||
|
errorMessage = "Invalid wallet password";
|
||||||
|
}
|
||||||
if(e instanceof JsonParseException || e.getCause() instanceof JsonParseException) {
|
if(e instanceof JsonParseException || e.getCause() instanceof JsonParseException) {
|
||||||
errorMessage = "File was not in JSON format";
|
errorMessage = "File was not in JSON format";
|
||||||
}
|
}
|
||||||
setContent(getContentBox(errorMessage));
|
setContent(getContentBox(errorMessage));
|
||||||
|
setExpanded(true);
|
||||||
|
showHideLink.setText("Hide Details...");
|
||||||
|
importButton.setDisable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,4 +202,28 @@ public class KeystoreFileImportPane extends TitledPane {
|
||||||
|
|
||||||
return contentBox;
|
return contentBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node getPasswordEntry(File file) {
|
||||||
|
CustomPasswordField passwordField = (CustomPasswordField) TextFields.createClearablePasswordField();
|
||||||
|
passwordField.setPromptText("Wallet password");
|
||||||
|
password.bind(passwordField.textProperty());
|
||||||
|
HBox.setHgrow(passwordField, Priority.ALWAYS);
|
||||||
|
|
||||||
|
Button importEncryptedButton = new Button("Import");
|
||||||
|
importEncryptedButton.setOnAction(event -> {
|
||||||
|
showHideLink.setVisible(true);
|
||||||
|
setExpanded(false);
|
||||||
|
importFile(file, password.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
HBox contentBox = new HBox();
|
||||||
|
contentBox.setAlignment(Pos.TOP_RIGHT);
|
||||||
|
contentBox.setSpacing(20);
|
||||||
|
contentBox.getChildren().add(passwordField);
|
||||||
|
contentBox.getChildren().add(importEncryptedButton);
|
||||||
|
contentBox.setPadding(new Insets(10, 30, 10, 30));
|
||||||
|
contentBox.setPrefHeight(60);
|
||||||
|
|
||||||
|
return contentBox;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class ColdcardMultisig implements MultisigWalletImport, KeystoreFileImpor
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream) throws ImportException {
|
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||||
InputStreamReader reader = new InputStreamReader(inputStream);
|
InputStreamReader reader = new InputStreamReader(inputStream);
|
||||||
ColdcardKeystore cck = Storage.getStorage().getGson().fromJson(reader, ColdcardKeystore.class);
|
ColdcardKeystore cck = Storage.getStorage().getGson().fromJson(reader, ColdcardKeystore.class);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ public class ColdcardMultisig implements MultisigWalletImport, KeystoreFileImpor
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wallet importWallet(InputStream inputStream) throws ImportException {
|
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
|
||||||
Wallet wallet = new Wallet();
|
Wallet wallet = new Wallet();
|
||||||
wallet.setPolicyType(PolicyType.MULTI);
|
wallet.setPolicyType(PolicyType.MULTI);
|
||||||
|
|
||||||
|
@ -193,4 +193,9 @@ public class ColdcardMultisig implements MultisigWalletImport, KeystoreFileImpor
|
||||||
public String getWalletExportDescription() {
|
public String getWalletExportDescription() {
|
||||||
return "Export file that can be read by your Coldcard using the Settings > Multisig Wallets > Import from SD feature";
|
return "Export file that can be read by your Coldcard using the Settings > Multisig Wallets > Import from SD feature";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEncrypted(File file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -42,14 +43,14 @@ public class ColdcardSinglesig implements KeystoreFileImport, SinglesigWalletImp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream) throws ImportException {
|
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||||
Wallet wallet = importWallet(scriptType, inputStream);
|
Wallet wallet = importWallet(scriptType, inputStream, password);
|
||||||
|
|
||||||
return wallet.getKeystores().get(0);
|
return wallet.getKeystores().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wallet importWallet(ScriptType scriptType, InputStream inputStream) throws ImportException {
|
public Wallet importWallet(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||||
if(!ALLOWED_SCRIPT_TYPES.contains(scriptType)) {
|
if(!ALLOWED_SCRIPT_TYPES.contains(scriptType)) {
|
||||||
throw new ImportException("Script type of " + scriptType + " is not allowed");
|
throw new ImportException("Script type of " + scriptType + " is not allowed");
|
||||||
}
|
}
|
||||||
|
@ -104,4 +105,9 @@ public class ColdcardSinglesig implements KeystoreFileImport, SinglesigWalletImp
|
||||||
public String getWalletImportDescription() {
|
public String getWalletImportDescription() {
|
||||||
return "Import file created by using the Advanced > Dump Summary feature on your Coldcard";
|
return "Import file created by using the Advanced > Dump Summary feature on your Coldcard";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEncrypted(File file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.google.gson.reflect.TypeToken;
|
||||||
import com.sparrowwallet.drongo.ExtendedPublicKey;
|
import com.sparrowwallet.drongo.ExtendedPublicKey;
|
||||||
import com.sparrowwallet.drongo.KeyDerivation;
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.Utils;
|
import com.sparrowwallet.drongo.Utils;
|
||||||
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
import com.sparrowwallet.drongo.policy.Policy;
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
import com.sparrowwallet.drongo.policy.PolicyType;
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
@ -18,6 +19,7 @@ import java.lang.reflect.Type;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
public class Electrum implements KeystoreFileImport, SinglesigWalletImport, MultisigWalletImport, WalletExport {
|
public class Electrum implements KeystoreFileImport, SinglesigWalletImport, MultisigWalletImport, WalletExport {
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,8 +43,8 @@ public class Electrum implements KeystoreFileImport, SinglesigWalletImport, Mult
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream) throws ImportException {
|
public Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||||
Wallet wallet = importWallet(inputStream);
|
Wallet wallet = importWallet(inputStream, password);
|
||||||
|
|
||||||
if(!wallet.getPolicyType().equals(PolicyType.SINGLE) || wallet.getKeystores().size() != 1) {
|
if(!wallet.getPolicyType().equals(PolicyType.SINGLE) || wallet.getKeystores().size() != 1) {
|
||||||
throw new ImportException("Multisig wallet detected - import it using File > Import > Electrum");
|
throw new ImportException("Multisig wallet detected - import it using File > Import > Electrum");
|
||||||
|
@ -57,14 +59,25 @@ public class Electrum implements KeystoreFileImport, SinglesigWalletImport, Mult
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wallet importWallet(InputStream inputStream) throws ImportException {
|
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
|
||||||
InputStreamReader reader = new InputStreamReader(inputStream);
|
Reader reader;
|
||||||
|
if(password != null) {
|
||||||
|
ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512(password);
|
||||||
|
reader = new InputStreamReader(new InflaterInputStream(new ECIESInputStream(inputStream, decryptionKey)));
|
||||||
|
} else {
|
||||||
|
reader = new InputStreamReader(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
Type stringStringMap = new TypeToken<Map<String, JsonElement>>(){}.getType();
|
Type stringStringMap = new TypeToken<Map<String, JsonElement>>(){}.getType();
|
||||||
Map<String,JsonElement> map = gson.fromJson(reader, stringStringMap);
|
Map<String,JsonElement> map = gson.fromJson(reader, stringStringMap);
|
||||||
|
|
||||||
ElectrumJsonWallet ew = new ElectrumJsonWallet();
|
ElectrumJsonWallet ew = new ElectrumJsonWallet();
|
||||||
|
if(map.get("wallet_type") == null) {
|
||||||
|
throw new ImportException("This is not a valid Electrum wallet");
|
||||||
|
}
|
||||||
|
|
||||||
ew.wallet_type = map.get("wallet_type").getAsString();
|
ew.wallet_type = map.get("wallet_type").getAsString();
|
||||||
|
|
||||||
for(String key : map.keySet()) {
|
for(String key : map.keySet()) {
|
||||||
|
@ -137,9 +150,10 @@ public class Electrum implements KeystoreFileImport, SinglesigWalletImport, Mult
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wallet importWallet(ScriptType scriptType, InputStream inputStream) throws ImportException {
|
public Wallet importWallet(ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
|
||||||
Wallet wallet = importWallet(inputStream);
|
Wallet wallet = importWallet(inputStream, password);
|
||||||
wallet.setScriptType(scriptType);
|
wallet.setScriptType(scriptType);
|
||||||
|
//TODO: Check this usage results in a valid wallet
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
@ -189,6 +203,11 @@ public class Electrum implements KeystoreFileImport, SinglesigWalletImport, Mult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEncrypted(File file) {
|
||||||
|
return FileType.BINARY.equals(IOUtils.getFileType(file));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWalletExportDescription() {
|
public String getWalletExportDescription() {
|
||||||
return "Export this wallet as an Electrum wallet file";
|
return "Export this wallet as an Electrum wallet file";
|
||||||
|
|
5
src/main/java/com/sparrowwallet/sparrow/io/FileType.java
Normal file
5
src/main/java/com/sparrowwallet/sparrow/io/FileType.java
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
|
public enum FileType {
|
||||||
|
TEXT, JSON, BINARY, UNKNOWN;
|
||||||
|
}
|
24
src/main/java/com/sparrowwallet/sparrow/io/IOUtils.java
Normal file
24
src/main/java/com/sparrowwallet/sparrow/io/IOUtils.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
public class IOUtils {
|
||||||
|
public static FileType getFileType(File file) {
|
||||||
|
try {
|
||||||
|
String type = Files.probeContentType(file.toPath());
|
||||||
|
if (type == null) {
|
||||||
|
return FileType.BINARY;
|
||||||
|
} else if (type.equals("application/json")) {
|
||||||
|
return FileType.JSON;
|
||||||
|
} else if (type.startsWith("text")) {
|
||||||
|
return FileType.TEXT;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileType.UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,10 @@ package com.sparrowwallet.sparrow.io;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.wallet.Keystore;
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public interface KeystoreFileImport extends KeystoreImport {
|
public interface KeystoreFileImport extends KeystoreImport {
|
||||||
Keystore getKeystore(ScriptType scriptType, InputStream inputStream) throws ImportException;
|
boolean isEncrypted(File file);
|
||||||
|
Keystore getKeystore(ScriptType scriptType, InputStream inputStream, String password) throws ImportException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@ package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public interface MultisigWalletImport extends Import {
|
public interface MultisigWalletImport extends Import {
|
||||||
String getWalletImportDescription();
|
String getWalletImportDescription();
|
||||||
Wallet importWallet(InputStream inputStream) throws ImportException;
|
Wallet importWallet(InputStream inputStream, String password) throws ImportException;
|
||||||
|
boolean isEncrypted(File file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,11 @@ package com.sparrowwallet.sparrow.io;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public interface SinglesigWalletImport extends Import {
|
public interface SinglesigWalletImport extends Import {
|
||||||
String getWalletImportDescription();
|
String getWalletImportDescription();
|
||||||
Wallet importWallet(ScriptType scriptType, InputStream inputStream) throws ImportException;
|
Wallet importWallet(ScriptType scriptType, InputStream inputStream, String password) throws ImportException;
|
||||||
|
boolean isEncrypted(File file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,15 +51,31 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-label .text, .description-label Text {
|
.status-label .text, .description-label .text {
|
||||||
-fx-fill: #a0a1a7;
|
-fx-fill: #a0a1a7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-error .text, .description-error Text {
|
.status-error .text, .description-error .text {
|
||||||
-fx-fill: #ca1243;
|
-fx-fill: #ca1243;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description-label .text, description-error .text {
|
.description-label, .description-error {
|
||||||
|
-fx-border-width: 0px;
|
||||||
|
-fx-border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink {
|
||||||
|
-fx-padding: 0;
|
||||||
|
-fx-border-width: 0;
|
||||||
-fx-fill: #1e88cf;
|
-fx-fill: #1e88cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hyperlink:visited {
|
||||||
|
-fx-text-fill: #1e88cf;
|
||||||
|
-fx-underline: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hyperlink:hover:visited {
|
||||||
|
-fx-underline: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class ECIESInputStreamTest extends IoTest {
|
||||||
public void decrypt() throws ImportException {
|
public void decrypt() throws ImportException {
|
||||||
Electrum electrum = new Electrum();
|
Electrum electrum = new Electrum();
|
||||||
ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512("pass");
|
ECKey decryptionKey = ECKey.createKeyPbkdf2HmacSha512("pass");
|
||||||
Wallet wallet = electrum.importWallet(new InflaterInputStream(new ECIESInputStream(getInputStream("electrum-encrypted"), decryptionKey)));
|
Wallet wallet = electrum.importWallet(new InflaterInputStream(new ECIESInputStream(getInputStream("electrum-encrypted"), decryptionKey)), null);
|
||||||
|
|
||||||
Assert.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
|
Assert.assertEquals(PolicyType.SINGLE, wallet.getPolicyType());
|
||||||
Assert.assertEquals(ScriptType.P2WPKH, wallet.getScriptType());
|
Assert.assertEquals(ScriptType.P2WPKH, wallet.getScriptType());
|
||||||
|
|
Loading…
Reference in a new issue