diff --git a/main/pom.xml b/main/pom.xml index 81481f20c..e2bd75511 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -26,7 +26,7 @@ 1.9.13 0.1.6 - 0.1.0-beta1 + 0.2.0 0.1.0-beta3 0.1.0-beta2 1.2.6 diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartMacStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartMacStrategy.java deleted file mode 100644 index 26811cdf2..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartMacStrategy.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.cryptomator.ui.preferences; - -import org.cryptomator.integrations.autostart.AutoStartProvider; -import org.cryptomator.integrations.autostart.ToggleAutoStartFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; - -@Deprecated -class AutoStartMacStrategy implements AutoStartStrategy { - - private static final Logger LOG = LoggerFactory.getLogger(AutoStartMacStrategy.class); - - private final AutoStartProvider autoStartProvider; - - public AutoStartMacStrategy(AutoStartProvider autoStartProvider) { - this.autoStartProvider = autoStartProvider; - } - - @Override - public CompletionStage isAutoStartEnabled() { - return CompletableFuture.completedFuture(autoStartProvider.isEnabled()); - } - - @Override - public void enableAutoStart() throws TogglingAutoStartFailedException { - try { - autoStartProvider.enable(); - LOG.debug("Added login item."); - } catch (ToggleAutoStartFailedException e) { - throw new TogglingAutoStartFailedException("Failed to add login item."); - } - } - - @Override - public void disableAutoStart() throws TogglingAutoStartFailedException { - try { - autoStartProvider.disable(); - LOG.debug("Removed login item."); - } catch (ToggleAutoStartFailedException e) { - throw new TogglingAutoStartFailedException("Failed to remove login item."); - } - } -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java deleted file mode 100644 index 7f6406f22..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.cryptomator.ui.preferences; - -import dagger.Module; -import dagger.Provides; -import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.integrations.autostart.AutoStartProvider; - -import java.util.Optional; - -@Deprecated -@Module -abstract class AutoStartModule { - - @Provides - @PreferencesScoped - public static Optional provideAutoStartStrategy(Optional autoStartProvider) { - if (SystemUtils.IS_OS_MAC_OSX && autoStartProvider.isPresent()) { - return Optional.of(new AutoStartMacStrategy(autoStartProvider.get())); - } else if (SystemUtils.IS_OS_WINDOWS) { - Optional exeName = ProcessHandle.current().info().command(); - return exeName.map(AutoStartWinStrategy::new); - } else { - return Optional.empty(); - } - } - -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java deleted file mode 100644 index 9848e58f8..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.cryptomator.ui.preferences; - -import java.util.concurrent.CompletionStage; - -@Deprecated -public interface AutoStartStrategy { - - CompletionStage isAutoStartEnabled(); - - void enableAutoStart() throws TogglingAutoStartFailedException; - - void disableAutoStart() throws TogglingAutoStartFailedException; - - class TogglingAutoStartFailedException extends Exception { - - public TogglingAutoStartFailedException(String message) { - super(message); - } - - public TogglingAutoStartFailedException(String message, Throwable cause) { - super(message, cause); - } - - } -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java deleted file mode 100644 index b3c0a4674..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.cryptomator.ui.preferences; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -/** - * OS specific class to check, en- and disable the auto start on Windows. - *

- * Two strategies are implemented for this feature, the first uses the registry and the second one the autostart folder. - *

- * The registry strategy checks/add/removes at the registry key {@value HKCU_AUTOSTART_KEY} an entry for Cryptomator. - * The folder strategy checks/add/removes at the location {@value WINDOWS_START_MENU_ENTRY}. - *

- * To check if the feature is active, both strategies are applied. - * To enable the feature, first the registry is tried and only on failure the autostart folder is used. - * To disable it, first it is determined by an internal state, which strategies must be used and in the second step those are executed. - * - * @apiNote This class is not thread safe, hence it should be avoided to call its methods simultaniously by different threads. - * @deprecated To be moved to integration-win project - */ -@Deprecated -class AutoStartWinStrategy implements AutoStartStrategy { - - private static final Logger LOG = LoggerFactory.getLogger(AutoStartWinStrategy.class); - private static final String HKCU_AUTOSTART_KEY = "\"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\""; - private static final String AUTOSTART_VALUE = "Cryptomator"; - private static final String WINDOWS_START_MENU_ENTRY = "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Cryptomator.lnk"; - - private final String exePath; - - private boolean activatedUsingFolder; - private boolean activatedUsingRegistry; - - public AutoStartWinStrategy(String exePath) { - this.exePath = exePath; - this.activatedUsingFolder = false; - this.activatedUsingRegistry = false; - } - - @Override - public CompletionStage isAutoStartEnabled() { - return isAutoStartEnabledUsingRegistry().thenCombine(isAutoStartEnabledUsingFolder(), (bReg, bFolder) -> bReg || bFolder); - } - - private CompletableFuture isAutoStartEnabledUsingFolder() { - Path autoStartEntry = Path.of(System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY); - this.activatedUsingFolder = Files.exists(autoStartEntry); - return CompletableFuture.completedFuture(activatedUsingFolder); - } - - private CompletableFuture isAutoStartEnabledUsingRegistry() { - ProcessBuilder regQuery = new ProcessBuilder("reg", "query", HKCU_AUTOSTART_KEY, // - "/v", AUTOSTART_VALUE); - try { - Process proc = regQuery.start(); - return proc.onExit().thenApply(p -> { - this.activatedUsingRegistry = p.exitValue() == 0; - return activatedUsingRegistry; - }); - } catch (IOException e) { - LOG.debug("Failed to query {} from registry key {}", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); - return CompletableFuture.completedFuture(false); - } - } - - @Override - public void enableAutoStart() throws TogglingAutoStartFailedException { - try { - enableAutoStartUsingRegistry().thenAccept((Void v) -> this.activatedUsingRegistry = true).exceptionallyCompose(e -> { - LOG.debug("Falling back to using autostart folder."); - return this.enableAutoStartUsingFolder(); - }).thenAccept((Void v) -> this.activatedUsingFolder = true).get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new TogglingAutoStartFailedException("Execution of enabling auto start setting was interrupted."); - } catch (ExecutionException e) { - throw new TogglingAutoStartFailedException("Enabling auto start failed both using registry and auto start folder."); - } - } - - private CompletableFuture enableAutoStartUsingRegistry() { - ProcessBuilder regAdd = new ProcessBuilder("reg", "add", HKCU_AUTOSTART_KEY, // - "/v", AUTOSTART_VALUE, // - "/t", "REG_SZ", // - "/d", "\"" + exePath + "\"", // - "/f"); - try { - Process proc = regAdd.start(); - boolean finishedInTime = waitForProcessOrCancel(proc, 5, TimeUnit.SECONDS); - if (finishedInTime && proc.exitValue() == 0) { - LOG.debug("Added {} to registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); - return CompletableFuture.completedFuture(null); - } else { - throw new IOException("Process exited with error code " + proc.exitValue()); - } - } catch (IOException e) { - LOG.debug("Registry could not be edited to set auto start.", e); - return CompletableFuture.failedFuture(new SystemCommandException("Adding registry value failed.")); - } - } - - private CompletableFuture enableAutoStartUsingFolder() { - String autoStartFolderEntry = System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY; - String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + autoStartFolderEntry + "');$s.TargetPath='" + exePath + "';$s.Save();"; - ProcessBuilder shortcutAdd = new ProcessBuilder("cmd", "/c", "Start powershell " + createShortcutCommand); - try { - Process proc = shortcutAdd.start(); - boolean finishedInTime = waitForProcessOrCancel(proc, 5, TimeUnit.SECONDS); - if (finishedInTime && proc.exitValue() == 0) { - LOG.debug("Created file {} for auto start.", autoStartFolderEntry); - return CompletableFuture.completedFuture(null); - } else { - throw new IOException("Process exited with error code " + proc.exitValue()); - } - } catch (IOException e) { - LOG.debug("Adding entry to auto start folder failed.", e); - return CompletableFuture.failedFuture(new SystemCommandException("Adding entry to auto start folder failed.")); - } - } - - - @Override - public void disableAutoStart() throws TogglingAutoStartFailedException { - if (activatedUsingRegistry) { - disableAutoStartUsingRegistry().whenComplete((voit, ex) -> { - if (ex == null) { - this.activatedUsingRegistry = false; - } - }); - } - - if (activatedUsingFolder) { - disableAutoStartUsingFolder().whenComplete((voit, ex) -> { - if (ex == null) { - this.activatedUsingFolder = false; - } - }); - } - - if (activatedUsingRegistry || activatedUsingFolder) { - throw new TogglingAutoStartFailedException("Disabling auto start failed using registry and/or auto start folder."); - } - } - - public CompletableFuture disableAutoStartUsingRegistry() { - ProcessBuilder regRemove = new ProcessBuilder("reg", "delete", HKCU_AUTOSTART_KEY, // - "/v", AUTOSTART_VALUE, // - "/f"); - try { - Process proc = regRemove.start(); - boolean finishedInTime = waitForProcessOrCancel(proc, 5, TimeUnit.SECONDS); - if (finishedInTime && proc.exitValue() == 0) { - LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); - return CompletableFuture.completedFuture(null); - } else { - throw new IOException("Process exited with error code " + proc.exitValue()); - } - } catch (IOException e) { - LOG.debug("Registry could not be edited to remove auto start.", e); - return CompletableFuture.failedFuture(new SystemCommandException("Removing registry value failed.")); - } - } - - private CompletableFuture disableAutoStartUsingFolder() { - try { - Files.delete(Path.of(WINDOWS_START_MENU_ENTRY)); - LOG.debug("Successfully deleted {}.", WINDOWS_START_MENU_ENTRY); - return CompletableFuture.completedFuture(null); - } catch (NoSuchFileException e) { - //that is also okay - return CompletableFuture.completedFuture(null); - } catch (IOException e) { - LOG.debug("Failed to delete entry from auto start folder.", e); - return CompletableFuture.failedFuture(e); - } - } - - private static boolean waitForProcessOrCancel(Process proc, int timeout, TimeUnit timeUnit) { - boolean finishedInTime = false; - try { - finishedInTime = proc.waitFor(timeout, timeUnit); - } catch (InterruptedException e) { - LOG.error("Timeout while reading registry", e); - Thread.currentThread().interrupt(); - } finally { - if (!finishedInTime) { - proc.destroyForcibly(); - } - } - return finishedInTime; - } - - private class SystemCommandException extends RuntimeException { - - public SystemCommandException(String msg) { - super(msg); - } - } - -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java index 496ada2ce..d17cc6a51 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java @@ -5,6 +5,8 @@ import org.cryptomator.common.LicenseHolder; import org.cryptomator.common.settings.KeychainBackend; import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.UiTheme; +import org.cryptomator.integrations.autostart.AutoStartProvider; +import org.cryptomator.integrations.autostart.ToggleAutoStartFailedException; import org.cryptomator.integrations.keychain.KeychainAccessProvider; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; @@ -14,10 +16,8 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Named; import javafx.application.Application; -import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.beans.value.ObservableValue; -import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.geometry.NodeOrientation; import javafx.scene.control.CheckBox; @@ -42,7 +42,7 @@ public class GeneralPreferencesController implements FxController { private final Stage window; private final Settings settings; private final boolean trayMenuSupported; - private final Optional autoStartStrategy; + private final Optional autoStartProvider; private final ObjectProperty selectedTabProperty; private final LicenseHolder licenseHolder; private final ExecutorService executor; @@ -61,11 +61,11 @@ public class GeneralPreferencesController implements FxController { public RadioButton nodeOrientationRtl; @Inject - GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional autoStartStrategy, Set keychainAccessProviders, ObjectProperty selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) { + GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional autoStartProvider, Set keychainAccessProviders, ObjectProperty selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) { this.window = window; this.settings = settings; this.trayMenuSupported = trayMenuSupported; - this.autoStartStrategy = autoStartStrategy; + this.autoStartProvider = autoStartProvider; this.keychainAccessProviders = keychainAccessProviders; this.selectedTabProperty = selectedTabProperty; this.licenseHolder = licenseHolder; @@ -89,11 +89,7 @@ public class GeneralPreferencesController implements FxController { debugModeCheckbox.selectedProperty().bindBidirectional(settings.debugMode()); - autoStartStrategy.ifPresent(autoStart -> { - autoStart.isAutoStartEnabled().thenAccept(enabled -> { - Platform.runLater(() -> autoStartCheckbox.setSelected(enabled)); - }); - }); + autoStartProvider.ifPresent(realProvider -> autoStartCheckbox.setSelected(realProvider.isEnabled())); nodeOrientationLtr.setSelected(settings.userInterfaceOrientation().get() == NodeOrientation.LEFT_TO_RIGHT); nodeOrientationRtl.setSelected(settings.userInterfaceOrientation().get() == NodeOrientation.RIGHT_TO_LEFT); @@ -114,7 +110,7 @@ public class GeneralPreferencesController implements FxController { } public boolean isAutoStartSupported() { - return autoStartStrategy.isPresent(); + return autoStartProvider.isPresent(); } private void toggleNodeOrientation(@SuppressWarnings("unused") ObservableValue observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) { @@ -129,15 +125,19 @@ public class GeneralPreferencesController implements FxController { @FXML public void toggleAutoStart() { - autoStartStrategy.ifPresent(autoStart -> { + autoStartProvider.ifPresent(autoStart -> { boolean enableAutoStart = autoStartCheckbox.isSelected(); - Task toggleTask = new ToggleAutoStartTask(autoStart, enableAutoStart); - toggleTask.setOnFailed(event -> { + try { + if (enableAutoStart) { + autoStart.enable(); + } else { + autoStart.disable(); + } + } catch (ToggleAutoStartFailedException e) { autoStartCheckbox.setSelected(!enableAutoStart); // restore previous state - LOG.error("Failed to toggle autostart.", event.getSource().getException()); - errorComponent.cause(event.getSource().getException()).window(window).returnToScene(window.getScene()).build().showErrorScene(); - }); - executor.execute(toggleTask); + LOG.error("Failed to toggle autostart.", e); + errorComponent.cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene(); + } }); } @@ -196,27 +196,4 @@ public class GeneralPreferencesController implements FxController { } } - private static class ToggleAutoStartTask extends Task { - - private final AutoStartStrategy autoStart; - private final boolean enable; - - public ToggleAutoStartTask(AutoStartStrategy autoStart, boolean enable) { - this.autoStart = autoStart; - this.enable = enable; - - setOnFailed(event -> LOG.error("Failed to toggle Autostart", getException())); - } - - @Override - protected Void call() throws Exception { - if (enable) { - autoStart.enableAutoStart(); - } else { - autoStart.disableAutoStart(); - } - return null; - } - } - } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java index 2558582fd..3cc012b03 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesModule.java @@ -20,7 +20,7 @@ import javafx.stage.Stage; import java.util.Map; import java.util.ResourceBundle; -@Module(includes = {AutoStartModule.class}) +@Module abstract class PreferencesModule { @Provides