support saving tapsigner backup as binary file

This commit is contained in:
Craig Raw 2023-03-09 13:40:57 +02:00
parent 40a3eb5d4f
commit 258d46a253
2 changed files with 51 additions and 3 deletions

View file

@ -11,10 +11,13 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.controlsfx.glyphfont.Glyph; import org.controlsfx.glyphfont.Glyph;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Optional; import java.util.Optional;
public class TextAreaDialog extends Dialog<String> { public class TextAreaDialog extends Dialog<String> {
@ -22,6 +25,8 @@ public class TextAreaDialog extends Dialog<String> {
private final TextArea textArea; private final TextArea textArea;
private final String defaultValue; private final String defaultValue;
private final String fileName;
private final byte[] fileBytes;
public TextAreaDialog() { public TextAreaDialog() {
this(""); this("");
@ -31,7 +36,11 @@ public class TextAreaDialog extends Dialog<String> {
this(defaultValue, true); this(defaultValue, true);
} }
public TextAreaDialog(@NamedArg("defaultValue") String defaultValue, @NamedArg("editable") boolean editable) { public TextAreaDialog(String defaultValue, boolean editable) {
this(defaultValue, editable, null, null);
}
public TextAreaDialog(@NamedArg("defaultValue") String defaultValue, @NamedArg("editable") boolean editable, @NamedArg("fileName") String fileName, @NamedArg("fileBytes") byte[] fileBytes) {
final DialogPane dialogPane = new TextAreaDialogPane(); final DialogPane dialogPane = new TextAreaDialogPane();
setDialogPane(dialogPane); setDialogPane(dialogPane);
@ -48,6 +57,8 @@ public class TextAreaDialog extends Dialog<String> {
HBox.setHgrow(this.textArea, Priority.ALWAYS); HBox.setHgrow(this.textArea, Priority.ALWAYS);
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
this.fileName = fileName;
this.fileBytes = fileBytes;
dialogPane.setContent(hbox); dialogPane.setContent(hbox);
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm()); dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
@ -60,6 +71,9 @@ public class TextAreaDialog extends Dialog<String> {
final ButtonType scanButtonType = new javafx.scene.control.ButtonType("Scan QR", ButtonBar.ButtonData.LEFT); final ButtonType scanButtonType = new javafx.scene.control.ButtonType("Scan QR", ButtonBar.ButtonData.LEFT);
dialogPane.getButtonTypes().add(scanButtonType); dialogPane.getButtonTypes().add(scanButtonType);
} else if(fileBytes != null) {
final ButtonType saveButtonType = new javafx.scene.control.ButtonType("Save File...", ButtonBar.ButtonData.LEFT);
dialogPane.getButtonTypes().add(saveButtonType);
} }
Platform.runLater(textArea::requestFocus); Platform.runLater(textArea::requestFocus);
@ -86,7 +100,7 @@ public class TextAreaDialog extends Dialog<String> {
@Override @Override
protected Node createButton(ButtonType buttonType) { protected Node createButton(ButtonType buttonType) {
Node button; Node button;
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) { if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT && buttonType.getText().equals("Scan QR")) {
Button scanButton = new Button(buttonType.getText()); Button scanButton = new Button(buttonType.getText());
scanButton.setGraphicTextGap(5); scanButton.setGraphicTextGap(5);
scanButton.setGraphic(getGlyph(FontAwesome5.Glyph.CAMERA)); scanButton.setGraphic(getGlyph(FontAwesome5.Glyph.CAMERA));
@ -118,6 +132,38 @@ public class TextAreaDialog extends Dialog<String> {
}); });
button = scanButton; button = scanButton;
} else if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT && buttonType.getText().equals("Save File...")) {
Button saveButton = new Button(buttonType.getText());
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
ButtonBar.setButtonData(saveButton, buttonData);
saveButton.setOnAction(event -> {
Stage window = new Stage();
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save File");
if(fileName != null) {
fileChooser.setInitialFileName(fileName);
}
AppServices.moveToActiveWindowScreen(window, 800, 450);
File file = fileChooser.showSaveDialog(window);
if(file != null) {
try {
try(OutputStream outputStream = new FileOutputStream(file)) {
outputStream.write(fileBytes);
outputStream.flush();
}
} catch(IOException e) {
log.error("Error saving file", e);
AppServices.showErrorDialog("Error saving file", "Cannot write to " + file.getAbsolutePath());
}
}
});
button = saveButton;
} else { } else {
button = super.createButton(buttonType); button = super.createButton(buttonType);
} }

View file

@ -35,6 +35,7 @@ import tornadofx.control.Field;
import javax.smartcardio.CardException; import javax.smartcardio.CardException;
import java.net.URL; import java.net.URL;
import java.util.Base64;
import java.util.Optional; import java.util.Optional;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -476,7 +477,8 @@ public class KeystoreController extends WalletFormController implements Initiali
Service<String> backupService = cardApi.getBackupService(); Service<String> backupService = cardApi.getBackupService();
backupService.setOnSucceeded(event -> { backupService.setOnSucceeded(event -> {
String backup = backupService.getValue(); String backup = backupService.getValue();
TextAreaDialog backupDialog = new TextAreaDialog(backup, false); String filename = fingerprint.getText() + ".aes";
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 ? "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();