From 300545b2896c5c9989758e72ce8ef83816e9b714 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 30 Jan 2023 14:47:00 +0200 Subject: [PATCH] refactor cardapi to generic service --- .../sparrowwallet/sparrow/AppServices.java | 1 - .../sparrow/control/CardImportPane.java | 19 ++--- .../sparrow/control/DevicePane.java | 25 +++--- .../sparrow/control/DeviceSignDialog.java | 4 - .../com/sparrowwallet/sparrow/io/CardApi.java | 78 +++++++++++++++++++ .../CardAuthorizationException.java | 2 +- .../sparrowwallet/sparrow/io/CardImport.java | 3 - .../{ckcard => }/CardSignFailedException.java | 2 +- .../CardUnluckyNumberException.java | 2 +- .../com/sparrowwallet/sparrow/io/Hwi.java | 22 +++--- .../sparrow/io/KeystoreCardImport.java | 3 +- .../sparrow/io/ckcard/CardProtocol.java | 2 + .../sparrow/io/ckcard/CardTransport.java | 2 + .../ckcard/{CardApi.java => CkCardApi.java} | 41 +++++++--- .../io/ckcard/{CkCard.java => Tapsigner.java} | 24 ++---- .../keystoreimport/HwAirgappedController.java | 6 +- .../sparrow/wallet/KeystoreController.java | 6 +- 17 files changed, 163 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/sparrowwallet/sparrow/io/CardApi.java rename src/main/java/com/sparrowwallet/sparrow/io/{ckcard => }/CardAuthorizationException.java (89%) rename src/main/java/com/sparrowwallet/sparrow/io/{ckcard => }/CardSignFailedException.java (89%) rename src/main/java/com/sparrowwallet/sparrow/io/{ckcard => }/CardUnluckyNumberException.java (89%) rename src/main/java/com/sparrowwallet/sparrow/io/ckcard/{CardApi.java => CkCardApi.java} (91%) rename src/main/java/com/sparrowwallet/sparrow/io/ckcard/{CkCard.java => Tapsigner.java} (80%) diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index 7cb39f57..0e3af4c9 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -14,7 +14,6 @@ import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.sparrow.control.WalletPasswordDialog; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; -import com.sparrowwallet.sparrow.io.ckcard.CardApi; import com.sparrowwallet.sparrow.net.Auth47; import com.sparrowwallet.drongo.protocol.BlockHeader; import com.sparrowwallet.drongo.protocol.ScriptType; diff --git a/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java index b69ee6ce..4b6c658e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/CardImportPane.java @@ -11,9 +11,10 @@ import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.event.KeystoreImportEvent; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.io.KeystoreCardImport; -import com.sparrowwallet.sparrow.io.ckcard.CardAuthorizationException; +import com.sparrowwallet.sparrow.io.CardAuthorizationException; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.concurrent.Service; import javafx.concurrent.Task; import javafx.geometry.Insets; @@ -81,10 +82,11 @@ public class CardImportPane extends TitledDescriptionPane { return; } - CardImportService cardImportService = new CardImportService(importer, pin.get(), derivation); - cardImportService.messageProperty().addListener((observable, oldValue, newValue) -> { - setDescription(newValue); + StringProperty messageProperty = new SimpleStringProperty(); + messageProperty.addListener((observable, oldValue, newValue) -> { + Platform.runLater(() -> setDescription(newValue)); }); + CardImportService cardImportService = new CardImportService(importer, pin.get(), derivation, messageProperty); cardImportService.setOnSucceeded(event -> { EventManager.get().post(new KeystoreImportEvent(cardImportService.getValue())); }); @@ -193,11 +195,13 @@ public class CardImportPane extends TitledDescriptionPane { private final KeystoreCardImport cardImport; private final String pin; private final List derivation; + private final StringProperty messageProperty; - public CardImportService(KeystoreCardImport cardImport, String pin, List derivation) { + public CardImportService(KeystoreCardImport cardImport, String pin, List derivation, StringProperty messageProperty) { this.cardImport = cardImport; this.pin = pin; this.derivation = derivation; + this.messageProperty = messageProperty; } @Override @@ -205,10 +209,7 @@ public class CardImportPane extends TitledDescriptionPane { return new Task<>() { @Override protected Keystore call() throws Exception { - cardImport.messageProperty().addListener((observable, oldValue, newValue) -> { - updateMessage(newValue); - }); - return cardImport.getKeystore(pin, derivation); + return cardImport.getKeystore(pin, derivation, messageProperty); } }; } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java index e02682ae..3b2699bb 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java @@ -14,13 +14,11 @@ import com.sparrowwallet.drongo.wallet.*; import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.event.*; +import com.sparrowwallet.sparrow.io.CardApi; import com.sparrowwallet.sparrow.io.Device; import com.sparrowwallet.sparrow.io.Hwi; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; -import com.sparrowwallet.sparrow.io.KeystoreCardImport; -import com.sparrowwallet.sparrow.io.ckcard.CardApi; -import com.sparrowwallet.sparrow.io.ckcard.CardAuthorizationException; -import com.sparrowwallet.sparrow.io.ckcard.CkCard; +import com.sparrowwallet.sparrow.io.CardAuthorizationException; import com.sparrowwallet.sparrow.net.ElectrumServer; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; @@ -579,19 +577,16 @@ public class DevicePane extends TitledDescriptionPane { private void importKeystore(List derivation) { if(device.isCard()) { try { - CkCard importer = new CkCard(); - if(!importer.isInitialized()) { + CardApi cardApi = CardApi.getCardApi(device.getModel(), pin.get()); + if(!cardApi.isInitialized()) { setDescription("Card not initialized"); - setContent(getCardInitializationPanel(importer)); + setContent(getCardInitializationPanel(cardApi)); showHideLink.setVisible(false); setExpanded(true); return; } - Service importService = new CardImportPane.CardImportService(importer, pin.get(), derivation); - importService.messageProperty().addListener((observable, oldValue, newValue) -> { - messageProperty.set(newValue); - }); + Service importService = cardApi.getImportService(derivation, messageProperty); handleCardOperation(importService, importButton, "Import", event -> { importKeystore(derivation, importService.getValue()); }); @@ -669,7 +664,7 @@ public class DevicePane extends TitledDescriptionPane { private void sign() { if(device.isCard()) { try { - CardApi cardApi = new CardApi(pin.get()); + CardApi cardApi = CardApi.getCardApi(device.getModel(), pin.get()); Service signService = cardApi.getSignService(wallet, psbt, messageProperty); handleCardOperation(signService, signButton, "Signing", event -> { EventManager.get().post(new PSBTSignedEvent(psbt, signService.getValue())); @@ -738,7 +733,7 @@ public class DevicePane extends TitledDescriptionPane { private void signMessage() { if(device.isCard()) { try { - CardApi cardApi = new CardApi(pin.get()); + CardApi cardApi = CardApi.getCardApi(device.getModel(), pin.get()); Service signMessageService = cardApi.getSignMessageService(message, wallet.getScriptType(), keyDerivation.getDerivation(), messageProperty); handleCardOperation(signMessageService, signMessageButton, "Signing", event -> { String signature = signMessageService.getValue(); @@ -889,7 +884,7 @@ public class DevicePane extends TitledDescriptionPane { return contentBox; } - private Node getCardInitializationPanel(KeystoreCardImport importer) { + private Node getCardInitializationPanel(CardApi cardApi) { VBox initTypeBox = new VBox(5); RadioButton automatic = new RadioButton("Automatic (Recommended)"); RadioButton advanced = new RadioButton("Advanced"); @@ -911,7 +906,7 @@ public class DevicePane extends TitledDescriptionPane { initializeButton.setDefaultButton(true); initializeButton.setOnAction(event -> { byte[] chainCode = toggleGroup.getSelectedToggle() == automatic ? null : Sha256Hash.hashTwice(entropy.getText().getBytes(StandardCharsets.UTF_8)); - CardImportPane.CardInitializationService cardInitializationService = new CardImportPane.CardInitializationService(importer, chainCode); + Service cardInitializationService = cardApi.getInitializationService(chainCode); cardInitializationService.setOnSucceeded(event1 -> { AppServices.showSuccessDialog("Card Initialized", "The card was successfully initialized.\n\nYou will now need to enter the PIN code found on the back. You can change the PIN code once it has been imported."); setDescription("Enter PIN code"); diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DeviceSignDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/DeviceSignDialog.java index 18f39c10..45a2ff6d 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DeviceSignDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DeviceSignDialog.java @@ -3,16 +3,12 @@ package com.sparrowwallet.sparrow.control; import com.google.common.eventbus.Subscribe; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.wallet.Wallet; -import com.sparrowwallet.drongo.wallet.WalletModel; import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.event.PSBTSignedEvent; import com.sparrowwallet.sparrow.io.Device; -import com.sparrowwallet.sparrow.io.ckcard.CardApi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.smartcardio.CardException; -import java.util.ArrayList; import java.util.List; public class DeviceSignDialog extends DeviceDialog { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java new file mode 100644 index 00000000..b7a3f3a4 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java @@ -0,0 +1,78 @@ +package com.sparrowwallet.sparrow.io; + +import com.sparrowwallet.drongo.crypto.ChildNumber; +import com.sparrowwallet.drongo.protocol.ScriptType; +import com.sparrowwallet.drongo.psbt.PSBT; +import com.sparrowwallet.drongo.wallet.Keystore; +import com.sparrowwallet.drongo.wallet.Wallet; +import com.sparrowwallet.drongo.wallet.WalletModel; +import com.sparrowwallet.sparrow.io.ckcard.CkCardApi; +import javafx.beans.property.StringProperty; +import javafx.concurrent.Service; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.smartcardio.CardException; +import javax.smartcardio.TerminalFactory; +import java.util.Collections; +import java.util.List; + +public abstract class CardApi { + private static final Logger log = LoggerFactory.getLogger(CardApi.class); + + public static List getConnectedCards() throws CardException { + try { + CkCardApi ckCardApi = new CkCardApi(null, null); + return List.of(ckCardApi.getCardType()); + } catch(Exception e) { + //ignore + } + + return Collections.emptyList(); + } + + public static CardApi getCardApi(WalletModel walletModel, String pin) throws CardException { + if(walletModel == WalletModel.TAPSIGNER || walletModel == WalletModel.SATSCARD) { + return new CkCardApi(walletModel, pin); + } + + throw new IllegalArgumentException("Cannot create card API for " + walletModel.toDisplayString()); + } + + public abstract boolean isInitialized() throws CardException; + + public abstract void initialize(byte[] entropy) throws CardException; + + public abstract WalletModel getCardType() throws CardException; + + public abstract Service getAuthDelayService() throws CardException; + + public abstract boolean requiresBackup() throws CardException; + + public abstract Service getBackupService(); + + public abstract boolean changePin(String newPin) throws CardException; + + public abstract Keystore getKeystore() throws CardException; + + public abstract Service getInitializationService(byte[] entropy); + + public abstract Service getImportService(List derivation, StringProperty messageProperty); + + public abstract Service getSignService(Wallet wallet, PSBT psbt, StringProperty messageProperty); + + public abstract Service getSignMessageService(String message, ScriptType scriptType, List derivation, StringProperty messageProperty); + + public abstract void disconnect(); + + public static boolean isReaderAvailable() { + try { + TerminalFactory tf = TerminalFactory.getDefault(); + return !tf.terminals().list().isEmpty(); + } catch(Exception e) { + log.error("Error detecting card terminals", e); + } + + return false; + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardAuthorizationException.java b/src/main/java/com/sparrowwallet/sparrow/io/CardAuthorizationException.java similarity index 89% rename from src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardAuthorizationException.java rename to src/main/java/com/sparrowwallet/sparrow/io/CardAuthorizationException.java index 4322f45d..8a9870a4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardAuthorizationException.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/CardAuthorizationException.java @@ -1,4 +1,4 @@ -package com.sparrowwallet.sparrow.io.ckcard; +package com.sparrowwallet.sparrow.io; import javax.smartcardio.CardException; diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CardImport.java b/src/main/java/com/sparrowwallet/sparrow/io/CardImport.java index 58f3c1f3..7dd8a527 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/CardImport.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/CardImport.java @@ -1,11 +1,8 @@ package com.sparrowwallet.sparrow.io; -import javafx.beans.property.StringProperty; - import javax.smartcardio.CardException; public interface CardImport extends ImportExport { boolean isInitialized() throws CardException; void initialize(byte[] chainCode) throws CardException; - StringProperty messageProperty(); } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardSignFailedException.java b/src/main/java/com/sparrowwallet/sparrow/io/CardSignFailedException.java similarity index 89% rename from src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardSignFailedException.java rename to src/main/java/com/sparrowwallet/sparrow/io/CardSignFailedException.java index 00fbb992..88cbeea3 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardSignFailedException.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/CardSignFailedException.java @@ -1,4 +1,4 @@ -package com.sparrowwallet.sparrow.io.ckcard; +package com.sparrowwallet.sparrow.io; import javax.smartcardio.CardException; diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardUnluckyNumberException.java b/src/main/java/com/sparrowwallet/sparrow/io/CardUnluckyNumberException.java similarity index 89% rename from src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardUnluckyNumberException.java rename to src/main/java/com/sparrowwallet/sparrow/io/CardUnluckyNumberException.java index 32a39339..7ff2b08b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardUnluckyNumberException.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/CardUnluckyNumberException.java @@ -1,4 +1,4 @@ -package com.sparrowwallet.sparrow.io.ckcard; +package com.sparrowwallet.sparrow.io; import javax.smartcardio.CardException; diff --git a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java index a815ebb5..d017801a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/Hwi.java @@ -10,7 +10,6 @@ import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTParseException; import com.sparrowwallet.drongo.wallet.StandardAccount; import com.sparrowwallet.drongo.wallet.WalletModel; -import com.sparrowwallet.sparrow.io.ckcard.CardApi; import javafx.concurrent.ScheduledService; import javafx.concurrent.Service; import javafx.concurrent.Task; @@ -98,16 +97,19 @@ public class Hwi { List devices = new ArrayList<>(); if(CardApi.isReaderAvailable()) { try { - CardApi cardApi = new CardApi(null); - WalletModel walletModel = cardApi.getCardType(); + List connectedCards = CardApi.getConnectedCards(); + for(WalletModel card : connectedCards) { + CardApi cardApi = CardApi.getCardApi(card, null); + WalletModel walletModel = cardApi.getCardType(); - Device cardDevice = new Device(); - cardDevice.setType(walletModel.getType()); - cardDevice.setModel(walletModel); - cardDevice.setNeedsPassphraseSent(Boolean.FALSE); - cardDevice.setNeedsPinSent(Boolean.FALSE); - cardDevice.setCard(true); - devices.add(cardDevice); + Device cardDevice = new Device(); + cardDevice.setType(walletModel.getType()); + cardDevice.setModel(walletModel); + cardDevice.setNeedsPassphraseSent(Boolean.FALSE); + cardDevice.setNeedsPinSent(Boolean.FALSE); + cardDevice.setCard(true); + devices.add(cardDevice); + } } catch(CardNotPresentException e) { //ignore } catch(CardException e) { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java index 05d36ea6..090e19db 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/KeystoreCardImport.java @@ -2,10 +2,11 @@ package com.sparrowwallet.sparrow.io; import com.sparrowwallet.drongo.crypto.ChildNumber; import com.sparrowwallet.drongo.wallet.Keystore; +import javafx.beans.property.StringProperty; import java.util.List; public interface KeystoreCardImport extends CardImport { - Keystore getKeystore(String pin, List derivation) throws ImportException; + Keystore getKeystore(String pin, List derivation, StringProperty messageProperty) throws ImportException; String getKeystoreImportDescription(int account); } diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardProtocol.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardProtocol.java index beb301e9..96ca9c70 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardProtocol.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardProtocol.java @@ -6,6 +6,8 @@ import com.sparrowwallet.drongo.crypto.ChildNumber; import com.sparrowwallet.drongo.crypto.ECDSASignature; import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.protocol.Sha256Hash; +import com.sparrowwallet.sparrow.io.CardSignFailedException; +import com.sparrowwallet.sparrow.io.CardUnluckyNumberException; import org.bitcoin.NativeSecp256k1; import org.bitcoin.NativeSecp256k1Util; import org.bitcoin.Secp256k1Context; diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardTransport.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardTransport.java index 4bce8a7d..c65c7ce1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardTransport.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardTransport.java @@ -12,6 +12,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.sparrowwallet.drongo.Utils; +import com.sparrowwallet.sparrow.io.CardAuthorizationException; +import com.sparrowwallet.sparrow.io.CardUnluckyNumberException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java similarity index 91% rename from src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardApi.java rename to src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java index 6fa78d7c..0b90ec04 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CardApi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java @@ -10,6 +10,8 @@ import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTInput; import com.sparrowwallet.drongo.psbt.PSBTInputSigner; import com.sparrowwallet.drongo.wallet.*; +import com.sparrowwallet.sparrow.control.CardImportPane; +import com.sparrowwallet.sparrow.io.CardApi; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; @@ -24,33 +26,36 @@ import java.util.List; import java.util.Map; import java.util.Optional; -public class CardApi { - private static final Logger log = LoggerFactory.getLogger(CardApi.class); +public class CkCardApi extends CardApi { + private static final Logger log = LoggerFactory.getLogger(CkCardApi.class); private final WalletModel cardType; private final CardProtocol cardProtocol; private String cvc; - public CardApi(String cvc) throws CardException { + public CkCardApi(String cvc) throws CardException { this(WalletModel.TAPSIGNER, cvc); } - public CardApi(WalletModel cardType, String cvc) throws CardException { + public CkCardApi(WalletModel cardType, String cvc) throws CardException { this.cardType = cardType; this.cardProtocol = new CardProtocol(); this.cvc = cvc; } + @Override public boolean isInitialized() throws CardException { CardStatus cardStatus = getStatus(); return cardStatus.isInitialized(); } + @Override public void initialize(byte[] chainCode) throws CardException { cardProtocol.verify(); cardProtocol.setup(cvc, chainCode); } + @Override public WalletModel getCardType() throws CardException { CardStatus cardStatus = getStatus(); return cardStatus.getCardType(); @@ -58,7 +63,7 @@ public class CardApi { CardStatus getStatus() throws CardException { CardStatus cardStatus = cardProtocol.getStatus(); - if(cardStatus.getCardType() != cardType) { + if(cardType != null && cardStatus.getCardType() != cardType) { throw new CardException("Please use a " + cardType.toDisplayString() + " card."); } return cardStatus; @@ -78,6 +83,7 @@ public class CardApi { } } + @Override public Service getAuthDelayService() throws CardException { CardStatus cardStatus = getStatus(); if(cardStatus.auth_delay != null) { @@ -87,11 +93,13 @@ public class CardApi { return null; } + @Override public boolean requiresBackup() throws CardException { CardStatus cardStatus = getStatus(); return cardStatus.requiresBackup(); } + @Override public Service getBackupService() { return new BackupService(); } @@ -101,6 +109,7 @@ public class CardApi { return Utils.bytesToHex(cardBackup.data); } + @Override public boolean changePin(String newCvc) throws CardException { CardChange cardChange = cardProtocol.change(cvc, newCvc); if(cardChange.success) { @@ -110,10 +119,21 @@ public class CardApi { return cardChange.success; } - public void setDerivation(List derivation) throws CardException { + void setDerivation(List derivation) throws CardException { cardProtocol.derive(cvc, derivation); } + @Override + public Service getInitializationService(byte[] entropy) { + return new CardImportPane.CardInitializationService(new Tapsigner(), entropy); + } + + @Override + public Service getImportService(List derivation, StringProperty messageProperty) { + return new CardImportPane.CardImportService(new Tapsigner(), cvc, derivation, messageProperty); + } + + @Override public Keystore getKeystore() throws CardException { KeyDerivation keyDerivation = getKeyDerivation(); @@ -141,6 +161,7 @@ public class CardApi { return Utils.bytesToHex(masterXpubkey.getKey().getFingerprint()); } + @Override public Service getSignService(Wallet wallet, PSBT psbt, StringProperty messageProperty) { return new SignService(wallet, psbt, messageProperty); } @@ -183,6 +204,7 @@ public class CardApi { } } + @Override public Service getSignMessageService(String message, ScriptType scriptType, List derivation, StringProperty messageProperty) { return new SignMessageService(message, scriptType, derivation, messageProperty); } @@ -217,6 +239,7 @@ public class CardApi { } } + @Override public void disconnect() { try { cardProtocol.disconnect(); @@ -225,10 +248,6 @@ public class CardApi { } } - public static boolean isReaderAvailable() { - return CardTransport.isReaderAvailable(); - } - public class AuthDelayService extends Service { private final CardStatus cardStatus; private final IntegerProperty delayProperty; @@ -303,7 +322,7 @@ public class CardApi { @Override public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { if(signatureType != TransactionSignature.Type.ECDSA) { - throw new IllegalStateException(cardType.toDisplayString() + " cannot sign " + signatureType + " transactions."); + throw new IllegalStateException(WalletModel.TAPSIGNER.toDisplayString() + " cannot sign " + signatureType + " transactions."); } try { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCard.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java similarity index 80% rename from src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCard.java rename to src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java index c931de11..918ff41f 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCard.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/Tapsigner.java @@ -6,20 +6,17 @@ import com.sparrowwallet.drongo.wallet.WalletModel; import com.sparrowwallet.sparrow.io.KeystoreCardImport; import com.sparrowwallet.sparrow.io.ImportException; import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javax.smartcardio.CardException; import java.util.List; -public class CkCard implements KeystoreCardImport { - private final StringProperty messageProperty = new SimpleStringProperty(""); - +public class Tapsigner implements KeystoreCardImport { @Override public boolean isInitialized() throws CardException { - CardApi cardApi = null; + CkCardApi cardApi = null; try { - cardApi = new CardApi(null); + cardApi = new CkCardApi(null); return cardApi.isInitialized(); } finally { if(cardApi != null) { @@ -30,9 +27,9 @@ public class CkCard implements KeystoreCardImport { @Override public void initialize(byte[] chainCode) throws CardException { - CardApi cardApi = null; + CkCardApi cardApi = null; try { - cardApi = new CardApi(null); + cardApi = new CkCardApi(null); cardApi.initialize(chainCode); } finally { if(cardApi != null) { @@ -42,7 +39,7 @@ public class CkCard implements KeystoreCardImport { } @Override - public Keystore getKeystore(String pin, List derivation) throws ImportException { + public Keystore getKeystore(String pin, List derivation, StringProperty messageProperty) throws ImportException { if(pin.length() < 6) { throw new ImportException("PIN too short."); } @@ -51,9 +48,9 @@ public class CkCard implements KeystoreCardImport { throw new ImportException("PIN too long."); } - CardApi cardApi = null; + CkCardApi cardApi = null; try { - cardApi = new CardApi(pin); + cardApi = new CkCardApi(pin); CardStatus cardStatus = cardApi.getStatus(); if(!cardStatus.isInitialized()) { throw new IllegalStateException("Card is not initialized."); @@ -87,9 +84,4 @@ public class CkCard implements KeystoreCardImport { public WalletModel getWalletModel() { return WalletModel.TAPSIGNER; } - - @Override - public StringProperty messageProperty() { - return messageProperty; - } } diff --git a/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java b/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java index b2f838b3..9bf251b6 100644 --- a/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java +++ b/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java @@ -5,7 +5,7 @@ import com.sparrowwallet.sparrow.control.CardImportPane; import com.sparrowwallet.sparrow.control.FileKeystoreImportPane; import com.sparrowwallet.sparrow.control.TitledDescriptionPane; import com.sparrowwallet.sparrow.io.*; -import com.sparrowwallet.sparrow.io.ckcard.CkCard; +import com.sparrowwallet.sparrow.io.ckcard.Tapsigner; import javafx.fxml.FXML; import javafx.scene.control.Accordion; import org.slf4j.Logger; @@ -15,7 +15,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import static com.sparrowwallet.sparrow.io.ckcard.CardApi.isReaderAvailable; +import static com.sparrowwallet.sparrow.io.CardApi.isReaderAvailable; public class HwAirgappedController extends KeystoreImportDetailController { private static final Logger log = LoggerFactory.getLogger(HwAirgappedController.class); @@ -42,7 +42,7 @@ public class HwAirgappedController extends KeystoreImportDetailController { List cardImporters = Collections.emptyList(); if(isReaderAvailable()) { - cardImporters = List.of(new CkCard()); + cardImporters = List.of(new Tapsigner()); } for(KeystoreCardImport importer : cardImporters) { if(!importer.isDeprecated() || Config.get().isShowDeprecatedImportExport()) { diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java b/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java index 8e8fdb18..d0d54e60 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/KeystoreController.java @@ -9,8 +9,8 @@ import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.event.*; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands; +import com.sparrowwallet.sparrow.io.CardApi; import com.sparrowwallet.sparrow.io.Storage; -import com.sparrowwallet.sparrow.io.ckcard.CardApi; import com.sparrowwallet.sparrow.keystoreimport.KeystoreImportDialog; import javafx.application.Platform; import javafx.concurrent.Service; @@ -37,7 +37,7 @@ import java.util.Optional; import java.util.ResourceBundle; import java.util.stream.Collectors; -import static com.sparrowwallet.sparrow.io.ckcard.CardApi.isReaderAvailable; +import static com.sparrowwallet.sparrow.io.CardApi.isReaderAvailable; public class KeystoreController extends WalletFormController implements Initializable { private static final Logger log = LoggerFactory.getLogger(KeystoreController.class); @@ -427,7 +427,7 @@ public class KeystoreController extends WalletFormController implements Initiali String newPin = optPinChange.get().newPin(); boolean backupFirst = optPinChange.get().backupFirst(); try { - CardApi cardApi = new CardApi(currentPin); + CardApi cardApi = CardApi.getCardApi(keystore.getWalletModel(), currentPin); Service authDelayService = cardApi.getAuthDelayService(); if(authDelayService != null) { authDelayService.setOnSucceeded(event1 -> {