Merge branch 'develop' into feature/#1013-#1061-cleanupAndInformation

This commit is contained in:
Sebastian Stenzel
2020-11-06 15:17:45 +01:00
committed by GitHub
52 changed files with 647 additions and 1376 deletions
-8
View File
@@ -10,18 +10,10 @@
<name>Cryptomator GUI</name>
<dependencies>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>keychain</artifactId>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>commons</artifactId>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>jni</artifactId>
</dependency>
<!-- JavaFx -->
<dependency>
@@ -1,10 +1,10 @@
package org.cryptomator.ui.changepassword;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
@@ -36,14 +36,14 @@ public class ChangePasswordController implements FxController {
private final Vault vault;
private final ObjectProperty<CharSequence> newPassword;
private final ErrorComponent.Builder errorComponent;
private final Optional<KeychainManager> keychain;
private final KeychainManager keychain;
public NiceSecurePasswordField oldPasswordField;
public CheckBox finalConfirmationCheckbox;
public Button finishButton;
@Inject
public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty<CharSequence> newPassword, ErrorComponent.Builder errorComponent, Optional<KeychainManager> keychain) {
public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty<CharSequence> newPassword, ErrorComponent.Builder errorComponent, KeychainManager keychain) {
this.window = window;
this.vault = vault;
this.newPassword = newPassword;
@@ -82,9 +82,9 @@ public class ChangePasswordController implements FxController {
}
private void updatePasswordInSystemkeychain() {
if (keychain.isPresent()) {
if (keychain.isSupported()) {
try {
keychain.get().changePassphrase(vault.getId(), CharBuffer.wrap(newPassword.get()));
keychain.changePassphrase(vault.getId(), CharBuffer.wrap(newPassword.get()));
LOG.info("Successfully updated password in system keychain for {}", vault.getDisplayName());
} catch (KeychainAccessException e) {
LOG.error("Failed to update password in system keychain.", e);
@@ -3,7 +3,6 @@ package org.cryptomator.ui.common;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.common.vaults.Volume;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,7 +13,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -25,12 +23,10 @@ public class VaultService {
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
private final ExecutorService executorService;
private final Optional<KeychainManager> keychain;
@Inject
public VaultService(ExecutorService executorService, Optional<KeychainManager> keychain) {
public VaultService(ExecutorService executorService) {
this.executorService = executorService;
this.keychain = keychain;
}
public void reveal(Vault vault) {
@@ -1,8 +1,8 @@
package org.cryptomator.ui.forgetPassword;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,7 +11,6 @@ import javax.inject.Inject;
import javafx.beans.property.BooleanProperty;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import java.util.Optional;
@ForgetPasswordScoped
public class ForgetPasswordController implements FxController {
@@ -20,11 +19,11 @@ public class ForgetPasswordController implements FxController {
private final Stage window;
private final Vault vault;
private final Optional<KeychainManager> keychain;
private final KeychainManager keychain;
private final BooleanProperty confirmedResult;
@Inject
public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, Optional<KeychainManager> keychain, @ForgetPasswordWindow BooleanProperty confirmedResult) {
public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, KeychainManager keychain, @ForgetPasswordWindow BooleanProperty confirmedResult) {
this.window = window;
this.vault = vault;
this.keychain = keychain;
@@ -38,9 +37,9 @@ public class ForgetPasswordController implements FxController {
@FXML
public void finish() {
if (keychain.isPresent()) {
if (keychain.isSupported()) {
try {
keychain.get().deletePassphrase(vault.getId());
keychain.deletePassphrase(vault.getId());
LOG.debug("Forgot password for vault {}.", vault.getDisplayName());
confirmedResult.setValue(true);
} catch (KeychainAccessException e) {
@@ -6,10 +6,11 @@ import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.UiTheme;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.jni.JniException;
import org.cryptomator.jni.MacApplicationUiAppearance;
import org.cryptomator.jni.MacApplicationUiState;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.integrations.uiappearance.Theme;
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
import org.cryptomator.integrations.uiappearance.UiAppearanceListener;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
import org.cryptomator.ui.preferences.PreferencesComponent;
@@ -41,21 +42,22 @@ public class FxApplication extends Application {
private final Lazy<PreferencesComponent> preferencesWindow;
private final Provider<UnlockComponent.Builder> unlockWindowBuilderProvider;
private final Provider<QuitComponent.Builder> quitWindowBuilderProvider;
private final Optional<MacFunctions> macFunctions;
private final Optional<TrayIntegrationProvider> trayIntegration;
private final Optional<UiAppearanceProvider> appearanceProvider;
private final VaultService vaultService;
private final LicenseHolder licenseHolder;
private final BooleanBinding hasVisibleStages;
private Optional<String> macApperanceObserverIdentifier = Optional.empty();
private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged;
@Inject
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<QuitComponent.Builder> quitWindowBuilderProvider, Optional<MacFunctions> macFunctions, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<QuitComponent.Builder> quitWindowBuilderProvider, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
this.settings = settings;
this.mainWindow = mainWindow;
this.preferencesWindow = preferencesWindow;
this.unlockWindowBuilderProvider = unlockWindowBuilderProvider;
this.quitWindowBuilderProvider = quitWindowBuilderProvider;
this.macFunctions = macFunctions;
this.trayIntegration = trayIntegration;
this.appearanceProvider = appearanceProvider;
this.vaultService = vaultService;
this.licenseHolder = licenseHolder;
this.hasVisibleStages = Bindings.isNotEmpty(visibleStages);
@@ -67,7 +69,7 @@ public class FxApplication extends Application {
EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged);
settings.theme().addListener(this::themeChanged);
settings.theme().addListener(this::appThemeChanged);
loadSelectedStyleSheet(settings.theme().get());
}
@@ -78,9 +80,9 @@ public class FxApplication extends Application {
private void hasVisibleStagesChanged(boolean newValue) {
if (newValue) {
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToForegroundApplication);
trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray);
} else {
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToAgentApplication);
trayIntegration.ifPresent(TrayIntegrationProvider::minimizedToTray);
}
}
@@ -116,45 +118,60 @@ public class FxApplication extends Application {
return vaultService;
}
private void themeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
if (macApperanceObserverIdentifier.isPresent()) {
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> uiAppearance.removeListener(macApperanceObserverIdentifier.get()));
macApperanceObserverIdentifier = Optional.empty();
}
private void appThemeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
appearanceProvider.ifPresent(appearanceProvider -> {
try {
appearanceProvider.removeListener(systemInterfaceThemeListener);
} catch (UiAppearanceException e) {
LOG.error("Failed to disable automatic theme switching.");
}
});
loadSelectedStyleSheet(newValue);
}
private void loadSelectedStyleSheet(UiTheme desiredTheme) {
UiTheme theme = licenseHolder.isValidLicense() ? desiredTheme : UiTheme.LIGHT;
switch (theme) {
case LIGHT -> setToLightTheme();
case DARK -> setToDarkTheme();
case LIGHT -> applyLightTheme();
case DARK -> applyDarkTheme();
case AUTOMATIC -> {
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> {
macApperanceObserverIdentifier = Optional.of(uiAppearance.addListener(this::macInterfaceThemeChanged));
appearanceProvider.ifPresent(appearanceProvider -> {
try {
appearanceProvider.addListener(systemInterfaceThemeListener);
} catch (UiAppearanceException e) {
LOG.error("Failed to enable automatic theme switching.");
}
});
macInterfaceThemeChanged();
applySystemTheme();
}
}
}
private void macInterfaceThemeChanged() {
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> {
switch (uiAppearance.getCurrentInterfaceStyle()) {
case LIGHT -> setToLightTheme();
case DARK -> setToDarkTheme();
}
private void systemInterfaceThemeChanged(Theme theme) {
switch (theme) {
case LIGHT -> applyLightTheme();
case DARK -> applyDarkTheme();
}
}
private void applySystemTheme() {
appearanceProvider.ifPresent(appearanceProvider -> {
systemInterfaceThemeChanged(appearanceProvider.getSystemTheme());
});
}
private void setToLightTheme() {
private void applyLightTheme() {
Application.setUserAgentStylesheet(getClass().getResource("/css/light_theme.css").toString());
macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToAqua));
appearanceProvider.ifPresent(appearanceProvider -> {
appearanceProvider.adjustToTheme(Theme.LIGHT);
});
}
private void setToDarkTheme() {
private void applyDarkTheme() {
Application.setUserAgentStylesheet(getClass().getResource("/css/dark_theme.css").toString());
macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToDarkAqua));
appearanceProvider.ifPresent(appearanceProvider -> {
appearanceProvider.adjustToTheme(Theme.DARK);
});
}
}
@@ -4,9 +4,7 @@ import org.cryptomator.common.Environment;
import org.cryptomator.common.mountpoint.IrregularUnmountCleaner;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.jni.JniException;
import org.cryptomator.jni.MacApplicationUiState;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.slf4j.Logger;
@@ -31,18 +29,18 @@ public class UiLauncher {
private final TrayMenuComponent.Builder trayComponent;
private final FxApplicationStarter fxApplicationStarter;
private final AppLaunchEventHandler launchEventHandler;
private final Optional<MacFunctions> macFunctions;
private final Environment env;
private final Optional<TrayIntegrationProvider> trayIntegration;
private final Environment env;
@Inject
public UiLauncher(Settings settings, ObservableList<Vault> vaults, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<MacFunctions> macFunctions, Environment env) {
public UiLauncher(Settings settings, ObservableList<Vault> vaults, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<TrayIntegrationProvider> trayIntegration, Environment env) {
this.settings = settings;
this.vaults = vaults;
this.trayComponent = trayComponent;
this.fxApplicationStarter = fxApplicationStarter;
this.launchEventHandler = launchEventHandler;
this.macFunctions = macFunctions;
this.env = env;
this.trayIntegration = trayIntegration;
this.env = env;
}
public void launch() {
@@ -57,7 +55,7 @@ public class UiLauncher {
// show window on start?
if (hasTrayIcon && settings.startHidden().get()) {
LOG.debug("Hiding application...");
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToAgentApplication));
trayIntegration.ifPresent(TrayIntegrationProvider::minimizedToTray);
} else {
showMainWindowAsync(hasTrayIcon);
}
@@ -2,20 +2,42 @@ package org.cryptomator.ui.launcher;
import dagger.Module;
import dagger.Provides;
import org.cryptomator.common.JniModule;
import org.cryptomator.keychain.KeychainModule;
import org.cryptomator.integrations.autostart.AutoStartProvider;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.ServiceLoader;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
@Module(includes = {JniModule.class, KeychainModule.class}, subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
@Module(subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
public abstract class UiLauncherModule {
@Provides
@Singleton
static Optional<UiAppearanceProvider> provideAppearanceProvider() {
return ServiceLoader.load(UiAppearanceProvider.class).findFirst();
}
@Provides
@Singleton
static Optional<AutoStartProvider> provideAutostartProvider() {
return ServiceLoader.load(AutoStartProvider.class).findFirst();
}
@Provides
@Singleton
static Optional<TrayIntegrationProvider> provideTrayIntegrationProvider() {
return ServiceLoader.load(TrayIntegrationProvider.class).findFirst();
}
@Provides
@Singleton
static ResourceBundle provideLocalization() {
@@ -1,8 +1,8 @@
package org.cryptomator.ui.mainwindow;
import com.tobiasdiez.easybind.EasyBind;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
@@ -22,19 +22,19 @@ public class VaultDetailLockedController implements FxController {
private final ReadOnlyObjectProperty<Vault> vault;
private final FxApplication application;
private final VaultOptionsComponent.Builder vaultOptionsWindow;
private final Optional<KeychainManager> keychainManagerOptional;
private final KeychainManager keychain;
private final Stage mainWindow;
private final BooleanExpression passwordSaved;
@Inject
VaultDetailLockedController(ObjectProperty<Vault> vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, Optional<KeychainManager> keychainManagerOptional, @MainWindow Stage mainWindow) {
VaultDetailLockedController(ObjectProperty<Vault> vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, KeychainManager keychain, @MainWindow Stage mainWindow) {
this.vault = vault;
this.application = application;
this.vaultOptionsWindow = vaultOptionsWindow;
this.keychainManagerOptional = keychainManagerOptional;
this.keychain = keychain;
this.mainWindow = mainWindow;
if (keychainManagerOptional.isPresent()) {
this.passwordSaved = BooleanExpression.booleanExpression(EasyBind.select(vault).selectObject(v -> keychainManagerOptional.get().getPassphraseStoredProperty(v.getId())));
if (keychain.isSupported()) {
this.passwordSaved = BooleanExpression.booleanExpression(EasyBind.select(vault).selectObject(v -> keychain.getPassphraseStoredProperty(v.getId())));
} else {
this.passwordSaved = new SimpleBooleanProperty(false);
}
@@ -65,8 +65,8 @@ public class VaultDetailLockedController implements FxController {
}
public boolean isPasswordSaved() {
if (keychainManagerOptional.isPresent() && vault.get() != null) {
return keychainManagerOptional.get().getPassphraseStoredProperty(vault.get().getId()).get();
if (keychain.isSupported() && vault.get() != null) {
return keychain.getPassphraseStoredProperty(vault.get().getId()).get();
} else return false;
}
}
@@ -1,6 +1,7 @@
package org.cryptomator.ui.migration;
import dagger.Lazy;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.cryptofs.FileNameTooLongException;
@@ -9,8 +10,7 @@ import org.cryptomator.cryptofs.migration.Migrators;
import org.cryptomator.cryptofs.migration.api.MigrationContinuationListener;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
@@ -37,7 +37,6 @@ import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -55,7 +54,7 @@ public class MigrationRunController implements FxController {
private final Vault vault;
private final ExecutorService executor;
private final ScheduledExecutorService scheduler;
private final Optional<KeychainManager> keychain;
private final KeychainManager keychain;
private final ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability;
private final ErrorComponent.Builder errorComponent;
private final Lazy<Scene> startScene;
@@ -69,8 +68,7 @@ public class MigrationRunController implements FxController {
public NiceSecurePasswordField passwordField;
@Inject
public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional<KeychainManager> keychain, @Named("capabilityErrorCause") ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy<Scene> capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy<Scene> impossibleScene, ErrorComponent.Builder errorComponent) {
public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, KeychainManager keychain, @Named("capabilityErrorCause") ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy<Scene> capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy<Scene> impossibleScene, ErrorComponent.Builder errorComponent) {
this.window = window;
this.vault = vault;
this.executor = executor;
@@ -88,7 +86,7 @@ public class MigrationRunController implements FxController {
}
public void initialize() {
if (keychain.isPresent()) {
if (keychain.isSupported()) {
loadStoredPassword();
}
migrationButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.NEEDS_MIGRATION).or(passwordField.textProperty().isEmpty()));
@@ -167,10 +165,10 @@ public class MigrationRunController implements FxController {
}
private void loadStoredPassword() {
assert keychain.isPresent();
assert keychain.isSupported();
char[] storedPw = null;
try {
storedPw = keychain.get().loadPassphrase(vault.getId());
storedPw = keychain.loadPassphrase(vault.getId());
if (storedPw != null) {
passwordField.setPassword(storedPw);
passwordField.selectRange(storedPw.length, storedPw.length);
@@ -1,42 +1,45 @@
package org.cryptomator.ui.preferences;
import org.cryptomator.jni.MacFunctions;
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 MacFunctions macFunctions;
private final AutoStartProvider autoStartProvider;
public AutoStartMacStrategy(MacFunctions macFunctions) {
this.macFunctions = macFunctions;
public AutoStartMacStrategy(AutoStartProvider autoStartProvider) {
this.autoStartProvider = autoStartProvider;
}
@Override
public CompletionStage<Boolean> isAutoStartEnabled() {
boolean enabled = macFunctions.launchServices().isLoginItemEnabled();
return CompletableFuture.completedFuture(enabled);
return CompletableFuture.completedFuture(autoStartProvider.isEnabled());
}
@Override
public void enableAutoStart() throws TogglingAutoStartFailedException {
if (macFunctions.launchServices().enableLoginItem()) {
try {
autoStartProvider.enable();
LOG.debug("Added login item.");
} else {
} catch (ToggleAutoStartFailedException e) {
throw new TogglingAutoStartFailedException("Failed to add login item.");
}
}
@Override
public void disableAutoStart() throws TogglingAutoStartFailedException {
if (macFunctions.launchServices().disableLoginItem()) {
try {
autoStartProvider.disable();
LOG.debug("Removed login item.");
} else {
} catch (ToggleAutoStartFailedException e) {
throw new TogglingAutoStartFailedException("Failed to remove login item.");
}
}
@@ -3,19 +3,19 @@ package org.cryptomator.ui.preferences;
import dagger.Module;
import dagger.Provides;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.integrations.autostart.AutoStartProvider;
import java.util.Optional;
@Deprecated
@Module
abstract class AutoStartModule {
@Provides
@PreferencesScoped
public static Optional<AutoStartStrategy> provideAutoStartStrategy(Optional<MacFunctions> macFunctions, Environment env) {
if (SystemUtils.IS_OS_MAC_OSX && macFunctions.isPresent()) {
return Optional.of(new AutoStartMacStrategy(macFunctions.get()));
public static Optional<AutoStartStrategy> provideAutoStartStrategy(Optional<AutoStartProvider> autoStartProvider) {
if (SystemUtils.IS_OS_MAC_OSX && autoStartProvider.isPresent()) {
return Optional.of(new AutoStartMacStrategy(autoStartProvider.get()));
} else if (SystemUtils.IS_OS_WINDOWS) {
Optional<String> exeName = ProcessHandle.current().info().command();
return exeName.map(AutoStartWinStrategy::new);
@@ -2,6 +2,7 @@ package org.cryptomator.ui.preferences;
import java.util.concurrent.CompletionStage;
@Deprecated
public interface AutoStartStrategy {
CompletionStage<Boolean> isAutoStartEnabled();
@@ -25,7 +25,9 @@ import java.util.concurrent.TimeUnit;
* 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);
@@ -1,13 +1,11 @@
package org.cryptomator.ui.preferences;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
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.keychain.KeychainAccessStrategy;
import org.cryptomator.keychain.LinuxSystemKeychainAccess;
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,12 +25,12 @@ import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.util.StringConverter;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@PreferencesScoped
public class GeneralPreferencesController implements FxController {
@@ -48,7 +46,7 @@ public class GeneralPreferencesController implements FxController {
private final ResourceBundle resourceBundle;
private final Application application;
private final Environment environment;
private Optional<KeychainAccessStrategy> keychain;
private final Set<KeychainAccessProvider> keychainAccessProviders;
public ChoiceBox<UiTheme> themeChoiceBox;
public ChoiceBox<KeychainBackend> keychainBackendChoiceBox;
public CheckBox startHiddenCheckbox;
@@ -59,11 +57,11 @@ public class GeneralPreferencesController implements FxController {
public RadioButton nodeOrientationRtl;
@Inject
GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartStrategy> autoStartStrategy, Optional<KeychainAccessStrategy> keychain, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment) {
GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartStrategy> autoStartStrategy, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment) {
this.settings = settings;
this.trayMenuSupported = trayMenuSupported;
this.autoStartStrategy = autoStartStrategy;
this.keychain = keychain;
this.keychainAccessProviders = keychainAccessProviders;
this.selectedTabProperty = selectedTabProperty;
this.licenseHolder = licenseHolder;
this.executor = executor;
@@ -96,16 +94,15 @@ public class GeneralPreferencesController implements FxController {
nodeOrientation.selectedToggleProperty().addListener(this::toggleNodeOrientation);
keychainBackendChoiceBox.getItems().addAll(getAvailableBackends());
if (keychain.isPresent() && SystemUtils.IS_OS_LINUX) {
keychainBackendChoiceBox.setValue(LinuxSystemKeychainAccess.getBackendActivated());
}
if (keychain.isPresent() && (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS)) {
keychainBackendChoiceBox.setValue(Arrays.stream(KeychainBackend.supportedBackends()).findFirst().orElseThrow(IllegalStateException::new));
}
keychainBackendChoiceBox.setConverter(new KeychainBackendConverter(resourceBundle));
keychainBackendChoiceBox.valueProperty().bindBidirectional(settings.keychainBackend());
}
private KeychainBackend[] getAvailableBackends() {
var namesOfAvailableProviders = keychainAccessProviders.stream().map(KeychainAccessProvider::getClass).map(Class::getName).collect(Collectors.toUnmodifiableSet());
return Arrays.stream(KeychainBackend.values()).filter(value -> namesOfAvailableProviders.contains(value.getProviderClass())).toArray(KeychainBackend[]::new);
}
public boolean isTrayMenuSupported() {
return this.trayMenuSupported;
}
@@ -183,7 +180,7 @@ public class GeneralPreferencesController implements FxController {
@Override
public String toString(KeychainBackend impl) {
return resourceBundle.getString(impl.getDisplayName());
return resourceBundle.getString("preferences.general.keychainBackend." + impl.getProviderClass());
}
@Override
@@ -215,17 +212,4 @@ public class GeneralPreferencesController implements FxController {
}
}
private KeychainBackend[] getAvailableBackends() {
if (!keychain.isPresent()) {
return new KeychainBackend[]{};
}
if (SystemUtils.IS_OS_LINUX) {
EnumSet<KeychainBackend> backends = LinuxSystemKeychainAccess.getAvailableKeychainBackends();
return backends.toArray(KeychainBackend[]::new);
}
if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS) {
return KeychainBackend.supportedBackends();
}
return new KeychainBackend[]{};
}
}
@@ -1,7 +1,9 @@
package org.cryptomator.ui.traymenu;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.integrations.uiappearance.Theme;
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,20 +19,26 @@ public class TrayIconController {
private static final Logger LOG = LoggerFactory.getLogger(TrayIconController.class);
private final TrayImageFactory imageFactory;
private final Optional<UiAppearanceProvider> appearanceProvider;
private final TrayMenuController trayMenuController;
private final TrayIcon trayIcon;
private final Optional<MacFunctions> macFunctions;
@Inject
TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<MacFunctions> macFunctions) {
TrayIconController(TrayImageFactory imageFactory, TrayMenuController trayMenuController, Optional<UiAppearanceProvider> appearanceProvider) {
this.trayMenuController = trayMenuController;
this.imageFactory = imageFactory;
this.appearanceProvider = appearanceProvider;
this.trayIcon = new TrayIcon(imageFactory.loadImage(), "Cryptomator", trayMenuController.getMenu());
this.macFunctions = macFunctions;
}
public void initializeTrayIcon() {
macFunctions.map(MacFunctions::uiAppearance).ifPresent(uiAppearance -> uiAppearance.addListener(this::macInterfaceThemeChanged));
appearanceProvider.ifPresent(appearanceProvider -> {
try {
appearanceProvider.addListener(this::systemInterfaceThemeChanged);
} catch (UiAppearanceException e) {
LOG.error("Failed to enable automatic tray icon theme switching.");
}
});
trayIcon.setImageAutoSize(true);
if (SystemUtils.IS_OS_WINDOWS) {
@@ -47,8 +55,8 @@ public class TrayIconController {
trayMenuController.initTrayMenu();
}
private void macInterfaceThemeChanged() {
trayIcon.setImage(imageFactory.loadImage());
private void systemInterfaceThemeChanged(Theme theme) {
trayIcon.setImage(imageFactory.loadImage()); // TODO refactor "theme" is re-queried in loadImage()
}
}
@@ -1,9 +1,8 @@
package org.cryptomator.ui.traymenu;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.jni.MacApplicationUiAppearance;
import org.cryptomator.jni.MacApplicationUiInterfaceStyle;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.integrations.uiappearance.Theme;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import javax.inject.Inject;
import java.awt.Image;
@@ -13,11 +12,11 @@ import java.util.Optional;
@TrayMenuScoped
class TrayImageFactory {
private final Optional<MacFunctions> macFunctions;
private final Optional<UiAppearanceProvider> appearanceProvider;
@Inject
TrayImageFactory(Optional<MacFunctions> macFunctions) {
this.macFunctions = macFunctions;
TrayImageFactory(Optional<UiAppearanceProvider> appearanceProvider) {
this.appearanceProvider = appearanceProvider;
}
public Image loadImage() {
@@ -26,10 +25,8 @@ class TrayImageFactory {
}
private String getMacResourceName() {
MacApplicationUiInterfaceStyle interfaceStyle = macFunctions.map(MacFunctions::uiAppearance) //
.map(MacApplicationUiAppearance::getCurrentInterfaceStyle) //
.orElse(MacApplicationUiInterfaceStyle.LIGHT);
return switch (interfaceStyle) {
var theme = appearanceProvider.map(UiAppearanceProvider::getSystemTheme).orElse(Theme.LIGHT);
return switch (theme) {
case DARK -> "/img/tray_icon_mac_white.png";
case LIGHT -> "/img/tray_icon_mac_black.png";
};
@@ -1,7 +1,7 @@
package org.cryptomator.ui.unlock;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.UserInteractionLock;
import org.cryptomator.ui.common.WeakBindings;
@@ -49,7 +49,7 @@ public class UnlockController implements FxController {
private final Optional<char[]> savedPassword;
private final UserInteractionLock<UnlockModule.PasswordEntry> passwordEntryLock;
private final ForgetPasswordComponent.Builder forgetPassword;
private final Optional<KeychainManager> keychain;
private final KeychainManager keychain;
private final ObjectBinding<ContentDisplay> unlockButtonContentDisplay;
private final BooleanBinding userInteractionDisabled;
private final BooleanProperty unlockButtonDisabled;
@@ -65,7 +65,7 @@ public class UnlockController implements FxController {
public Animation unlockAnimation;
@Inject
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<UnlockModule.PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional<KeychainManager> keychain) {
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<UnlockModule.PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, KeychainManager keychain) {
this.window = window;
this.vault = vault;
this.password = password;
@@ -214,6 +214,6 @@ public class UnlockController implements FxController {
}
public boolean isKeychainAccessAvailable() {
return keychain.isPresent();
return keychain.isSupported();
}
}
@@ -4,9 +4,9 @@ import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FXMLLoaderFactory;
import org.cryptomator.ui.common.FxController;
@@ -49,15 +49,17 @@ abstract class UnlockModule {
@Provides
@Named("savedPassword")
@UnlockScoped
static Optional<char[]> provideStoredPassword(Optional<KeychainManager> keychain, @UnlockWindow Vault vault) {
return keychain.map(k -> {
static Optional<char[]> provideStoredPassword(KeychainManager keychain, @UnlockWindow Vault vault) {
if (!keychain.isSupported()) {
return Optional.empty();
} else {
try {
return k.loadPassphrase(vault.getId());
return Optional.ofNullable(keychain.loadPassphrase(vault.getId()));
} catch (KeychainAccessException e) {
LOG.error("Failed to load entry from system keychain.", e);
return null;
return Optional.empty();
}
});
}
}
@Provides
@@ -1,14 +1,14 @@
package org.cryptomator.ui.unlock;
import dagger.Lazy;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.mountpoint.InvalidMountPointException;
import org.cryptomator.common.vaults.MountPointRequirement;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.common.vaults.Volume.VolumeException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxmlFile;
@@ -53,14 +53,14 @@ public class UnlockWorkflow extends Task<Boolean> {
private final AtomicBoolean savePassword;
private final Optional<char[]> savedPassword;
private final UserInteractionLock<PasswordEntry> passwordEntryLock;
private final Optional<KeychainManager> keychain;
private final KeychainManager keychain;
private final Lazy<Scene> unlockScene;
private final Lazy<Scene> successScene;
private final Lazy<Scene> invalidMountPointScene;
private final ErrorComponent.Builder errorComponent;
@Inject
UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, Optional<KeychainManager> keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent) {
UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, KeychainManager keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent) {
this.window = window;
this.vault = vault;
this.vaultService = vaultService;
@@ -150,9 +150,9 @@ public class UnlockWorkflow extends Task<Boolean> {
}
private void savePasswordToSystemkeychain() {
if (keychain.isPresent()) {
if (keychain.isSupported()) {
try {
keychain.get().storePassphrase(vault.getId(), CharBuffer.wrap(password.get()));
keychain.storePassphrase(vault.getId(), CharBuffer.wrap(password.get()));
} catch (KeychainAccessException e) {
LOG.error("Failed to store passphrase in system keychain.", e);
}
@@ -1,11 +1,13 @@
package org.cryptomator.ui.vaultoptions;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Bindings;
@@ -13,29 +15,32 @@ import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import java.util.Optional;
@VaultOptionsScoped
public class MasterkeyOptionsController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(MasterkeyOptionsController.class);
private final Vault vault;
private final Stage window;
private final ChangePasswordComponent.Builder changePasswordWindow;
private final RecoveryKeyComponent.Builder recoveryKeyWindow;
private final Optional<KeychainManager> keychainManagerOptional;
private final KeychainManager keychain;
private final BooleanExpression passwordSaved;
@Inject
MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, Optional<KeychainManager> keychainManagerOptional) {
MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, KeychainManager keychain) {
this.vault = vault;
this.window = window;
this.changePasswordWindow = changePasswordWindow;
this.recoveryKeyWindow = recoveryKeyWindow;
this.keychainManagerOptional = keychainManagerOptional;
if (keychainManagerOptional.isPresent()) {
this.passwordSaved = Bindings.createBooleanBinding(this::isPasswordSaved, keychainManagerOptional.get().getPassphraseStoredProperty(vault.getId()));
} else this.passwordSaved = new SimpleBooleanProperty(false);
this.keychain = keychain;
if (keychain.isSupported()) {
this.passwordSaved = Bindings.createBooleanBinding(this::isPasswordSaved, keychain.getPassphraseStoredProperty(vault.getId()));
} else {
this.passwordSaved = new SimpleBooleanProperty(false);
}
}
@FXML
@@ -54,8 +59,13 @@ public class MasterkeyOptionsController implements FxController {
}
@FXML
public void removePasswordFromKeychain() throws KeychainAccessException {
keychainManagerOptional.get().deletePassphrase(vault.getId());
public void removePasswordFromKeychain() {
assert keychain.isSupported();
try {
keychain.deletePassphrase(vault.getId());
} catch (KeychainAccessException e) {
LOG.error("Failed to delete passphrase from system keychain.", e);
}
window.close();
}
@@ -64,8 +74,8 @@ public class MasterkeyOptionsController implements FxController {
}
public boolean isPasswordSaved() {
if (keychainManagerOptional.isPresent() && vault != null) {
return keychainManagerOptional.get().getPassphraseStoredProperty(vault.getId()).get();
if (keychain.isSupported() && vault != null) {
return keychain.getPassphraseStoredProperty(vault.getId()).get();
} else return false;
}
}
@@ -3,6 +3,7 @@
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<HBox xmlns:fx="http://javafx.com/fxml"
@@ -21,7 +22,11 @@
</VBox>
<VBox spacing="4" HBox.hgrow="ALWAYS">
<Label styleClass="header-label" text="${controller.vault.displayName}"/>
<Label styleClass="detail-label" text="${controller.vault.displayablePath}" textOverrun="CENTER_ELLIPSIS"/>
<Label styleClass="detail-label" text="${controller.vault.displayablePath}" textOverrun="CENTER_ELLIPSIS">
<tooltip>
<Tooltip text="${controller.vault.displayablePath}"/>
</tooltip>
</Label>
</VBox>
</children>
</HBox>
@@ -146,10 +146,10 @@ preferences.general.debugLogging=Enable debug logging
preferences.general.debugDirectory=Reveal log files
preferences.general.autoStart=Launch Cryptomator on system start
preferences.general.keychainBackend=Store passwords with
preferences.general.keychainBackend.gnome=Gnome Keyring
preferences.general.keychainBackend.kde=KDE KWallet
preferences.general.keychainBackend.macSystemKeychain=macOS Keychain Access
preferences.general.keychainBackend.winSystemKeychain=Windows Data Protection Keychain
preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Gnome Keyring
preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=KDE Wallet
preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=macOS Keychain Access
preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection
preferences.general.interfaceOrientation=Interface Orientation
preferences.general.interfaceOrientation.ltr=Left to Right
preferences.general.interfaceOrientation.rtl=Right to Left
@@ -11,82 +11,75 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
Cryptomator uses 53 third-party dependencies under the following licenses:
Apache License v2.0:
- HKDF-RFC5869 (at.favre.lib:hkdf:1.1.0 - https://github.com/patrickfav/hkdf)
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
- jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
- jnr-constants (com.github.jnr:jnr-constants:0.9.15 - http://github.com/jnr/jnr-constants)
- jnr-enxio (com.github.jnr:jnr-enxio:0.28 - http://github.com/jnr/jnr-enxio)
- jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
- jnr-unixsocket (com.github.jnr:jnr-unixsocket:0.33 - http://github.com/jnr/jnr-unixsocket)
- FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
- Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
- Dagger (com.google.dagger:dagger:2.22 - https://github.com/google/dagger)
- error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
- Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
- Guava: Google Core Libraries for Java (com.google.guava:guava:29.0-jre - https://github.com/google/guava/guava)
- Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
- J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
- Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
- Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
- Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/)
- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.3 - http://jackrabbit.apache.org/jackrabbit-webdav/)
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
BSD:
- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
- asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
- asm-commons (org.ow2.asm:asm-commons:7.1 - http://asm.ow2.org/)
- asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
- asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
Eclipse Public License - Version 1.0:
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
Eclipse Public License - v 2.0:
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
GPLv2:
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
GPLv2+CE:
- Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
- javafx-base (org.openjfx:javafx-base:14 - https://openjdk.java.net/projects/openjfx/javafx-base/)
- javafx-controls (org.openjfx:javafx-controls:14 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
- javafx-fxml (org.openjfx:javafx-fxml:14 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
- javafx-graphics (org.openjfx:javafx-graphics:14 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
LGPL 2.1:
- dbus-java (com.github.hypfvieh:dbus-java:3.2.3 - https://github.com/hypfvieh/dbus-java/dbus-java)
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
MIT License:
- java jwt (com.auth0:java-jwt:3.10.3 - https://github.com/auth0/java-jwt)
- java-utils (com.github.hypfvieh:java-utils:1.0.6 - https://github.com/hypfvieh/java-utils)
- jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
- jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
- secret-service (de.swiesend:secret-service:1.1.0 - https://github.com/swiesend/secret-service)
- Checker Qual (org.checkerframework:checker-qual:2.11.1 - https://checkerframework.org)
- kdewallet (org.purejava:kdewallet:1.1.1 - https://github.com/purejava/kdewallet)
- SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org)
The BSD 2-Clause License:
- EasyBind (com.tobiasdiez:easybind:2.1.0 - https://github.com/tobiasdiez/EasyBind)
Cryptomator uses 46 third-party dependencies under the following licenses:
Apache License v2.0:
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
- jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
- jnr-constants (com.github.jnr:jnr-constants:0.9.15 - http://github.com/jnr/jnr-constants)
- jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
- FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
- Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
- Dagger (com.google.dagger:dagger:2.22 - https://github.com/google/dagger)
- error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
- Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
- Guava: Google Core Libraries for Java (com.google.guava:guava:30.0-jre - https://github.com/google/guava/guava)
- Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
- J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
- Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
- Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
- Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/)
- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.3 - http://jackrabbit.apache.org/jackrabbit-webdav/)
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
BSD:
- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
- asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
- asm-commons (org.ow2.asm:asm-commons:7.1 - http://asm.ow2.org/)
- asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
- asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
Eclipse Public License - Version 1.0:
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
Eclipse Public License - v 2.0:
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
GPLv2:
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
GPLv2+CE:
- Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
- javafx-base (org.openjfx:javafx-base:14 - https://openjdk.java.net/projects/openjfx/javafx-base/)
- javafx-controls (org.openjfx:javafx-controls:14 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
- javafx-fxml (org.openjfx:javafx-fxml:14 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
- javafx-graphics (org.openjfx:javafx-graphics:14 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
LGPL 2.1:
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
MIT License:
- java jwt (com.auth0:java-jwt:3.10.3 - https://github.com/auth0/java-jwt)
- jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
- jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
- Checker Qual (org.checkerframework:checker-qual:3.5.0 - https://checkerframework.org)
- SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org)
The BSD 2-Clause License:
- EasyBind (com.tobiasdiez:easybind:2.1.0 - https://github.com/tobiasdiez/EasyBind)
Cryptomator uses other third-party assets under the following licenses:
SIL OFL 1.1 License:
- Font Awesome 5.12.0 (https://fontawesome.com/)
SIL OFL 1.1 License:
- Font Awesome 5.12.0 (https://fontawesome.com/)