diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 1f8510d99..5b33a9765 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -5,16 +5,6 @@ *******************************************************************************/ package org.cryptomator.common.settings; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.Base64; -import java.util.Objects; -import java.util.UUID; - -import org.apache.commons.lang3.StringUtils; -import org.fxmisc.easybind.EasyBind; - import javafx.beans.Observable; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; @@ -22,7 +12,20 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import org.apache.commons.lang3.StringUtils; +import org.fxmisc.easybind.EasyBind; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.Base64; +import java.util.Objects; +import java.util.UUID; + +/** + * The settings specific to a single vault. + * TODO: Change the name of individualMountPath and its derivatives to customMountPath + */ public class VaultSettings { public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false; diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java index 5fb30ef88..866b78bc9 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java @@ -5,14 +5,13 @@ *******************************************************************************/ package org.cryptomator.common.settings; -import java.io.IOException; -import java.nio.file.Paths; - +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.nio.file.Paths; class VaultSettingsJsonAdapter { @@ -27,8 +26,7 @@ class VaultSettingsJsonAdapter { out.name("unlockAfterStartup").value(value.unlockAfterStartup().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!) - out.name("individualMountPath").value(value.individualMountPath().get()); + out.name("individualMountPath").value(value.individualMountPath().get()); //TODO: should this always be written? ( because it could contain metadata, which the user may not want to save!) out.endObject(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java index 9584bfc81..6c102d6cc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java @@ -8,13 +8,6 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; -import javax.inject.Inject; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ExecutorService; - import com.google.common.base.CharMatcher; import com.google.common.base.Strings; import javafx.application.Application; @@ -45,9 +38,9 @@ import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; import org.cryptomator.frontend.webdav.ServerLifecycleException; import org.cryptomator.keychain.KeychainAccess; -import org.cryptomator.ui.model.InvalidSettingsException; import org.cryptomator.ui.controls.SecPasswordField; import org.cryptomator.ui.l10n.Localization; +import org.cryptomator.ui.model.InvalidSettingsException; import org.cryptomator.ui.model.Vault; import org.cryptomator.ui.model.WindowsDriveLetters; import org.cryptomator.ui.util.DialogBuilderUtil; @@ -57,6 +50,13 @@ import org.fxmisc.easybind.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.inject.Inject; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ExecutorService; + public class UnlockController implements ViewController { private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class); @@ -115,13 +115,13 @@ public class UnlockController implements ViewController { private ChoiceBox winDriveLetter; @FXML - private CheckBox useOwnMountPath; + private CheckBox useCustomMountPath; @FXML - private Label mountPathLabel; + private Label customMountPathLabel; @FXML - private TextField mountPath; + private TextField customMountPathField; @FXML private ProgressIndicator progressIndicator; @@ -150,27 +150,31 @@ public class UnlockController implements ViewController { savePassword.setDisable(!keychainAccess.isPresent()); unlockAfterStartup.disableProperty().bind(savePassword.disabledProperty().or(savePassword.selectedProperty().not())); - mountPathLabel.visibleProperty().bind(useOwnMountPath.selectedProperty()); - mountPath.visibleProperty().bind(useOwnMountPath.selectedProperty()); - mountPath.managedProperty().bind(useOwnMountPath.selectedProperty()); - mountPath.textProperty().addListener(this::mountPathDidChange); + customMountPathLabel.visibleProperty().bind(useCustomMountPath.selectedProperty()); + customMountPathLabel.managedProperty().bind(useCustomMountPath.selectedProperty()); + customMountPathField.visibleProperty().bind(useCustomMountPath.selectedProperty()); + customMountPathField.managedProperty().bind(useCustomMountPath.selectedProperty()); + customMountPathField.textProperty().addListener(this::mountPathDidChange); + winDriveLetter.setConverter(new WinDriveLetterLabelConverter()); - if (SystemUtils.IS_OS_WINDOWS) { - winDriveLetter.setConverter(new WinDriveLetterLabelConverter()); - useOwnMountPath.setVisible(false); - useOwnMountPath.setManaged(false); - mountPathLabel.setManaged(false); - //dirty cheat - mountPath.setMouseTransparent(true); - } else { + if (!SystemUtils.IS_OS_WINDOWS) { winDriveLetterLabel.setVisible(false); winDriveLetterLabel.setManaged(false); winDriveLetter.setVisible(false); winDriveLetter.setManaged(false); - if (VolumeImpl.WEBDAV.equals(settings.preferredVolumeImpl().get())) { - useOwnMountPath.setVisible(false); - useOwnMountPath.setManaged(false); - mountPathLabel.setManaged(false); + } + + if (VolumeImpl.WEBDAV.equals(settings.preferredVolumeImpl().get())) { + useCustomMountPath.setVisible(false); + useCustomMountPath.setManaged(false); + customMountPathField.setMouseTransparent(true); + } else { + useCustomMountPath.setVisible(true); + if (SystemUtils.IS_OS_WINDOWS) { + winDriveLetter.visibleProperty().bind(useCustomMountPath.selectedProperty().not()); + winDriveLetter.managedProperty().bind(useCustomMountPath.selectedProperty().not()); + winDriveLetterLabel.visibleProperty().bind(useCustomMountPath.selectedProperty().not()); + winDriveLetterLabel.managedProperty().bind(useCustomMountPath.selectedProperty().not()); } } } @@ -210,13 +214,11 @@ public class UnlockController implements ViewController { winDriveLetter.getItems().addAll(driveLetters.getAvailableDriveLetters()); winDriveLetter.getItems().sort(new WinDriveLetterComparator()); winDriveLetter.valueProperty().addListener(driveLetterChangeListener); + chooseSelectedDriveLetter(); } downloadsPageLink.setVisible(false); messageText.setText(null); mountName.setText(vault.getMountName()); - if (SystemUtils.IS_OS_WINDOWS) { - chooseSelectedDriveLetter(); - } savePassword.setSelected(false); // auto-fill pw from keychain: if (keychainAccess.isPresent()) { @@ -231,14 +233,15 @@ public class UnlockController implements ViewController { VaultSettings vaultSettings = vault.getVaultSettings(); unlockAfterStartup.setSelected(savePassword.isSelected() && vaultSettings.unlockAfterStartup().get()); revealAfterMount.setSelected(vaultSettings.revealAfterMount().get()); - useOwnMountPath.setSelected(vaultSettings.usesIndividualMountPath().get()); + + if (!settings.preferredVolumeImpl().get().equals(VolumeImpl.WEBDAV)) { + useCustomMountPath.setSelected(vaultSettings.usesIndividualMountPath().get()); + customMountPathField.textProperty().setValue(vaultSettings.individualMountPath().getValueSafe()); + } vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), vaultSettings.unlockAfterStartup()::set)); vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), vaultSettings.revealAfterMount()::set)); - vaultSubs = vaultSubs.and(EasyBind.subscribe(useOwnMountPath.selectedProperty(), vaultSettings.usesIndividualMountPath()::set)); - - - mountPath.textProperty().setValue(vaultSettings.individualMountPath().getValueSafe()); + vaultSubs = vaultSubs.and(EasyBind.subscribe(useCustomMountPath.selectedProperty(), vaultSettings.usesIndividualMountPath()::set)); } @@ -282,7 +285,7 @@ public class UnlockController implements ViewController { } private void mountPathDidChange(ObservableValue property, String oldValue, String newValue) { - vault.setIndividualMountPath(newValue); + vault.setCustomMountPath(newValue); } /** @@ -389,6 +392,7 @@ public class UnlockController implements ViewController { CharSequence password = passwordField.getCharacters(); Tasks.create(() -> { + messageText.setText(localization.getString("unlock.pendingMessage.unlocking")); vault.unlock(password); if (keychainAccess.isPresent() && savePassword.isSelected()) { keychainAccess.get().storePassphrase(vault.getId(), password); @@ -400,7 +404,7 @@ public class UnlockController implements ViewController { }).onError(InvalidSettingsException.class, e -> { messageText.setText(localization.getString("unlock.errorMessage.invalidMountPath")); advancedOptions.setVisible(true); - mountPath.setStyle("-fx-border-color: red;"); + customMountPathField.setStyle("-fx-border-color: red;"); }).onError(InvalidPassphraseException.class, e -> { messageText.setText(localization.getString("unlock.errorMessage.wrongPassword")); passwordField.selectAll(); @@ -429,7 +433,7 @@ public class UnlockController implements ViewController { advancedOptions.setDisable(false); progressIndicator.setVisible(false); if (advancedOptions.isVisible()) { //dirty programming, but otherwise the focus is wrong - mountPath.requestFocus(); + customMountPathField.requestFocus(); } }).runOnce(executor); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java b/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java index f986b6e3f..26a4b7993 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java @@ -1,17 +1,17 @@ package org.cryptomator.ui.model; -import javax.inject.Inject; -import java.nio.file.Paths; -import java.util.Set; -import java.util.concurrent.ExecutorService; - -import com.google.common.collect.Sets; +import com.google.common.base.Strings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; import org.cryptomator.frontend.dokany.Mount; import org.cryptomator.frontend.dokany.MountFactory; import org.cryptomator.frontend.dokany.MountFailedException; +import javax.inject.Inject; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; + public class DokanyVolume implements Volume { private static final String FS_TYPE_NAME = "Cryptomator File System"; @@ -34,29 +34,31 @@ public class DokanyVolume implements Volume { return DokanyVolume.isSupportedStatic(); } - //TODO: Drive letter 'A' as mount point is invalid in dokany. maybe we should do already here something against it @Override public void mount(CryptoFileSystem fs) throws VolumeException { - char driveLetter; - if (!vaultSettings.winDriveLetter().getValueSafe().equals("")) { - driveLetter = vaultSettings.winDriveLetter().get().charAt(0); + Path mountPath = Paths.get(getMountPathString()); + String mountName = vaultSettings.mountName().get(); + try { + this.mount = mountFactory.mount(fs.getPath("/"), mountPath, mountName, FS_TYPE_NAME); + } catch (MountFailedException e) { + throw new VolumeException("Unable to mount Filesystem", e); + } + } + + private String getMountPathString() throws VolumeException { + if (vaultSettings.usesIndividualMountPath().get()) { + return vaultSettings.individualMountPath().get(); + } else if (!Strings.isNullOrEmpty(vaultSettings.winDriveLetter().get())) { + return vaultSettings.winDriveLetter().get().charAt(0) + ":\\"; } else { //auto assign drive letter if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) { - //this is a temporary fix for 'A' being an invalid drive letter - Set availableLettersWithoutA = Sets.difference(windowsDriveLetters.getAvailableDriveLetters(), Set.of('A')); - driveLetter = availableLettersWithoutA.iterator().next(); -// driveLetter = windowsDriveLetters.getAvailableDriveLetters().iterator().next(); + return windowsDriveLetters.getAvailableDriveLetters().iterator().next() + ":\\"; } else { throw new VolumeException("No free drive letter available."); } } - String mountName = vaultSettings.mountName().get(); - try { - this.mount = mountFactory.mount(fs.getPath("/"), Paths.get(driveLetter + ":\\") , mountName, FS_TYPE_NAME); - } catch (MountFailedException e) { - throw new VolumeException("Unable to mount Filesystem", e); - } + } @Override diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index cf0e6d7cc..ec1b889b3 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -8,19 +8,6 @@ *******************************************************************************/ package org.cryptomator.ui.model; -import java.io.IOException; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; - -import javax.inject.Inject; -import javax.inject.Provider; - import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.binding.Binding; @@ -42,6 +29,18 @@ import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.inject.Inject; +import javax.inject.Provider; +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; + @PerVault public class Vault { @@ -241,11 +240,11 @@ public class Vault { return vaultSettings.mountName().get(); } - public String getIndividualMountPath() { + public String getCustomMountPath() { return vaultSettings.individualMountPath().getValueSafe(); } - public void setIndividualMountPath(String mountPath) { + public void setCustomMountPath(String mountPath) { vaultSettings.individualMountPath().set(mountPath); } diff --git a/main/ui/src/main/resources/fxml/unlock.fxml b/main/ui/src/main/resources/fxml/unlock.fxml index 5675556a1..0add97f49 100644 --- a/main/ui/src/main/resources/fxml/unlock.fxml +++ b/main/ui/src/main/resources/fxml/unlock.fxml @@ -82,16 +82,17 @@ - - -