improve bitbox pairing flow

This commit is contained in:
Craig Raw 2025-01-22 12:59:23 +02:00
parent d7511c62bf
commit 95200c7143
4 changed files with 58 additions and 12 deletions

2
drongo

@ -1 +1 @@
Subproject commit 89a6b1296e75508eae498f0199928cff0b8a660c
Subproject commit 0df1f79e5c7e9fc1daa212c875c9da5dbcc0ee56

2
lark

@ -1 +1 @@
Subproject commit 529184057a7ac5e0ccad9c84dd4b32796a8e835d
Subproject commit 6bfa13a3afccddeac2f4148a8abaaefed552261f

View file

@ -0,0 +1,33 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppServices;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import static com.sparrowwallet.sparrow.AppServices.*;
public class BitBoxPairingDialog extends Alert {
public BitBoxPairingDialog(String code) {
super(AlertType.INFORMATION);
initOwner(getActiveWindow());
setStageIcon(getDialogPane().getScene().getWindow());
getDialogPane().getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
setTitle("Confirm BitBox02 Pairing");
setHeaderText(getTitle());
VBox vBox = new VBox(20);
vBox.setAlignment(Pos.CENTER);
vBox.setPadding(new Insets(10, 20, 10, 20));
Label instructions = new Label("Confirm the following code is shown on BitBox02");
Label codeLabel = new Label(code);
codeLabel.getStyleClass().add("fixed-width");
vBox.getChildren().addAll(instructions, codeLabel);
getDialogPane().setContent(vBox);
moveToActiveWindowScreen(this);
getDialogPane().getButtonTypes().clear();
getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
}
}

View file

@ -11,11 +11,11 @@ import com.sparrowwallet.lark.DeviceException;
import com.sparrowwallet.lark.Lark;
import com.sparrowwallet.lark.bitbox02.BitBoxFileNoiseConfig;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.control.BitBoxPairingDialog;
import javafx.application.Platform;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -31,6 +31,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class Hwi {
private static final Logger log = LoggerFactory.getLogger(Hwi.class);
private static final String HWI_HOME_DIR = "hwi";
private static final String LARK_HOME_DIR = "lark";
private static final String BITBOX_FILENAME = "bitbox02.json";
private static boolean isPromptActive = false;
@ -482,32 +484,34 @@ public class Hwi {
}
private static final class BitBoxFxNoiseConfig extends BitBoxFileNoiseConfig {
private BitBoxPairingDialog pairingDialog;
public BitBoxFxNoiseConfig() {
super(Path.of(Storage.getSparrowDir().getAbsolutePath(), "lark", "bitbox02.json").toFile());
super(Path.of(Storage.getSparrowHome().getAbsolutePath(), LARK_HOME_DIR, BITBOX_FILENAME).toFile());
}
@Override
public boolean showPairing(String code, DeviceResponse response) throws DeviceException {
CountDownLatch latch = new CountDownLatch(2);
CountDownLatch latch = new CountDownLatch(1);
AtomicBoolean confirmedDevice = new AtomicBoolean(false);
AtomicBoolean confirmedApp = new AtomicBoolean(false);
Thread showPairingDeviceThread = new Thread(() -> {
try {
isPromptActive = true;
confirmedDevice.set(response.call());
latch.countDown();
} catch(DeviceException e) {
throw new RuntimeException(e);
} finally {
isPromptActive = false;
}
});
showPairingDeviceThread.start();
Platform.runLater(() -> {
Optional<ButtonType> optConfirm = AppServices.showAlertDialog("Confirm Pairing", "Confirm the following code is shown on BitBox02:\n\n" + code, Alert.AlertType.CONFIRMATION, ButtonType.NO, ButtonType.YES);
if(optConfirm.isPresent() && optConfirm.get() == ButtonType.YES) {
confirmedApp.set(true);
}
latch.countDown();
pairingDialog = new BitBoxPairingDialog(code);
pairingDialog.initOwner(AppServices.getActiveWindow());
pairingDialog.show();
});
try {
@ -516,7 +520,16 @@ public class Hwi {
Thread.currentThread().interrupt();
}
return confirmedDevice.get() && confirmedApp.get();
Platform.runLater(() -> {
if(pairingDialog != null && pairingDialog.isShowing()) {
pairingDialog.setResult(ButtonType.APPLY);
}
if(!confirmedDevice.get()) {
AppServices.showWarningDialog("Pairing Refused", "Pairing was refused on the device.");
}
});
return confirmedDevice.get();
}
}
}