diff --git a/src/main/java/org/cryptomator/common/RecoverUtil.java b/src/main/java/org/cryptomator/common/RecoverUtil.java index 0e00ad346..86d8aa4af 100644 --- a/src/main/java/org/cryptomator/common/RecoverUtil.java +++ b/src/main/java/org/cryptomator/common/RecoverUtil.java @@ -14,7 +14,9 @@ import org.cryptomator.cryptolib.api.CryptoException; import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.api.CryptorProvider; import org.cryptomator.cryptolib.api.Masterkey; +import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.cryptomator.integrations.mount.MountService; +import org.cryptomator.ui.addvaultwizard.CreateNewVaultExpertSettingsController; import org.cryptomator.ui.changepassword.NewPasswordController; import org.cryptomator.ui.dialogs.Dialogs; import org.cryptomator.ui.fxapp.FxApplicationWindows; @@ -23,6 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.StringProperty; import javafx.concurrent.Task; import javafx.scene.Scene; @@ -39,6 +42,7 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Stream; +import org.cryptomator.cryptolib.api.MasterkeyLoader; import static org.cryptomator.common.Constants.DEFAULT_KEY_ID; import static org.cryptomator.common.Constants.MASTERKEY_FILENAME; @@ -54,7 +58,11 @@ public class RecoverUtil { public static CryptorProvider.Scheme detectCipherCombo(byte[] masterkey, Path pathToVault) { try (Stream paths = Files.walk(pathToVault.resolve(DATA_DIR_NAME))) { - return paths.filter(path -> path.toString().endsWith(".c9r")).findFirst().map(c9rFile -> determineScheme(c9rFile, masterkey)).orElseThrow(() -> new IllegalStateException("No .c9r file found.")); + return paths.filter(path -> path.toString() + .endsWith(".c9r")) + .findFirst() + .map(c9rFile -> determineScheme(c9rFile, masterkey)) + .orElseThrow(() -> new IllegalStateException("No .c9r file found.")); } catch (IOException e) { throw new IllegalStateException("Failed to detect cipher combo.", e); } @@ -117,9 +125,30 @@ public class RecoverUtil { return masterkeyFileAccess.load(masterkeyFilePath, password); } + public static boolean validateRecoveryKey(RecoveryKeyFactory recoveryKeyFactory, Vault vault, StringProperty recoveryKey, MasterkeyFileAccess masterkeyFileAccess) { + Path tempRecoveryPath = null; + CharSequence tmpPass = "asdasdasd"; + try { + tempRecoveryPath = createRecoveryDirectory(vault.getPath()); + createNewMasterkeyFile(recoveryKeyFactory, tempRecoveryPath, recoveryKey.get(), tmpPass); + Path masterkeyFilePath = tempRecoveryPath.resolve(MASTERKEY_FILENAME); + try (Masterkey masterkey = loadMasterkey(masterkeyFileAccess, masterkeyFilePath, tmpPass)) { + initializeCryptoFileSystem(tempRecoveryPath, vault.getPath(), masterkey, new SimpleIntegerProperty(CreateNewVaultExpertSettingsController.MAX_SHORTENING_THRESHOLD)); + return true; + } + } catch (IOException | CryptoException e) { + LOG.warn("Recovery key validation failed", e); + return false; + } finally { + if (tempRecoveryPath != null) { + deleteRecoveryDirectory(tempRecoveryPath); + } + } + } + public static void initializeCryptoFileSystem(Path recoveryPath, Path vaultPath, Masterkey masterkey, IntegerProperty shorteningThreshold) throws IOException, CryptoException { var combo = RecoverUtil.detectCipherCombo(masterkey.getEncoded(), vaultPath); - org.cryptomator.cryptolib.api.MasterkeyLoader loader = ignored -> masterkey.copy(); + MasterkeyLoader loader = ignored -> masterkey.copy(); CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(combo).withKeyLoader(loader).withShorteningThreshold(shorteningThreshold.get()).build(); CryptoFileSystemProvider.initialize(recoveryPath, fsProps, DEFAULT_KEY_ID); } @@ -240,7 +269,8 @@ public class RecoverUtil { RESTORE_VAULT_CONFIG, RESTORE_MASTERKEY, RESET_PASSWORD, - SHOW_KEY; + SHOW_KEY, + CONVERT_VAULT; } } diff --git a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java index f70242d2b..aa290b621 100644 --- a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java +++ b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java @@ -4,6 +4,7 @@ import dagger.Binds; import dagger.Module; import dagger.Provides; import dagger.multibindings.IntoMap; +import org.cryptomator.common.RecoverUtil; import org.cryptomator.common.vaults.Vault; import org.cryptomator.cryptofs.VaultConfig; import org.cryptomator.ui.changepassword.NewPasswordController; @@ -20,6 +21,8 @@ import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController; import javax.inject.Named; import javax.inject.Provider; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.scene.Scene; @@ -120,7 +123,7 @@ abstract class ConvertVaultModule { @IntoMap @FxControllerKey(RecoveryKeyValidateController.class) static FxController bindRecoveryKeyValidateController(@ConvertVaultWindow Vault vault, @ConvertVaultWindow VaultConfig.UnverifiedVaultConfig vaultConfig, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) { - return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory); + return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory, new SimpleObjectProperty<>(RecoverUtil.Type.CONVERT_VAULT),null); } } diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java index ef925cbf4..08c23a0db 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java @@ -8,6 +8,7 @@ import org.cryptomator.common.Nullable; import org.cryptomator.common.RecoverUtil; import org.cryptomator.common.vaults.Vault; import org.cryptomator.cryptofs.VaultConfig; +import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.cryptomator.ui.addvaultwizard.CreateNewVaultExpertSettingsController; import org.cryptomator.ui.common.DefaultSceneFactory; import org.cryptomator.ui.common.FxController; @@ -193,8 +194,8 @@ abstract class RecoveryKeyModule { @Provides @IntoMap @FxControllerKey(RecoveryKeyValidateController.class) - static FxController bindRecoveryKeyValidateController(@RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) { - return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory); + static FxController bindRecoveryKeyValidateController(@RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, @Named("recoverType") ObjectProperty recoverType, @Nullable MasterkeyFileAccess masterkeyFileAccess) { + return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory, recoverType, masterkeyFileAccess); } @Provides diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java index 7392d5768..9f2842f34 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java @@ -48,6 +48,9 @@ public class RecoveryKeyRecoverController implements FxController { window.setTitle(resourceBundle.getString("recoveryKey.display.title")); yield resetPasswordScene; } + default -> { + yield null; + } }; } diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java index 4a8224ffe..6472d3849 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java @@ -5,14 +5,17 @@ import com.google.common.base.CharMatcher; import com.google.common.base.Strings; import org.cryptomator.common.Nullable; import org.cryptomator.common.ObservableUtil; +import org.cryptomator.common.RecoverUtil; import org.cryptomator.common.vaults.Vault; import org.cryptomator.cryptofs.VaultConfig; import org.cryptomator.cryptofs.VaultConfigLoadException; import org.cryptomator.cryptofs.VaultKeyInvalidException; +import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.cryptomator.ui.common.FxController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.inject.Named; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.StringProperty; @@ -37,12 +40,19 @@ public class RecoveryKeyValidateController implements FxController { private final RecoveryKeyFactory recoveryKeyFactory; private final ObjectProperty recoveryKeyState; private final AutoCompleter autoCompleter; + private final ObjectProperty recoverType; + private final MasterkeyFileAccess masterkeyFileAccess; private volatile boolean isWrongKey; public TextArea textarea; - public RecoveryKeyValidateController(Vault vault, @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) { + public RecoveryKeyValidateController(Vault vault, // + @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, // + StringProperty recoveryKey, // + RecoveryKeyFactory recoveryKeyFactory, // + @Named("recoverType") ObjectProperty recoverType, // + MasterkeyFileAccess masterkeyFileAccess) { this.vault = vault; this.unverifiedVaultConfig = vaultConfig; this.recoveryKey = recoveryKey; @@ -52,6 +62,8 @@ public class RecoveryKeyValidateController implements FxController { this.recoveryKeyCorrect = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.CORRECT::equals, false); this.recoveryKeyWrong = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.WRONG::equals, false); this.recoveryKeyInvalid = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.INVALID::equals, false); + this.recoverType = recoverType; + this.masterkeyFileAccess = masterkeyFileAccess; } @FXML @@ -118,7 +130,23 @@ public class RecoveryKeyValidateController implements FxController { private void validateRecoveryKey() { isWrongKey = false; - var valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null); + var valid = false; + switch (recoverType.get()) { + case RESTORE_VAULT_CONFIG -> { + try{ + valid = RecoverUtil.validateRecoveryKey(recoveryKeyFactory, vault, recoveryKey, masterkeyFileAccess); + } + catch (IllegalStateException e){ + isWrongKey = true; + } + catch (IllegalArgumentException e){ + isWrongKey = false; + } + } + case RESTORE_MASTERKEY, RESET_PASSWORD, SHOW_KEY, CONVERT_VAULT -> { + valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null); + } + }; if (valid) { recoveryKeyState.set(RecoveryKeyState.CORRECT); } else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig()