satscard: retrieve private keys for previously used slots

This commit is contained in:
Craig Raw 2023-02-01 11:37:36 +02:00
parent 73dcef9fd1
commit 0b980f6ab5
3 changed files with 65 additions and 18 deletions

View file

@ -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<ECKey> privateKeyService = cardApi.getPrivateKeyService(messageProperty);
Service<ECKey> 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)) {

View file

@ -53,6 +53,8 @@ public abstract class CardApi {
public abstract ScriptType getDefaultScriptType();
public abstract int getCurrentSlot() throws CardException;
public abstract Service<Void> getAuthDelayService() throws CardException;
public abstract boolean requiresBackup() throws CardException;
@ -71,7 +73,7 @@ public abstract class CardApi {
public abstract Service<String> getSignMessageService(String message, ScriptType scriptType, List<ChildNumber> derivation, StringProperty messageProperty);
public abstract Service<ECKey> getPrivateKeyService(StringProperty messageProperty);
public abstract Service<ECKey> getPrivateKeyService(Integer slot, StringProperty messageProperty);
public abstract Service<Address> getAddressService(StringProperty messageProperty);

View file

@ -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<ECKey> getPrivateKeyService(StringProperty messageProperty) {
return new PrivateKeyService(messageProperty);
public Service<ECKey> 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<ECKey> {
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);
}
};
}