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 @@
-
-
-
-
-
-
+
-
+
-
diff --git a/src/main/resources/fxml/hub_register_device.fxml b/src/main/resources/fxml/hub_register_device.fxml
new file mode 100644
index 000000000..5daa3596e
--- /dev/null
+++ b/src/main/resources/fxml/hub_register_device.fxml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/org/cryptomator/ui/keyloading/hub/AuthFlowIntegrationTest.java b/src/test/java/org/cryptomator/ui/keyloading/hub/AuthFlowIntegrationTest.java
index af34d0c0a..2b0f93c25 100644
--- a/src/test/java/org/cryptomator/ui/keyloading/hub/AuthFlowIntegrationTest.java
+++ b/src/test/java/org/cryptomator/ui/keyloading/hub/AuthFlowIntegrationTest.java
@@ -15,14 +15,18 @@ public class AuthFlowIntegrationTest {
}
private static final Logger LOG = LoggerFactory.getLogger(AuthFlowIntegrationTest.class);
- private static final URI AUTH_URI = URI.create("http://localhost:8080/auth/realms/cryptomator/protocol/openid-connect/auth");
- private static final URI TOKEN_URI = URI.create("http://localhost:8080/auth/realms/cryptomator/protocol/openid-connect/token");
- private static final String CLIENT_ID = "cryptomator-hub";
@Test
@Disabled // only to be run manually
public void testRetrieveToken() throws Exception {
- try (var authFlow = AuthFlow.init(AUTH_URI, TOKEN_URI, CLIENT_ID)) {
+ var hubConfig = new HubConfig();
+ hubConfig.authEndpoint = "http://localhost:8080/auth/realms/cryptomator/protocol/openid-connect/auth";
+ hubConfig.tokenEndpoint = "http://localhost:8080/auth/realms/cryptomator/protocol/openid-connect/token";
+ hubConfig.clientId = "cryptomator-hub";
+ hubConfig.unlockSuccessUrl = "http://localhost:3000/#/unlock-success";
+ hubConfig.unlockErrorUrl = "http://localhost:3000/#/unlock-error";
+
+ try (var authFlow = AuthFlow.init(hubConfig)) {
var token = authFlow.run(uri -> {
LOG.info("Visit {} to authenticate", uri);
});