integrate keystore importer

This commit is contained in:
Craig Raw 2020-05-09 14:17:48 +02:00
parent 9af17bcac8
commit 6872e069a9
5 changed files with 75 additions and 8 deletions

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.io;
import com.google.gson.*;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.wallet.Wallet;
@ -22,7 +23,9 @@ public class Storage {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(ExtendedKey.class, new ExtendedPublicKeySerializer());
gsonBuilder.registerTypeAdapter(ExtendedKey.class, new ExtendedPublicKeyDeserializer());
gson = gsonBuilder.setPrettyPrinting().create();
gsonBuilder.registerTypeAdapter(byte[].class, new ByteArraySerializer());
gsonBuilder.registerTypeAdapter(byte[].class, new ByteArrayDeserializer());
gson = gsonBuilder.setPrettyPrinting().disableHtmlEscaping().create();
}
public static Storage getStorage() {
@ -76,7 +79,7 @@ public class Storage {
}
private static byte[] getEncryptionMagic() {
return "BIE1".getBytes(StandardCharsets.UTF_8);
return "SPRW1".getBytes(StandardCharsets.UTF_8);
}
public File getWalletFile(String walletName) {
@ -84,7 +87,12 @@ public class Storage {
}
public File getWalletsDir() {
return new File(getSparrowDir(), WALLETS_DIR);
File walletsDir = new File(getSparrowDir(), WALLETS_DIR);
if(!walletsDir.exists()) {
walletsDir.mkdirs();
}
return walletsDir;
}
private File getSparrowDir() {
@ -108,4 +116,18 @@ public class Storage {
return ExtendedKey.fromDescriptor(json.getAsJsonPrimitive().getAsString());
}
}
private static class ByteArraySerializer implements JsonSerializer<byte[]> {
@Override
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(Utils.bytesToHex(src));
}
}
private static class ByteArrayDeserializer implements JsonDeserializer<byte[]> {
@Override
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return Utils.hexToBytes(json.getAsJsonPrimitive().getAsString());
}
}
}

View file

@ -43,7 +43,7 @@ public class KeystoreImportDialog extends Dialog<Keystore> {
@Subscribe
public void keystoreImported(KeystoreImportEvent event) {
this.keystore = event.getKeystore();
System.out.println(keystore.getLabel() + " " + keystore.getKeyDerivation().getMasterFingerprint());
setResult(keystore);
this.close();
}
}

View file

@ -4,6 +4,7 @@ import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.keystoreimport.KeystoreImportDialog;
import com.sparrowwallet.sparrow.event.SettingsChangedEvent;
@ -12,6 +13,7 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import org.controlsfx.validation.ValidationResult;
@ -27,6 +29,9 @@ import java.util.stream.Collectors;
public class KeystoreController extends WalletFormController implements Initializable {
private Keystore keystore;
@FXML
private Label type;
@FXML
private TextField label;
@ -55,6 +60,8 @@ public class KeystoreController extends WalletFormController implements Initiali
public void initializeView() {
Platform.runLater(this::setupValidation);
updateType();
label.setText(keystore.getLabel());
if(keystore.getExtendedPublicKey() != null) {
@ -102,7 +109,7 @@ public class KeystoreController extends WalletFormController implements Initiali
validationSupport.registerValidator(label, Validator.combine(
Validator.createEmptyValidator("Label is required"),
(Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Label is not unique", walletForm.getWallet().getKeystores().stream().filter(k -> k != keystore).map(Keystore::getLabel).collect(Collectors.toList()).contains(newValue)),
(Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Label is too long", newValue.length() > 16)
(Control c, String newValue) -> ValidationResult.fromErrorIf( c, "Label is too long", newValue.replace(" ", "").length() > 16)
));
validationSupport.registerValidator(xpub, Validator.combine(
@ -123,11 +130,43 @@ public class KeystoreController extends WalletFormController implements Initiali
validationSupport.setValidationDecorator(new StyleClassValidationDecoration());
}
private void updateType() {
type.setText(getTypeLabel(keystore));
boolean editable = (keystore.getSource() == KeystoreSource.SW_WATCH);
label.setEditable(editable);
fingerprint.setEditable(editable);
derivation.setEditable(editable);
xpub.setEditable(editable);
}
private String getTypeLabel(Keystore keystore) {
switch (keystore.getSource()) {
case HW_USB:
return "Connected Hardware Wallet (" + keystore.getWalletModel().toDisplayString() + ")";
case HW_AIRGAPPED:
return "Airgapped Hardware Wallet (" + keystore.getWalletModel().toDisplayString() + ")";
case SW_SEED:
return "Software Wallet";
case SW_WATCH:
default:
return "Software Wallet (Watch Only)";
}
}
public void importKeystore(ActionEvent event) {
KeystoreImportDialog dlg = new KeystoreImportDialog(getWalletForm().getWallet());
Optional<Keystore> result = dlg.showAndWait();
if(result.isPresent()) {
Keystore keystore = result.get();
Keystore importedKeystore = result.get();
keystore.setSource(importedKeystore.getSource());
keystore.setWalletModel(importedKeystore.getWalletModel());
keystore.setLabel(importedKeystore.getLabel());
keystore.setKeyDerivation(importedKeystore.getKeyDerivation());
keystore.setExtendedPublicKey(importedKeystore.getExtendedPublicKey());
keystore.setSeed(importedKeystore.getSeed());
updateType();
label.setText(keystore.getLabel());
fingerprint.setText(keystore.getKeyDerivation().getMasterFingerprint());
derivation.setText(keystore.getKeyDerivation().getDerivationPath());

View file

@ -89,9 +89,12 @@ public class SettingsController extends WalletFormController implements Initiali
multisigFieldset.setVisible(policyType.equals(PolicyType.MULTI));
if(policyType.equals(PolicyType.MULTI)) {
totalKeystores.unbind();
totalKeystores.set(0);
totalKeystores.bind(multisigControl.highValueProperty());
} else {
totalKeystores.unbind();
totalKeystores.set(0);
totalKeystores.set(1);
}
});

View file

@ -16,11 +16,14 @@
</padding>
<Form GridPane.columnIndex="0" GridPane.rowIndex="0">
<Fieldset inputGrow="SOMETIMES" text="">
<Field text="Label:">
<TextField fx:id="label" maxWidth="160"/>
<Field text="Type:">
<Label fx:id="type"/>
<Pane HBox.hgrow="ALWAYS" />
<Button text="Import..." onAction="#importKeystore"/>
</Field>
<Field text="Label:">
<TextField fx:id="label" maxWidth="160"/>
</Field>
<Field text="Master fingerprint:">
<TextField fx:id="fingerprint" maxWidth="80"/>
</Field>