add separate button to backup tapsigner without changing pin

This commit is contained in:
Craig Raw 2023-06-22 10:41:59 +02:00
parent bcbb531414
commit f8fa7f4cf2
3 changed files with 66 additions and 28 deletions

View file

@ -22,20 +22,25 @@ public class CardPinDialog extends Dialog<CardPinDialog.CardPinChange> {
private final CheckBox backupFirst;
private final ButtonType okButtonType;
public CardPinDialog() {
public CardPinDialog(boolean backupOnly) {
this.existingPin = new ViewPasswordField();
this.newPin = new ViewPasswordField();
this.newPinConfirm = new ViewPasswordField();
this.backupFirst = new CheckBox();
if(backupOnly) {
newPin.textProperty().bind(existingPin.textProperty());
newPinConfirm.textProperty().bind(existingPin.textProperty());
}
final DialogPane dialogPane = getDialogPane();
setTitle("Change Card PIN");
dialogPane.setHeaderText("Enter the current PIN, and then the new PIN twice. PIN must be between 6 and 32 digits.");
setTitle(backupOnly ? "Backup Card" : "Change Card PIN");
dialogPane.setHeaderText(backupOnly ? "Enter the current card PIN." : "Enter the current PIN, and then the new PIN twice. PIN must be between 6 and 32 digits.");
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
dialogPane.setPrefWidth(380);
dialogPane.setPrefHeight(260);
dialogPane.setPrefHeight(backupOnly ? 135 : 260);
AppServices.moveToActiveWindowScreen(this);
Glyph lock = new Glyph("FontAwesome", FontAwesome.Glyph.LOCK);
@ -63,7 +68,12 @@ public class CardPinDialog extends Dialog<CardPinDialog.CardPinChange> {
backupField.setText("Backup First:");
backupField.getInputs().add(backupFirst);
fieldset.getChildren().addAll(currentField, newField, confirmField, backupField);
if(backupOnly) {
fieldset.getChildren().addAll(currentField);
} else {
fieldset.getChildren().addAll(currentField, newField, confirmField, backupField);
}
form.getChildren().add(fieldset);
dialogPane.setContent(form);
@ -75,7 +85,7 @@ public class CardPinDialog extends Dialog<CardPinDialog.CardPinChange> {
validationSupport.registerValidator(newPinConfirm, (Control c, String newValue) -> ValidationResult.fromErrorIf(c, "PIN confirmation does not match", !newPinConfirm.getText().equals(newPin.getText())));
});
okButtonType = new javafx.scene.control.ButtonType("Change", ButtonBar.ButtonData.OK_DONE);
okButtonType = new javafx.scene.control.ButtonType(backupOnly ? "Backup" : "Change", ButtonBar.ButtonData.OK_DONE);
dialogPane.getButtonTypes().addAll(okButtonType);
Button okButton = (Button) dialogPane.lookupButton(okButtonType);
okButton.setPrefWidth(130);

View file

@ -24,6 +24,7 @@ import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.StackPane;
import org.controlsfx.control.SegmentedButton;
import org.controlsfx.glyphfont.Glyph;
import org.controlsfx.validation.ValidationResult;
import org.controlsfx.validation.ValidationSupport;
@ -68,7 +69,10 @@ public class KeystoreController extends WalletFormController implements Initiali
private Button viewKeyButton;
@FXML
private Button changePinButton;
private ToggleGroup cardServiceToggleGroup;
@FXML
private SegmentedButton cardServiceButtons;
@FXML
private Button importButton;
@ -137,7 +141,7 @@ public class KeystoreController extends WalletFormController implements Initiali
exportButton.managedProperty().bind(exportButton.visibleProperty());
viewSeedButton.managedProperty().bind(viewSeedButton.visibleProperty());
viewKeyButton.managedProperty().bind(viewKeyButton.visibleProperty());
changePinButton.managedProperty().bind(changePinButton.visibleProperty());
cardServiceButtons.managedProperty().bind(cardServiceButtons.visibleProperty());
scanXpubQR.managedProperty().bind(scanXpubQR.visibleProperty());
displayXpubQR.managedProperty().bind(displayXpubQR.visibleProperty());
displayXpubQR.visibleProperty().bind(scanXpubQR.visibleProperty().not());
@ -294,7 +298,7 @@ public class KeystoreController extends WalletFormController implements Initiali
exportButton.setVisible(showExport && getWalletForm().getWallet().getPolicyType() == PolicyType.MULTI);
viewSeedButton.setVisible(keystore.getSource() == KeystoreSource.SW_SEED && keystore.hasSeed());
viewKeyButton.setVisible(keystore.getSource() == KeystoreSource.SW_SEED && keystore.hasMasterPrivateExtendedKey());
changePinButton.setVisible(keystore.getWalletModel().isCard());
cardServiceButtons.setVisible(keystore.getWalletModel().isCard());
importButton.setText(keystore.getSource() == KeystoreSource.SW_WATCH ? "Import..." : "Replace...");
importButton.setTooltip(new Tooltip(keystore.getSource() == KeystoreSource.SW_WATCH ? "Import a keystore from an external source" : "Replace this keystore with another source"));
@ -432,12 +436,22 @@ public class KeystoreController extends WalletFormController implements Initiali
}
public void changeCardPin(ActionEvent event) {
cardServiceToggleGroup.selectToggle(null);
changeCardPinOrBackup(false);
}
public void backupCard(ActionEvent event) {
cardServiceToggleGroup.selectToggle(null);
changeCardPinOrBackup(true);
}
public void changeCardPinOrBackup(boolean backupOnly) {
if(!isReaderAvailable()) {
AppServices.showErrorDialog("No card reader", "Connect a card reader to change the card PIN.");
return;
}
CardPinDialog cardPinDialog = new CardPinDialog();
CardPinDialog cardPinDialog = new CardPinDialog(backupOnly);
Optional<CardPinDialog.CardPinChange> optPinChange = cardPinDialog.showAndWait();
if(optPinChange.isPresent()) {
String currentPin = optPinChange.get().currentPin();
@ -449,7 +463,7 @@ public class KeystoreController extends WalletFormController implements Initiali
if(authDelayService != null) {
authDelayService.setOnSucceeded(event1 -> {
try {
changeCardPin(newPin, backupFirst, cardApi);
changeCardPin(newPin, backupFirst, backupOnly, cardApi);
} catch(CardException e) {
log.error("Error communicating with card", e);
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
@ -464,7 +478,7 @@ public class KeystoreController extends WalletFormController implements Initiali
AppServices.moveToActiveWindowScreen(serviceProgressDialog);
authDelayService.start();
} else {
changeCardPin(newPin, backupFirst, cardApi);
changeCardPin(newPin, backupFirst, backupOnly, cardApi);
}
} catch(CardException e) {
log.error("Error communicating with card", e);
@ -473,22 +487,24 @@ public class KeystoreController extends WalletFormController implements Initiali
}
}
private void changeCardPin(String newPin, boolean backupFirst, CardApi cardApi) throws CardException {
private void changeCardPin(String newPin, boolean backupFirst, boolean backupOnly, CardApi cardApi) throws CardException {
boolean requiresBackup = cardApi.requiresBackup();
if(backupFirst || requiresBackup) {
if(backupOnly || backupFirst || requiresBackup) {
Service<String> backupService = cardApi.getBackupService();
backupService.setOnSucceeded(event -> {
String backup = backupService.getValue();
String filename = fingerprint.getText() + ".aes";
TextAreaDialog backupDialog = new TextAreaDialog(backup, false, filename, Base64.getDecoder().decode(backup));
backupDialog.setTitle("Backup Private Key");
backupDialog.getDialogPane().setHeaderText((requiresBackup ? "Please backup first by saving" : "Save") + " the following text in a safe place. It contains an encrypted copy of the card's private key, and can be decrypted using the backup key written on the back of the card.");
backupDialog.getDialogPane().setHeaderText((requiresBackup && !backupOnly ? "Please backup first by saving" : "Save") + " the following text in a safe place. It contains an encrypted copy of the card's private key, and can be decrypted using the backup key written on the back of the card.");
backupDialog.showAndWait();
try {
changePin(newPin, cardApi);
} catch(Exception e) {
log.error("Error communicating with card", e);
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
if(!backupOnly) {
try {
changePin(newPin, cardApi);
} catch(Exception e) {
log.error("Error communicating with card", e);
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
}
}
});
backupService.setOnFailed(event -> {

View file

@ -41,14 +41,26 @@
<Tooltip text="View master private key"/>
</tooltip>
</Button>
<Button fx:id="changePinButton" text="Change Pin..." graphicTextGap="5" onAction="#changeCardPin">
<graphic>
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="12" icon="WIFI" />
</graphic>
<tooltip>
<Tooltip text="Change the PIN of current card"/>
</tooltip>
</Button>
<SegmentedButton fx:id="cardServiceButtons">
<toggleGroup>
<ToggleGroup fx:id="cardServiceToggleGroup" />
</toggleGroup>
<buttons>
<ToggleButton toggleGroup="$cardServiceToggleGroup" text="Change Pin" graphicTextGap="5" onAction="#changeCardPin">
<graphic>
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="12" icon="WIFI" />
</graphic>
<tooltip>
<Tooltip text="Change the PIN of the current card"/>
</tooltip>
</ToggleButton>
<ToggleButton toggleGroup="$cardServiceToggleGroup" text="Backup" onAction="#backupCard">
<tooltip>
<Tooltip text="Backup the current card"/>
</tooltip>
</ToggleButton>
</buttons>
</SegmentedButton>
<Button fx:id="exportButton" text="Export..." onAction="#export">
<tooltip>
<Tooltip text="Export this keystore as a signer for a multisig wallet"/>