~exprez135/cryptomator-libre

aec56c48c5b0ebb5df9d95a3e542b28fa0da71d6 — Armin Schrenk 9 months ago 1cd4da0 + 3b73544
Merge branch 'develop' into feature/#1228-forcedUnmountDialog

# Conflicts:
#	main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
A .github/ISSUE_TEMPLATE/config.yml => .github/ISSUE_TEMPLATE/config.yml +8 -0
@@ 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

D main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java => main/commons/src/main/java/org/cryptomator/common/LazyInitializer.java +0 -79
@@ 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);
		}

	}
}

M main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java => main/commons/src/main/java/org/cryptomator/common/settings/SettingsProvider.java +3 -3
@@ 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() {

M main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java => main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java +9 -9
@@ 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 {

M main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java => main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java +1 -1
@@ 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"));
	}


M main/pom.xml => main/pom.xml +7 -0
@@ 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>

M main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java => main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java +9 -5
@@ 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 {

M main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java => main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +1 -15
@@ 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;


@@ 33,12 32,6 @@ import java.util.List;
abstract class FxApplicationModule {

	@Provides
	@FxApplicationScoped
	static ObservableSet<Stage> provideVisibleStages() {
		return FXCollections.observableSet();
	}

	@Provides
	@Named("windowIcons")
	@FxApplicationScoped
	static List<Image> provideWindowIcons() {


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