Browse Source

Merge branch 'develop' into feature/#1228-forcedUnmountDialog

# Conflicts:
#	main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
Armin Schrenk 4 years ago
parent
commit
aec56c48c5

+ 8 - 0
.github/ISSUE_TEMPLATE/config.yml

@@ -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

+ 0 - 79
main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java

@@ -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);
-		}
-
-	}
-}

+ 3 - 3
main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java

@@ -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() {

+ 9 - 9
main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java

@@ -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 {

+ 1 - 1
main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java

@@ -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"));
 	}
 

+ 7 - 0
main/pom.xml

@@ -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>

+ 9 - 5
main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java

@@ -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 {

+ 1 - 15
main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java

@@ -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);
-				}
-			});
 		});
 	}