mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 10:11:27 +00:00
Removed "Mount after unlock" option. Mounting/unmounting no longer visible to the user, but merged with unlocking/locking.
This commit is contained in:
@@ -26,7 +26,6 @@ import javafx.beans.property.StringProperty;
|
||||
public class VaultSettings {
|
||||
|
||||
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
||||
public static final boolean DEFAULT_MOUNT_AFTER_UNLOCK = true;
|
||||
public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true;
|
||||
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
|
||||
|
||||
@@ -35,7 +34,6 @@ public class VaultSettings {
|
||||
private final StringProperty mountName = new SimpleStringProperty();
|
||||
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty mountAfterUnlock = new SimpleBooleanProperty(DEFAULT_MOUNT_AFTER_UNLOCK);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
|
||||
private final BooleanProperty usesIndividualMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
|
||||
private final StringProperty individualMountPath = new SimpleStringProperty();
|
||||
@@ -47,7 +45,7 @@ public class VaultSettings {
|
||||
}
|
||||
|
||||
Observable[] observables() {
|
||||
return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, mountAfterUnlock, revealAfterMount, usesIndividualMountPath, individualMountPath};
|
||||
return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath};
|
||||
}
|
||||
|
||||
private void deriveMountNameFromPath(Path path) {
|
||||
@@ -118,10 +116,6 @@ public class VaultSettings {
|
||||
return unlockAfterStartup;
|
||||
}
|
||||
|
||||
public BooleanProperty mountAfterUnlock() {
|
||||
return mountAfterUnlock;
|
||||
}
|
||||
|
||||
public BooleanProperty revealAfterMount() {
|
||||
return revealAfterMount;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ class VaultSettingsJsonAdapter {
|
||||
out.name("mountName").value(value.mountName().get());
|
||||
out.name("winDriveLetter").value(value.winDriveLetter().get());
|
||||
out.name("unlockAfterStartup").value(value.unlockAfterStartup().get());
|
||||
out.name("mountAfterUnlock").value(value.mountAfterUnlock().get());
|
||||
out.name("revealAfterMount").value(value.revealAfterMount().get());
|
||||
out.name("usesIndividualMountPath").value(value.usesIndividualMountPath().get());
|
||||
//TODO: should this always be written? ( because it could contain metadata, which the user does not want to save!)
|
||||
@@ -40,7 +39,6 @@ class VaultSettingsJsonAdapter {
|
||||
String individualMountPath = null;
|
||||
String winDriveLetter = null;
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
boolean mountAfterUnlock = VaultSettings.DEFAULT_MOUNT_AFTER_UNLOCK;
|
||||
boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT;
|
||||
boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
|
||||
|
||||
@@ -63,9 +61,6 @@ class VaultSettingsJsonAdapter {
|
||||
case "unlockAfterStartup":
|
||||
unlockAfterStartup = in.nextBoolean();
|
||||
break;
|
||||
case "mountAfterUnlock":
|
||||
mountAfterUnlock = in.nextBoolean();
|
||||
break;
|
||||
case "revealAfterMount":
|
||||
revealAfterMount = in.nextBoolean();
|
||||
break;
|
||||
@@ -87,7 +82,6 @@ class VaultSettingsJsonAdapter {
|
||||
vaultSettings.path().set(Paths.get(path));
|
||||
vaultSettings.winDriveLetter().set(winDriveLetter);
|
||||
vaultSettings.unlockAfterStartup().set(unlockAfterStartup);
|
||||
vaultSettings.mountAfterUnlock().set(mountAfterUnlock);
|
||||
vaultSettings.revealAfterMount().set(revealAfterMount);
|
||||
vaultSettings.usesIndividualMountPath().set(usesIndividualMountPath);
|
||||
vaultSettings.individualMountPath().set(individualMountPath);
|
||||
|
||||
@@ -107,9 +107,6 @@ public class UnlockController implements ViewController {
|
||||
@FXML
|
||||
private CheckBox savePassword;
|
||||
|
||||
@FXML
|
||||
private CheckBox mountAfterUnlock;
|
||||
|
||||
@FXML
|
||||
private TextField mountName;
|
||||
|
||||
@@ -159,8 +156,6 @@ public class UnlockController implements ViewController {
|
||||
public void initialize() {
|
||||
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
|
||||
unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
|
||||
mountName.disableProperty().bind(mountAfterUnlock.selectedProperty().not());
|
||||
revealAfterMount.disableProperty().bind(mountAfterUnlock.selectedProperty().not());
|
||||
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
|
||||
mountName.textProperty().addListener(this::mountNameDidChange);
|
||||
savePassword.setDisable(!keychainAccess.isPresent());
|
||||
@@ -250,12 +245,10 @@ public class UnlockController implements ViewController {
|
||||
}
|
||||
VaultSettings vaultSettings = vault.getVaultSettings();
|
||||
unlockAfterStartup.setSelected(savePassword.isSelected() && vaultSettings.unlockAfterStartup().get());
|
||||
mountAfterUnlock.setSelected(vaultSettings.mountAfterUnlock().get());
|
||||
revealAfterMount.setSelected(vaultSettings.revealAfterMount().get());
|
||||
useOwnMountPath.setSelected(vaultSettings.usesIndividualMountPath().get());
|
||||
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), vaultSettings.unlockAfterStartup()::set));
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(mountAfterUnlock.selectedProperty(), vaultSettings.mountAfterUnlock()::set));
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), vaultSettings.revealAfterMount()::set));
|
||||
vaultSubs = vaultSubs.and(EasyBind.subscribe(useOwnMountPath.selectedProperty(), vaultSettings.usesIndividualMountPath()::set));
|
||||
|
||||
|
||||
@@ -83,15 +83,6 @@ public class UnlockedController implements ViewController {
|
||||
@FXML
|
||||
private ContextMenu moreOptionsMenu;
|
||||
|
||||
@FXML
|
||||
private MenuItem mountVaultMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem unmountVaultMenuItem;
|
||||
|
||||
@FXML
|
||||
private MenuItem revealVaultMenuItem;
|
||||
|
||||
@FXML
|
||||
private VBox root;
|
||||
|
||||
@@ -103,10 +94,6 @@ public class UnlockedController implements ViewController {
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
mountVaultMenuItem.disableProperty().bind(vaultState.isEqualTo(Vault.State.UNLOCKED).not()); // enable when unlocked
|
||||
unmountVaultMenuItem.disableProperty().bind(vaultState.isEqualTo(Vault.State.MOUNTED).not()); // enable when mounted
|
||||
revealVaultMenuItem.disableProperty().bind(vaultState.isEqualTo(Vault.State.MOUNTED).not()); // enable when mounted
|
||||
|
||||
EasyBind.subscribe(vault, this::vaultChanged);
|
||||
EasyBind.subscribe(moreOptionsMenu.showingProperty(), moreOptionsButton::setSelected);
|
||||
}
|
||||
@@ -121,10 +108,6 @@ public class UnlockedController implements ViewController {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVault.getState() == Vault.State.UNLOCKED && newVault.getVaultSettings().mountAfterUnlock().get()) {
|
||||
mountVault(newVault);
|
||||
}
|
||||
|
||||
// (re)start throughput statistics:
|
||||
stopIoSampling();
|
||||
startIoSampling();
|
||||
@@ -132,57 +115,16 @@ public class UnlockedController implements ViewController {
|
||||
|
||||
@FXML
|
||||
private void didClickLockVault(ActionEvent event) {
|
||||
regularUnmountVault(this::lockVault);
|
||||
regularLockVault(this::lockVaultSucceeded);
|
||||
}
|
||||
|
||||
private void lockVault() {
|
||||
try {
|
||||
vault.get().lock();
|
||||
} catch (ServerLifecycleException | IOException e) {
|
||||
LOG.error("Lock failed", e);
|
||||
}
|
||||
private void lockVaultSucceeded() {
|
||||
listener.ifPresent(listener -> listener.didLock(this));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void didClickMoreOptions(ActionEvent event) {
|
||||
if (moreOptionsMenu.isShowing()) {
|
||||
moreOptionsMenu.hide();
|
||||
} else {
|
||||
moreOptionsMenu.setAnchorLocation(AnchorLocation.CONTENT_TOP_RIGHT);
|
||||
moreOptionsMenu.show(moreOptionsButton, Side.BOTTOM, moreOptionsButton.getWidth(), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void didClickMountVault(ActionEvent event) {
|
||||
mountVault(vault.get());
|
||||
}
|
||||
|
||||
private void mountVault(Vault vault) {
|
||||
private void regularLockVault(Runnable onSuccess) {
|
||||
asyncTaskService.asyncTaskOf(() -> {
|
||||
vault.mount();
|
||||
}).onSuccess(() -> {
|
||||
LOG.trace("Mount succeeded.");
|
||||
messageLabel.setText(null);
|
||||
if (vault.getVaultSettings().revealAfterMount().get()) {
|
||||
revealVault(vault);
|
||||
}
|
||||
}).onError(CommandFailedException.class, e -> {
|
||||
LOG.error("Mount failed.", e);
|
||||
// TODO Markus Kreusch #393: hyperlink auf FAQ oder sowas?
|
||||
messageLabel.setText(localization.getString("unlocked.label.mountFailed"));
|
||||
}).run();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void didClickUnmountVault(ActionEvent event) {
|
||||
regularUnmountVault(Runnables.doNothing());
|
||||
}
|
||||
|
||||
private void regularUnmountVault(Runnable onSuccess) {
|
||||
asyncTaskService.asyncTaskOf(() -> {
|
||||
vault.get().unmount();
|
||||
vault.get().lock(false);
|
||||
}).onSuccess(() -> {
|
||||
LOG.trace("Regular unmount succeeded.");
|
||||
onSuccess.run();
|
||||
@@ -191,18 +133,6 @@ public class UnlockedController implements ViewController {
|
||||
}).run();
|
||||
}
|
||||
|
||||
private void forcedUnmountVault(Runnable onSuccess) {
|
||||
asyncTaskService.asyncTaskOf(() -> {
|
||||
vault.get().unmountForced();
|
||||
}).onSuccess(() -> {
|
||||
LOG.trace("Forced unmount succeeded.");
|
||||
onSuccess.run();
|
||||
}).onError(Exception.class, e -> {
|
||||
LOG.error("Forced unmount failed.", e);
|
||||
messageLabel.setText(localization.getString("unlocked.label.unmountFailed"));
|
||||
}).run();
|
||||
}
|
||||
|
||||
private void onRegularUnmountVaultFailed(Exception e, Runnable onSuccess) {
|
||||
if (vault.get().supportsForcedUnmount()) {
|
||||
LOG.trace("Regular unmount failed.", e);
|
||||
@@ -214,7 +144,7 @@ public class UnlockedController implements ViewController {
|
||||
|
||||
Optional<ButtonType> choice = confirmDialog.showAndWait();
|
||||
if (ButtonType.YES.equals(choice.get())) {
|
||||
forcedUnmountVault(onSuccess);
|
||||
forcedLockVault(onSuccess);
|
||||
} else {
|
||||
LOG.trace("Unmount cancelled.", e);
|
||||
}
|
||||
@@ -224,6 +154,28 @@ public class UnlockedController implements ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private void forcedLockVault(Runnable onSuccess) {
|
||||
asyncTaskService.asyncTaskOf(() -> {
|
||||
vault.get().lock(true);
|
||||
}).onSuccess(() -> {
|
||||
LOG.trace("Forced unmount succeeded.");
|
||||
onSuccess.run();
|
||||
}).onError(Exception.class, e -> {
|
||||
LOG.error("Forced unmount failed.", e);
|
||||
messageLabel.setText(localization.getString("unlocked.label.unmountFailed"));
|
||||
}).run();
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void didClickMoreOptions(ActionEvent event) {
|
||||
if (moreOptionsMenu.isShowing()) {
|
||||
moreOptionsMenu.hide();
|
||||
} else {
|
||||
moreOptionsMenu.setAnchorLocation(AnchorLocation.CONTENT_TOP_RIGHT);
|
||||
moreOptionsMenu.show(moreOptionsButton, Side.BOTTOM, moreOptionsButton.getWidth(), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void didClickRevealVault(ActionEvent event) {
|
||||
revealVault(vault.get());
|
||||
|
||||
@@ -68,9 +68,7 @@ public class DirectoryListCell extends DraggableListCell<Vault> {
|
||||
}
|
||||
switch (state) {
|
||||
case UNLOCKED:
|
||||
case MOUNTED:
|
||||
case MOUNTING:
|
||||
case UNMOUNTING:
|
||||
case PROCESSING:
|
||||
return "\uf09c";
|
||||
case LOCKED:
|
||||
default:
|
||||
@@ -84,9 +82,7 @@ public class DirectoryListCell extends DraggableListCell<Vault> {
|
||||
}
|
||||
switch (state) {
|
||||
case UNLOCKED:
|
||||
case MOUNTED:
|
||||
case MOUNTING:
|
||||
case UNMOUNTING:
|
||||
case PROCESSING:
|
||||
return UNLOCKED_ICON_COLOR;
|
||||
case LOCKED:
|
||||
default:
|
||||
|
||||
@@ -73,26 +73,14 @@ public class AutoUnlocker {
|
||||
}
|
||||
try {
|
||||
vault.unlock(CharBuffer.wrap(storedPw));
|
||||
mountSilently(vault);
|
||||
} catch (IOException | CryptoException e) {
|
||||
revealSilently(vault);
|
||||
} catch (IOException | CryptoException | CommandFailedException e) {
|
||||
LOG.error("Auto unlock failed.", e);
|
||||
} finally {
|
||||
Arrays.fill(storedPw, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
private void mountSilently(Vault unlockedVault) {
|
||||
if (!unlockedVault.getVaultSettings().mountAfterUnlock().get()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
unlockedVault.mount();
|
||||
revealSilently(unlockedVault);
|
||||
} catch (CommandFailedException e) {
|
||||
LOG.error("Auto unlock succeded, but mounting the drive failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void revealSilently(Vault mountedVault) {
|
||||
if (!mountedVault.getVaultSettings().revealAfterMount().get()) {
|
||||
return;
|
||||
|
||||
@@ -31,7 +31,6 @@ public class FuseVolume implements Volume {
|
||||
private static final String DEFAULT_MOUNTROOTPATH_LINUX = System.getProperty("user.home") + "/.Cryptomator";
|
||||
|
||||
private final VaultSettings vaultSettings;
|
||||
private final WindowsDriveLetters windowsDriveLetters;
|
||||
|
||||
private Mount fuseMnt;
|
||||
private CryptoFileSystem cfs;
|
||||
@@ -39,26 +38,16 @@ public class FuseVolume implements Volume {
|
||||
private boolean extraDirCreated;
|
||||
|
||||
@Inject
|
||||
public FuseVolume(VaultSettings vaultSettings, WindowsDriveLetters windowsDriveLetters) {
|
||||
public FuseVolume(VaultSettings vaultSettings) {
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.windowsDriveLetters = windowsDriveLetters;
|
||||
this.extraDirCreated = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(CryptoFileSystem fs) throws IOException, FuseNotSupportedException {
|
||||
public void mount(CryptoFileSystem fs) throws IOException, FuseNotSupportedException, CommandFailedException {
|
||||
this.cfs = fs;
|
||||
String mountPath;
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
//windows case
|
||||
if (vaultSettings.winDriveLetter().get() != null) {
|
||||
// specific drive letter selected
|
||||
mountPath = vaultSettings.winDriveLetter().get() + ":\\";
|
||||
} else {
|
||||
// auto assign drive letter
|
||||
mountPath = windowsDriveLetters.getAvailableDriveLetters().iterator().next() + ":\\";
|
||||
}
|
||||
} else if (vaultSettings.usesIndividualMountPath().get()) {
|
||||
if (vaultSettings.usesIndividualMountPath().get()) {
|
||||
//specific path given
|
||||
mountPath = vaultSettings.individualMountPath().get();
|
||||
} else {
|
||||
@@ -67,6 +56,7 @@ public class FuseVolume implements Volume {
|
||||
extraDirCreated = true;
|
||||
}
|
||||
this.mountPath = Paths.get(mountPath).toAbsolutePath();
|
||||
mount();
|
||||
}
|
||||
|
||||
private String createDirIfNotExist(String prefix, String dirName) throws IOException {
|
||||
@@ -87,8 +77,7 @@ public class FuseVolume implements Volume {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mount() throws CommandFailedException {
|
||||
private void mount() throws CommandFailedException {
|
||||
try {
|
||||
EnvironmentVariables envVars = EnvironmentVariables.create()
|
||||
.withMountName(vaultSettings.mountName().getValue())
|
||||
@@ -117,15 +106,10 @@ public class FuseVolume implements Volume {
|
||||
} catch (org.cryptomator.frontend.fuse.mount.CommandFailedException e) {
|
||||
throw new CommandFailedException(e);
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unmountForced() throws CommandFailedException {
|
||||
unmount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
private void cleanup() {
|
||||
if (extraDirCreated) {
|
||||
try {
|
||||
Files.delete(mountPath);
|
||||
@@ -135,19 +119,9 @@ public class FuseVolume implements Volume {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMountUri() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return FuseMountFactory.isFuseSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsForcedUnmount() {
|
||||
return false;
|
||||
return (SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_LINUX) && FuseMountFactory.isFuseSupported();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,16 +20,6 @@ import java.util.function.Predicate;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.cryptomator.common.LazyInitializer;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||
import org.cryptomator.cryptolib.api.CryptoException;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.ui.model.VaultModule.PerVault;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Binding;
|
||||
@@ -39,6 +29,15 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.LazyInitializer;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||
import org.cryptomator.cryptolib.api.CryptoException;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.ui.model.VaultModule.PerVault;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -59,7 +58,7 @@ public class Vault {
|
||||
private Volume volume;
|
||||
|
||||
public enum State {
|
||||
LOCKED, UNLOCKED, MOUNTING, MOUNTED, UNMOUNTING
|
||||
LOCKED, PROCESSING, UNLOCKED
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -98,51 +97,33 @@ public class Vault {
|
||||
CryptoFileSystemProvider.changePassphrase(getPath(), MASTERKEY_FILENAME, oldPassphrase, newPassphrase);
|
||||
}
|
||||
|
||||
public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException {
|
||||
public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException, CommandFailedException {
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.PROCESSING);
|
||||
});
|
||||
CryptoFileSystem fs = getCryptoFileSystem(passphrase);
|
||||
volume.prepare(fs);
|
||||
volume.mount(fs);
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.UNLOCKED);
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void mount() throws CommandFailedException {
|
||||
public synchronized void lock(boolean forced) throws CommandFailedException {
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.MOUNTING);
|
||||
});
|
||||
volume.mount();
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.MOUNTED);
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void unmountForced() throws CommandFailedException {
|
||||
unmount(true);
|
||||
}
|
||||
|
||||
public synchronized void unmount() throws CommandFailedException {
|
||||
unmount(false);
|
||||
}
|
||||
|
||||
private synchronized void unmount(boolean forced) throws CommandFailedException {
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.UNMOUNTING);
|
||||
state.set(State.PROCESSING);
|
||||
});
|
||||
if (forced && volume.supportsForcedUnmount()) {
|
||||
volume.unmountForced();
|
||||
} else {
|
||||
volume.unmount();
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.UNLOCKED);
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized void lock() throws IOException {
|
||||
volume.stop();
|
||||
CryptoFileSystem fs = cryptoFileSystem.getAndSet(null);
|
||||
if (fs != null) {
|
||||
fs.close();
|
||||
try {
|
||||
fs.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error closing file system.", e);
|
||||
}
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
state.set(State.LOCKED);
|
||||
@@ -154,23 +135,18 @@ public class Vault {
|
||||
*/
|
||||
public void prepareForShutdown() {
|
||||
try {
|
||||
unmount();
|
||||
lock(false);
|
||||
} catch (CommandFailedException e) {
|
||||
if (volume.supportsForcedUnmount()) {
|
||||
try {
|
||||
unmountForced();
|
||||
lock(true);
|
||||
} catch (CommandFailedException e1) {
|
||||
LOG.warn("Failed to force unmount vault.");
|
||||
LOG.warn("Failed to force lock vault.", e1);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Failed to gracefully unmount vault.");
|
||||
LOG.warn("Failed to gracefully lock vault.", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
lock();
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to lock vault.");
|
||||
}
|
||||
}
|
||||
|
||||
public void reveal() throws CommandFailedException {
|
||||
@@ -289,10 +265,6 @@ public class Vault {
|
||||
}
|
||||
}
|
||||
|
||||
public String getFilesystemRootUrl() {
|
||||
return volume.getMountUri();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return vaultSettings.getId();
|
||||
}
|
||||
|
||||
@@ -9,9 +9,18 @@ import java.io.IOException;
|
||||
*/
|
||||
public interface Volume {
|
||||
|
||||
void prepare(CryptoFileSystem fs) throws IOException;
|
||||
/**
|
||||
* Checks in constant time whether this volume type is supported on the system running Cryptomator.
|
||||
* @return true if this volume can be mounted
|
||||
*/
|
||||
boolean isSupported();
|
||||
|
||||
void mount() throws CommandFailedException;
|
||||
/**
|
||||
*
|
||||
* @param fs
|
||||
* @throws IOException
|
||||
*/
|
||||
void mount(CryptoFileSystem fs) throws IOException, CommandFailedException;
|
||||
|
||||
default void reveal() throws CommandFailedException {
|
||||
throw new CommandFailedException("Not implemented.");
|
||||
@@ -19,20 +28,14 @@ public interface Volume {
|
||||
|
||||
void unmount() throws CommandFailedException;
|
||||
|
||||
default void unmountForced() throws CommandFailedException {
|
||||
throw new CommandFailedException("Operation not supported.");
|
||||
}
|
||||
|
||||
void stop();
|
||||
|
||||
String getMountUri();
|
||||
|
||||
default boolean isSupported() {
|
||||
return false;
|
||||
}
|
||||
// optional forced unmounting:
|
||||
|
||||
default boolean supportsForcedUnmount() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void unmountForced() throws CommandFailedException {
|
||||
throw new CommandFailedException("Operation not supported.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class WebDavVolume implements Volume {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(CryptoFileSystem fs) {
|
||||
public void mount(CryptoFileSystem fs) throws CommandFailedException {
|
||||
if (server == null) {
|
||||
server = serverProvider.get();
|
||||
}
|
||||
@@ -45,10 +45,10 @@ public class WebDavVolume implements Volume {
|
||||
}
|
||||
servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + vaultSettings.mountName().get());
|
||||
servlet.start();
|
||||
mount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mount() throws CommandFailedException {
|
||||
private void mount() throws CommandFailedException {
|
||||
if (servlet == null) {
|
||||
throw new IllegalStateException("Mounting requires unlocked WebDAV servlet.");
|
||||
}
|
||||
@@ -82,11 +82,17 @@ public class WebDavVolume implements Volume {
|
||||
} catch (Mounter.CommandFailedException e) {
|
||||
throw new CommandFailedException(e);
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unmountForced() {
|
||||
mount.forced();
|
||||
public synchronized void unmountForced() throws CommandFailedException {
|
||||
try {
|
||||
mount.forced().orElseThrow(IllegalStateException::new).unmount();
|
||||
} catch (Mounter.CommandFailedException e) {
|
||||
throw new CommandFailedException(e);
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private String getLocalhostAliasOrNull() {
|
||||
@@ -102,28 +108,19 @@ public class WebDavVolume implements Volume {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
private void cleanup() {
|
||||
if (servlet != null) {
|
||||
servlet.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized String getMountUri() {
|
||||
return servlet.getServletRootUri().toString() + "/";
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: what to check wether it is implemented?
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsForcedUnmount() {
|
||||
return mount != null && mount.forced().isPresent();
|
||||
}
|
||||
|
||||
@@ -75,28 +75,25 @@
|
||||
|
||||
<!-- Row 3.2 -->
|
||||
<CheckBox GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="unlockAfterStartup" text="%unlock.label.unlockAfterStartup" cacheShape="true" cache="true" />
|
||||
|
||||
|
||||
<!-- Row 3.3 -->
|
||||
<CheckBox GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="mountAfterUnlock" text="%unlock.label.mountAfterUnlock" cacheShape="true" cache="true" />
|
||||
<Label GridPane.rowIndex="3" GridPane.columnIndex="0" text="%unlock.label.mountName" cacheShape="true" cache="true" />
|
||||
<TextField GridPane.rowIndex="3" GridPane.columnIndex="1" fx:id="mountName" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.4 -->
|
||||
<Label GridPane.rowIndex="4" GridPane.columnIndex="0" text="%unlock.label.mountName" cacheShape="true" cache="true" />
|
||||
<TextField GridPane.rowIndex="4" GridPane.columnIndex="1" fx:id="mountName" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
<CheckBox GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="revealAfterMount" text="%unlock.label.revealAfterMount" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.5 -->
|
||||
<CheckBox GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="revealAfterMount" text="%unlock.label.revealAfterMount" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.6 Alt1 -->
|
||||
<Label GridPane.rowIndex="6" GridPane.columnIndex="0" fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="6" GridPane.columnIndex="1" fx:id="winDriveLetter" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
<!-- Row 3.5 Alt1 -->
|
||||
<Label GridPane.rowIndex="5" GridPane.columnIndex="0" fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="5" GridPane.columnIndex="1" fx:id="winDriveLetter" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.6 Alt2 -->
|
||||
<CheckBox GridPane.rowIndex="6" GridPane.columnIndex="0" fx:id="useOwnMountPath" text="%unlock.label.useOwnMountPath" cacheShape="true" cache="true" />
|
||||
<!-- Row 3.5 Alt2 -->
|
||||
<CheckBox GridPane.rowIndex="5" GridPane.columnIndex="0" fx:id="useOwnMountPath" text="%unlock.label.useOwnMountPath" cacheShape="true" cache="true" />
|
||||
|
||||
<Label GridPane.rowIndex="7" GridPane.columnIndex="0" fx:id="mountPathLabel" text="%unlock.label.mountPath" cacheShape="true" cache="true" />
|
||||
<Label GridPane.rowIndex="6" GridPane.columnIndex="0" fx:id="mountPathLabel" text="%unlock.label.mountPath" cacheShape="true" cache="true" />
|
||||
|
||||
<HBox GridPane.rowIndex="7" GridPane.columnIndex="1" fx:id="mountPathBox" spacing="6.0">
|
||||
<TextField GridPane.rowIndex="7" GridPane.columnIndex="1" fx:id="mountPath" cacheShape="true" cache="true" />
|
||||
<HBox GridPane.rowIndex="6" GridPane.columnIndex="1" fx:id="mountPathBox" spacing="6.0">
|
||||
<TextField fx:id="mountPath" cacheShape="true" cache="true" />
|
||||
<Button text="%unlock.label.mountPathButton" fx:id="changeMountPathButton" onAction="#didClickchangeMountPathButton"/>
|
||||
</HBox>
|
||||
|
||||
|
||||
@@ -28,12 +28,6 @@
|
||||
<fx:define>
|
||||
<ContextMenu fx:id="moreOptionsMenu">
|
||||
<items>
|
||||
<MenuItem fx:id="mountVaultMenuItem" text="%unlocked.moreOptions.mount" onAction="#didClickMountVault">
|
||||
<graphic><Label text="" styleClass="ionicons"/></graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="unmountVaultMenuItem" text="%unlocked.moreOptions.unmount" onAction="#didClickUnmountVault">
|
||||
<graphic><Label text="" styleClass="ionicons"/></graphic>
|
||||
</MenuItem>
|
||||
<MenuItem fx:id="revealVaultMenuItem" text="%unlocked.moreOptions.reveal" onAction="#didClickRevealVault">
|
||||
<graphic><Label text="" styleClass="ionicons"/></graphic>
|
||||
</MenuItem>
|
||||
|
||||
@@ -62,7 +62,6 @@ upgrade.version5toX.msg=This vault needs to be migrated to a newer format.\nPlea
|
||||
# unlock.fxml
|
||||
unlock.label.password=Password
|
||||
unlock.label.savePassword=Save Password
|
||||
unlock.label.mountAfterUnlock=Mount Drive
|
||||
unlock.label.mountName=Drive Name
|
||||
unlock.label.unlockAfterStartup=Auto-Unlock on Start (Experimental)
|
||||
unlock.label.revealAfterMount=Reveal Drive
|
||||
@@ -100,8 +99,6 @@ changePassword.errorMessage.decryptionFailed=Decryption failed
|
||||
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock=Lock Vault
|
||||
unlocked.moreOptions.mount=Mount Drive
|
||||
unlocked.moreOptions.unmount=Eject Drive
|
||||
unlocked.moreOptions.reveal=Reveal Drive
|
||||
unlocked.label.mountFailed=Connecting drive failed
|
||||
unlocked.label.revealFailed=Command failed
|
||||
|
||||
Reference in New Issue
Block a user