Преглед на файлове

legacy vaults supported now

Jan-Peter Klein преди 1 месец
родител
ревизия
b00ee4740a

+ 4 - 2
src/main/java/org/cryptomator/common/recovery/BackupRestorer.java

@@ -18,7 +18,7 @@ public final class BackupRestorer {
 
 	private BackupRestorer() {}
 
-	public static void restoreIfPresent(Path vaultPath, String filePrefix) {
+	public static void restoreIfBackupPresent(Path vaultPath, String filePrefix) {
 		Path targetFile = vaultPath.resolve(filePrefix);
 
 		try (Stream<Path> files = Files.list(vaultPath)) {
@@ -45,7 +45,9 @@ public final class BackupRestorer {
 	private static void copyBackupFile(Path backupFile, Path configPath) {
 		try {
 			Files.copy(backupFile, configPath, StandardCopyOption.REPLACE_EXISTING);
+			LOG.debug("Backup restored - file: '{}'  path: '{}'", backupFile, configPath);
 		} catch (IOException e) {
-			LOG.warn("Unable to copy backup file from '{}' to '{}'", backupFile, configPath, e);		}
+			LOG.warn("Unable to copy backup file from '{}' to '{}'", backupFile, configPath, e);
+		}
 	}
 }

+ 12 - 6
src/main/java/org/cryptomator/common/recovery/MasterkeyService.java

@@ -19,7 +19,6 @@ import java.nio.file.StandardOpenOption;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.stream.Stream;
@@ -64,19 +63,22 @@ public final class MasterkeyService {
 
 	public static Optional<CryptorProvider.Scheme> detect(Masterkey masterkey, Path vaultPath) {
 		try (Stream<Path> paths = Files.walk(vaultPath.resolve(DATA_DIR_NAME))) {
-			List<String> excludedFilenames = List.of("dirid.c9r", "dir.c9r");
-			Optional<Path> c9rFile = paths.filter(p -> p.toString().endsWith(".c9r")).filter(p -> excludedFilenames.stream().noneMatch(p.toString()::endsWith)).findFirst();
+			Optional<Path> c9rFile = paths //
+					.filter(p -> p.toString().endsWith(".c9r")) //
+					.filter(p -> !p.toString().equals("dir.c9r")) //
+					.findFirst();
 			if (c9rFile.isEmpty()) {
 				LOG.info("Unable to detect Crypto scheme: No *.c9r file found in {}", vaultPath);
 				return Optional.empty();
 			}
-			return determineScheme(c9rFile.get(), masterkey); //
+			return determineScheme(c9rFile.get(), masterkey);
 		} catch (IOException e) {
 			LOG.info("Unable to detect Crypto scheme: Failed to inspect vault", e);
 			return Optional.empty();
 		}
 	}
 
+
 	private static Optional<CryptorProvider.Scheme> determineScheme(Path c9rFile, Masterkey masterkey) {
 		return Arrays.stream(CryptorProvider.Scheme.values()).filter(scheme -> {
 			try (Cryptor cryptor = CryptorProvider.forScheme(scheme).provide(masterkey.copy(), SecureRandom.getInstanceStrong())) {
@@ -90,9 +92,13 @@ public final class MasterkeyService {
 
 				headerBuf.flip();
 				cryptor.fileHeaderCryptor().decryptHeader(headerBuf.duplicate());
+				LOG.debug("Detected Crypto scheme: {}", scheme);
 				return true;
-			} catch (IOException | CryptoException | NoSuchAlgorithmException e) {
-				LOG.info("Unable to detect Crypto scheme: Failed to decrypt .c9r file", e);
+			} catch (CryptoException e) {
+				LOG.debug("Could not decrypt with scheme: {}", scheme);
+				return false;
+			} catch (IOException | NoSuchAlgorithmException e) {
+				LOG.warn("Unable to detect Crypto scheme: Failed to decrypt .c9r file", e);
 				return false;
 			}
 		}).findFirst();

+ 14 - 19
src/main/java/org/cryptomator/common/vaults/VaultListManager.java

@@ -23,13 +23,7 @@ import java.util.ResourceBundle;
 
 import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
 import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
-import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
-import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
-import static org.cryptomator.common.vaults.VaultState.Value.ALL_MISSING;
-import static org.cryptomator.common.vaults.VaultState.Value.NEEDS_MIGRATION;
-import static org.cryptomator.common.vaults.VaultState.Value.PROCESSING;
-import static org.cryptomator.common.vaults.VaultState.Value.UNLOCKED;
-import static org.cryptomator.common.vaults.VaultState.Value.VAULT_CONFIG_MISSING;
+import static org.cryptomator.common.vaults.VaultState.Value.*;
 
 import org.apache.commons.lang3.SystemUtils;
 import org.cryptomator.common.Constants;
@@ -194,31 +188,32 @@ public class VaultListManager {
 		Path pathToMasterkey = pathToVault.resolve(MASTERKEY_FILENAME);
 
 		if (!Files.exists(pathToVault)) {
-			return VaultState.Value.MISSING;
+			return MISSING;
 		}
 
-		BackupRestorer.restoreIfPresent(pathToVaultConfig.getParent(), VAULTCONFIG_FILENAME);
-
-		BackupRestorer.restoreIfPresent(pathToMasterkey.getParent(), MASTERKEY_FILENAME);
+		if(!Files.exists(pathToVaultConfig)) {
+			BackupRestorer.restoreIfBackupPresent(pathToVault, VAULTCONFIG_FILENAME);
+		}
+		if(!Files.exists(pathToMasterkey)){
+			BackupRestorer.restoreIfBackupPresent(pathToVault, MASTERKEY_FILENAME);
+		}
 
 		if (!Files.exists(pathToVaultConfig) && !Files.exists(pathToMasterkey)) {
 			return ALL_MISSING;
 		}
-
+		var checkedDirStructureVaultState = checkDirStructure(pathToVault);
 		if (!Files.exists(pathToVaultConfig)) {
-			return VAULT_CONFIG_MISSING;
+			return checkedDirStructureVaultState.equals(LOCKED) ? VAULT_CONFIG_MISSING : checkedDirStructureVaultState ;
 		}
 
-		return checkDirStructure(pathToVault);
+		return checkedDirStructureVaultState;
 	}
 
 	private static VaultState.Value checkDirStructure(Path pathToVault) throws IOException {
 		return switch (CryptoFileSystemProvider.checkDirStructureForVault(pathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME)) {
-			case VAULT -> VaultState.Value.LOCKED;
-			case UNRELATED -> VaultState.Value.MISSING;
-			case MAYBE_LEGACY -> Migrators.get().needsMigration(pathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) ? //
-					VaultState.Value.NEEDS_MIGRATION //
-					: VaultState.Value.MISSING;
+			case VAULT -> LOCKED;
+			case UNRELATED -> MISSING;
+			case MAYBE_LEGACY -> Migrators.get().needsMigration(pathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) ? NEEDS_MIGRATION : MISSING;
 		};
 	}
 

+ 1 - 1
src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java

@@ -270,7 +270,7 @@ public class VaultListController implements FxController {
 						recoveryKeyWindow.create(preparedVault, mainWindow, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)).showOnboardingDialogWindow();
 				case ALL_MISSING ->
 						recoveryKeyWindow.create(preparedVault, mainWindow, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)).showOnboardingDialogWindow();
-				case LOCKED -> {
+				case LOCKED, NEEDS_MIGRATION -> {
 					vaultListManager.addVault(preparedVault);
 					dialogs.prepareRecoveryVaultAdded(mainWindow, preparedVault.getDisplayName()).setOkAction(Stage::close).build().showAndWait();
 				}

+ 11 - 16
src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java

@@ -65,7 +65,6 @@ public class RecoveryKeyResetPasswordController implements FxController {
 	private final Stage owner;
 
 	public NewPasswordController newPasswordController;
-	public Button backButton;
 	public Button nextButton;
 
 	@Inject
@@ -104,18 +103,8 @@ public class RecoveryKeyResetPasswordController implements FxController {
 	@FXML
 	public void initialize() {
 		switch (recoverType.get()) {
-			case RESTORE_MASTERKEY -> {
-				nextButton.setText(resourceBundle.getString("recoveryKey.recover.recoverBtn"));
-				nextButton.setOnAction((_) -> resetPassword());
-			}
-			case RESTORE_ALL -> {
-				nextButton.setText(resourceBundle.getString("recoveryKey.recover.recoverBtn"));
-				nextButton.setOnAction((_) -> restorePassword());
-			}
-			case RESET_PASSWORD -> {
-				nextButton.setText(resourceBundle.getString("recoveryKey.recover.resetBtn"));
-				nextButton.setOnAction((_) -> resetPassword());
-			}
+			case RESTORE_MASTERKEY, RESTORE_ALL -> nextButton.setText(resourceBundle.getString("recoveryKey.recover.recoverBtn"));
+			case RESET_PASSWORD -> nextButton.setText(resourceBundle.getString("recoveryKey.recover.resetBtn"));
 		}
 	}
 
@@ -128,15 +117,21 @@ public class RecoveryKeyResetPasswordController implements FxController {
 		}
 	}
 
+	@FXML
+	public void next() {
+		switch (recoverType.get()) {
+			case RESTORE_ALL -> restorePassword();
+			case RESTORE_MASTERKEY, RESET_PASSWORD -> resetPassword();
+		}
+	}
+
 	@FXML
 	public void restorePassword() {
 		try (RecoveryDirectory recoveryDirectory = RecoveryDirectory.create(vault.getPath())) {
 			Path recoveryPath = recoveryDirectory.getRecoveryPath();
 			MasterkeyService.recoverFromRecoveryKey(recoveryKey.get(), recoveryKeyFactory, recoveryPath, newPasswordController.passwordField.getCharacters());
 
-			Path masterkeyFilePath = recoveryPath.resolve(MASTERKEY_FILENAME);
-
-			try (Masterkey masterkey = MasterkeyService.load(masterkeyFileAccess, masterkeyFilePath, newPasswordController.passwordField.getCharacters())) {
+			try (Masterkey masterkey = MasterkeyService.load(masterkeyFileAccess, recoveryPath.resolve(MASTERKEY_FILENAME), newPasswordController.passwordField.getCharacters())) {
 				CryptoFsInitializer.init(recoveryPath, masterkey, shorteningThreshold.get(), cipherCombo.get());
 			}
 

+ 6 - 10
src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java

@@ -1,10 +1,11 @@
 package org.cryptomator.ui.recoverykey;
 
-
 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.recovery.MasterkeyService;
+import org.cryptomator.common.recovery.RecoveryActionType;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.cryptofs.VaultConfig;
 import org.cryptomator.cryptofs.VaultConfigLoadException;
@@ -26,12 +27,9 @@ import javafx.scene.control.TextFormatter;
 import javafx.scene.input.KeyCode;
 import javafx.scene.input.KeyEvent;
 
-import org.cryptomator.common.recovery.MasterkeyService;
-import org.cryptomator.common.recovery.RecoveryActionType;
-
 public class RecoveryKeyValidateController implements FxController {
 
-	private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
+	private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyValidateController.class);
 	private static final CharMatcher ALLOWED_CHARS = CharMatcher.inRange('a', 'z').or(CharMatcher.is(' '));
 
 	private final Vault vault;
@@ -137,7 +135,7 @@ public class RecoveryKeyValidateController implements FxController {
 	private void validateRecoveryKey() {
 		switch (recoverType.get()) {
 			case RESTORE_ALL, RESTORE_VAULT_CONFIG -> {
-				try{
+				try {
 					var combo = MasterkeyService.validateRecoveryKeyAndDetectCombo(recoveryKeyFactory, vault, recoveryKey.get(), masterkeyFileAccess);
 					combo.ifPresent(cipherCombo::set);
 					if (combo.isPresent()) {
@@ -145,15 +143,13 @@ public class RecoveryKeyValidateController implements FxController {
 					} else {
 						recoveryKeyState.set(RecoveryKeyState.WRONG);
 					}
-				}
-				catch (IllegalArgumentException e){
+				} catch (IllegalArgumentException e) {
 					recoveryKeyState.set(RecoveryKeyState.INVALID);
 				}
 			}
 			case RESTORE_MASTERKEY, RESET_PASSWORD, SHOW_KEY, CONVERT_VAULT -> {
 				isWrongKey = false;
-				boolean valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(),
-						unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
+				boolean 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()

+ 2 - 2
src/main/resources/fxml/recoverykey_reset_password.fxml

@@ -24,8 +24,8 @@
 		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
 			<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
 				<buttons>
-					<Button fx:id="backButton" text="%generic.button.back" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
-					<Button fx:id="nextButton" text="%recoveryKey.recover.recoverBtn" ButtonBar.buttonData="FINISH" defaultButton="true" disable="${!controller.passwordSufficientAndMatching}"/>
+					<Button text="%generic.button.back" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
+					<Button fx:id="nextButton" ButtonBar.buttonData="FINISH" defaultButton="true" disable="${!controller.passwordSufficientAndMatching}" onAction="#next"/>
 				</buttons>
 			</ButtonBar>
 		</VBox>