|
@@ -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<HubKeyLoadingModule.HubLoadingResult> 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<HubKeyLoadingModule.HubLoadingResult> result) {
|
|
|
- this.application = application;
|
|
|
+ public RegisterDeviceController(@KeyLoading Stage window, ExecutorService executor, HubConfig hubConfig, @Named("deviceId") String deviceId, DeviceKey deviceKey, UserInteractionLock<HubKeyLoadingModule.HubLoadingResult> result, @Named("bearerToken") AtomicReference<String> 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<Void> 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();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
}
|