From 8ba2540b35b1e981f2f231a468564565b4b02693 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Mon, 11 Sep 2023 14:23:31 +0200 Subject: [PATCH 01/41] implemented volume type selection in 'vault options mount' --- .../vaultoptions/MountOptionsController.java | 126 ++++++++++++++++-- .../resources/fxml/vault_options_mount.fxml | 29 +++- 2 files changed, 140 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 5eeab43e0..4e97e7fd5 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -1,18 +1,26 @@ package org.cryptomator.ui.vaultoptions; import com.google.common.base.Strings; +import dagger.Lazy; +import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.mount.ActualMountService; +import org.cryptomator.common.mount.MountModule; import org.cryptomator.common.mount.WindowsDriveLetters; +import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.vaults.Vault; import org.cryptomator.integrations.mount.MountCapability; +import org.cryptomator.integrations.mount.MountService; import org.cryptomator.ui.common.FxController; -import org.cryptomator.ui.fxapp.FxApplicationWindows; -import org.cryptomator.ui.preferences.SelectedPreferencesTab; import javax.inject.Inject; +import javax.inject.Named; +import javafx.application.Application; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanExpression; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ChoiceBox; import javafx.scene.control.RadioButton; @@ -26,16 +34,25 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; +import java.util.List; +import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; @VaultOptionsScoped public class MountOptionsController implements FxController { + private static final String DOCS_MOUNTING_URL = "https://docs.cryptomator.org/en/1.7/desktop/volume-type/"; + private static final int MIN_PORT = 1024; + private static final int MAX_PORT = 65535; + private final Stage window; private final VaultSettings vaultSettings; private final WindowsDriveLetters windowsDriveLetters; private final ResourceBundle resourceBundle; + private final Lazy application; + private final Settings settings; private final ObservableValue defaultMountFlags; private final ObservableValue mountpointDirSupported; @@ -43,7 +60,10 @@ public class MountOptionsController implements FxController { private final ObservableValue readOnlySupported; private final ObservableValue mountFlagsSupported; private final ObservableValue directoryPath; - private final FxApplicationWindows applicationWindows; + private final List mountProviders; + private final ObservableValue selectedMountService; + private final ObservableValue fuseRestartRequired; + private final BooleanExpression loopbackPortSupported; //-- FXML objects -- @@ -56,9 +76,21 @@ public class MountOptionsController implements FxController { public RadioButton mountPointDirBtn; public TextField directoryPathField; public ChoiceBox driveLetterSelection; + public ChoiceBox volumeTypeChoiceBox; + public TextField loopbackPortField; + public Button loopbackPortApplyButton; + @Inject - MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObservableValue mountService, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle, FxApplicationWindows applicationWindows) { + MountOptionsController(@VaultOptionsWindow Stage window, // + @VaultOptionsWindow Vault vault, // + ObservableValue mountService, // + WindowsDriveLetters windowsDriveLetters, // + ResourceBundle resourceBundle, // + Lazy application, + Settings settings, // + List mountProviders, // + @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService) { this.window = window; this.vaultSettings = vault.getVaultSettings(); this.windowsDriveLetters = windowsDriveLetters; @@ -75,7 +107,17 @@ public class MountOptionsController implements FxController { this.mountFlagsSupported = mountService.map(as -> as.service().hasCapability(MountCapability.MOUNT_FLAGS)); this.readOnlySupported = mountService.map(as -> as.service().hasCapability(MountCapability.READ_ONLY)); this.directoryPath = vault.getVaultSettings().mountPoint.map(p -> isDriveLetter(p) ? null : p.toString()); - this.applicationWindows = applicationWindows; + this.application = application; + this.settings = settings; + this.mountProviders = mountProviders; + var fallbackProvider = mountProviders.stream().findFirst().orElse(null); + this.selectedMountService = ObservableUtil.mapWithDefault(settings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), fallbackProvider); + this.fuseRestartRequired = selectedMountService.map(s -> {// + return firstUsedProblematicFuseMountService.get() != null // + && MountModule.isProblematicFuseService(s) // + && !firstUsedProblematicFuseMountService.get().equals(s); + }); + this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT))); } @FXML @@ -106,11 +148,21 @@ public class MountOptionsController implements FxController { mountPointToggleGroup.selectToggle(mountPointDirBtn); } mountPointToggleGroup.selectedToggleProperty().addListener(this::selectedToggleChanged); - } - @FXML - public void openVolumePreferences() { - applicationWindows.showPreferencesWindow(SelectedPreferencesTab.VOLUME); + volumeTypeChoiceBox.getItems().add(null); + volumeTypeChoiceBox.getItems().addAll(mountProviders); + volumeTypeChoiceBox.setConverter(new MountServiceConverter()); + boolean autoSelected = settings.mountService.get() == null; + volumeTypeChoiceBox.getSelectionModel().select(autoSelected ? null : selectedMountService.getValue()); + volumeTypeChoiceBox.valueProperty().addListener((observableValue, oldProvider, newProvider) -> { + var toSet = Optional.ofNullable(newProvider).map(nP -> nP.getClass().getName()).orElse(null); + settings.mountService.set(toSet); + }); + + loopbackPortField.setText(String.valueOf(settings.port.get())); + loopbackPortApplyButton.visibleProperty().bind(settings.port.asString().isNotEqualTo(loopbackPortField.textProperty())); + loopbackPortApplyButton.disableProperty().bind(Bindings.createBooleanBinding(this::validateLoopbackPort, loopbackPortField.textProperty()).not()); + } @FXML @@ -229,6 +281,26 @@ public class MountOptionsController implements FxController { } + public void openDocs() { + application.get().getHostServices().showDocument(DOCS_MOUNTING_URL); + } + + private boolean validateLoopbackPort() { + try { + int port = Integer.parseInt(loopbackPortField.getText()); + return port == 0 // choose port automatically + || port >= MIN_PORT && port <= MAX_PORT; // port within range + } catch (NumberFormatException e) { + return false; + } + } + + public void doChangeLoopbackPort() { + if (validateLoopbackPort()) { + settings.port.set(Integer.parseInt(loopbackPortField.getText())); + } + } + //@formatter:off private static class NoDirSelectedException extends Exception {} //@formatter:on @@ -274,4 +346,40 @@ public class MountOptionsController implements FxController { public String getDirectoryPath() { return directoryPath.getValue(); } + + public ObservableValue fuseRestartRequiredProperty() { + return fuseRestartRequired; + } + + public boolean getFuseRestartRequired() { + return fuseRestartRequired.getValue(); + } + + public BooleanExpression loopbackPortSupportedProperty() { + return loopbackPortSupported; + } + + public boolean isLoopbackPortSupported() { + return loopbackPortSupported.get(); + } + + //Helpers + /* Helpers */ + + private class MountServiceConverter extends StringConverter { + + @Override + public String toString(MountService provider) { + if (provider == null) { + return resourceBundle.getString("preferences.volume.type.automatic"); + } else { + return provider.displayName(); + } + } + + @Override + public MountService fromString(String string) { + throw new UnsupportedOperationException(); + } + } } diff --git a/src/main/resources/fxml/vault_options_mount.fxml b/src/main/resources/fxml/vault_options_mount.fxml index 762d36d27..921747132 100644 --- a/src/main/resources/fxml/vault_options_mount.fxml +++ b/src/main/resources/fxml/vault_options_mount.fxml @@ -1,6 +1,7 @@ + @@ -12,7 +13,7 @@ - + - - + + + + From e7e88f13e3d096c7e61b6fbf87afde8ebcf10377 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Fri, 17 Nov 2023 14:51:13 +0100 Subject: [PATCH 21/41] improved code quality --- .../java/org/cryptomator/common/CommonsModule.java | 13 ------------- .../cryptomator/common/vaults/VaultListManager.java | 2 -- .../ui/preferences/VolumePreferencesController.java | 6 +----- .../unlock/UnlockFuseRestartRequiredController.java | 9 +++++++++ .../org/cryptomator/ui/unlock/UnlockWorkflow.java | 5 ----- .../cryptomator/common/settings/SettingsTest.java | 8 ++++++-- 6 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/cryptomator/common/CommonsModule.java b/src/main/java/org/cryptomator/common/CommonsModule.java index 9cba60131..5ea69da6d 100644 --- a/src/main/java/org/cryptomator/common/CommonsModule.java +++ b/src/main/java/org/cryptomator/common/CommonsModule.java @@ -7,12 +7,10 @@ package org.cryptomator.common; import dagger.Module; import dagger.Provides; -import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.keychain.KeychainModule; import org.cryptomator.common.mount.MountModule; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.SettingsProvider; -import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.vaults.VaultComponent; import org.cryptomator.common.vaults.VaultListModule; import org.cryptomator.cryptolib.common.MasterkeyFileAccess; @@ -23,8 +21,6 @@ import org.slf4j.LoggerFactory; import javax.inject.Named; import javax.inject.Singleton; -import javafx.beans.value.ObservableValue; -import java.net.InetSocketAddress; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Comparator; @@ -138,15 +134,6 @@ public abstract class CommonsModule { LOG.error("Uncaught exception in " + thread.getName(), throwable); } - @Provides - @Singleton - static ObservableValue provideServerSocketAddressBinding(VaultSettings vaultSettings) { - return vaultSettings.port.map(port -> { - String host = SystemUtils.IS_OS_WINDOWS ? "127.0.0.1" : "localhost"; - return InetSocketAddress.createUnresolved(host, vaultSettings.port.intValue()); - }); - } - @Provides @Singleton @Named("FUPFMS") diff --git a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java index 0351981a0..cbcc281ac 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java @@ -73,8 +73,6 @@ public class VaultListManager { private VaultSettings newVaultSettings(Path path) { VaultSettings vaultSettings = VaultSettings.withRandomId(); vaultSettings.path.set(path); - vaultSettings.mountService.set(vaultSettings.mountService.getValue()); - vaultSettings.port.set(vaultSettings.port.getValue()); if (path.getFileName() != null) { vaultSettings.displayName.set(path.getFileName().toString()); } else { diff --git a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java index fbd5d11ec..c06a4596b 100644 --- a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java +++ b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java @@ -3,13 +3,11 @@ package org.cryptomator.ui.preferences; import dagger.Lazy; import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.settings.Settings; -import org.cryptomator.common.vaults.VaultModule; import org.cryptomator.integrations.mount.MountCapability; import org.cryptomator.integrations.mount.MountService; import org.cryptomator.ui.common.FxController; import javax.inject.Inject; -import javax.inject.Named; import javafx.application.Application; import javafx.beans.value.ObservableValue; import javafx.scene.control.ChoiceBox; @@ -17,7 +15,6 @@ import javafx.util.StringConverter; import java.util.List; import java.util.Optional; import java.util.ResourceBundle; -import java.util.concurrent.atomic.AtomicReference; @PreferencesScoped public class VolumePreferencesController implements FxController { @@ -39,7 +36,6 @@ public class VolumePreferencesController implements FxController { VolumePreferencesController(Settings settings, Lazy application, List mountProviders, - @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService, ResourceBundle resourceBundle) { this.settings = settings; this.application = application; @@ -101,7 +97,7 @@ public class VolumePreferencesController implements FxController { /* Helpers */ - public class MountServiceConverter extends StringConverter { + private class MountServiceConverter extends StringConverter { @Override public String toString(MountService provider) { diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockFuseRestartRequiredController.java b/src/main/java/org/cryptomator/ui/unlock/UnlockFuseRestartRequiredController.java index 26ef4c7de..4f9e5649b 100644 --- a/src/main/java/org/cryptomator/ui/unlock/UnlockFuseRestartRequiredController.java +++ b/src/main/java/org/cryptomator/ui/unlock/UnlockFuseRestartRequiredController.java @@ -8,22 +8,31 @@ import org.cryptomator.ui.vaultoptions.SelectedVaultOptionsTab; import javax.inject.Inject; import javafx.fxml.FXML; import javafx.stage.Stage; +import java.util.ResourceBundle; @UnlockScoped public class UnlockFuseRestartRequiredController implements FxController { private final Stage window; + private final ResourceBundle resourceBundle; private final FxApplicationWindows appWindows; private final Vault vault; + @Inject UnlockFuseRestartRequiredController(@UnlockWindow Stage window, + ResourceBundle resourceBundle, FxApplicationWindows appWindows, @UnlockWindow Vault vault) { this.window = window; + this.resourceBundle = resourceBundle; this.appWindows = appWindows; this.vault = vault; } + public void initialize() { + window.setTitle(String.format(resourceBundle.getString("unlock.error.fuseRestartRequired.title"), vault.getDisplayName())); + } + @FXML public void close() { window.close(); diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java b/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java index 7c776ad14..98385f1d6 100644 --- a/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java +++ b/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java @@ -23,7 +23,6 @@ import javafx.concurrent.Task; import javafx.scene.Scene; import javafx.stage.Stage; import java.io.IOException; -import java.util.ResourceBundle; /** * A multi-step task that consists of background activities as well as user interaction. @@ -36,7 +35,6 @@ public class UnlockWorkflow extends Task { private static final Logger LOG = LoggerFactory.getLogger(UnlockWorkflow.class); private final Stage window; - private final ResourceBundle resourceBundle; private final Vault vault; private final VaultService vaultService; private final Lazy successScene; @@ -48,7 +46,6 @@ public class UnlockWorkflow extends Task { @Inject UnlockWorkflow(@UnlockWindow Stage window, // - ResourceBundle resourceBundle, @UnlockWindow Vault vault, // VaultService vaultService, // @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy successScene, // @@ -58,7 +55,6 @@ public class UnlockWorkflow extends Task { @UnlockWindow KeyLoadingStrategy keyLoadingStrategy, // @UnlockWindow ObjectProperty illegalMountPointException) { this.window = window; - this.resourceBundle = resourceBundle; this.vault = vault; this.vaultService = vaultService; this.successScene = successScene; @@ -103,7 +99,6 @@ public class UnlockWorkflow extends Task { private void handleFuseRestartRequiredError(FuseRestartRequiredException fRRE) { Platform.runLater(() -> { window.setScene(fuseRestartRequiredScene.get()); - window.setTitle(String.format(resourceBundle.getString("unlock.error.fuseRestartRequired.title"), vault.getDisplayName())); window.show(); }); } diff --git a/src/test/java/org/cryptomator/common/settings/SettingsTest.java b/src/test/java/org/cryptomator/common/settings/SettingsTest.java index ee18b50c1..114b7f980 100644 --- a/src/test/java/org/cryptomator/common/settings/SettingsTest.java +++ b/src/test/java/org/cryptomator/common/settings/SettingsTest.java @@ -24,12 +24,16 @@ public class SettingsTest { Mockito.verify(changeListener, Mockito.times(0)).accept(settings); // first change (to property): - settings.directories.add(vaultSettings); + settings.windowXPosition.set(100); Mockito.verify(changeListener, Mockito.times(1)).accept(settings); // second change (to list): - vaultSettings.displayName.set("asd"); + settings.directories.add(vaultSettings); Mockito.verify(changeListener, Mockito.times(2)).accept(settings); + + // third change (to property of list item): + vaultSettings.displayName.set("asd"); + Mockito.verify(changeListener, Mockito.times(3)).accept(settings); } } From 1052e4c3d2a0d4a5efe72d8e28124ad4bdd8f8d5 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Thu, 23 Nov 2023 10:55:17 +0100 Subject: [PATCH 22/41] fix gui issues in vault mount settings --- .../vaultoptions/MountOptionsController.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 66c0b1685..9d28d8d9d 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -97,12 +97,15 @@ public class MountOptionsController implements FxController { this.application = application; this.mountProviders = mountProviders; var fallbackProvider = mountProviders.stream().findFirst().orElse(null); - this.defaultMountService = ObservableUtil.mapWithDefault(settings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), fallbackProvider); - this.selectedMountService = ObservableUtil.mapWithDefault(vaultSettings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(defaultMountService.getValue()), defaultMountService.getValue()); - this.fuseRestartRequired = selectedMountService.map(s -> // - firstUsedProblematicFuseMountService.get() != null // - && VaultModule.isProblematicFuseService(s) // - && !firstUsedProblematicFuseMountService.get().equals(s) + this.defaultMountService = ObservableUtil.mapWithDefault(settings.mountService, // + serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), // + fallbackProvider); + this.selectedMountService = Bindings.createObjectBinding(this::reselectMountService, defaultMountService, vaultSettings.mountService); + this.fuseRestartRequired = selectedMountService.map(s -> { + return firstUsedProblematicFuseMountService.get() != null // + && VaultModule.isProblematicFuseService(s) // + && !firstUsedProblematicFuseMountService.get().equals(s); + } ); this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT))); @@ -119,8 +122,16 @@ public class MountOptionsController implements FxController { this.mountpointDriveLetterSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_AS_DRIVE_LETTER)); } + private MountService reselectMountService() { + var desired = vaultSettings.mountService.getValue(); + var defaultMS = defaultMountService.getValue(); + return mountProviders.stream().filter(s -> s.getClass().getName().equals(desired)).findFirst().orElse(defaultMS); + } + @FXML public void initialize() { + defaultMountService.addListener((_,_,_) -> vaultVolumeTypeChoiceBox.setConverter(new MountServiceConverter())); + // readonly: readOnlyCheckbox.selectedProperty().bindBidirectional(vaultSettings.usesReadOnlyMode); From 38c102a64b59ed2d6646edfcb491e6cf3328d979 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Mon, 27 Nov 2023 12:46:29 +0100 Subject: [PATCH 23/41] refactored code by removing unnecessary observables --- .../org/cryptomator/common/vaults/Vault.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index afe5380c1..d617a5db3 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -10,7 +10,6 @@ package org.cryptomator.common.vaults; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.Constants; -import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.mount.ActualMountService; import org.cryptomator.common.mount.FuseRestartRequiredException; import org.cryptomator.common.mount.Mounter; @@ -83,16 +82,16 @@ public class Vault { private final AtomicReference mountHandle = new AtomicReference<>(null); @Inject - Vault(Settings settings, - VaultSettings vaultSettings, - VaultConfigCache configCache, - AtomicReference cryptoFileSystem, - List mountProviders, - VaultState state, - @Named("lastKnownException") ObjectProperty lastKnownException, - VaultStats stats, - Mounter mounter, - @Named("vaultMountService") ObservableValue actualMountService, + Vault(Settings settings, // + VaultSettings vaultSettings, // + VaultConfigCache configCache, // + AtomicReference cryptoFileSystem, // + List mountProviders, // + VaultState state, // + @Named("lastKnownException") ObjectProperty lastKnownException, // + VaultStats stats, // + Mounter mounter, // + @Named("vaultMountService") ObservableValue actualMountService, // @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService) { this.settings = settings; this.vaultSettings = vaultSettings; @@ -167,13 +166,12 @@ public class Vault { throw new IllegalStateException("Already unlocked."); } var fallbackProvider = mountProviders.stream().findFirst().orElse(null); - var defMntServ = ObservableUtil.mapWithDefault(settings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), fallbackProvider).getValue(); - var selMntServ = ObservableUtil.mapWithDefault(vaultSettings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(defMntServ), defMntServ); - var fuseRestartRequired = selMntServ.map(s -> // - firstUsedProblematicFuseMountService.get() != null // - && VaultModule.isProblematicFuseService(s) // - && !firstUsedProblematicFuseMountService.get().equals(s)).getValue(); - if(fuseRestartRequired){ + var defMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(settings.mountService.getValue())).findFirst().orElse(fallbackProvider); + var selMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defMntServ); + var fuseRestartRequired = firstUsedProblematicFuseMountService.get() != null // + && VaultModule.isProblematicFuseService(selMntServ) // + && !firstUsedProblematicFuseMountService.get().equals(selMntServ); + if (fuseRestartRequired) { throw new FuseRestartRequiredException("fuseRestartRequired"); } From 98590ecec532197e92b7bfc5169a8c1ab598d60a Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Fri, 1 Dec 2023 09:11:43 +0100 Subject: [PATCH 24/41] refactoring --- .../common/mount/ActualMountService.java | 6 --- .../org/cryptomator/common/mount/Mounter.java | 48 +++++++++++++++--- .../org/cryptomator/common/vaults/Vault.java | 33 ++---------- .../common/vaults/VaultListManager.java | 10 ++-- .../common/vaults/VaultModule.java | 50 ------------------- .../vaultoptions/MountOptionsController.java | 13 +++-- 6 files changed, 55 insertions(+), 105 deletions(-) delete mode 100644 src/main/java/org/cryptomator/common/mount/ActualMountService.java diff --git a/src/main/java/org/cryptomator/common/mount/ActualMountService.java b/src/main/java/org/cryptomator/common/mount/ActualMountService.java deleted file mode 100644 index a96cc8e37..000000000 --- a/src/main/java/org/cryptomator/common/mount/ActualMountService.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.cryptomator.common.mount; - -import org.cryptomator.integrations.mount.MountService; - -public record ActualMountService(MountService service, boolean isDesired) { -} diff --git a/src/main/java/org/cryptomator/common/mount/Mounter.java b/src/main/java/org/cryptomator/common/mount/Mounter.java index 0cd838b9e..cf5f2b678 100644 --- a/src/main/java/org/cryptomator/common/mount/Mounter.java +++ b/src/main/java/org/cryptomator/common/mount/Mounter.java @@ -1,6 +1,7 @@ package org.cryptomator.common.mount; import org.cryptomator.common.Environment; +import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.integrations.mount.Mount; import org.cryptomator.integrations.mount.MountBuilder; @@ -8,11 +9,13 @@ import org.cryptomator.integrations.mount.MountFailedException; import org.cryptomator.integrations.mount.MountService; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; -import javafx.beans.value.ObservableValue; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import static org.cryptomator.integrations.mount.MountCapability.MOUNT_AS_DRIVE_LETTER; import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_EXISTING_DIR; @@ -23,13 +26,24 @@ import static org.cryptomator.integrations.mount.MountCapability.UNMOUNT_FORCED; @Singleton public class Mounter { + private static final List problematicFuseMountServices = List.of("org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", "org.cryptomator.frontend.fuse.mount.FuseTMountProvider"); + private final Environment env; private final WindowsDriveLetters driveLetters; + private final Settings settings; + private final List mountProviders; + private final AtomicReference firstUsedProblematicFuseMountService; @Inject - public Mounter(Environment env, WindowsDriveLetters driveLetters) { + public Mounter(Environment env, // + WindowsDriveLetters driveLetters, // + Settings settings, List mountProviders, // + @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService) { this.env = env; this.driveLetters = driveLetters; + this.settings = settings; + this.mountProviders = mountProviders; + this.firstUsedProblematicFuseMountService = firstUsedProblematicFuseMountService; } private class SettledMounter { @@ -124,12 +138,32 @@ public class Mounter { } - public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot, ObservableValue actualMountService) throws IOException, MountFailedException { - var mountService = actualMountService.getValue().service(); - var builder = mountService.forFileSystem(cryptoFsRoot); - var internal = new SettledMounter(mountService, builder, vaultSettings); + public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot) throws IOException, MountFailedException { + var fallbackProvider = mountProviders.stream().findFirst().orElse(null); + var defMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(settings.mountService.getValue())).findFirst().orElse(fallbackProvider); + var selMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defMntServ); + + var targetIsProblematicFuse = isProblematicFuseService(selMntServ); + if (targetIsProblematicFuse && firstUsedProblematicFuseMountService.get() == null) { + firstUsedProblematicFuseMountService.set(selMntServ); + } + + var fuseRestartRequired = firstUsedProblematicFuseMountService.get() != null // + && isProblematicFuseService(selMntServ) // + && !firstUsedProblematicFuseMountService.get().equals(selMntServ); + + if (fuseRestartRequired) { + throw new FuseRestartRequiredException("fuseRestartRequired"); + } + + var builder = selMntServ.forFileSystem(cryptoFsRoot); + var internal = new SettledMounter(selMntServ, builder, vaultSettings); var cleanup = internal.prepare(); - return new MountHandle(builder.mount(), mountService.hasCapability(UNMOUNT_FORCED), cleanup); + return new MountHandle(builder.mount(), selMntServ.hasCapability(UNMOUNT_FORCED), cleanup); + } + + public static boolean isProblematicFuseService(MountService service) { + return problematicFuseMountServices.contains(service.getClass().getName()); } public record MountHandle(Mount mountObj, boolean supportsUnmountForced, Runnable specialCleanup) { diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index d617a5db3..d741ae5c4 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -10,10 +10,7 @@ package org.cryptomator.common.vaults; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.Constants; -import org.cryptomator.common.mount.ActualMountService; -import org.cryptomator.common.mount.FuseRestartRequiredException; import org.cryptomator.common.mount.Mounter; -import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; import org.cryptomator.cryptofs.CryptoFileSystemProperties; @@ -24,7 +21,6 @@ import org.cryptomator.cryptolib.api.CryptoException; import org.cryptomator.cryptolib.api.MasterkeyLoader; import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException; import org.cryptomator.integrations.mount.MountFailedException; -import org.cryptomator.integrations.mount.MountService; import org.cryptomator.integrations.mount.Mountpoint; import org.cryptomator.integrations.mount.UnmountFailedException; import org.slf4j.Logger; @@ -41,12 +37,10 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.value.ObservableValue; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.EnumSet; -import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -58,9 +52,7 @@ public class Vault { private static final Path HOME_DIR = Paths.get(SystemUtils.USER_HOME); private static final int UNLIMITED_FILENAME_LENGTH = Integer.MAX_VALUE; - private final Settings settings; private final VaultSettings vaultSettings; - private final List mountProviders; private final AtomicReference cryptoFileSystem; private final VaultState state; private final ObjectProperty lastKnownException; @@ -76,28 +68,20 @@ public class Vault { private final ObjectBinding mountPoint; private final Mounter mounter; private final BooleanProperty showingStats; - private final ObservableValue actualMountService; - private final AtomicReference firstUsedProblematicFuseMountService; private final AtomicReference mountHandle = new AtomicReference<>(null); @Inject - Vault(Settings settings, // - VaultSettings vaultSettings, // + Vault(VaultSettings vaultSettings, // VaultConfigCache configCache, // AtomicReference cryptoFileSystem, // - List mountProviders, // VaultState state, // @Named("lastKnownException") ObjectProperty lastKnownException, // VaultStats stats, // - Mounter mounter, // - @Named("vaultMountService") ObservableValue actualMountService, // - @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService) { - this.settings = settings; + Mounter mounter) { this.vaultSettings = vaultSettings; this.configCache = configCache; this.cryptoFileSystem = cryptoFileSystem; - this.mountProviders = mountProviders; this.state = state; this.lastKnownException = lastKnownException; this.stats = stats; @@ -111,8 +95,6 @@ public class Vault { this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state); this.mounter = mounter; this.showingStats = new SimpleBooleanProperty(false); - this.actualMountService = actualMountService; - this.firstUsedProblematicFuseMountService = firstUsedProblematicFuseMountService; } // ****************************************************************************** @@ -165,22 +147,13 @@ public class Vault { if (cryptoFileSystem.get() != null) { throw new IllegalStateException("Already unlocked."); } - var fallbackProvider = mountProviders.stream().findFirst().orElse(null); - var defMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(settings.mountService.getValue())).findFirst().orElse(fallbackProvider); - var selMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defMntServ); - var fuseRestartRequired = firstUsedProblematicFuseMountService.get() != null // - && VaultModule.isProblematicFuseService(selMntServ) // - && !firstUsedProblematicFuseMountService.get().equals(selMntServ); - if (fuseRestartRequired) { - throw new FuseRestartRequiredException("fuseRestartRequired"); - } CryptoFileSystem fs = createCryptoFileSystem(keyLoader); boolean success = false; try { cryptoFileSystem.set(fs); var rootPath = fs.getRootDirectories().iterator().next(); - var mountHandle = mounter.mount(vaultSettings, rootPath, actualMountService); + var mountHandle = mounter.mount(vaultSettings, rootPath); success = this.mountHandle.compareAndSet(null, mountHandle); } finally { if (!success) { diff --git a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java index cbcc281ac..6f0e30153 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java @@ -37,19 +37,19 @@ public class VaultListManager { private static final Logger LOG = LoggerFactory.getLogger(VaultListManager.class); - private final AutoLocker autoLocker; private final VaultComponent.Factory vaultComponentFactory; private final ObservableList vaultList; private final String defaultVaultName; - private final Settings settings; + @Inject - public VaultListManager(ObservableList vaultList, AutoLocker autoLocker, VaultComponent.Factory vaultComponentFactory, ResourceBundle resourceBundle, Settings settings) { + public VaultListManager(ObservableList vaultList, // + AutoLocker autoLocker, // + VaultComponent.Factory vaultComponentFactory, // + ResourceBundle resourceBundle, Settings settings) { this.vaultList = vaultList; - this.autoLocker = autoLocker; this.vaultComponentFactory = vaultComponentFactory; this.defaultVaultName = resourceBundle.getString("defaults.vault.vaultName"); - this.settings = settings; addAll(settings.directories); vaultList.addListener(new VaultListChangeListener(settings.directories)); diff --git a/src/main/java/org/cryptomator/common/vaults/VaultModule.java b/src/main/java/org/cryptomator/common/vaults/VaultModule.java index b172a1e03..276af9f96 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultModule.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultModule.java @@ -8,72 +8,22 @@ package org.cryptomator.common.vaults; import dagger.Module; import dagger.Provides; import org.cryptomator.common.Nullable; -import org.cryptomator.common.ObservableUtil; -import org.cryptomator.common.mount.ActualMountService; -import org.cryptomator.common.settings.Settings; -import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; -import org.cryptomator.integrations.mount.MountService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.inject.Named; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; -import java.util.List; import java.util.concurrent.atomic.AtomicReference; @Module public class VaultModule { - private static final AtomicReference formerSelectedMountService = new AtomicReference<>(null); - private static final List problematicFuseMountServices = List.of("org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", "org.cryptomator.frontend.fuse.mount.FuseTMountProvider"); - private static final Logger LOG = LoggerFactory.getLogger(VaultModule.class); - @Provides @PerVault public AtomicReference provideCryptoFileSystemReference() { return new AtomicReference<>(); } - @Provides - @Named("vaultMountService") - @PerVault - static ObservableValue provideMountService(Settings settings, VaultSettings vaultSettings, List serviceImpls, @Named("FUPFMS") AtomicReference fupfms) { - var fallbackProvider = serviceImpls.stream().findFirst().orElse(null); - var defaultMountService = ObservableUtil.mapWithDefault(settings.mountService, serviceName -> serviceImpls.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), fallbackProvider); - return ObservableUtil.mapWithDefault(vaultSettings.mountService, // - desiredServiceImpl -> { // - var serviceFromSettings = serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny(); // - var targetedService = serviceFromSettings.orElse(defaultMountService.getValue()); - return applyWorkaroundForProblematicFuse(targetedService, serviceFromSettings.isPresent(), fupfms); - }, // - () -> applyWorkaroundForProblematicFuse(defaultMountService.getValue(), true, fupfms) - ); - } - - //see https://github.com/cryptomator/cryptomator/issues/2786 - private synchronized static ActualMountService applyWorkaroundForProblematicFuse(MountService targetedService, boolean isDesired, AtomicReference firstUsedProblematicFuseMountService) { - //set the first used problematic fuse service if applicable - var targetIsProblematicFuse = isProblematicFuseService(targetedService); - if (targetIsProblematicFuse && firstUsedProblematicFuseMountService.get() == null) { - firstUsedProblematicFuseMountService.set(targetedService); - } - - //do not use the targeted mount service and fallback to former one, if the service is problematic _and_ not the first problematic one used. - if (targetIsProblematicFuse && !firstUsedProblematicFuseMountService.get().equals(targetedService)) { - return new ActualMountService(formerSelectedMountService.get(), false); - } else { - formerSelectedMountService.set(targetedService); - return new ActualMountService(targetedService, isDesired); - } - } - - public static boolean isProblematicFuseService(MountService service) { - return problematicFuseMountServices.contains(service.getClass().getName()); - } - @Provides @Named("lastKnownException") @PerVault diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 9d28d8d9d..0583e4fbb 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -3,11 +3,11 @@ package org.cryptomator.ui.vaultoptions; import com.google.common.base.Strings; import dagger.Lazy; import org.cryptomator.common.ObservableUtil; +import org.cryptomator.common.mount.Mounter; import org.cryptomator.common.mount.WindowsDriveLetters; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.vaults.Vault; -import org.cryptomator.common.vaults.VaultModule; import org.cryptomator.integrations.mount.MountCapability; import org.cryptomator.integrations.mount.MountService; import org.cryptomator.ui.common.FxController; @@ -102,11 +102,10 @@ public class MountOptionsController implements FxController { fallbackProvider); this.selectedMountService = Bindings.createObjectBinding(this::reselectMountService, defaultMountService, vaultSettings.mountService); this.fuseRestartRequired = selectedMountService.map(s -> { - return firstUsedProblematicFuseMountService.get() != null // - && VaultModule.isProblematicFuseService(s) // - && !firstUsedProblematicFuseMountService.get().equals(s); - } - ); + return firstUsedProblematicFuseMountService.get() != null // + && Mounter.isProblematicFuseService(s) // + && !firstUsedProblematicFuseMountService.get().equals(s); + }); this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT))); this.defaultMountFlags = selectedMountService.map(s -> { @@ -130,7 +129,7 @@ public class MountOptionsController implements FxController { @FXML public void initialize() { - defaultMountService.addListener((_,_,_) -> vaultVolumeTypeChoiceBox.setConverter(new MountServiceConverter())); + defaultMountService.addListener((_, _, _) -> vaultVolumeTypeChoiceBox.setConverter(new MountServiceConverter())); // readonly: readOnlyCheckbox.selectedProperty().bindBidirectional(vaultSettings.usesReadOnlyMode); From 63bf0315c7ce476de6b2ed9ff0657efe3186d5e3 Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Tue, 5 Dec 2023 16:21:12 +0100 Subject: [PATCH 25/41] created global mountService --- .../org/cryptomator/common/CommonsModule.java | 11 ++++++++++ .../org/cryptomator/common/mount/Mounter.java | 20 +++++++++---------- .../vaultoptions/MountOptionsController.java | 8 ++------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/cryptomator/common/CommonsModule.java b/src/main/java/org/cryptomator/common/CommonsModule.java index 5ea69da6d..ab52d43fd 100644 --- a/src/main/java/org/cryptomator/common/CommonsModule.java +++ b/src/main/java/org/cryptomator/common/CommonsModule.java @@ -21,9 +21,11 @@ import org.slf4j.LoggerFactory; import javax.inject.Named; import javax.inject.Singleton; +import javafx.beans.value.ObservableValue; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Comparator; +import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; @@ -141,4 +143,13 @@ public abstract class CommonsModule { return new AtomicReference<>(null); } + @Provides + @Singleton + static ObservableValue provideDefaultMountService(List mountProviders, Settings settings) { + var fallbackProvider = mountProviders.stream().findFirst().orElse(null); + + return ObservableUtil.mapWithDefault(settings.mountService, // + serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), // + fallbackProvider); + } } diff --git a/src/main/java/org/cryptomator/common/mount/Mounter.java b/src/main/java/org/cryptomator/common/mount/Mounter.java index cf5f2b678..4bdaa580b 100644 --- a/src/main/java/org/cryptomator/common/mount/Mounter.java +++ b/src/main/java/org/cryptomator/common/mount/Mounter.java @@ -11,6 +11,7 @@ import org.cryptomator.integrations.mount.MountService; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; +import javafx.beans.value.ObservableValue; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -30,27 +31,28 @@ public class Mounter { private final Environment env; private final WindowsDriveLetters driveLetters; - private final Settings settings; private final List mountProviders; private final AtomicReference firstUsedProblematicFuseMountService; + private final ObservableValue defaultMountService; @Inject public Mounter(Environment env, // WindowsDriveLetters driveLetters, // - Settings settings, List mountProviders, // - @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService) { + List mountProviders, // + @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService, + ObservableValue defaultMountService) { this.env = env; this.driveLetters = driveLetters; - this.settings = settings; this.mountProviders = mountProviders; this.firstUsedProblematicFuseMountService = firstUsedProblematicFuseMountService; + this.defaultMountService = defaultMountService; } private class SettledMounter { - private MountService service; - private MountBuilder builder; - private VaultSettings vaultSettings; + private final MountService service; + private final MountBuilder builder; + private final VaultSettings vaultSettings; public SettledMounter(MountService service, MountBuilder builder, VaultSettings vaultSettings) { this.service = service; @@ -139,9 +141,7 @@ public class Mounter { } public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot) throws IOException, MountFailedException { - var fallbackProvider = mountProviders.stream().findFirst().orElse(null); - var defMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(settings.mountService.getValue())).findFirst().orElse(fallbackProvider); - var selMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defMntServ); + var selMntServ = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defaultMountService.getValue()); var targetIsProblematicFuse = isProblematicFuseService(selMntServ); if (targetIsProblematicFuse && firstUsedProblematicFuseMountService.get() == null) { diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 0583e4fbb..edcf0bb23 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -2,7 +2,6 @@ package org.cryptomator.ui.vaultoptions; import com.google.common.base.Strings; import dagger.Lazy; -import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.mount.Mounter; import org.cryptomator.common.mount.WindowsDriveLetters; import org.cryptomator.common.settings.Settings; @@ -88,7 +87,7 @@ public class MountOptionsController implements FxController { ResourceBundle resourceBundle, // Lazy application, // List mountProviders, // - @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService) { + @Named("FUPFMS") AtomicReference firstUsedProblematicFuseMountService, ObservableValue defaultMountService) { this.window = window; this.vaultSettings = vault.getVaultSettings(); this.windowsDriveLetters = windowsDriveLetters; @@ -96,10 +95,7 @@ public class MountOptionsController implements FxController { this.directoryPath = vault.getVaultSettings().mountPoint.map(p -> isDriveLetter(p) ? null : p.toString()); this.application = application; this.mountProviders = mountProviders; - var fallbackProvider = mountProviders.stream().findFirst().orElse(null); - this.defaultMountService = ObservableUtil.mapWithDefault(settings.mountService, // - serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), // - fallbackProvider); + this.defaultMountService = defaultMountService; this.selectedMountService = Bindings.createObjectBinding(this::reselectMountService, defaultMountService, vaultSettings.mountService); this.fuseRestartRequired = selectedMountService.map(s -> { return firstUsedProblematicFuseMountService.get() != null // From dce4c608812724d4888cd5051a211125143d8ddc Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 6 Dec 2023 08:40:43 +0100 Subject: [PATCH 26/41] removed pr unrelated changes and code cleanup --- src/main/java/org/cryptomator/common/vaults/Vault.java | 1 - .../java/org/cryptomator/common/vaults/VaultListManager.java | 4 +++- src/main/java/org/cryptomator/common/vaults/VaultModule.java | 4 ++++ src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java | 4 ++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index d741ae5c4..ac913d316 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -147,7 +147,6 @@ public class Vault { if (cryptoFileSystem.get() != null) { throw new IllegalStateException("Already unlocked."); } - CryptoFileSystem fs = createCryptoFileSystem(keyLoader); boolean success = false; try { diff --git a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java index 6f0e30153..2399a5107 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java @@ -37,6 +37,7 @@ public class VaultListManager { private static final Logger LOG = LoggerFactory.getLogger(VaultListManager.class); + private final AutoLocker autoLocker; private final VaultComponent.Factory vaultComponentFactory; private final ObservableList vaultList; private final String defaultVaultName; @@ -48,9 +49,10 @@ public class VaultListManager { VaultComponent.Factory vaultComponentFactory, // ResourceBundle resourceBundle, Settings settings) { this.vaultList = vaultList; + this.autoLocker = autoLocker; this.vaultComponentFactory = vaultComponentFactory; this.defaultVaultName = resourceBundle.getString("defaults.vault.vaultName"); - + addAll(settings.directories); vaultList.addListener(new VaultListChangeListener(settings.directories)); autoLocker.init(); diff --git a/src/main/java/org/cryptomator/common/vaults/VaultModule.java b/src/main/java/org/cryptomator/common/vaults/VaultModule.java index 276af9f96..c8853fa5b 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultModule.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultModule.java @@ -9,6 +9,8 @@ import dagger.Module; import dagger.Provides; import org.cryptomator.common.Nullable; import org.cryptomator.cryptofs.CryptoFileSystem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.inject.Named; import javafx.beans.property.ObjectProperty; @@ -18,6 +20,8 @@ import java.util.concurrent.atomic.AtomicReference; @Module public class VaultModule { + private static final Logger LOG = LoggerFactory.getLogger(VaultModule.class); + @Provides @PerVault public AtomicReference provideCryptoFileSystemReference() { diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java b/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java index 98385f1d6..6be17ff26 100644 --- a/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java +++ b/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java @@ -133,8 +133,8 @@ public class UnlockWorkflow extends Task { Throwable throwable = super.getException(); if(throwable instanceof IllegalMountPointException impe) { handleIllegalMountPointError(impe); - } else if (throwable instanceof FuseRestartRequiredException fRRE) { - handleFuseRestartRequiredError(fRRE); + } else if (throwable instanceof FuseRestartRequiredException e) { + handleFuseRestartRequiredError(e); } else { handleGenericError(throwable); } From 5cbed502ed4bd0da355cc484d1d6f75532350f4a Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 6 Dec 2023 08:49:21 +0100 Subject: [PATCH 27/41] undo VaultListManager changes --- .../org/cryptomator/common/vaults/VaultListManager.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java index 2399a5107..53616c3db 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java @@ -42,12 +42,8 @@ public class VaultListManager { private final ObservableList vaultList; private final String defaultVaultName; - @Inject - public VaultListManager(ObservableList vaultList, // - AutoLocker autoLocker, // - VaultComponent.Factory vaultComponentFactory, // - ResourceBundle resourceBundle, Settings settings) { + public VaultListManager(ObservableList vaultList, AutoLocker autoLocker, VaultComponent.Factory vaultComponentFactory, ResourceBundle resourceBundle, Settings settings) { this.vaultList = vaultList; this.autoLocker = autoLocker; this.vaultComponentFactory = vaultComponentFactory; From fac72ca24aec3466a0a4a61c9d8e4fa766b82e9c Mon Sep 17 00:00:00 2001 From: Jan-Peter Klein Date: Wed, 6 Dec 2023 09:44:05 +0100 Subject: [PATCH 28/41] undo remove settings port --- .../cryptomator/common/settings/Settings.java | 15 +++----- .../common/settings/SettingsJson.java | 5 +-- .../VolumePreferencesController.java | 38 +++++++++++++++++++ .../resources/fxml/preferences_volume.fxml | 6 +++ .../common/settings/SettingsJsonTest.java | 2 + .../common/settings/SettingsTest.java | 2 +- 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/cryptomator/common/settings/Settings.java b/src/main/java/org/cryptomator/common/settings/Settings.java index 13e3d32ec..4e0e0df97 100644 --- a/src/main/java/org/cryptomator/common/settings/Settings.java +++ b/src/main/java/org/cryptomator/common/settings/Settings.java @@ -36,6 +36,7 @@ public class Settings { static final boolean DEFAULT_START_HIDDEN = false; static final boolean DEFAULT_AUTO_CLOSE_VAULTS = false; static final boolean DEFAULT_USE_KEYCHAIN = true; + static final int DEFAULT_PORT = 42427; static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3; static final boolean DEFAULT_DEBUG_MODE = false; static final UiTheme DEFAULT_THEME = UiTheme.LIGHT; @@ -51,6 +52,7 @@ public class Settings { public final BooleanProperty startHidden; public final BooleanProperty autoCloseVaults; public final BooleanProperty useKeychain; + public final IntegerProperty port; public final IntegerProperty numTrayNotifications; public final BooleanProperty debugMode; public final ObjectProperty theme; @@ -87,6 +89,7 @@ public class Settings { this.startHidden = new SimpleBooleanProperty(this, "startHidden", json.startHidden); this.autoCloseVaults = new SimpleBooleanProperty(this, "autoCloseVaults", json.autoCloseVaults); this.useKeychain = new SimpleBooleanProperty(this, "useKeychain", json.useKeychain); + this.port = new SimpleIntegerProperty(this, "webDavPort", json.port); this.numTrayNotifications = new SimpleIntegerProperty(this, "numTrayNotifications", json.numTrayNotifications); this.debugMode = new SimpleBooleanProperty(this, "debugMode", json.debugMode); this.theme = new SimpleObjectProperty<>(this, "theme", json.theme); @@ -106,7 +109,6 @@ public class Settings { this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList()); migrateLegacySettings(json); - migratePortToVaultSettings(json); directories.addListener(this::somethingChanged); askedForUpdateCheck.addListener(this::somethingChanged); @@ -114,6 +116,7 @@ public class Settings { startHidden.addListener(this::somethingChanged); autoCloseVaults.addListener(this::somethingChanged); useKeychain.addListener(this::somethingChanged); + port.addListener(this::somethingChanged); numTrayNotifications.addListener(this::somethingChanged); debugMode.addListener(this::somethingChanged); theme.addListener(this::somethingChanged); @@ -131,15 +134,6 @@ public class Settings { lastUpdateCheck.addListener(this::somethingChanged); } - @SuppressWarnings("deprecation") - private void migratePortToVaultSettings(SettingsJson json) { - if(json.port != 0){ - for (VaultSettings vaultSettings : directories) { - vaultSettings.port.set(json.port); - } - } - } - @SuppressWarnings("deprecation") private void migrateLegacySettings(SettingsJson json) { // implicit migration of 1.6.x legacy setting "preferredVolumeImpl": @@ -176,6 +170,7 @@ public class Settings { json.startHidden = startHidden.get(); json.autoCloseVaults = autoCloseVaults.get(); json.useKeychain = useKeychain.get(); + json.port = port.get(); json.numTrayNotifications = numTrayNotifications.get(); json.debugMode = debugMode.get(); json.theme = theme.get(); diff --git a/src/main/java/org/cryptomator/common/settings/SettingsJson.java b/src/main/java/org/cryptomator/common/settings/SettingsJson.java index bf1514b1d..2c7c963da 100644 --- a/src/main/java/org/cryptomator/common/settings/SettingsJson.java +++ b/src/main/java/org/cryptomator/common/settings/SettingsJson.java @@ -46,9 +46,8 @@ class SettingsJson { @JsonProperty("numTrayNotifications") int numTrayNotifications = Settings.DEFAULT_NUM_TRAY_NOTIFICATIONS; - @Deprecated(since = "1.12.0") - @JsonProperty(value = "port", access = JsonProperty.Access.WRITE_ONLY) // WRITE_ONLY means value is "written" into the java object during deserialization. Upvote this: https://github.com/FasterXML/jackson-annotations/issues/233 - int port; + @JsonProperty("port") + int port = Settings.DEFAULT_PORT; @JsonProperty("showMinimizeButton") boolean showMinimizeButton = Settings.DEFAULT_SHOW_MINIMIZE_BUTTON; diff --git a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java index c06a4596b..c02a59ee5 100644 --- a/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java +++ b/src/main/java/org/cryptomator/ui/preferences/VolumePreferencesController.java @@ -9,8 +9,12 @@ import org.cryptomator.ui.common.FxController; import javax.inject.Inject; import javafx.application.Application; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanExpression; import javafx.beans.value.ObservableValue; +import javafx.scene.control.Button; import javafx.scene.control.ChoiceBox; +import javafx.scene.control.TextField; import javafx.util.StringConverter; import java.util.List; import java.util.Optional; @@ -20,10 +24,13 @@ import java.util.ResourceBundle; public class VolumePreferencesController implements FxController { private static final String DOCS_MOUNTING_URL = "https://docs.cryptomator.org/en/1.7/desktop/volume-type/"; + private static final int MIN_PORT = 1024; + private static final int MAX_PORT = 65535; private final Settings settings; private final ObservableValue selectedMountService; private final ResourceBundle resourceBundle; + private final BooleanExpression loopbackPortSupported; private final ObservableValue mountToDirSupported; private final ObservableValue mountToDriveLetterSupported; private final ObservableValue mountFlagsSupported; @@ -31,6 +38,8 @@ public class VolumePreferencesController implements FxController { private final Lazy application; private final List mountProviders; public ChoiceBox volumeTypeChoiceBox; + public TextField loopbackPortField; + public Button loopbackPortApplyButton; @Inject VolumePreferencesController(Settings settings, @@ -44,6 +53,7 @@ public class VolumePreferencesController implements FxController { var fallbackProvider = mountProviders.stream().findFirst().orElse(null); this.selectedMountService = ObservableUtil.mapWithDefault(settings.mountService, serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), fallbackProvider); + this.loopbackPortSupported = BooleanExpression.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT))); this.mountToDirSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_WITHIN_EXISTING_PARENT) || s.hasCapability(MountCapability.MOUNT_TO_EXISTING_DIR)); this.mountToDriveLetterSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_AS_DRIVE_LETTER)); this.mountFlagsSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_FLAGS)); @@ -60,9 +70,37 @@ public class VolumePreferencesController implements FxController { var toSet = Optional.ofNullable(newProvider).map(nP -> nP.getClass().getName()).orElse(null); settings.mountService.set(toSet); }); + + loopbackPortField.setText(String.valueOf(settings.port.get())); + loopbackPortApplyButton.visibleProperty().bind(settings.port.asString().isNotEqualTo(loopbackPortField.textProperty())); + loopbackPortApplyButton.disableProperty().bind(Bindings.createBooleanBinding(this::validateLoopbackPort, loopbackPortField.textProperty()).not()); + } + + private boolean validateLoopbackPort() { + try { + int port = Integer.parseInt(loopbackPortField.getText()); + return port == 0 // choose port automatically + || port >= MIN_PORT && port <= MAX_PORT; // port within range + } catch (NumberFormatException e) { + return false; + } + } + + public void doChangeLoopbackPort() { + if (validateLoopbackPort()) { + settings.port.set(Integer.parseInt(loopbackPortField.getText())); + } } /* Property Getters */ + + public BooleanExpression loopbackPortSupportedProperty() { + return loopbackPortSupported; + } + + public boolean isLoopbackPortSupported() { + return loopbackPortSupported.get(); + } public ObservableValue readonlySupportedProperty() { return readonlySupported; } diff --git a/src/main/resources/fxml/preferences_volume.fxml b/src/main/resources/fxml/preferences_volume.fxml index b2f955801..fef85aadc 100644 --- a/src/main/resources/fxml/preferences_volume.fxml +++ b/src/main/resources/fxml/preferences_volume.fxml @@ -32,6 +32,12 @@ + +