refactor cardapi to generic service

This commit is contained in:
Craig Raw 2023-01-30 14:47:00 +02:00
parent 057a9efb1f
commit 300545b289
17 changed files with 163 additions and 79 deletions

View file

@ -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;

View file

@ -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<ChildNumber> derivation;
private final StringProperty messageProperty;
public CardImportService(KeystoreCardImport cardImport, String pin, List<ChildNumber> derivation) {
public CardImportService(KeystoreCardImport cardImport, String pin, List<ChildNumber> 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);
}
};
}

View file

@ -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<ChildNumber> 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<Keystore> importService = new CardImportPane.CardImportService(importer, pin.get(), derivation);
importService.messageProperty().addListener((observable, oldValue, newValue) -> {
messageProperty.set(newValue);
});
Service<Keystore> 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<PSBT> 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<String> 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<Void> 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");

View file

@ -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<PSBT> {

View file

@ -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<WalletModel> 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<Void> getAuthDelayService() throws CardException;
public abstract boolean requiresBackup() throws CardException;
public abstract Service<String> getBackupService();
public abstract boolean changePin(String newPin) throws CardException;
public abstract Keystore getKeystore() throws CardException;
public abstract Service<Void> getInitializationService(byte[] entropy);
public abstract Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty);
public abstract Service<PSBT> getSignService(Wallet wallet, PSBT psbt, StringProperty messageProperty);
public abstract Service<String> getSignMessageService(String message, ScriptType scriptType, List<ChildNumber> 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;
}
}

View file

@ -1,4 +1,4 @@
package com.sparrowwallet.sparrow.io.ckcard;
package com.sparrowwallet.sparrow.io;
import javax.smartcardio.CardException;

View file

@ -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();
}

View file

@ -1,4 +1,4 @@
package com.sparrowwallet.sparrow.io.ckcard;
package com.sparrowwallet.sparrow.io;
import javax.smartcardio.CardException;

View file

@ -1,4 +1,4 @@
package com.sparrowwallet.sparrow.io.ckcard;
package com.sparrowwallet.sparrow.io;
import javax.smartcardio.CardException;

View file

@ -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<Device> devices = new ArrayList<>();
if(CardApi.isReaderAvailable()) {
try {
CardApi cardApi = new CardApi(null);
WalletModel walletModel = cardApi.getCardType();
List<WalletModel> 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) {

View file

@ -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<ChildNumber> derivation) throws ImportException;
Keystore getKeystore(String pin, List<ChildNumber> derivation, StringProperty messageProperty) throws ImportException;
String getKeystoreImportDescription(int account);
}

View file

@ -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;

View file

@ -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;

View file

@ -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<Void> 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<String> 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<ChildNumber> derivation) throws CardException {
void setDerivation(List<ChildNumber> derivation) throws CardException {
cardProtocol.derive(cvc, derivation);
}
@Override
public Service<Void> getInitializationService(byte[] entropy) {
return new CardImportPane.CardInitializationService(new Tapsigner(), entropy);
}
@Override
public Service<Keystore> getImportService(List<ChildNumber> 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<PSBT> getSignService(Wallet wallet, PSBT psbt, StringProperty messageProperty) {
return new SignService(wallet, psbt, messageProperty);
}
@ -183,6 +204,7 @@ public class CardApi {
}
}
@Override
public Service<String> getSignMessageService(String message, ScriptType scriptType, List<ChildNumber> 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<Void> {
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 {

View file

@ -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<ChildNumber> derivation) throws ImportException {
public Keystore getKeystore(String pin, List<ChildNumber> 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;
}
}

View file

@ -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<KeystoreCardImport> 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()) {

View file

@ -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<Void> authDelayService = cardApi.getAuthDelayService();
if(authDelayService != null) {
authDelayService.setOnSucceeded(event1 -> {