mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
satscard: retrieve private keys for previously used slots
This commit is contained in:
parent
73dcef9fd1
commit
0b980f6ab5
3 changed files with 65 additions and 18 deletions
|
@ -45,6 +45,7 @@ import org.slf4j.LoggerFactory;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class DevicePane extends TitledDescriptionPane {
|
public class DevicePane extends TitledDescriptionPane {
|
||||||
private static final Logger log = LoggerFactory.getLogger(DevicePane.class);
|
private static final Logger log = LoggerFactory.getLogger(DevicePane.class);
|
||||||
|
@ -67,7 +68,7 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
private Button displayAddressButton;
|
private Button displayAddressButton;
|
||||||
private Button signMessageButton;
|
private Button signMessageButton;
|
||||||
private Button discoverKeystoresButton;
|
private Button discoverKeystoresButton;
|
||||||
private Button getPrivateKeyButton;
|
private ButtonBase getPrivateKeyButton;
|
||||||
private Button getAddressButton;
|
private Button getAddressButton;
|
||||||
|
|
||||||
private final SimpleStringProperty passphrase = new SimpleStringProperty("");
|
private final SimpleStringProperty passphrase = new SimpleStringProperty("");
|
||||||
|
@ -218,7 +219,7 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
setDefaultStatus();
|
setDefaultStatus();
|
||||||
showHideLink.setVisible(false);
|
showHideLink.setVisible(false);
|
||||||
|
|
||||||
Button button;
|
ButtonBase button;
|
||||||
if(deviceOperation == DeviceOperation.GET_PRIVATE_KEY) {
|
if(deviceOperation == DeviceOperation.GET_PRIVATE_KEY) {
|
||||||
createGetPrivateKeyButton();
|
createGetPrivateKeyButton();
|
||||||
button = getPrivateKeyButton;
|
button = getPrivateKeyButton;
|
||||||
|
@ -382,12 +383,44 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createGetPrivateKeyButton() {
|
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.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
getPrivateKeyButton.setText("Get Private Key");
|
||||||
getPrivateKeyButton.setOnAction(event -> {
|
getPrivateKeyButton.setOnAction(event -> {
|
||||||
getPrivateKeyButton.setDisable(true);
|
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.managedProperty().bind(getPrivateKeyButton.visibleProperty());
|
||||||
getPrivateKeyButton.setVisible(false);
|
getPrivateKeyButton.setVisible(false);
|
||||||
}
|
}
|
||||||
|
@ -886,11 +919,11 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
getXpubsService.start();
|
getXpubsService.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getPrivateKey() {
|
private void getPrivateKey(Integer slot) {
|
||||||
if(device.isCard()) {
|
if(device.isCard()) {
|
||||||
try {
|
try {
|
||||||
CardApi cardApi = CardApi.getCardApi(device.getModel(), pin.get());
|
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 -> {
|
handleCardOperation(privateKeyService, getPrivateKeyButton, "Private Key", true, event -> {
|
||||||
EventManager.get().post(new DeviceGetPrivateKeyEvent(privateKeyService.getValue(), cardApi.getDefaultScriptType()));
|
EventManager.get().post(new DeviceGetPrivateKeyEvent(privateKeyService.getValue(), cardApi.getDefaultScriptType()));
|
||||||
});
|
});
|
||||||
|
@ -962,7 +995,9 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
discoverKeystoresButton.setVisible(true);
|
discoverKeystoresButton.setVisible(true);
|
||||||
showHideLink.setVisible(false);
|
showHideLink.setVisible(false);
|
||||||
} else if(deviceOperation.equals(DeviceOperation.GET_PRIVATE_KEY)) {
|
} else if(deviceOperation.equals(DeviceOperation.GET_PRIVATE_KEY)) {
|
||||||
getPrivateKeyButton.setDefaultButton(defaultDevice);
|
if(defaultDevice) {
|
||||||
|
getPrivateKeyButton.getStyleClass().add("default-button");
|
||||||
|
}
|
||||||
getPrivateKeyButton.setVisible(true);
|
getPrivateKeyButton.setVisible(true);
|
||||||
showHideLink.setVisible(false);
|
showHideLink.setVisible(false);
|
||||||
} else if(deviceOperation.equals(DeviceOperation.GET_ADDRESS)) {
|
} else if(deviceOperation.equals(DeviceOperation.GET_ADDRESS)) {
|
||||||
|
|
|
@ -53,6 +53,8 @@ public abstract class CardApi {
|
||||||
|
|
||||||
public abstract ScriptType getDefaultScriptType();
|
public abstract ScriptType getDefaultScriptType();
|
||||||
|
|
||||||
|
public abstract int getCurrentSlot() throws CardException;
|
||||||
|
|
||||||
public abstract Service<Void> getAuthDelayService() throws CardException;
|
public abstract Service<Void> getAuthDelayService() throws CardException;
|
||||||
|
|
||||||
public abstract boolean requiresBackup() 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<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);
|
public abstract Service<Address> getAddressService(StringProperty messageProperty);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,12 @@ public class CkCardApi extends CardApi {
|
||||||
return cardStatus.getCardType();
|
return cardStatus.getCardType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurrentSlot() throws CardException {
|
||||||
|
CardStatus cardStatus = getStatus();
|
||||||
|
return cardStatus.getCurrentSlot();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScriptType getDefaultScriptType() {
|
public ScriptType getDefaultScriptType() {
|
||||||
return ScriptType.P2WPKH;
|
return ScriptType.P2WPKH;
|
||||||
|
@ -250,12 +256,12 @@ public class CkCardApi extends CardApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Service<ECKey> getPrivateKeyService(StringProperty messageProperty) {
|
public Service<ECKey> getPrivateKeyService(Integer slot, StringProperty messageProperty) {
|
||||||
return new PrivateKeyService(messageProperty);
|
return new PrivateKeyService(slot, messageProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECKey getPrivateKey(int slot, boolean unsealed) throws CardException {
|
ECKey getPrivateKey(int slot, int currentSlot) throws CardException {
|
||||||
if(unsealed) {
|
if(slot != currentSlot) {
|
||||||
CardAuthDump cardAuthDump = cardProtocol.dump(cvc, slot);
|
CardAuthDump cardAuthDump = cardProtocol.dump(cvc, slot);
|
||||||
return cardAuthDump.getPrivateKey();
|
return cardAuthDump.getPrivateKey();
|
||||||
}
|
}
|
||||||
|
@ -458,9 +464,11 @@ public class CkCardApi extends CardApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PrivateKeyService extends Service<ECKey> {
|
public class PrivateKeyService extends Service<ECKey> {
|
||||||
|
private Integer slot;
|
||||||
private final StringProperty messageProperty;
|
private final StringProperty messageProperty;
|
||||||
|
|
||||||
public PrivateKeyService(StringProperty messageProperty) {
|
public PrivateKeyService(Integer slot, StringProperty messageProperty) {
|
||||||
|
this.slot = slot;
|
||||||
this.messageProperty = messageProperty;
|
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.");
|
throw new IllegalStateException("Please use a " + WalletModel.SATSCARD.toDisplayString() + " to retrieve a private key.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int slot = cardStatus.getCurrentSlot();
|
int currentSlot = cardStatus.getCurrentSlot();
|
||||||
boolean unsealed = false;
|
if(slot == null) {
|
||||||
if(!cardStatus.isInitialized()) {
|
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
|
//If card has been unsealed, but a new slot is not initialized, retrieve private key for previous slot
|
||||||
slot = slot - 1;
|
slot = slot - 1;
|
||||||
unsealed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkWait(cardStatus, new SimpleIntegerProperty(), messageProperty);
|
checkWait(cardStatus, new SimpleIntegerProperty(), messageProperty);
|
||||||
|
|
||||||
return getPrivateKey(slot, unsealed);
|
return getPrivateKey(slot, currentSlot);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue