فهرست منبع

pass a single keyloader to cryptofs

Sebastian Stenzel 4 سال پیش
والد
کامیت
69c63702f2

+ 1 - 1
main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java

@@ -123,7 +123,7 @@ public class Vault {
 		}
 
 		CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
-				.withKeyLoaders(keyLoader) //
+				.withKeyLoader(keyLoader) //
 				.withFlags(flags) //
 				.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength().get()) //
 				.build();

+ 1 - 1
main/pom.xml

@@ -25,7 +25,7 @@
 		<project.jdk.version>16</project.jdk.version>
 
 		<!-- cryptomator dependencies -->
-		<cryptomator.cryptofs.version>2.0.0-beta7</cryptomator.cryptofs.version>
+		<cryptomator.cryptofs.version>2.0.0-beta8</cryptomator.cryptofs.version>
 		<cryptomator.integrations.version>1.0.0-beta2</cryptomator.integrations.version>
 		<cryptomator.integrations.win.version>1.0.0-beta2</cryptomator.integrations.win.version>
 		<cryptomator.integrations.mac.version>1.0.0-beta2</cryptomator.integrations.mac.version>

+ 18 - 16
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java

@@ -8,13 +8,14 @@ import org.cryptomator.cryptofs.CryptoFileSystemProvider;
 import org.cryptomator.cryptofs.VaultCipherCombo;
 import org.cryptomator.cryptolib.api.CryptoException;
 import org.cryptomator.cryptolib.api.Masterkey;
+import org.cryptomator.cryptolib.api.MasterkeyLoader;
 import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
-import org.cryptomator.cryptolib.common.MasterkeyFileLoader;
 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.Tasks;
+import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
 import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,6 +37,7 @@ import javafx.scene.control.ToggleGroup;
 import javafx.stage.Stage;
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.net.URI;
 import java.nio.channels.WritableByteChannel;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
@@ -53,6 +55,7 @@ import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
 public class CreateNewVaultPasswordController implements FxController {
 
 	private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultPasswordController.class);
+	private static final URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME); // TODO better place?
 
 	private final Stage window;
 	private final Lazy<Scene> chooseLocationScene;
@@ -174,23 +177,22 @@ public class CreateNewVaultPasswordController implements FxController {
 		Path masterkeyFilePath = path.resolve(MASTERKEY_FILENAME);
 		try (Masterkey masterkey = Masterkey.generate(csprng)) {
 			masterkeyFileAccess.persist(masterkey, masterkeyFilePath, passphrase);
-		}
 
-		// 2. initialize vault:
-		var context = new StaticMasterkeyFileLoaderContext(masterkeyFilePath, passphrase);
-		var loader = masterkeyFileAccess.keyLoader(path, context);
-		try {
-			CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(VaultCipherCombo.SIV_CTRMAC).withKeyLoaders(loader).build();
-			CryptoFileSystemProvider.initialize(path, fsProps, MasterkeyFileLoader.keyId(MASTERKEY_FILENAME));
-
-			// 3. write vault-internal readme file:
-			String vaultReadmeFileName = resourceBundle.getString("addvault.new.readme.accessLocation.fileName");
-			try (FileSystem fs = CryptoFileSystemProvider.newFileSystem(path, fsProps); //
-				 WritableByteChannel ch = Files.newByteChannel(fs.getPath("/", vaultReadmeFileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
-				ch.write(US_ASCII.encode(readmeGenerator.createVaultAccessLocationReadmeRtf()));
+			// 2. initialize vault:
+			try {
+				MasterkeyLoader loader = ignored -> masterkey;
+				CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(VaultCipherCombo.SIV_CTRMAC).withKeyLoader(loader).build();
+				CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
+
+				// 3. write vault-internal readme file:
+				String vaultReadmeFileName = resourceBundle.getString("addvault.new.readme.accessLocation.fileName");
+				try (FileSystem fs = CryptoFileSystemProvider.newFileSystem(path, fsProps); //
+					 WritableByteChannel ch = Files.newByteChannel(fs.getPath("/", vaultReadmeFileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
+					ch.write(US_ASCII.encode(readmeGenerator.createVaultAccessLocationReadmeRtf()));
+				}
+			} catch (CryptoException e) {
+				throw new IOException("Failed initialize vault.", e);
 			}
-		} catch (CryptoException e) {
-			throw new IOException("Failed initialize vault.", e);
 		}
 
 		// 4. write vault-external readme file:

+ 0 - 28
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/StaticMasterkeyFileLoaderContext.java

@@ -1,28 +0,0 @@
-package org.cryptomator.ui.addvaultwizard;
-
-import com.google.common.base.Preconditions;
-import org.cryptomator.cryptolib.common.MasterkeyFileLoaderContext;
-
-import java.nio.file.Path;
-
-class StaticMasterkeyFileLoaderContext implements MasterkeyFileLoaderContext {
-
-	private final Path masterkeyFilePath;
-	private final CharSequence passphrase;
-
-	StaticMasterkeyFileLoaderContext(Path masterkeyFilePath, CharSequence passphrase) {
-		this.masterkeyFilePath = masterkeyFilePath;
-		this.passphrase = passphrase;
-	}
-
-	@Override
-	public Path getCorrectMasterkeyFilePath(String s) {
-		return masterkeyFilePath;
-	}
-
-	@Override
-	public CharSequence getPassphrase(Path path) {
-		Preconditions.checkArgument(masterkeyFilePath.equals(path));
-		return passphrase;
-	}
-}

+ 3 - 0
main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java

@@ -3,8 +3,11 @@ package org.cryptomator.ui.keyloading;
 import dagger.BindsInstance;
 import dagger.Subcomponent;
 import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.cryptolib.api.MasterkeyLoader;
 
 import javafx.stage.Stage;
+import java.util.Map;
+import java.util.function.Supplier;
 
 @KeyLoadingScoped
 @Subcomponent(modules = {KeyLoadingModule.class})

+ 2 - 2
main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingModule.java

@@ -35,13 +35,13 @@ abstract class KeyLoadingModule {
 	@Provides
 	@KeyLoading
 	@KeyLoadingScoped
-	static KeyLoadingStrategy provideKeyLoaderProvider(@KeyLoading Optional<URI> keyId, Map<String, KeyLoadingStrategy> strategies) {
+	static KeyLoadingStrategy provideKeyLoaderProvider(@KeyLoading Optional<URI> keyId, Map<String, Provider<KeyLoadingStrategy>> strategies) {
 		if (keyId.isEmpty()) {
 			return KeyLoadingStrategy.failed(new IllegalArgumentException("No key id provided"));
 		} else {
 			String scheme = keyId.get().getScheme();
 			var fallback = KeyLoadingStrategy.failed(new IllegalArgumentException("Unsupported key id " + scheme));
-			return strategies.getOrDefault(scheme, fallback);
+			return strategies.getOrDefault(scheme, () -> fallback).get();
 		}
 	}
 

+ 21 - 8
main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingStrategy.java

@@ -1,21 +1,34 @@
 package org.cryptomator.ui.keyloading;
 
+import org.cryptomator.cryptolib.api.Masterkey;
 import org.cryptomator.cryptolib.api.MasterkeyLoader;
 import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
 
-public interface KeyLoadingStrategy {
+import java.net.URI;
+
+/**
+ * A reusable, stateful {@link MasterkeyLoader}, that can deal with certain exceptions.
+ */
+@FunctionalInterface
+public interface KeyLoadingStrategy extends MasterkeyLoader {
 
 	/**
-	 * @return A reusable masterkey loader, preconfigured with the vault of the current unlock process
-	 * @throws MasterkeyLoadingFailedException If unable to provide the masterkey loader
+	 * Loads a master key. This might be a long-running operation, as it may require user input or expensive computations.
+	 * <p>
+	 * If loading fails exceptionally, this strategy might be able to {@link #recoverFromException(MasterkeyLoadingFailedException) recover from this exception}, so it can be used in a further attempt.
+	 *
+	 * @param keyId An URI uniquely identifying the source and identity of the key
+	 * @return The raw key bytes. Must not be null
+	 * @throws MasterkeyLoadingFailedException Thrown when it is impossible to fulfill the request
 	 */
-	MasterkeyLoader masterkeyLoader() throws MasterkeyLoadingFailedException;
+	@Override
+	Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException;
 
 	/**
-	 * Allows the component to try and recover from an exception thrown while loading a masterkey.
+	 * Allows the loader to try and recover from an exception thrown during the last attempt.
 	 *
-	 * @param exception An exception thrown either by {@link #masterkeyLoader()} or by the returned {@link MasterkeyLoader}.
-	 * @return <code>true</code> if this component was able to handle the exception and another attempt should be made to load a masterkey
+	 * @param exception An exception thrown by {@link #loadKey(URI)}.
+	 * @return <code>true</code> if this component was able to handle the exception and another attempt can be made to load a masterkey
 	 */
 	default boolean recoverFromException(MasterkeyLoadingFailedException exception) {
 		return false;
@@ -38,7 +51,7 @@ public interface KeyLoadingStrategy {
 	 * @return A new KeyLoadingStrategy that will always fail with an {@link MasterkeyLoadingFailedException}.
 	 */
 	static KeyLoadingStrategy failed(Exception exception) {
-		return () -> {
+		return keyid -> {
 			if (exception instanceof MasterkeyLoadingFailedException e) {
 				throw e;
 			} else {

+ 0 - 129
main/ui/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingContext.java

@@ -1,129 +0,0 @@
-package org.cryptomator.ui.keyloading.masterkeyfile;
-
-import dagger.Lazy;
-import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
-import org.cryptomator.cryptolib.common.MasterkeyFileLoaderContext;
-import org.cryptomator.ui.common.Animations;
-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;
-import org.cryptomator.ui.unlock.UnlockCancelledException;
-
-import javax.inject.Inject;
-import javafx.application.Platform;
-import javafx.scene.Scene;
-import javafx.stage.Stage;
-import javafx.stage.Window;
-import java.nio.CharBuffer;
-import java.nio.file.Path;
-import java.util.concurrent.atomic.AtomicReference;
-
-@KeyLoadingScoped
-class MasterkeyFileLoadingContext implements MasterkeyFileLoaderContext {
-
-	private final Stage window;
-	private final Lazy<Scene> passphraseEntryScene;
-	private final Lazy<Scene> selectMasterkeyFileScene;
-	private final UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock;
-	private final UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock;
-	private final AtomicReference<char[]> password;
-	private final AtomicReference<Path> filePath;
-
-	private boolean wrongPassword;
-
-	@Inject
-	public MasterkeyFileLoadingContext(@KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath) {
-		this.window = window;
-		this.passphraseEntryScene = passphraseEntryScene;
-		this.selectMasterkeyFileScene = selectMasterkeyFileScene;
-		this.passwordEntryLock = passwordEntryLock;
-		this.masterkeyFileProvisionLock = masterkeyFileProvisionLock;
-		this.password = password;
-		this.filePath = filePath;
-	}
-
-	@Override
-	public Path getCorrectMasterkeyFilePath(String masterkeyFilePath) {
-		if (filePath.get() != null) { // e.g. already chosen on previous attempt with wrong password
-			return filePath.get();
-		}
-
-		assert filePath.get() == null;
-		try {
-			if (askForCorrectMasterkeyFile() == MasterkeyFileLoadingModule.MasterkeyFileProvision.MASTERKEYFILE_PROVIDED) {
-				return filePath.get();
-			} else {
-				throw new UnlockCancelledException("Choosing masterkey file cancelled.");
-			}
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			throw new UnlockCancelledException("Choosing masterkey file interrupted", e);
-		}
-	}
-
-	private MasterkeyFileLoadingModule.MasterkeyFileProvision askForCorrectMasterkeyFile() throws InterruptedException {
-		Platform.runLater(() -> {
-			window.setScene(selectMasterkeyFileScene.get());
-			window.show();
-			Window owner = window.getOwner();
-			if (owner != null) {
-				window.setX(owner.getX() + (owner.getWidth() - window.getWidth()) / 2);
-				window.setY(owner.getY() + (owner.getHeight() - window.getHeight()) / 2);
-			} else {
-				window.centerOnScreen();
-			}
-		});
-		return masterkeyFileProvisionLock.awaitInteraction();
-	}
-
-	@Override
-	public CharSequence getPassphrase(Path path) throws UnlockCancelledException {
-		if (password.get() != null) { // e.g. pre-filled from keychain
-			return CharBuffer.wrap(password.get());
-		}
-
-		assert password.get() == null;
-		try {
-			if (askForPassphrase() == MasterkeyFileLoadingModule.PasswordEntry.PASSWORD_ENTERED) {
-				assert password.get() != null;
-				return CharBuffer.wrap(password.get());
-			} else {
-				throw new UnlockCancelledException("Password entry cancelled.");
-			}
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			throw new UnlockCancelledException("Password entry interrupted", e);
-		}
-	}
-
-	private MasterkeyFileLoadingModule.PasswordEntry askForPassphrase() throws InterruptedException {
-		Platform.runLater(() -> {
-			window.setScene(passphraseEntryScene.get());
-			window.show();
-			Window owner = window.getOwner();
-			if (owner != null) {
-				window.setX(owner.getX() + (owner.getWidth() - window.getWidth()) / 2);
-				window.setY(owner.getY() + (owner.getHeight() - window.getHeight()) / 2);
-			} else {
-				window.centerOnScreen();
-			}
-			if (wrongPassword) {
-				Animations.createShakeWindowAnimation(window).play();
-			}
-		});
-		return passwordEntryLock.awaitInteraction();
-	}
-
-	public boolean recoverFromException(MasterkeyLoadingFailedException exception) {
-		if (exception instanceof InvalidPassphraseException) {
-			this.wrongPassword = true;
-			password.set(null);
-			return true; // reattempting key load
-		} else {
-			return false; // nothing we can do
-		}
-	}
-}

+ 1 - 9
main/ui/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingModule.java

@@ -7,8 +7,6 @@ import dagger.multibindings.IntoMap;
 import dagger.multibindings.StringKey;
 import org.cryptomator.common.keychain.KeychainManager;
 import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
-import org.cryptomator.cryptolib.common.MasterkeyFileLoader;
 import org.cryptomator.integrations.keychain.KeychainAccessException;
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.FxControllerKey;
@@ -45,12 +43,6 @@ public abstract class MasterkeyFileLoadingModule {
 		CANCELED
 	}
 
-	@Provides
-	@KeyLoadingScoped
-	static MasterkeyFileLoader provideMasterkeyFileLoader(MasterkeyFileAccess masterkeyFileAccess, @KeyLoading Vault vault, MasterkeyFileLoadingContext context) {
-		return masterkeyFileAccess.keyLoader(vault.getPath(), context);
-	}
-
 	@Provides
 	@KeyLoadingScoped
 	static UserInteractionLock<PasswordEntry> providePasswordEntryLock() {
@@ -125,7 +117,7 @@ public abstract class MasterkeyFileLoadingModule {
 	@Binds
 	@IntoMap
 	@KeyLoadingScoped
-	@StringKey("masterkeyfile")
+	@StringKey(MasterkeyFileLoadingStrategy.SCHEME)
 	abstract KeyLoadingStrategy bindMasterkeyFileLoadingStrategy(MasterkeyFileLoadingStrategy strategy);
 
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 122 - 10
main/ui/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingStrategy.java


+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java

@@ -70,7 +70,7 @@ public class UnlockWorkflow extends Task<Boolean> {
 	private void attemptUnlock() throws IOException, VolumeException, InvalidMountPointException, CryptoException {
 		boolean success = false;
 		try {
-			vault.unlock(keyLoadingStrategy.masterkeyLoader());
+			vault.unlock(keyLoadingStrategy);
 			success = true;
 		} catch (MasterkeyLoadingFailedException e) {
 			if (keyLoadingStrategy.recoverFromException(e)) {