diff --git a/pom.xml b/pom.xml index a27983938..2cd2baec6 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ com.github.serceman,com.github.jnr,org.ow2.asm,net.java.dev.jna,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh - 2.1.0-beta10 + 2.1.0-beta11 1.0.0-rc1 1.0.0-beta2 1.0.0-beta2 diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index fae730bd1..b8e899845 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -42,6 +42,8 @@ module org.cryptomator.desktop { uses TrayIntegrationProvider; uses UiAppearanceProvider; + exports org.cryptomator.ui.keyloading.hub to com.fasterxml.jackson.databind; + opens org.cryptomator.common.settings to com.google.gson; opens org.cryptomator.common to javafx.fxml; diff --git a/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/src/main/java/org/cryptomator/ui/common/FxmlFile.java index aec859702..84ef8983f 100644 --- a/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -17,6 +17,7 @@ public enum FxmlFile { HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), // HUB_P12("/fxml/hub_p12.fxml"), // HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), // + HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), // LOCK_FORCED("/fxml/lock_forced.fxml"), // LOCK_FAILED("/fxml/lock_failed.fxml"), // MAIN_WINDOW("/fxml/main_window.fxml"), // diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlow.java b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlow.java index c587889f6..b261b6cee 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlow.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlow.java @@ -46,15 +46,15 @@ class AuthFlow implements AutoCloseable { public static final Escaper QUERY_STRING_ESCAPER = new PercentEscaper("-_.!~*'()@:$,;/?", false); private final AuthFlowReceiver receiver; - private final URI authEndpoint; - private final URI tokenEndpoint; - private final String clientId; + private final URI authEndpoint; // see https://datatracker.ietf.org/doc/html/rfc6749#section-3.1 + private final URI tokenEndpoint; // see https://datatracker.ietf.org/doc/html/rfc6749#section-3.2 + private final String clientId; // see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1 - private AuthFlow(AuthFlowReceiver receiver, URI authEndpoint, URI tokenEndpoint, String clientId) { + private AuthFlow(AuthFlowReceiver receiver, HubConfig hubConfig) { this.receiver = receiver; - this.authEndpoint = authEndpoint; - this.tokenEndpoint = tokenEndpoint; - this.clientId = clientId; + this.authEndpoint = URI.create(hubConfig.authEndpoint); + this.tokenEndpoint = URI.create(hubConfig.tokenEndpoint); + this.clientId = hubConfig.clientId; } /** @@ -62,15 +62,13 @@ class AuthFlow implements AutoCloseable { *

* This will start a loopback server, so make sure to {@link #close()} this resource. * - * @param authEndpoint Address of the Authorization Endpoint - * @param tokenEndpoint Address of the Token Endpoint - * @param clientId The client_id + * @param hubConfig A hub config object containing parameters required for this auth flow * @return An authorization flow * @throws Exception In case of any problems starting the server */ - public static AuthFlow init(URI authEndpoint, URI tokenEndpoint, String clientId) throws Exception { - var receiver = AuthFlowReceiver.start(); - return new AuthFlow(receiver, authEndpoint, tokenEndpoint, clientId); + public static AuthFlow init(HubConfig hubConfig) throws Exception { + var receiver = AuthFlowReceiver.start(hubConfig); + return new AuthFlow(receiver, hubConfig); } /** diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowController.java index 42114f29f..436516fca 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowController.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowController.java @@ -1,7 +1,6 @@ package org.cryptomator.ui.keyloading.hub; import dagger.Lazy; -import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; @@ -24,7 +23,6 @@ import javafx.fxml.FXML; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.stage.WindowEvent; -import java.io.IOException; import java.net.URI; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; @@ -33,14 +31,11 @@ import java.util.concurrent.atomic.AtomicReference; public class AuthFlowController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(AuthFlowController.class); - private static final String JWT_KEY_AUTH_ENDPOINT = "authEndpoint"; - private static final String JWT_KEY_TOKEN_ENDPOINT = "tokenEndpoint"; - private static final String JWT_KEY_CLIENT_ID = "clientId"; private final Application application; private final Stage window; private final ExecutorService executor; - private final Vault vault; + private final HubConfig hubConfig; private final AtomicReference tokenRef; private final UserInteractionLock result; private final Lazy receiveKeyScene; @@ -50,11 +45,11 @@ public class AuthFlowController implements FxController { private AuthFlowTask task; @Inject - public AuthFlowController(Application application, @KeyLoading Stage window, ExecutorService executor, @KeyLoading Vault vault, @Named("bearerToken") AtomicReference tokenRef, UserInteractionLock result, @FxmlScene(FxmlFile.HUB_RECEIVE_KEY) Lazy receiveKeyScene, ErrorComponent.Builder errorComponent) { + public AuthFlowController(Application application, @KeyLoading Stage window, ExecutorService executor, HubConfig hubConfig, @Named("bearerToken") AtomicReference tokenRef, UserInteractionLock result, @FxmlScene(FxmlFile.HUB_RECEIVE_KEY) Lazy receiveKeyScene, ErrorComponent.Builder errorComponent) { this.application = application; this.window = window; this.executor = executor; - this.vault = vault; + this.hubConfig = hubConfig; this.tokenRef = tokenRef; this.result = result; this.receiveKeyScene = receiveKeyScene; @@ -67,15 +62,10 @@ public class AuthFlowController implements FxController { @FXML public void initialize() { assert task == null; - try { - task = setupTask(); - task.setOnFailed(this::authFailed); - task.setOnSucceeded(this::authSucceeded); - executor.submit(task); - } catch (IOException e) { - LOG.error("Unreadable vault config", e); - errorComponent.cause(e).window(window).build().showErrorScene(); - } + task = new AuthFlowTask(hubConfig, this::setAuthUri);; + task.setOnFailed(this::authFailed); + task.setOnSucceeded(this::authSucceeded); + executor.submit(task); } @FXML @@ -88,13 +78,6 @@ public class AuthFlowController implements FxController { window.close(); } - private AuthFlowTask setupTask() throws IOException { - var authUri = URI.create(vault.getUnverifiedVaultConfig().get(JWT_KEY_AUTH_ENDPOINT).asString()); - var tokenUri = URI.create(vault.getUnverifiedVaultConfig().get(JWT_KEY_TOKEN_ENDPOINT).asString()); - var clientId = vault.getUnverifiedVaultConfig().get(JWT_KEY_CLIENT_ID).asString(); - return new AuthFlowTask(authUri, tokenUri, clientId, this::setAuthUri); - } - private void setAuthUri(URI uri) { authUri.set(uri); browse(); @@ -138,4 +121,5 @@ public class AuthFlowController implements FxController { return uri.getAuthority().toString(); } } + } diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowReceiver.java b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowReceiver.java index 6b8383884..1a1788635 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowReceiver.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowReceiver.java @@ -40,18 +40,20 @@ class AuthFlowReceiver implements AutoCloseable { private final Server server; private final ServerConnector connector; private final CallbackServlet servlet; + private final HubConfig hubConfig; - private AuthFlowReceiver(Server server, ServerConnector connector, CallbackServlet servlet) { + private AuthFlowReceiver(Server server, ServerConnector connector, CallbackServlet servlet, HubConfig hubConfig) { this.server = server; this.connector = connector; this.servlet = servlet; + this.hubConfig = hubConfig; } - public static AuthFlowReceiver start() throws Exception { + public static AuthFlowReceiver start(HubConfig hubConfig) throws Exception { var server = new Server(); var context = new ServletContextHandler(); - var servlet = new CallbackServlet(); + var servlet = new CallbackServlet(hubConfig); context.addServlet(new ServletHolder(servlet), CALLBACK_PATH); var connector = new ServerConnector(server); @@ -60,7 +62,7 @@ class AuthFlowReceiver implements AutoCloseable { server.setConnectors(new Connector[]{connector}); server.setHandler(context); server.start(); - return new AuthFlowReceiver(server, connector, servlet); + return new AuthFlowReceiver(server, connector, servlet, hubConfig); } public String getRedirectUri() { @@ -81,6 +83,11 @@ class AuthFlowReceiver implements AutoCloseable { private static class CallbackServlet extends HttpServlet { private final BlockingQueue callback = new LinkedBlockingQueue<>(); + private final HubConfig hubConfig; + + public CallbackServlet(HubConfig hubConfig) { + this.hubConfig = hubConfig; + } @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { @@ -88,14 +95,15 @@ class AuthFlowReceiver implements AutoCloseable { var code = req.getParameter("code"); var state = req.getParameter("state"); - // TODO 302 use redirect to configurable site - res.setContentType("text/html;charset=utf-8"); - res.getWriter().write(HTML_SUCCESS); - res.getWriter().flush(); + res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + if (error == null && code != null) { + res.setHeader("Location", hubConfig.unlockSuccessUrl); + } else { + res.setHeader("Location", hubConfig.unlockErrorUrl); + } callback.add(new Callback(error, code, state)); } - } } diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowTask.java b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowTask.java index 4f303b712..901c7acc7 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowTask.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/AuthFlowTask.java @@ -7,27 +7,25 @@ import java.util.function.Consumer; class AuthFlowTask extends Task { - private final URI authUri; - private final URI tokenUri; - private final String clientId; private final Consumer redirectUriConsumer; /** * Spawns a server and waits for the redirectUri to be called. * + * @param hubConfig Configuration object holding parameters required by {@link AuthFlow} * @param redirectUriConsumer A callback invoked with the redirectUri, as soon as the server has started */ - public AuthFlowTask(URI authUri, URI tokenUri, String clientId, Consumer redirectUriConsumer) { - this.authUri = authUri; - this.tokenUri = tokenUri; - this.clientId = clientId; + public AuthFlowTask(HubConfig hubConfig, Consumer redirectUriConsumer) { + this.hubConfig = hubConfig; this.redirectUriConsumer = redirectUriConsumer; } @Override protected String call() throws Exception { - try (var authFlow = AuthFlow.init(authUri, tokenUri, clientId)) { + try (var authFlow = AuthFlow.init(hubConfig)) { return authFlow.run(uri -> Platform.runLater(() -> redirectUriConsumer.accept(uri))); } } + + private final HubConfig hubConfig; } diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubConfig.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubConfig.java new file mode 100644 index 000000000..0e53351e5 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubConfig.java @@ -0,0 +1,13 @@ +package org.cryptomator.ui.keyloading.hub; + +// needs to be accessible by JSON decoder +public class HubConfig { + + public String clientId; + public String authEndpoint; + public String tokenEndpoint; + public String deviceRegistrationUrl; + public String unlockSuccessUrl; + public String unlockErrorUrl; + +} diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java index 5de793857..ad2c5c02b 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java @@ -5,6 +5,7 @@ import dagger.Module; import dagger.Provides; import dagger.multibindings.IntoMap; import dagger.multibindings.StringKey; +import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; @@ -19,6 +20,8 @@ import org.cryptomator.ui.keyloading.KeyLoadingStrategy; import javax.inject.Named; import javafx.scene.Scene; +import java.io.IOException; +import java.io.UncheckedIOException; import java.net.URI; import java.security.KeyPair; import java.util.ResourceBundle; @@ -33,6 +36,16 @@ public abstract class HubKeyLoadingModule { CANCELLED } + @Provides + @KeyLoadingScoped + static HubConfig provideHubConfig(@KeyLoading Vault vault) { + try { + return vault.getUnverifiedVaultConfig().getHeader("hub", HubConfig.class); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + @Provides @KeyLoadingScoped static AtomicReference provideKeyPair() { @@ -92,6 +105,14 @@ public abstract class HubKeyLoadingModule { return fxmlLoaders.createScene(FxmlFile.HUB_RECEIVE_KEY); } + @Provides + @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) + @KeyLoadingScoped + static Scene provideHubRegisterDeviceScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene(FxmlFile.HUB_REGISTER_DEVICE); + } + + @Binds @IntoMap @FxControllerKey(P12Controller.class) @@ -124,4 +145,9 @@ public abstract class HubKeyLoadingModule { @FxControllerKey(ReceiveKeyController.class) abstract FxController bindReceiveKeyController(ReceiveKeyController controller); + @Binds + @IntoMap + @FxControllerKey(RegisterDeviceController.class) + abstract FxController bindRegisterDeviceController(RegisterDeviceController controller); + } diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java index 1343f8cc9..b3b213b34 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java @@ -29,7 +29,6 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy { static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http"; static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https"; - private final Vault vault; private final Stage window; private final Lazy p12LoadingScene; private final UserInteractionLock userInteraction; @@ -37,8 +36,7 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy { private final AtomicReference eciesParams; @Inject - public HubKeyLoadingStrategy(@KeyLoading Vault vault, @KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_P12) Lazy p12LoadingScene, UserInteractionLock userInteraction, AtomicReference keyPairRef, AtomicReference eciesParams) { - this.vault = vault; + public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_P12) Lazy p12LoadingScene, UserInteractionLock userInteraction, AtomicReference keyPairRef, AtomicReference eciesParams) { this.window = window; this.p12LoadingScene = p12LoadingScene; this.userInteraction = userInteraction; diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java index c87a09efc..9707981ec 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java @@ -5,9 +5,12 @@ import com.google.common.base.Strings; import com.google.common.io.BaseEncoding; import com.google.gson.Gson; import com.google.gson.JsonElement; +import dagger.Lazy; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.UserInteractionLock; import org.cryptomator.ui.keyloading.KeyLoading; import org.cryptomator.ui.keyloading.KeyLoadingScoped; @@ -23,6 +26,7 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; +import javafx.scene.Scene; import javafx.scene.control.TextField; import javafx.stage.Stage; import javafx.stage.WindowEvent; @@ -47,23 +51,20 @@ public class ReceiveKeyController implements FxController { private final Stage window; private final String bearerToken; - private final KeyPair keyPair; private final AtomicReference eciesParamsRef; private final UserInteractionLock result; + private final Lazy registerDeviceScene; private final ErrorComponent.Builder errorComponent; private final URI vaultBaseUri; - private final ObjectProperty state = new SimpleObjectProperty<>(ReceiveKeyState.LOADING); private final HttpClient httpClient; - public TextField deviceName; - @Inject - public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, AtomicReference keyPairRef, @Named("bearerToken") AtomicReference tokenRef, AtomicReference eciesParamsRef, UserInteractionLock result, ErrorComponent.Builder errorComponent) { + public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, AtomicReference keyPairRef, @Named("bearerToken") AtomicReference tokenRef, AtomicReference eciesParamsRef, UserInteractionLock result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy registerDeviceScene, ErrorComponent.Builder errorComponent) { this.window = window; this.bearerToken = Objects.requireNonNull(tokenRef.get()); - this.keyPair = Objects.requireNonNull(keyPairRef.get()); this.eciesParamsRef = eciesParamsRef; this.result = result; + this.registerDeviceScene = registerDeviceScene; this.errorComponent = errorComponent; this.vaultBaseUri = getVaultBaseUri(vault); this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed); @@ -87,41 +88,8 @@ public class ReceiveKeyController implements FxController { } else { switch (response.statusCode()) { case 200 -> retrievalSucceeded(response); - case 404 -> state.set(ReceiveKeyState.NEEDS_REGISTRATION); - default -> retrievalFailed(new IOException("Unexpected response " + response.statusCode())); - } - } - } - - @FXML - public void register() { - Preconditions.checkArgument(!Strings.isNullOrEmpty(deviceName.getText()), "device name must not be empty"); - var deviceKey = BaseEncoding.base64Url().omitPadding().encode(keyPair.getPublic().getEncoded()); - var json = """ - { - "id": "desktop-app", - "name": "%s", - "publicKey": "%s" - } - """.formatted(deviceName.getText(), deviceKey); // TODO use gson - - var regUri = URI.create("http://localhost:9090/devices/desktop-app"); // TODO read api base from vault config! - var request = HttpRequest.newBuilder(regUri) // - .header("Authorization", "Bearer " + bearerToken) // - .header("Content-Type", "application/json; charset=UTF-8") // - .PUT(HttpRequest.BodyPublishers.ofString(json)) // - .build(); - httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()) // - .whenCompleteAsync(this::createdNewDevice, Platform::runLater); - } - - private void createdNewDevice(HttpResponse response, Throwable error) { - if (error != null) { - retrievalFailed(error); - } else { - switch (response.statusCode()) { - case 201 -> LOG.info("TODO device created, waiting for authorization"); - case 409 -> LOG.info("TODO device already exists. still waiting for authorization"); + case 403 -> accessNotGranted(); + case 404 -> needsDeviceRegistration(); default -> retrievalFailed(new IOException("Unexpected response " + response.statusCode())); } } @@ -143,6 +111,14 @@ public class ReceiveKeyController implements FxController { } } + private void needsDeviceRegistration() { + window.setScene(registerDeviceScene.get()); + } + + private void accessNotGranted() { + LOG.warn("unauthorized device"); // TODO + } + private void retrievalFailed(Throwable cause) { result.interacted(HubKeyLoadingModule.HubLoadingResult.FAILED); LOG.error("Key retrieval failed", cause); @@ -183,13 +159,5 @@ public class ReceiveKeyController implements FxController { throw new IllegalStateException("URI constructed from params known to be valid", e); } } - /* Getter/Setter */ - public ObjectProperty stateProperty() { - return state; - } - - public ReceiveKeyState getState() { - return state.get(); - } } diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyState.java b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyState.java deleted file mode 100644 index ae1562ded..000000000 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyState.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.cryptomator.ui.keyloading.hub; - -public enum ReceiveKeyState { - LOADING, - NEEDS_REGISTRATION -} diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java new file mode 100644 index 000000000..1110f3b15 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java @@ -0,0 +1,59 @@ +package org.cryptomator.ui.keyloading.hub; + +import com.google.common.io.BaseEncoding; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.UserInteractionLock; +import org.cryptomator.ui.keyloading.KeyLoading; +import org.cryptomator.ui.keyloading.KeyLoadingScoped; + +import javax.inject.Inject; +import javafx.application.Application; +import javafx.event.Event; +import javafx.fxml.FXML; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; +import java.security.KeyPair; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +@KeyLoadingScoped +public class RegisterDeviceController implements FxController { + + private final Application application; + private final Stage window; + private final HubConfig hubConfig; + private final KeyPair keyPair; + private final UserInteractionLock result; + + @Inject + public RegisterDeviceController(Application application, @KeyLoading Stage window, HubConfig hubConfig, AtomicReference keyPairRef, UserInteractionLock result) { + this.application = application; + this.window = window; + this.hubConfig = hubConfig; + this.keyPair = Objects.requireNonNull(keyPairRef.get()); + this.result = result; + this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed); + } + + @FXML + public void browse() { + var deviceKey = BaseEncoding.base64Url().omitPadding().encode(keyPair.getPublic().getEncoded()); + var url = hubConfig.deviceRegistrationUrl + "?device_key=" + deviceKey; + // TODO append further params (including hmac of shown verification code) + application.getHostServices().showDocument(url); + } + + @FXML + public void close() { + window.close(); + } + + private void windowClosed(WindowEvent windowEvent) { + // if not already interacted, mark this workflow as cancelled: + if (result.awaitingInteraction().get()) { + result.interacted(HubKeyLoadingModule.HubLoadingResult.CANCELLED); + } + } + +} diff --git a/src/main/resources/fxml/hub_receive_key.fxml b/src/main/resources/fxml/hub_receive_key.fxml index ef10291e7..0ea9d012c 100644 --- a/src/main/resources/fxml/hub_receive_key.fxml +++ b/src/main/resources/fxml/hub_receive_key.fxml @@ -1,12 +1,9 @@ - - - @@ -18,10 +15,6 @@ maxWidth="400" minHeight="145" spacing="12"> - - - - @@ -31,19 +24,13 @@ - - - - + - +