add coldcard single sig wallet import

This commit is contained in:
Craig Raw 2020-08-24 12:05:32 +02:00
parent 750f6483cb
commit f95cb67912
4 changed files with 129 additions and 5 deletions

View file

@ -770,6 +770,18 @@ public class AppController implements Initializable {
if(optionalWallet.isPresent()) { if(optionalWallet.isPresent()) {
Wallet wallet = optionalWallet.get(); Wallet wallet = optionalWallet.get();
File walletFile = Storage.getWalletFile(wallet.getName()); File walletFile = Storage.getWalletFile(wallet.getName());
if(walletFile.exists()) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Existing wallet found");
alert.setHeaderText("Replace existing wallet?");
alert.setContentText("Wallet file " + wallet.getName() + " already exists");
Optional<ButtonType> result = alert.showAndWait();
if(result.isPresent() && result.get() == ButtonType.CANCEL) {
return;
}
}
Storage storage = new Storage(walletFile); Storage storage = new Storage(walletFile);
Tab tab = addWalletTab(storage, wallet); Tab tab = addWalletTab(storage, wallet);
tabs.getSelectionModel().select(tab); tabs.getSelectionModel().select(tab);

View file

@ -28,7 +28,7 @@ public abstract class FileImportPane extends TitledDescriptionPane {
private static final Logger log = LoggerFactory.getLogger(FileImportPane.class); private static final Logger log = LoggerFactory.getLogger(FileImportPane.class);
private final FileImport importer; private final FileImport importer;
private Button importButton; protected Button importButton;
private final SimpleStringProperty password = new SimpleStringProperty(""); private final SimpleStringProperty password = new SimpleStringProperty("");
public FileImportPane(FileImport importer, String title, String description, String content, String imageUrl) { public FileImportPane(FileImport importer, String title, String description, String content, String imageUrl) {

View file

@ -0,0 +1,106 @@
package com.sparrowwallet.sparrow.control;
import com.google.common.io.ByteStreams;
import com.google.gson.JsonParseException;
import com.sparrowwallet.drongo.policy.Policy;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletImportEvent;
import com.sparrowwallet.sparrow.io.ImportException;
import com.sparrowwallet.sparrow.io.KeystoreFileImport;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileWalletKeystoreImportPane extends FileImportPane {
private static final Logger log = LoggerFactory.getLogger(FileWalletKeystoreImportPane.class);
private final KeystoreFileImport importer;
private String fileName;
private byte[] fileBytes;
public FileWalletKeystoreImportPane(KeystoreFileImport importer) {
super(importer, importer.getName(), "Wallet file import", importer.getKeystoreImportDescription(), "image/" + importer.getWalletModel().getType() + ".png");
this.importer = importer;
}
protected void importFile(String fileName, InputStream inputStream, String password) throws ImportException {
this.fileName = fileName;
try {
fileBytes = ByteStreams.toByteArray(inputStream);
} catch(IOException e) {
throw new ImportException("Could not read file", e);
}
setContent(getScriptTypeEntry());
setExpanded(true);
importButton.setDisable(true);
}
private void importWallet(ScriptType scriptType) throws ImportException {
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
Keystore keystore = importer.getKeystore(scriptType, bais, "");
Wallet wallet = new Wallet();
wallet.setName(fileName);
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setScriptType(scriptType);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, scriptType, wallet.getKeystores(), null));
EventManager.get().post(new WalletImportEvent(wallet));
}
private Node getScriptTypeEntry() {
Label label = new Label("Script Type:");
ComboBox<ScriptType> scriptTypeComboBox = new ComboBox<>(FXCollections.observableArrayList(ScriptType.getAddressableScriptTypes(PolicyType.SINGLE)));
scriptTypeComboBox.setValue(ScriptType.P2WPKH);
Region region = new Region();
HBox.setHgrow(region, Priority.SOMETIMES);
Button importFileButton = new Button("Import");
importFileButton.setOnAction(event -> {
showHideLink.setVisible(true);
setExpanded(false);
try {
importWallet(scriptTypeComboBox.getValue());
} catch(ImportException e) {
log.error("Error importing file", e);
String errorMessage = e.getMessage();
if(e.getCause() instanceof JsonParseException) {
errorMessage = "File was not in JSON format";
} else if(e.getCause() != null && e.getCause().getMessage() != null && !e.getCause().getMessage().isEmpty()) {
errorMessage = e.getCause().getMessage();
}
setError("Import Error", errorMessage);
importButton.setDisable(false);
}
});
HBox contentBox = new HBox();
contentBox.setAlignment(Pos.CENTER_RIGHT);
contentBox.setSpacing(20);
contentBox.getChildren().addAll(label, scriptTypeComboBox, region, importFileButton);
contentBox.setPadding(new Insets(10, 30, 10, 30));
contentBox.setPrefHeight(60);
return contentBox;
}
}

View file

@ -29,16 +29,22 @@ public class WalletImportDialog extends Dialog<Wallet> {
stackPane.getChildren().add(anchorPane); stackPane.getChildren().add(anchorPane);
ScrollPane scrollPane = new ScrollPane(); ScrollPane scrollPane = new ScrollPane();
scrollPane.setPrefHeight(280); scrollPane.setPrefHeight(320);
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
anchorPane.getChildren().add(scrollPane); anchorPane.getChildren().add(scrollPane);
scrollPane.setFitToWidth(true); scrollPane.setFitToWidth(true);
AnchorPane.setLeftAnchor(scrollPane, 0.0); AnchorPane.setLeftAnchor(scrollPane, 0.0);
AnchorPane.setRightAnchor(scrollPane, 0.0); AnchorPane.setRightAnchor(scrollPane, 0.0);
List<WalletImport> importers = List.of(new ColdcardMultisig(), new Electrum());
Accordion importAccordion = new Accordion(); Accordion importAccordion = new Accordion();
for(WalletImport importer : importers) { List<KeystoreFileImport> keystoreImporters = List.of(new ColdcardSinglesig());
for(KeystoreFileImport importer : keystoreImporters) {
FileWalletKeystoreImportPane importPane = new FileWalletKeystoreImportPane(importer);
importAccordion.getPanes().add(importPane);
}
List<WalletImport> walletImporters = List.of(new ColdcardMultisig(), new Electrum());
for(WalletImport importer : walletImporters) {
FileWalletImportPane importPane = new FileWalletImportPane(importer); FileWalletImportPane importPane = new FileWalletImportPane(importer);
importAccordion.getPanes().add(importPane); importAccordion.getPanes().add(importPane);
} }
@ -47,7 +53,7 @@ public class WalletImportDialog extends Dialog<Wallet> {
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE); final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
dialogPane.getButtonTypes().addAll(cancelButtonType); dialogPane.getButtonTypes().addAll(cancelButtonType);
dialogPane.setPrefWidth(500); dialogPane.setPrefWidth(500);
dialogPane.setPrefHeight(360); dialogPane.setPrefHeight(400);
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? wallet : null); setResultConverter(dialogButton -> dialogButton != cancelButtonType ? wallet : null);
} }