diff --git a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java index 39350e45..6d6c9551 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/DevicePane.java @@ -45,6 +45,7 @@ import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.IntStream; public class DevicePane extends TitledDescriptionPane { private static final Logger log = LoggerFactory.getLogger(DevicePane.class); @@ -67,7 +68,7 @@ public class DevicePane extends TitledDescriptionPane { private Button displayAddressButton; private Button signMessageButton; private Button discoverKeystoresButton; - private Button getPrivateKeyButton; + private ButtonBase getPrivateKeyButton; private Button getAddressButton; private final SimpleStringProperty passphrase = new SimpleStringProperty(""); @@ -218,7 +219,7 @@ public class DevicePane extends TitledDescriptionPane { setDefaultStatus(); showHideLink.setVisible(false); - Button button; + ButtonBase button; if(deviceOperation == DeviceOperation.GET_PRIVATE_KEY) { createGetPrivateKeyButton(); button = getPrivateKeyButton; @@ -382,12 +383,44 @@ public class DevicePane extends TitledDescriptionPane { } private void createGetPrivateKeyButton() { - getPrivateKeyButton = new Button("Get Private Key"); + int currentSlot = 0; + boolean initialized = true; + try { + CardApi cardApi = CardApi.getCardApi(device.getModel(), null); + currentSlot = cardApi.getCurrentSlot(); + initialized = cardApi.isInitialized(); + } catch(Exception e) { + //ignore + } + + getPrivateKeyButton = currentSlot > 0 ? new SplitMenuButton() : new Button(); getPrivateKeyButton.setAlignment(Pos.CENTER_RIGHT); + getPrivateKeyButton.setText("Get Private Key"); getPrivateKeyButton.setOnAction(event -> { getPrivateKeyButton.setDisable(true); - getPrivateKey(); + getPrivateKey(null); }); + + if(getPrivateKeyButton instanceof SplitMenuButton getPrivateKeyMenuButton) { + int[] previousSlots = IntStream.range(0, currentSlot).toArray(); + for(int previousSlot : previousSlots) { + MenuItem previousSlotItem = new MenuItem("Slot #" + previousSlot); + previousSlotItem.setOnAction(event -> { + getPrivateKeyButton.setDisable(true); + getPrivateKey(previousSlot); + }); + getPrivateKeyMenuButton.getItems().add(previousSlotItem); + } + if(initialized) { + int finalSlot = currentSlot; + MenuItem currentSlotItem = new MenuItem("Current Slot"); + currentSlotItem.setOnAction(event -> { + getPrivateKeyButton.setDisable(true); + getPrivateKey(finalSlot); + }); + getPrivateKeyMenuButton.getItems().add(currentSlotItem); + } + } getPrivateKeyButton.managedProperty().bind(getPrivateKeyButton.visibleProperty()); getPrivateKeyButton.setVisible(false); } @@ -886,11 +919,11 @@ public class DevicePane extends TitledDescriptionPane { getXpubsService.start(); } - private void getPrivateKey() { + private void getPrivateKey(Integer slot) { if(device.isCard()) { try { CardApi cardApi = CardApi.getCardApi(device.getModel(), pin.get()); - Service privateKeyService = cardApi.getPrivateKeyService(messageProperty); + Service privateKeyService = cardApi.getPrivateKeyService(slot, messageProperty); handleCardOperation(privateKeyService, getPrivateKeyButton, "Private Key", true, event -> { EventManager.get().post(new DeviceGetPrivateKeyEvent(privateKeyService.getValue(), cardApi.getDefaultScriptType())); }); @@ -962,7 +995,9 @@ public class DevicePane extends TitledDescriptionPane { discoverKeystoresButton.setVisible(true); showHideLink.setVisible(false); } else if(deviceOperation.equals(DeviceOperation.GET_PRIVATE_KEY)) { - getPrivateKeyButton.setDefaultButton(defaultDevice); + if(defaultDevice) { + getPrivateKeyButton.getStyleClass().add("default-button"); + } getPrivateKeyButton.setVisible(true); showHideLink.setVisible(false); } else if(deviceOperation.equals(DeviceOperation.GET_ADDRESS)) { diff --git a/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java index 3dfee893..804ecf27 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/CardApi.java @@ -53,6 +53,8 @@ public abstract class CardApi { public abstract ScriptType getDefaultScriptType(); + public abstract int getCurrentSlot() throws CardException; + public abstract Service getAuthDelayService() throws CardException; public abstract boolean requiresBackup() throws CardException; @@ -71,7 +73,7 @@ public abstract class CardApi { public abstract Service getSignMessageService(String message, ScriptType scriptType, List derivation, StringProperty messageProperty); - public abstract Service getPrivateKeyService(StringProperty messageProperty); + public abstract Service getPrivateKeyService(Integer slot, StringProperty messageProperty); public abstract Service
getAddressService(StringProperty messageProperty); diff --git a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java index 75738b03..897c446b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java +++ b/src/main/java/com/sparrowwallet/sparrow/io/ckcard/CkCardApi.java @@ -62,6 +62,12 @@ public class CkCardApi extends CardApi { return cardStatus.getCardType(); } + @Override + public int getCurrentSlot() throws CardException { + CardStatus cardStatus = getStatus(); + return cardStatus.getCurrentSlot(); + } + @Override public ScriptType getDefaultScriptType() { return ScriptType.P2WPKH; @@ -250,12 +256,12 @@ public class CkCardApi extends CardApi { } @Override - public Service getPrivateKeyService(StringProperty messageProperty) { - return new PrivateKeyService(messageProperty); + public Service getPrivateKeyService(Integer slot, StringProperty messageProperty) { + return new PrivateKeyService(slot, messageProperty); } - ECKey getPrivateKey(int slot, boolean unsealed) throws CardException { - if(unsealed) { + ECKey getPrivateKey(int slot, int currentSlot) throws CardException { + if(slot != currentSlot) { CardAuthDump cardAuthDump = cardProtocol.dump(cvc, slot); return cardAuthDump.getPrivateKey(); } @@ -458,9 +464,11 @@ public class CkCardApi extends CardApi { } public class PrivateKeyService extends Service { + private Integer slot; private final StringProperty messageProperty; - public PrivateKeyService(StringProperty messageProperty) { + public PrivateKeyService(Integer slot, StringProperty messageProperty) { + this.slot = slot; this.messageProperty = messageProperty; } @@ -474,17 +482,19 @@ public class CkCardApi extends CardApi { throw new IllegalStateException("Please use a " + WalletModel.SATSCARD.toDisplayString() + " to retrieve a private key."); } - int slot = cardStatus.getCurrentSlot(); - boolean unsealed = false; - if(!cardStatus.isInitialized()) { + int currentSlot = cardStatus.getCurrentSlot(); + if(slot == null) { + slot = currentSlot; + } + + if(slot == currentSlot && !cardStatus.isInitialized()) { //If card has been unsealed, but a new slot is not initialized, retrieve private key for previous slot slot = slot - 1; - unsealed = true; } checkWait(cardStatus, new SimpleIntegerProperty(), messageProperty); - return getPrivateKey(slot, unsealed); + return getPrivateKey(slot, currentSlot); } }; }