mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
add separate button to backup tapsigner without changing pin
This commit is contained in:
parent
bcbb531414
commit
f8fa7f4cf2
3 changed files with 66 additions and 28 deletions
|
@ -22,20 +22,25 @@ public class CardPinDialog extends Dialog<CardPinDialog.CardPinChange> {
|
||||||
private final CheckBox backupFirst;
|
private final CheckBox backupFirst;
|
||||||
private final ButtonType okButtonType;
|
private final ButtonType okButtonType;
|
||||||
|
|
||||||
public CardPinDialog() {
|
public CardPinDialog(boolean backupOnly) {
|
||||||
this.existingPin = new ViewPasswordField();
|
this.existingPin = new ViewPasswordField();
|
||||||
this.newPin = new ViewPasswordField();
|
this.newPin = new ViewPasswordField();
|
||||||
this.newPinConfirm = new ViewPasswordField();
|
this.newPinConfirm = new ViewPasswordField();
|
||||||
this.backupFirst = new CheckBox();
|
this.backupFirst = new CheckBox();
|
||||||
|
|
||||||
|
if(backupOnly) {
|
||||||
|
newPin.textProperty().bind(existingPin.textProperty());
|
||||||
|
newPinConfirm.textProperty().bind(existingPin.textProperty());
|
||||||
|
}
|
||||||
|
|
||||||
final DialogPane dialogPane = getDialogPane();
|
final DialogPane dialogPane = getDialogPane();
|
||||||
setTitle("Change Card PIN");
|
setTitle(backupOnly ? "Backup Card" : "Change Card PIN");
|
||||||
dialogPane.setHeaderText("Enter the current PIN, and then the new PIN twice. PIN must be between 6 and 32 digits.");
|
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());
|
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||||
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
||||||
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
|
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
|
||||||
dialogPane.setPrefWidth(380);
|
dialogPane.setPrefWidth(380);
|
||||||
dialogPane.setPrefHeight(260);
|
dialogPane.setPrefHeight(backupOnly ? 135 : 260);
|
||||||
AppServices.moveToActiveWindowScreen(this);
|
AppServices.moveToActiveWindowScreen(this);
|
||||||
|
|
||||||
Glyph lock = new Glyph("FontAwesome", FontAwesome.Glyph.LOCK);
|
Glyph lock = new Glyph("FontAwesome", FontAwesome.Glyph.LOCK);
|
||||||
|
@ -63,7 +68,12 @@ public class CardPinDialog extends Dialog<CardPinDialog.CardPinChange> {
|
||||||
backupField.setText("Backup First:");
|
backupField.setText("Backup First:");
|
||||||
backupField.getInputs().add(backupFirst);
|
backupField.getInputs().add(backupFirst);
|
||||||
|
|
||||||
|
if(backupOnly) {
|
||||||
|
fieldset.getChildren().addAll(currentField);
|
||||||
|
} else {
|
||||||
fieldset.getChildren().addAll(currentField, newField, confirmField, backupField);
|
fieldset.getChildren().addAll(currentField, newField, confirmField, backupField);
|
||||||
|
}
|
||||||
|
|
||||||
form.getChildren().add(fieldset);
|
form.getChildren().add(fieldset);
|
||||||
dialogPane.setContent(form);
|
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())));
|
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);
|
dialogPane.getButtonTypes().addAll(okButtonType);
|
||||||
Button okButton = (Button) dialogPane.lookupButton(okButtonType);
|
Button okButton = (Button) dialogPane.lookupButton(okButtonType);
|
||||||
okButton.setPrefWidth(130);
|
okButton.setPrefWidth(130);
|
||||||
|
|
|
@ -24,6 +24,7 @@ import javafx.scene.control.*;
|
||||||
import javafx.scene.input.Clipboard;
|
import javafx.scene.input.Clipboard;
|
||||||
import javafx.scene.input.ClipboardContent;
|
import javafx.scene.input.ClipboardContent;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
import org.controlsfx.control.SegmentedButton;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.validation.ValidationResult;
|
import org.controlsfx.validation.ValidationResult;
|
||||||
import org.controlsfx.validation.ValidationSupport;
|
import org.controlsfx.validation.ValidationSupport;
|
||||||
|
@ -68,7 +69,10 @@ public class KeystoreController extends WalletFormController implements Initiali
|
||||||
private Button viewKeyButton;
|
private Button viewKeyButton;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button changePinButton;
|
private ToggleGroup cardServiceToggleGroup;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private SegmentedButton cardServiceButtons;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button importButton;
|
private Button importButton;
|
||||||
|
@ -137,7 +141,7 @@ public class KeystoreController extends WalletFormController implements Initiali
|
||||||
exportButton.managedProperty().bind(exportButton.visibleProperty());
|
exportButton.managedProperty().bind(exportButton.visibleProperty());
|
||||||
viewSeedButton.managedProperty().bind(viewSeedButton.visibleProperty());
|
viewSeedButton.managedProperty().bind(viewSeedButton.visibleProperty());
|
||||||
viewKeyButton.managedProperty().bind(viewKeyButton.visibleProperty());
|
viewKeyButton.managedProperty().bind(viewKeyButton.visibleProperty());
|
||||||
changePinButton.managedProperty().bind(changePinButton.visibleProperty());
|
cardServiceButtons.managedProperty().bind(cardServiceButtons.visibleProperty());
|
||||||
scanXpubQR.managedProperty().bind(scanXpubQR.visibleProperty());
|
scanXpubQR.managedProperty().bind(scanXpubQR.visibleProperty());
|
||||||
displayXpubQR.managedProperty().bind(displayXpubQR.visibleProperty());
|
displayXpubQR.managedProperty().bind(displayXpubQR.visibleProperty());
|
||||||
displayXpubQR.visibleProperty().bind(scanXpubQR.visibleProperty().not());
|
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);
|
exportButton.setVisible(showExport && getWalletForm().getWallet().getPolicyType() == PolicyType.MULTI);
|
||||||
viewSeedButton.setVisible(keystore.getSource() == KeystoreSource.SW_SEED && keystore.hasSeed());
|
viewSeedButton.setVisible(keystore.getSource() == KeystoreSource.SW_SEED && keystore.hasSeed());
|
||||||
viewKeyButton.setVisible(keystore.getSource() == KeystoreSource.SW_SEED && keystore.hasMasterPrivateExtendedKey());
|
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.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"));
|
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) {
|
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()) {
|
if(!isReaderAvailable()) {
|
||||||
AppServices.showErrorDialog("No card reader", "Connect a card reader to change the card PIN.");
|
AppServices.showErrorDialog("No card reader", "Connect a card reader to change the card PIN.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CardPinDialog cardPinDialog = new CardPinDialog();
|
CardPinDialog cardPinDialog = new CardPinDialog(backupOnly);
|
||||||
Optional<CardPinDialog.CardPinChange> optPinChange = cardPinDialog.showAndWait();
|
Optional<CardPinDialog.CardPinChange> optPinChange = cardPinDialog.showAndWait();
|
||||||
if(optPinChange.isPresent()) {
|
if(optPinChange.isPresent()) {
|
||||||
String currentPin = optPinChange.get().currentPin();
|
String currentPin = optPinChange.get().currentPin();
|
||||||
|
@ -449,7 +463,7 @@ public class KeystoreController extends WalletFormController implements Initiali
|
||||||
if(authDelayService != null) {
|
if(authDelayService != null) {
|
||||||
authDelayService.setOnSucceeded(event1 -> {
|
authDelayService.setOnSucceeded(event1 -> {
|
||||||
try {
|
try {
|
||||||
changeCardPin(newPin, backupFirst, cardApi);
|
changeCardPin(newPin, backupFirst, backupOnly, cardApi);
|
||||||
} catch(CardException e) {
|
} catch(CardException e) {
|
||||||
log.error("Error communicating with card", e);
|
log.error("Error communicating with card", e);
|
||||||
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
|
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
|
||||||
|
@ -464,7 +478,7 @@ public class KeystoreController extends WalletFormController implements Initiali
|
||||||
AppServices.moveToActiveWindowScreen(serviceProgressDialog);
|
AppServices.moveToActiveWindowScreen(serviceProgressDialog);
|
||||||
authDelayService.start();
|
authDelayService.start();
|
||||||
} else {
|
} else {
|
||||||
changeCardPin(newPin, backupFirst, cardApi);
|
changeCardPin(newPin, backupFirst, backupOnly, cardApi);
|
||||||
}
|
}
|
||||||
} catch(CardException e) {
|
} catch(CardException e) {
|
||||||
log.error("Error communicating with card", e);
|
log.error("Error communicating with card", e);
|
||||||
|
@ -473,23 +487,25 @@ 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();
|
boolean requiresBackup = cardApi.requiresBackup();
|
||||||
if(backupFirst || requiresBackup) {
|
if(backupOnly || backupFirst || requiresBackup) {
|
||||||
Service<String> backupService = cardApi.getBackupService();
|
Service<String> backupService = cardApi.getBackupService();
|
||||||
backupService.setOnSucceeded(event -> {
|
backupService.setOnSucceeded(event -> {
|
||||||
String backup = backupService.getValue();
|
String backup = backupService.getValue();
|
||||||
String filename = fingerprint.getText() + ".aes";
|
String filename = fingerprint.getText() + ".aes";
|
||||||
TextAreaDialog backupDialog = new TextAreaDialog(backup, false, filename, Base64.getDecoder().decode(backup));
|
TextAreaDialog backupDialog = new TextAreaDialog(backup, false, filename, Base64.getDecoder().decode(backup));
|
||||||
backupDialog.setTitle("Backup Private Key");
|
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();
|
backupDialog.showAndWait();
|
||||||
|
if(!backupOnly) {
|
||||||
try {
|
try {
|
||||||
changePin(newPin, cardApi);
|
changePin(newPin, cardApi);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
log.error("Error communicating with card", e);
|
log.error("Error communicating with card", e);
|
||||||
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
|
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
backupService.setOnFailed(event -> {
|
backupService.setOnFailed(event -> {
|
||||||
Throwable e = event.getSource().getException();
|
Throwable e = event.getSource().getException();
|
||||||
|
|
|
@ -41,14 +41,26 @@
|
||||||
<Tooltip text="View master private key"/>
|
<Tooltip text="View master private key"/>
|
||||||
</tooltip>
|
</tooltip>
|
||||||
</Button>
|
</Button>
|
||||||
<Button fx:id="changePinButton" text="Change Pin..." graphicTextGap="5" onAction="#changeCardPin">
|
<SegmentedButton fx:id="cardServiceButtons">
|
||||||
|
<toggleGroup>
|
||||||
|
<ToggleGroup fx:id="cardServiceToggleGroup" />
|
||||||
|
</toggleGroup>
|
||||||
|
<buttons>
|
||||||
|
<ToggleButton toggleGroup="$cardServiceToggleGroup" text="Change Pin" graphicTextGap="5" onAction="#changeCardPin">
|
||||||
<graphic>
|
<graphic>
|
||||||
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="12" icon="WIFI" />
|
<Glyph fontFamily="Font Awesome 5 Free Solid" fontSize="12" icon="WIFI" />
|
||||||
</graphic>
|
</graphic>
|
||||||
<tooltip>
|
<tooltip>
|
||||||
<Tooltip text="Change the PIN of current card"/>
|
<Tooltip text="Change the PIN of the current card"/>
|
||||||
</tooltip>
|
</tooltip>
|
||||||
</Button>
|
</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">
|
<Button fx:id="exportButton" text="Export..." onAction="#export">
|
||||||
<tooltip>
|
<tooltip>
|
||||||
<Tooltip text="Export this keystore as a signer for a multisig wallet"/>
|
<Tooltip text="Export this keystore as a signer for a multisig wallet"/>
|
||||||
|
|
Loading…
Reference in a new issue