This commit is contained in:
Sebastian Stenzel
2021-07-21 12:30:23 +02:00
parent b5fcfec4a4
commit 27a7c8323b
3 changed files with 52 additions and 30 deletions

View File

@@ -6,7 +6,6 @@ import org.cryptomator.cryptofs.VaultConfig;
import org.cryptomator.cryptofs.VaultConfigLoadException;
import org.cryptomator.cryptofs.VaultKeyInvalidException;
import org.cryptomator.cryptolib.api.Masterkey;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
@@ -73,9 +72,15 @@ public class StartController implements FxController {
private void loadKey() {
assert !Platform.isFxApplicationThread();
assert unverifiedVaultConfig.get() != null;
try {
keyLoadingStrategy.use(this::verifyVaultConfig);
} catch (VaultConfigLoadException e) {
throw new LoadingFailedException(e);
}
}
private void verifyVaultConfig(KeyLoadingStrategy keyLoadingStrategy) throws VaultConfigLoadException {
var unverifiedCfg = unverifiedVaultConfig.get();
// TODO: dedup keyloading w/ UnlockWorkflow.attemptUnlock()
boolean success = false;
try (var masterkey = keyLoadingStrategy.loadKey(unverifiedCfg.getKeyId())) {
var verifiedCfg = unverifiedCfg.verify(masterkey.getEncoded(), unverifiedCfg.allegedVaultVersion());
vaultConfigRef.set(verifiedCfg);
@@ -83,18 +88,6 @@ public class StartController implements FxController {
if (old != null) {
old.destroy();
}
success = true;
} catch (MasterkeyLoadingFailedException e) {
if (keyLoadingStrategy.recoverFromException(e)) {
// retry
loadKey();
} else {
throw new LoadingFailedException(e);
}
} catch (VaultConfigLoadException e) {
throw new LoadingFailedException(e);
} finally {
keyLoadingStrategy.cleanup(success);
}
}

View File

@@ -3,6 +3,8 @@ package org.cryptomator.ui.keyloading;
import org.cryptomator.cryptolib.api.Masterkey;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
@@ -12,6 +14,8 @@ import java.net.URI;
@FunctionalInterface
public interface KeyLoadingStrategy extends MasterkeyLoader {
Logger LOG = LoggerFactory.getLogger(KeyLoadingStrategy.class);
/**
* Loads a master key. This might be a long-running operation, as it may require user input or expensive computations.
* <p>
@@ -60,4 +64,36 @@ public interface KeyLoadingStrategy extends MasterkeyLoader {
};
}
/**
* Makes the given <code>user</code> apply this key loading strategy. If the user fails with a {@link MasterkeyLoadingFailedException},
* an attempt is made to {@link #recoverFromException(MasterkeyLoadingFailedException) recover} from it. Any other exception will be rethrown.
*
* @param user Some method using this strategy. May be invoked multiple times in case of recoverable {@link MasterkeyLoadingFailedException}s
* @param <E> Optional exception type thrown by <code>user</code>
* @throws MasterkeyLoadingFailedException If a non-recoverable exception is thrown by <code>user</code>
* @throws E Exception thrown by <code>user</code> and rethrown by this method
*/
default <E extends Exception> void use(KeyLoadingStrategyUser<E> user) throws MasterkeyLoadingFailedException, E {
boolean success = false;
try {
user.use(this);
} catch (MasterkeyLoadingFailedException e) {
if (recoverFromException(e)) {
LOG.info("Unlock attempt threw {}. Reattempting...", e.getClass().getSimpleName());
use(user);
} else {
throw e;
}
} finally {
cleanup(success);
}
}
@FunctionalInterface
interface KeyLoadingStrategyUser<E extends Exception> {
void use(KeyLoadingStrategy strategy) throws MasterkeyLoadingFailedException, E;
}
}

View File

@@ -1,5 +1,6 @@
package org.cryptomator.ui.unlock;
import com.google.common.base.Throwables;
import dagger.Lazy;
import org.cryptomator.common.mountpoint.InvalidMountPointException;
import org.cryptomator.common.vaults.MountPointRequirement;
@@ -7,12 +8,10 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.common.vaults.Volume.VolumeException;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.keyloading.KeyLoadingComponent;
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,20 +67,14 @@ public class UnlockWorkflow extends Task<Boolean> {
}
private void attemptUnlock() throws IOException, VolumeException, InvalidMountPointException, CryptoException {
// TODO: dedup keyloading w/ StartController.loadKey()
boolean success = false;
try {
vault.unlock(keyLoadingStrategy);
success = true;
} catch (MasterkeyLoadingFailedException e) {
if (keyLoadingStrategy.recoverFromException(e)) {
LOG.info("Unlock attempt threw {}. Reattempting...", e.getClass().getSimpleName());
attemptUnlock();
} else {
throw e;
}
} finally {
keyLoadingStrategy.cleanup(success);
keyLoadingStrategy.use(vault::unlock);
} catch (Exception e) {
Throwables.propagateIfPossible(e, IOException.class);
Throwables.propagateIfPossible(e, VolumeException.class);
Throwables.propagateIfPossible(e, InvalidMountPointException.class);
Throwables.propagateIfPossible(e, CryptoException.class);
throw new IllegalStateException("unexpected exception type", e);
}
}