diff --git a/main/filesystem-charsets/src/main/java/org/cryptomator/filesystem/charsets/NormalizedNameFolder.java b/main/filesystem-charsets/src/main/java/org/cryptomator/filesystem/charsets/NormalizedNameFolder.java index e2762059b..d03c42d86 100644 --- a/main/filesystem-charsets/src/main/java/org/cryptomator/filesystem/charsets/NormalizedNameFolder.java +++ b/main/filesystem-charsets/src/main/java/org/cryptomator/filesystem/charsets/NormalizedNameFolder.java @@ -40,9 +40,9 @@ class NormalizedNameFolder extends DelegatingFolder extractFrontendId(String path) { Matcher matcher = SERVLET_PATH_WITH_FRONTEND_ID_PATTERN.matcher(path); if (matcher.matches()) { diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/FontendIdHidingServletContextHandler.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/FontendIdHidingServletContextHandler.java new file mode 100644 index 000000000..9b983d9ac --- /dev/null +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/FontendIdHidingServletContextHandler.java @@ -0,0 +1,17 @@ +package org.cryptomator.frontend.webdav; + +import org.eclipse.jetty.server.HandlerContainer; +import org.eclipse.jetty.servlet.ServletContextHandler; + +class FontendIdHidingServletContextHandler extends ServletContextHandler { + + public FontendIdHidingServletContextHandler(HandlerContainer parent, String contextPath, int options) { + super(parent, contextPath, options); + } + + @Override + public String toString() { + return ContextPaths.removeFrontendId(super.toString()); + } + +} diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServer.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServer.java index cf40f1ce1..81ed65087 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServer.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServer.java @@ -8,8 +8,6 @@ *******************************************************************************/ package org.cryptomator.frontend.webdav; -import static java.lang.String.format; - import java.net.URI; import java.net.URISyntaxException; import java.util.Collection; @@ -110,7 +108,7 @@ public class WebDavServer implements FrontendFactory { @Override public Frontend create(Folder root, FrontendId id, String name) throws FrontendCreationFailedException { - String contextPath = format("/%s/%s", id, name); + String contextPath = ContextPaths.from(id, name); final URI uri; try { uri = new URI("http", null, "localhost", getPort(), contextPath, null, null); @@ -118,10 +116,10 @@ public class WebDavServer implements FrontendFactory { throw new IllegalStateException(e); } final ServletContextHandler handler = addServlet(root, uri); - LOG.info("Servlet available under " + uri); + LOG.info("Servlet available under " + ContextPaths.removeFrontendId(uri.toString())); return new WebDavFrontend(webdavMounterProvider, handler, uri); } - + public void setValidFrontendIds(Collection validFrontendIds) { tarpit.setValidFrontendIds(validFrontendIds); } diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServletContextFactory.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServletContextFactory.java index 85915d192..ca6fcbebf 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServletContextFactory.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavServletContextFactory.java @@ -35,9 +35,10 @@ import org.eclipse.jetty.servlet.ServletHolder; class WebDavServletContextFactory { private static final String WILDCARD = "/*"; - + @Inject - public WebDavServletContextFactory() {} + public WebDavServletContextFactory() { + } /** * Creates a new Jetty ServletContextHandler, that can be be added to a servletCollection as follows: @@ -63,7 +64,7 @@ class WebDavServletContextFactory { } }; final String contextPath = StringUtils.removeEnd(contextRoot.getPath(), "/"); - final ServletContextHandler servletContext = new ServletContextHandler(null, contextPath, ServletContextHandler.SESSIONS); + final ServletContextHandler servletContext = new FontendIdHidingServletContextHandler(null, contextPath, ServletContextHandler.SESSIONS); final ServletHolder servletHolder = new ServletHolder(contextPath, new WebDavServlet(contextRoot, root)); servletContext.addServlet(servletHolder, WILDCARD); servletContext.addFilter(LoopbackFilter.class, WILDCARD, EnumSet.of(DispatcherType.REQUEST)); diff --git a/main/ui/src/main/java/org/cryptomator/ui/Cryptomator.java b/main/ui/src/main/java/org/cryptomator/ui/Cryptomator.java index 3150ddc4d..1f7e07531 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/Cryptomator.java +++ b/main/ui/src/main/java/org/cryptomator/ui/Cryptomator.java @@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.ui.util.ApplicationVersion; import org.cryptomator.ui.util.SingleInstanceManager; import org.cryptomator.ui.util.SingleInstanceManager.RemoteInstance; import org.eclipse.jetty.util.ConcurrentHashSet; @@ -33,63 +34,62 @@ public class Cryptomator { public static final CompletableFuture> OPEN_FILE_HANDLER = new CompletableFuture<>(); private static final Logger LOG = LoggerFactory.getLogger(Cryptomator.class); private static final Set SHUTDOWN_TASKS = new ConcurrentHashSet<>(); - private static final CleanShutdownPerformer CLEAN_SHUTDOWN_PERFORMER = new CleanShutdownPerformer(); public static void main(String[] args) { - String cryptomatorVersion = Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion()).orElse("SNAPSHOT"); - LOG.info("Starting Cryptomator {} on {} {} ({})", cryptomatorVersion, SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH); + LOG.info("Starting Cryptomator {} on {} {} ({})", ApplicationVersion.orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH); + if (SystemUtils.IS_OS_MAC_OSX) { - /* - * On OSX we're in an awkward position. We need to register a handler in the main thread of this application. However, we can't - * even pass objects to the application, so we're forced to use a static CompletableFuture for the handler, which actually opens - * the file in the application. - * - * Code taken from https://github.com/axet/desktop/blob/master/src/main/java/com/github/axet/desktop/os/mac/AppleHandlers.java - */ - try { - final Class applicationClass = Class.forName("com.apple.eawt.Application"); - final Class openFilesHandlerClass = Class.forName("com.apple.eawt.OpenFilesHandler"); - final Method getApplication = applicationClass.getMethod("getApplication"); - final Object application = getApplication.invoke(null); - final Method setOpenFileHandler = applicationClass.getMethod("setOpenFileHandler", openFilesHandlerClass); - - final ClassLoader openFilesHandlerClassLoader = openFilesHandlerClass.getClassLoader(); - final OpenFilesHandlerClassHandler openFilesHandlerHandler = new OpenFilesHandlerClassHandler(); - final Object openFilesHandlerObject = Proxy.newProxyInstance(openFilesHandlerClassLoader, new Class[] {openFilesHandlerClass}, openFilesHandlerHandler); - - setOpenFileHandler.invoke(application, openFilesHandlerObject); - } catch (ReflectiveOperationException | RuntimeException e) { - // Since we're trying to call OS-specific code, we'll just have - // to hope for the best. - LOG.error("exception adding OSX file open handler", e); - } + addOsxFileOpenHandler(); } - /* - * Perform certain things on VM termination. - */ - Runtime.getRuntime().addShutdownHook(CLEAN_SHUTDOWN_PERFORMER); + new CleanShutdownPerformer().registerShutdownHook(); - /* - * Before starting the application, we check if there is already an instance running on this computer. If so, we send our command - * line arguments to that instance and quit. - */ - final Optional remoteInstance = SingleInstanceManager.getRemoteInstance(MainApplication.APPLICATION_KEY); - - if (remoteInstance.isPresent()) { - try (RemoteInstance instance = remoteInstance.get()) { - LOG.info("An instance of Cryptomator is already running at {}.", instance.getRemotePort()); - for (int i = 0; i < args.length; i++) { - remoteInstance.get().sendMessage(args[i], 100); - } - } catch (Exception e) { - LOG.error("Error forwarding arguments to remote instance", e); - } + final Optional runningInstance = SingleInstanceManager.getRemoteInstance(MainApplication.APPLICATION_KEY); + if (runningInstance.isPresent()) { + sendArgsToRunningInstance(args, runningInstance); } else { Application.launch(MainApplication.class, args); } } + private static void addOsxFileOpenHandler() { + /* + * On OSX we're in an awkward position. We need to register a handler in the main thread of this application. However, we can't + * even pass objects to the application, so we're forced to use a static CompletableFuture for the handler, which actually opens + * the file in the application. + * + * Code taken from https://github.com/axet/desktop/blob/master/src/main/java/com/github/axet/desktop/os/mac/AppleHandlers.java + */ + try { + final Class applicationClass = Class.forName("com.apple.eawt.Application"); + final Class openFilesHandlerClass = Class.forName("com.apple.eawt.OpenFilesHandler"); + final Method getApplication = applicationClass.getMethod("getApplication"); + final Object application = getApplication.invoke(null); + final Method setOpenFileHandler = applicationClass.getMethod("setOpenFileHandler", openFilesHandlerClass); + + final ClassLoader openFilesHandlerClassLoader = openFilesHandlerClass.getClassLoader(); + final OpenFilesHandlerClassHandler openFilesHandlerHandler = new OpenFilesHandlerClassHandler(); + final Object openFilesHandlerObject = Proxy.newProxyInstance(openFilesHandlerClassLoader, new Class[] {openFilesHandlerClass}, openFilesHandlerHandler); + + setOpenFileHandler.invoke(application, openFilesHandlerObject); + } catch (ReflectiveOperationException | RuntimeException e) { + // Since we're trying to call OS-specific code, we'll just have + // to hope for the best. + LOG.error("exception adding OSX file open handler", e); + } + } + + private static void sendArgsToRunningInstance(String[] args, final Optional remoteInstance) { + try (RemoteInstance instance = remoteInstance.get()) { + LOG.info("An instance of Cryptomator is already running at {}.", instance.getRemotePort()); + for (int i = 0; i < args.length; i++) { + remoteInstance.get().sendMessage(args[i], 100); + } + } catch (Exception e) { + LOG.error("Error forwarding arguments to remote instance", e); + } + } + public static void addShutdownTask(Runnable r) { SHUTDOWN_TASKS.add(r); } @@ -111,6 +111,10 @@ public class Cryptomator { }); SHUTDOWN_TASKS.clear(); } + + public void registerShutdownHook() { + Runtime.getRuntime().addShutdownHook(this); + } } private static void handleOpenFileRequest(File file) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/CryptomatorComponent.java b/main/ui/src/main/java/org/cryptomator/ui/CryptomatorComponent.java index e82e006e9..c4360fe56 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/CryptomatorComponent.java +++ b/main/ui/src/main/java/org/cryptomator/ui/CryptomatorComponent.java @@ -37,6 +37,8 @@ interface CryptomatorComponent { ExitUtil exitUtil(); + DebugMode debugMode(); + Optional nativeMacFunctions(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/DebugMode.java b/main/ui/src/main/java/org/cryptomator/ui/DebugMode.java new file mode 100644 index 000000000..037e68a42 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/DebugMode.java @@ -0,0 +1,75 @@ +package org.cryptomator.ui; + +import static java.util.Arrays.asList; +import static org.apache.logging.log4j.LogManager.ROOT_LOGGER_NAME; + +import java.util.Collection; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.cryptomator.ui.settings.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public class DebugMode { + + private static final Logger LOG = LoggerFactory.getLogger(DebugMode.class); + + private static final Collection LOGGER_UPGRADES = asList( // + loggerUpgrade(ROOT_LOGGER_NAME, Level.INFO), // + loggerUpgrade("org.cryptomator", Level.TRACE), // + loggerUpgrade("org.eclipse.jetty.server.Server", Level.DEBUG) // + ); + + private final Settings settings; + + @Inject + public DebugMode(Settings settings) { + this.settings = settings; + } + + public void initialize() { + if (settings.getDebugMode()) { + enable(); + LOG.debug("Debug mode initialized"); + } + } + + private void enable() { + LoggerContext context = (LoggerContext) LogManager.getContext(false); + Configuration config = context.getConfiguration(); + LOGGER_UPGRADES.forEach(loggerUpgrade -> loggerUpgrade.execute(config)); + context.updateLoggers(); + } + + private static LoggerUpgrade loggerUpgrade(String loggerName, Level minLevel) { + return new LoggerUpgrade(loggerName, minLevel); + } + + private static class LoggerUpgrade { + + private final Level level; + private final String loggerName; + + public LoggerUpgrade(String loggerName, Level minLevel) { + this.loggerName = loggerName; + this.level = minLevel; + } + + public void execute(Configuration config) { + LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); + if (loggerConfig.getLevel().isMoreSpecificThan(level)) { + loggerConfig.setLevel(level); + } + } + + } + +} \ No newline at end of file diff --git a/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java b/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java index 11628a65c..e54277d10 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java @@ -43,18 +43,46 @@ public class MainApplication extends Application { @Override public void start(Stage primaryStage) throws IOException { LOG.info("JavaFX application started"); - final CryptomatorComponent comp; + + CryptomatorComponent comp = createCryptomatorComponent(primaryStage); + MainController mainCtrl = comp.mainController(); + closer = comp.deferredCloser(); + + comp.debugMode().initialize(); + + setupFXMLClassLoader(); + setupStylesheets(); + + initializeStage(primaryStage, mainCtrl); + showWindow(primaryStage); + + registerExitHandler(comp); + + openFilesRequestedDuringStartup(primaryStage, mainCtrl); + registerApplicationToProcessOpenFileRequests(primaryStage, comp, mainCtrl); + } + + @Override + public void stop() { try { - comp = DaggerCryptomatorComponent.builder() // + closer.close(); + } catch (ExecutionException e) { + LOG.error("Error closing ressources", e); + } + } + + private CryptomatorComponent createCryptomatorComponent(Stage primaryStage) { + try { + return DaggerCryptomatorComponent.builder() // .cryptomatorModule(new CryptomatorModule(this, primaryStage)) // .secureRandomModule(new SecureRandomModule(SecureRandom.getInstanceStrong())) // .build(); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("Every implementation of the Java platform is required to support at least one strong SecureRandom implementation.", e); } - final MainController mainCtrl = comp.mainController(); - closer = comp.deferredCloser(); + } + private void setupFXMLClassLoader() { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); FXMLLoader.setDefaultClassLoader(contextClassLoader); Platform.runLater(() -> { @@ -66,35 +94,55 @@ public class MainApplication extends Application { Thread.currentThread().setContextClassLoader(contextClassLoader); } }); + } - // Set stylesheets and initialize stage: + private void setupStylesheets() { Font.loadFont(getClass().getResourceAsStream("/css/ionicons.ttf"), 12.0); chooseNativeStylesheet(); + } + + private void initializeStage(Stage primaryStage, MainController mainCtrl) { mainCtrl.initStage(primaryStage); primaryStage.titleProperty().bind(mainCtrl.windowTitle()); primaryStage.setResizable(false); if (SystemUtils.IS_OS_WINDOWS) { primaryStage.getIcons().add(new Image(MainApplication.class.getResourceAsStream("/window_icon.png"))); } + } - // show window and start observing its focus: + private void showWindow(Stage primaryStage) { primaryStage.show(); ActiveWindowStyleSupport.startObservingFocus(primaryStage); - comp.exitUtil().initExitHandler(this::quit); + } - // open files, if requested during startup: + private void registerExitHandler(CryptomatorComponent comp) { + comp.exitUtil().initExitHandler(this::quit); + } + + private void openFilesRequestedDuringStartup(Stage primaryStage, final MainController mainCtrl) { for (String arg : getParameters().getUnnamed()) { handleCommandLineArg(arg, primaryStage, mainCtrl); } if (SystemUtils.IS_OS_MAC_OSX) { Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(file.getAbsolutePath(), primaryStage, mainCtrl)); } + } - // register this application instance as primary application, that other instances can send open file requests to: + private void registerApplicationToProcessOpenFileRequests(Stage primaryStage, final CryptomatorComponent comp, final MainController mainCtrl) throws IOException { LocalInstance cryptomatorGuiInstance = closer.closeLater(SingleInstanceManager.startLocalInstance(APPLICATION_KEY, comp.executorService()), LocalInstance::close).get().get(); cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(arg, primaryStage, mainCtrl)); } + private void chooseNativeStylesheet() { + if (SystemUtils.IS_OS_MAC_OSX) { + setUserAgentStylesheet(getClass().getResource("/css/mac_theme.css").toString()); + } else if (SystemUtils.IS_OS_LINUX) { + setUserAgentStylesheet(getClass().getResource("/css/linux_theme.css").toString()); + } else if (SystemUtils.IS_OS_WINDOWS) { + setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString()); + } + } + private void handleCommandLineArg(String arg, Stage primaryStage, MainController mainCtrl) { // find correct location: final Path path = FileSystems.getDefault().getPath(arg); @@ -118,16 +166,6 @@ public class MainApplication extends Application { }); } - private void chooseNativeStylesheet() { - if (SystemUtils.IS_OS_MAC_OSX) { - setUserAgentStylesheet(getClass().getResource("/css/mac_theme.css").toString()); - } else if (SystemUtils.IS_OS_LINUX) { - setUserAgentStylesheet(getClass().getResource("/css/linux_theme.css").toString()); - } else if (SystemUtils.IS_OS_WINDOWS) { - setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString()); - } - } - private void quit() { Platform.runLater(() -> { stop(); @@ -136,13 +174,4 @@ public class MainApplication extends Application { }); } - @Override - public void stop() { - try { - closer.close(); - } catch (ExecutionException e) { - LOG.error("Error closing ressources", e); - } - } - } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java index 34ef59b0d..7861a5962 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/SettingsController.java @@ -59,6 +59,9 @@ public class SettingsController extends LocalizedFXMLViewController { @FXML private ChoiceBox prefGvfsScheme; + @FXML + private CheckBox debugModeCheckbox; + @Override public void initialize() { checkForUpdatesCheckbox.setDisable(areUpdatesManagedExternally()); @@ -74,11 +77,13 @@ public class SettingsController extends LocalizedFXMLViewController { prefGvfsScheme.getItems().add("dav"); prefGvfsScheme.getItems().add("webdav"); prefGvfsScheme.setValue(settings.getPreferredGvfsScheme()); + debugModeCheckbox.setSelected(settings.getDebugMode()); EasyBind.subscribe(checkForUpdatesCheckbox.selectedProperty(), this::checkForUpdateDidChange); EasyBind.subscribe(portField.textProperty(), this::portDidChange); EasyBind.subscribe(useIpv6Checkbox.selectedProperty(), this::useIpv6DidChange); EasyBind.subscribe(prefGvfsScheme.valueProperty(), this::prefGvfsSchemeDidChange); + EasyBind.subscribe(debugModeCheckbox.selectedProperty(), this::debugModeDidChange); } @Override @@ -114,6 +119,11 @@ public class SettingsController extends LocalizedFXMLViewController { settings.save(); } + private void debugModeDidChange(Boolean newValue) { + settings.setDebugMode(newValue); + settings.save(); + } + private void prefGvfsSchemeDidChange(String newValue) { settings.setPreferredGvfsScheme(newValue); settings.save(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java index ae11098d2..610260092 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java @@ -58,15 +58,6 @@ public class UnlockedController extends LocalizedFXMLViewController { private Optional listener = Optional.empty(); private Timeline ioAnimation; - @Inject - public UnlockedController(Localization localization, Provider macWarningsControllerProvider, AsyncTaskService asyncTaskService) { - super(localization); - this.macWarningsController = macWarningsControllerProvider.get(); - this.asyncTaskService = asyncTaskService; - - macWarningsController.vault.bind(this.vault); - } - @FXML private Label messageLabel; @@ -85,6 +76,15 @@ public class UnlockedController extends LocalizedFXMLViewController { @FXML private MenuItem revealVaultMenuItem; + @Inject + public UnlockedController(Localization localization, Provider macWarningsControllerProvider, AsyncTaskService asyncTaskService) { + super(localization); + this.macWarningsController = macWarningsControllerProvider.get(); + this.asyncTaskService = asyncTaskService; + + macWarningsController.vault.bind(this.vault); + } + @Override public void initialize() { macWarningsController.initStage(macWarningsWindow); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java index 143a43ef9..e1a59956f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java @@ -13,7 +13,6 @@ import java.net.URL; import java.util.Comparator; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import javax.inject.Inject; import javax.inject.Named; @@ -29,6 +28,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.settings.Settings; +import org.cryptomator.ui.util.ApplicationVersion; import org.cryptomator.ui.util.AsyncTaskService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,7 +104,7 @@ public class WelcomeController extends LocalizedFXMLViewController { asyncTaskService.asyncTaskOf(() -> { final HttpClient client = new HttpClient(); final HttpMethod method = new GetMethod("https://cryptomator.org/downloads/latestVersion.json"); - client.getParams().setParameter(HttpClientParams.USER_AGENT, "Cryptomator VersionChecker/" + applicationVersion().orElse("SNAPSHOT")); + client.getParams().setParameter(HttpClientParams.USER_AGENT, "Cryptomator VersionChecker/" + ApplicationVersion.orElse("SNAPSHOT")); client.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); client.getParams().setConnectionManagerTimeout(5000); client.executeMethod(method); @@ -124,10 +124,6 @@ public class WelcomeController extends LocalizedFXMLViewController { }).run(); } - private Optional applicationVersion() { - return Optional.ofNullable(getClass().getPackage().getImplementationVersion()); - } - private void compareVersions(final Map latestVersions) { final String latestVersion; if (SystemUtils.IS_OS_MAC_OSX) { @@ -140,7 +136,7 @@ public class WelcomeController extends LocalizedFXMLViewController { // no version check possible on unsupported OS return; } - final String currentVersion = applicationVersion().orElse(null); + final String currentVersion = ApplicationVersion.orElse(null); LOG.debug("Current version: {}, lastest version: {}", currentVersion, latestVersion); if (currentVersion != null && semVerComparator.compare(currentVersion, latestVersion) < 0) { final String msg = String.format(localization.getString("welcome.newVersionMessage"), latestVersion, currentVersion); diff --git a/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java b/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java index f9323bf99..e4180f969 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java +++ b/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java @@ -28,6 +28,7 @@ public class Settings implements Serializable { public static final boolean DEFAULT_USE_IPV6 = false; public static final Integer DEFAULT_NUM_TRAY_NOTIFICATIONS = 3; public static final String DEFAULT_GVFS_SCHEME = "dav"; + public static final boolean DEFAULT_DEBUG_MODE = false; private final Consumer saveCmd; @@ -49,6 +50,9 @@ public class Settings implements Serializable { @JsonProperty("preferredGvfsScheme") private String preferredGvfsScheme; + @JsonProperty("debugMode") + private Boolean debugMode; + /** * Package-private constructor; use {@link SettingsProvider}. */ @@ -125,4 +129,12 @@ public class Settings implements Serializable { this.preferredGvfsScheme = preferredGvfsScheme; } + public boolean getDebugMode() { + return debugMode == null ? DEFAULT_DEBUG_MODE : debugMode; + } + + public void setDebugMode(boolean debugMode) { + this.debugMode = debugMode; + } + } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/ApplicationVersion.java b/main/ui/src/main/java/org/cryptomator/ui/util/ApplicationVersion.java new file mode 100644 index 000000000..beaaf46df --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/util/ApplicationVersion.java @@ -0,0 +1,17 @@ +package org.cryptomator.ui.util; + +import java.util.Optional; + +import org.cryptomator.ui.Cryptomator; + +public class ApplicationVersion { + + public static String orElse(String other) { + return get().orElse(other); + } + + public static Optional get() { + return Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion()); + } + +} diff --git a/main/ui/src/main/resources/fxml/settings.fxml b/main/ui/src/main/resources/fxml/settings.fxml index 41f770be2..e18995898 100644 --- a/main/ui/src/main/resources/fxml/settings.fxml +++ b/main/ui/src/main/resources/fxml/settings.fxml @@ -46,6 +46,10 @@