diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 6627f5528..fe1da0f3e 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -45,6 +45,7 @@ module org.cryptomator.desktop { exports org.cryptomator.ui.keyloading.hub to com.fasterxml.jackson.databind; opens org.cryptomator.common.settings to com.google.gson; + opens org.cryptomator.ui.keyloading.hub to com.google.gson, javafx.fxml; opens org.cryptomator.common to javafx.fxml; opens org.cryptomator.common.vaults to javafx.fxml; @@ -55,7 +56,6 @@ module org.cryptomator.desktop { opens org.cryptomator.ui.forgetPassword to javafx.fxml; opens org.cryptomator.ui.fxapp to javafx.fxml; opens org.cryptomator.ui.health to javafx.fxml; - opens org.cryptomator.ui.keyloading.hub to javafx.fxml; opens org.cryptomator.ui.keyloading.masterkeyfile to javafx.fxml; opens org.cryptomator.ui.lock to javafx.fxml; opens org.cryptomator.ui.mainwindow to javafx.fxml; diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/CreateDeviceDto.java b/src/main/java/org/cryptomator/ui/keyloading/hub/CreateDeviceDto.java new file mode 100644 index 000000000..71377a318 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/CreateDeviceDto.java @@ -0,0 +1,9 @@ +package org.cryptomator.ui.keyloading.hub; + +class CreateDeviceDto { + + public String id; + public String name; + public String publicKey; + +} 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 2aadfb1d0..8316f640a 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java @@ -19,6 +19,7 @@ import javafx.scene.Scene; import javafx.stage.Stage; import javafx.stage.Window; import java.net.URI; +import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.AtomicReference; @KeyLoading 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 90efc6abc..5bc8bc419 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java @@ -10,6 +10,7 @@ import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.UserInteractionLock; import org.cryptomator.ui.keyloading.KeyLoading; import org.cryptomator.ui.keyloading.KeyLoadingScoped; +import org.eclipse.jetty.io.RuntimeIOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,30 +74,31 @@ public class ReceiveKeyController implements FxController { .GET() // .build(); httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()) // - .whenCompleteAsync(this::loadedExistingKey, Platform::runLater); + .thenAcceptAsync(this::loadedExistingKey, Platform::runLater) // + .exceptionallyAsync(this::retrievalFailed, Platform::runLater); } - private void loadedExistingKey(HttpResponse response, Throwable error) { - if (error != null) { - retrievalFailed(error); - } else { + private void loadedExistingKey(HttpResponse response) { + try { switch (response.statusCode()) { case 200 -> retrievalSucceeded(response); case 403 -> accessNotGranted(); case 404 -> needsDeviceRegistration(); - default -> retrievalFailed(new IOException("Unexpected response " + response.statusCode())); + default -> throw new IOException("Unexpected response " + response.statusCode()); } + } catch (IOException e) { + throw new RuntimeIOException(e); } } - private void retrievalSucceeded(HttpResponse response) { + private void retrievalSucceeded(HttpResponse response) throws IOException { try { var string = HttpHelper.readBody(response); jweRef.set(JWEObject.parse(string)); result.interacted(HubKeyLoadingModule.HubLoadingResult.SUCCESS); window.close(); - } catch (ParseException | IOException e) { - retrievalFailed(e); + } catch (ParseException e) { + throw new IOException("Failed to parse JWE", e); } } @@ -108,10 +110,11 @@ public class ReceiveKeyController implements FxController { window.setScene(unauthorizedScene.get()); } - private void retrievalFailed(Throwable cause) { + private Void retrievalFailed(Throwable cause) { result.interacted(HubKeyLoadingModule.HubLoadingResult.FAILED); LOG.error("Key retrieval failed", cause); errorComponent.cause(cause).window(window).build().showErrorScene(); + return null; } @FXML diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java index 46349280b..442fe2022 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java @@ -1,57 +1,92 @@ package org.cryptomator.ui.keyloading.hub; +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; import com.google.common.io.BaseEncoding; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import org.cryptomator.common.settings.DeviceKey; -import org.cryptomator.cryptolib.common.MessageDigestSupplier; import org.cryptomator.cryptolib.common.P384KeyPair; 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.inject.Inject; -import javafx.application.Application; +import javax.inject.Named; +import javafx.application.Platform; import javafx.fxml.FXML; +import javafx.scene.control.TextField; import javafx.stage.Stage; import javafx.stage.WindowEvent; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; -import java.security.KeyPair; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import java.util.Objects; +import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; @KeyLoadingScoped public class RegisterDeviceController implements FxController { - private final Application application; + private static final Logger LOG = LoggerFactory.getLogger(RegisterDeviceController.class); + private static final Gson GSON = new GsonBuilder().setLenient().create(); + private final Stage window; private final HubConfig hubConfig; + private final String bearerToken; + private final String deviceId; private final P384KeyPair keyPair; private final UserInteractionLock result; - private final String verificationCode; + private final DecodedJWT jwt; + private final HttpClient httpClient; + + public TextField deviceNameField; @Inject - public RegisterDeviceController(Application application, SecureRandom csprng, @KeyLoading Stage window, HubConfig hubConfig, DeviceKey deviceKey, UserInteractionLock result) { - this.application = application; + public RegisterDeviceController(@KeyLoading Stage window, ExecutorService executor, HubConfig hubConfig, @Named("deviceId") String deviceId, DeviceKey deviceKey, UserInteractionLock result, @Named("bearerToken") AtomicReference bearerToken) { this.window = window; this.hubConfig = hubConfig; + this.deviceId = deviceId; this.keyPair = Objects.requireNonNull(deviceKey.get()); this.result = result; + this.bearerToken = Objects.requireNonNull(bearerToken.get()); + this.jwt = JWT.decode(this.bearerToken); this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed); - this.verificationCode = String.format("%06d", csprng.nextInt(1_000_000)); + this.httpClient = HttpClient.newBuilder().executor(executor).build(); } @FXML - public void browse() { + public void register() { + var keyUri = URI.create("http://localhost:9090/devices/" + deviceId); // TODO lol hubConfig.deviceRegistrationUrl var deviceKey = keyPair.getPublic().getEncoded(); - var encodedKey = BaseEncoding.base64Url().omitPadding().encode(deviceKey); - var hashedKey = MessageDigestSupplier.SHA256.get().digest(deviceKey); - var deviceId = BaseEncoding.base16().encode(hashedKey); - var hash = computeVerificationHash(deviceId + encodedKey + verificationCode); - var url = hubConfig.deviceRegistrationUrl + "&device_key=" + encodedKey + "&device_id=" + deviceId + "&verification_hash=" + hash; - application.getHostServices().showDocument(url); + var dto = new CreateDeviceDto(); + dto.id = deviceId; + dto.name = deviceNameField.getText(); + dto.publicKey = BaseEncoding.base64Url().omitPadding().encode(deviceKey); + var json = GSON.toJson(dto); // TODO: do we want to keep GSON? doesn't support records -.- + var request = HttpRequest.newBuilder(keyUri) // + .header("Authorization", "Bearer " + bearerToken) // + .header("Content-Type", "application/json").PUT(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8)) // + .build(); + httpClient.sendAsync(request, HttpResponse.BodyHandlers.discarding()) // + .thenAcceptAsync(this::registrationSucceeded, Platform::runLater) // + .exceptionallyAsync(this::registrationFailed, Platform::runLater); + } + + private void registrationSucceeded(HttpResponse voidHttpResponse) { + LOG.info("Registered!"); + } + + private Void registrationFailed(Throwable cause) { + result.interacted(HubKeyLoadingModule.HubLoadingResult.FAILED); + LOG.error("Key retrieval failed", cause); + // TODO errorComponent.cause(cause).window(window).build().showErrorScene(); + return null; } @FXML @@ -66,20 +101,11 @@ public class RegisterDeviceController implements FxController { } } - private static String computeVerificationHash(String input) { - try { - var digest = MessageDigest.getInstance("SHA-256"); - digest.update(StandardCharsets.UTF_8.encode(input)); - return BaseEncoding.base64Url().omitPadding().encode(digest.digest()); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("Every implementation of the Java platform is required to support SHA-256."); - } - } - /* Getter */ - public String getVerificationCode() { - return verificationCode; + public String getUserName() { + return jwt.getClaim("email").asString(); } + } diff --git a/src/main/resources/fxml/hub_register_device.fxml b/src/main/resources/fxml/hub_register_device.fxml index edf7249e6..2fd5ceaa5 100644 --- a/src/main/resources/fxml/hub_register_device.fxml +++ b/src/main/resources/fxml/hub_register_device.fxml @@ -1,16 +1,15 @@ - + + - - - @@ -42,11 +44,7 @@ +