mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-20 01:26:52 -04:00
Merge branch 'develop' into feature/#1228-forcedUnmountDialog
# Conflicts: # main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
This commit is contained in:
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Cryptomator Community
|
||||
url: https://community.cryptomator.org/
|
||||
about: Please ask and answer questions here
|
||||
- name: Documentation
|
||||
url: https://docs.cryptomator.org/
|
||||
about: Get instructions on how to use Cryptomator
|
||||
@@ -1,79 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public final class LazyInitializer {
|
||||
|
||||
private LazyInitializer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #initializeLazily(AtomicReference, SupplierThrowingException, Class)} except that no checked exception may be thrown by the factory function.
|
||||
*
|
||||
* @param <T> Type of the value
|
||||
* @param reference A reference to a maybe not yet initialized value.
|
||||
* @param factory A factory providing a value for the reference, if it doesn't exist yet. The factory may be invoked multiple times, but only one result will survive.
|
||||
* @return The initialized value
|
||||
*/
|
||||
public static <T> T initializeLazily(AtomicReference<T> reference, Supplier<T> factory) {
|
||||
SupplierThrowingException<T, RuntimeException> factoryThrowingRuntimeExceptions = () -> factory.get();
|
||||
return initializeLazily(reference, factoryThrowingRuntimeExceptions, RuntimeException.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Threadsafe lazy initialization pattern as proposed on http://stackoverflow.com/a/30247202/4014509
|
||||
*
|
||||
* @param <T> Type of the value
|
||||
* @param <E> Type of the any expected exception that may occur during initialization
|
||||
* @param reference A reference to a maybe not yet initialized value.
|
||||
* @param factory A factory providing a value for the reference, if it doesn't exist yet. The factory may be invoked multiple times, but only one result will survive.
|
||||
* @param exceptionType Expected exception type.
|
||||
* @return The initialized value
|
||||
* @throws E Exception thrown by the factory function.
|
||||
*/
|
||||
public static <T, E extends Exception> T initializeLazily(AtomicReference<T> reference, SupplierThrowingException<T, E> factory, Class<E> exceptionType) throws E {
|
||||
final T existing = reference.get();
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
} else {
|
||||
try {
|
||||
return reference.updateAndGet(invokeFactoryIfNull(factory));
|
||||
} catch (InitializationException e) {
|
||||
Throwables.throwIfUnchecked(e.getCause());
|
||||
Throwables.throwIfInstanceOf(e.getCause(), exceptionType);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <T, E extends Exception> UnaryOperator<T> invokeFactoryIfNull(SupplierThrowingException<T, E> factory) throws InitializationException {
|
||||
return currentValue -> {
|
||||
if (currentValue == null) {
|
||||
try {
|
||||
return factory.get();
|
||||
} catch (Exception e) {
|
||||
throw new InitializationException(e);
|
||||
}
|
||||
} else {
|
||||
return currentValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class InitializationException extends RuntimeException {
|
||||
|
||||
public InitializationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,13 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.LazyInitializer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
private static final long SAVE_DELAY_MS = 1000;
|
||||
|
||||
private final AtomicReference<ScheduledFuture<?>> scheduledSaveCmd = new AtomicReference<>();
|
||||
private final AtomicReference<Settings> settings = new AtomicReference<>();
|
||||
private final Supplier<Settings> settings = Suppliers.memoize(this::load);
|
||||
private final SettingsJsonAdapter settingsJsonAdapter = new SettingsJsonAdapter();
|
||||
private final Environment env;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
@@ -66,7 +66,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
|
||||
@Override
|
||||
public Settings get() {
|
||||
return LazyInitializer.initializeLazily(settings, this::load);
|
||||
return settings.get();
|
||||
}
|
||||
|
||||
private Settings load() {
|
||||
|
||||
@@ -10,7 +10,6 @@ package org.cryptomator.common.vaults;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.LazyInitializer;
|
||||
import org.cryptomator.common.mountpoint.InvalidMountPointException;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.common.vaults.Volume.VolumeException;
|
||||
@@ -100,11 +99,7 @@ public class Vault {
|
||||
// Commands
|
||||
// ********************************************************************************/
|
||||
|
||||
private CryptoFileSystem getCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException {
|
||||
return LazyInitializer.initializeLazily(cryptoFileSystem, () -> unlockCryptoFileSystem(passphrase), IOException.class);
|
||||
}
|
||||
|
||||
private CryptoFileSystem unlockCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException {
|
||||
private CryptoFileSystem createCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException {
|
||||
Set<FileSystemFlags> flags = EnumSet.noneOf(FileSystemFlags.class);
|
||||
if (vaultSettings.usesReadOnlyMode().get()) {
|
||||
flags.add(FileSystemFlags.READONLY);
|
||||
@@ -127,9 +122,14 @@ public class Vault {
|
||||
}
|
||||
|
||||
public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException, VolumeException, InvalidMountPointException {
|
||||
CryptoFileSystem fs = getCryptoFileSystem(passphrase);
|
||||
volume = volumeProvider.get();
|
||||
volume.mount(fs, getEffectiveMountFlags());
|
||||
if (cryptoFileSystem.get() == null) {
|
||||
CryptoFileSystem fs = createCryptoFileSystem(passphrase);
|
||||
cryptoFileSystem.set(fs);
|
||||
volume = volumeProvider.get();
|
||||
volume.mount(fs, getEffectiveMountFlags());
|
||||
} else {
|
||||
throw new IllegalStateException("Already unlocked.");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void lock(boolean forced) throws VolumeException {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class VaultModuleTest {
|
||||
|
||||
StringBinding result = module.provideDefaultMountFlags(settings, vaultSettings);
|
||||
|
||||
MatcherAssert.assertThat(result.get(), CoreMatchers.containsString("-ovolname=TEST"));
|
||||
MatcherAssert.assertThat(result.get(), CoreMatchers.containsString("-ovolname=\"TEST\""));
|
||||
MatcherAssert.assertThat(result.get(), CoreMatchers.containsString("-ordonly"));
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,13 @@
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
<!-- fixes CVE-2020-25649, can be removed once https://github.com/auth0/java-jwt/pull/463 is closed and released -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.10.5.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
|
||||
@@ -27,8 +27,9 @@ import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.ObservableSet;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -47,11 +48,12 @@ public class FxApplication extends Application {
|
||||
private final Optional<UiAppearanceProvider> appearanceProvider;
|
||||
private final VaultService vaultService;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final BooleanBinding hasVisibleStages;
|
||||
private final ObservableList<Window> visibleWindows;
|
||||
private final BooleanBinding hasVisibleWindows;
|
||||
private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged;
|
||||
|
||||
@Inject
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<LockComponent.Builder> lockWindowBuilderProvider, Lazy<QuitComponent> quitWindow, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<LockComponent.Builder> lockWindowBuilderProvider, Lazy<QuitComponent> quitWindow, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder) {
|
||||
this.settings = settings;
|
||||
this.mainWindow = mainWindow;
|
||||
this.preferencesWindow = preferencesWindow;
|
||||
@@ -62,14 +64,15 @@ public class FxApplication extends Application {
|
||||
this.appearanceProvider = appearanceProvider;
|
||||
this.vaultService = vaultService;
|
||||
this.licenseHolder = licenseHolder;
|
||||
this.hasVisibleStages = Bindings.isNotEmpty(visibleStages);
|
||||
this.visibleWindows = Stage.getWindows().filtered(Window::isShowing);
|
||||
this.hasVisibleWindows = Bindings.isNotEmpty(visibleWindows);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
LOG.trace("FxApplication.start()");
|
||||
Platform.setImplicitExit(false);
|
||||
|
||||
hasVisibleStages.addListener(this::hasVisibleStagesChanged);
|
||||
hasVisibleWindows.addListener(this::hasVisibleStagesChanged);
|
||||
|
||||
settings.theme().addListener(this::appThemeChanged);
|
||||
loadSelectedStyleSheet(settings.theme().get());
|
||||
@@ -81,6 +84,7 @@ public class FxApplication extends Application {
|
||||
}
|
||||
|
||||
private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
|
||||
LOG.warn("has visible stages: {}", newValue);
|
||||
if (newValue) {
|
||||
trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray);
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Application;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableSet;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
@@ -32,12 +31,6 @@ import java.util.List;
|
||||
@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class})
|
||||
abstract class FxApplicationModule {
|
||||
|
||||
@Provides
|
||||
@FxApplicationScoped
|
||||
static ObservableSet<Stage> provideVisibleStages() {
|
||||
return FXCollections.observableSet();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("windowIcons")
|
||||
@FxApplicationScoped
|
||||
@@ -57,16 +50,9 @@ abstract class FxApplicationModule {
|
||||
|
||||
@Provides
|
||||
@FxApplicationScoped
|
||||
static StageFactory provideStageFactory(@Named("windowIcons") List<Image> windowIcons, ObservableSet<Stage> visibleStages) {
|
||||
static StageFactory provideStageFactory(@Named("windowIcons") List<Image> windowIcons) {
|
||||
return new StageFactory(stage -> {
|
||||
stage.getIcons().addAll(windowIcons);
|
||||
stage.showingProperty().addListener((observableValue, wasShowing, isShowing) -> {
|
||||
if (isShowing) {
|
||||
visibleStages.add(stage);
|
||||
} else {
|
||||
visibleStages.remove(stage);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user