diff --git a/.travis.yml b/.travis.yml index 8d9c59e8e..b7789ec3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,70 +2,49 @@ language: java sudo: false jdk: - oraclejdk10 -branches: - except: - - continuous # To avoid infinite loops, as this tag is created by this Travis config cache: directories: - $HOME/.m2 env: global: - - secure: "IfYURwZaDWuBDvyn47n0k1Zod/IQw1FF+CS5nnV08Q+NfC3vGGJMwV8m59XnbfwnWGxwvCaAbk4qP6s6+ijgZNKkvgfFMo3rfTok5zt43bIqgaFOANYV+OC/1c59gYD6ZUxhW5iNgMgU3qdsRtJuwSmfkVv/jKyLGfAbS4kN8BA=" # COVERITY_SCAN_TOKEN - secure: "lV9OwUbHMrMpLUH1CY+Z4puLDdFXytudyPlG1eGRsesdpuG6KM3uQVz6uAtf6lrU8DRbMM/T7ML+PmvQ4UoPPYLdLxESLLBat2qUPOIVBOhTSlCc7I0DmGy04CSvkeMy8dPaQC0ukgNiR7zwoNzfcpGRN/U9S8tziDruuHoZSrg=" # BINTRAY_API_KEY - secure: "oWFgRTVP6lyTa7qVxlvkpm20MtVc3BtmsNXQJS6bfg2A0o/iCQMNx7OD59BaafCLGRKvCcJVESiC8FlSylVMS7CDSyYu0gg70NUiIuHp4NBM5inFWYCy/PdQsCTzr5uvNG+rMFQpMFRaCV0FrfM3tLondcVkhsHL68l93Xoexx4=" # CODACY_PROJECT_TOKEN - secure: "zJxgytA2Ks5Xzv+7kUaUq+EBFNQw9Qec63lcMJVuXVWczjL16nKW1EzzV515ag+OWL46z3lEPForDhufw0VtFnNmaX68jkO0mp01eLrHApc1llN2Y/U8GBXfNNazN4+Kom4H+z/AO+wJr8EsKMMUczCdQ3APgd9uVI0hzXw/Z3M=" # GITHUB_API_KEY - - secure: "PiH/o9MLOyPdjIwECIEfj3TuUxx7QB0CIs3o1WXjqb1PbDdHDbQyvswYit6xDw9NrJp/A+ov2k00jq+n+8fLTSd4AY21y5WiJN/ccCTWUuUiFhGxOyM37aeWAPAn4rUp7D7o8jLxEdpGZAfglIzaz+GCEQYxfV/w3FDwztViXgQ=" # GPG_PASSPHRASE addons: apt: packages: - haveged - coverity_scan: - project: - name: "cryptomator/cryptomator" - notification_email: sebastian.stenzel@cryptomator.org - build_command: "mvn -fmain/pom.xml clean test -DskipTests" - branch_pattern: release.* install: - curl -o $HOME/.m2/settings.xml https://gist.githubusercontent.com/cryptobot/cf5fbd909c4782aaeeeb7c7f4a1a43da/raw/e60ee486e34ee0c79f89f947abe2c83b4290c6bb/settings.xml - mvn -fmain/pom.xml clean install -DskipTests org.codehaus.mojo:versions-maven-plugin:help dependency:go-offline -Pcoverage,release # "clean install" needed until we can exclude artifacts currently in the reactor, see https://maven.apache.org/plugins/maven-dependency-plugin/go-offline-mojo.html#excludeReactor and https://issues.apache.org/jira/browse/MDEP-568 script: - mvn --update-snapshots -fmain/pom.xml clean test verify -Pcoverage +after_success: +- curl -o ~/codacy-coverage-reporter.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.2/codacy-coverage-reporter-4.0.2-assembly.jar +- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial +- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/keychain/target/site/jacoco/jacoco.xml --partial +- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial +- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial +- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar final before_deploy: -- | - if [[ $TRAVIS_BRANCH == "develop" ]] && [[ $TRAVIS_PULL_REQUEST == "false" ]]; then - CONTINUOUS_RELEASE_URL=`curl -s https://api.github.com/repos/cryptomator/cryptomator/releases/tags/continuous | jq -re '.url'` - echo "Existing continuous release: ${CONTINUOUS_RELEASE_URL}" - if [[ $CONTINUOUS_RELEASE_URL == http* ]]; then - curl -u cryptobot:$GITHUB_API_KEY -X DELETE $CONTINUOUS_RELEASE_URL - fi - fi - | if [[ -n "$TRAVIS_TAG" ]]; then mvn -fmain/pom.xml org.codehaus.mojo:versions-maven-plugin:set -DnewVersion=$TRAVIS_TAG elif [[ $TRAVIS_BRANCH == "develop" ]] && [[ $TRAVIS_PULL_REQUEST == "false" ]]; then mvn -fmain/pom.xml org.codehaus.mojo:versions-maven-plugin:set -DnewVersion=SNAPSHOT-$(echo $TRAVIS_COMMIT | head -c7) - git tag -f continuous - git remote add gh https://cryptobot:${GITHUB_API_KEY}@github.com/cryptomator/cryptomator.git - git push -f gh continuous - git remote remove gh fi - mvn -fmain/pom.xml clean package -Prelease -DskipTests -- gpg --import 34C80F11.gpg -- gpg --detach-sign -a -u 34C80F11 --batch --passphrase ${GPG_PASSPHRASE} main/ant-kit/target/antkit.zip deploy: -- provider: releases # CONTINUOUS - prerelease: true - api-key: $GITHUB_API_KEY - tag_name: continuous - overwrite: true - file_glob: true - file: - - "main/uber-jar/target/Cryptomator-*.jar" - - "main/ant-kit/target/antkit.zip" - - "main/ant-kit/target/antkit.zip.asc" +- provider: script # SNAPSHOTS skip_cleanup: true - name: Cryptomator continuous build - body: Automatically built on $(date +'%F %T %Z'). + script: >- + curl -T main/ant-kit/target/antkit.zip + -u cryptobot:${BINTRAY_API_KEY} + -H "X-Bintray-Package:ant-kit" + -H "X-Bintray-Version:continuous" + -H "X-Bintray-Override:1" + -H "X-Bintray-Publish:1" + https://api.bintray.com/content/cryptomator/cryptomator/antkit-continuous.zip on: repo: cryptomator/cryptomator branch: develop @@ -75,27 +54,20 @@ deploy: api_key: $GITHUB_API_KEY file: - "main/uber-jar/target/Cryptomator-$TRAVIS_TAG.jar" - - "main/ant-kit/target/antkit.zip" - - "main/ant-kit/target/antkit.zip.asc" skip_cleanup: true on: repo: cryptomator/cryptomator tags: true - provider: script - script: "curl -X POST -u cryptobot:${BINTRAY_API_KEY} -H 'Content-Type: application/json' -d '{\"name\": \"${TRAVIS_TAG}\", \"vcs_tag\": \"${TRAVIS_TAG}\"}' https://api.bintray.com/packages/cryptomator/cryptomator/cryptomator-win/versions" + skip_cleanup: true + script: >- + curl -T main/ant-kit/target/antkit.zip + -u cryptobot:${BINTRAY_API_KEY} + -H "X-Bintray-Package:ant-kit" + -H "X-Bintray-Version:${TRAVIS_TAG}" + -H "X-Bintray-Override:1" + -H "X-Bintray-Publish:1" + https://api.bintray.com/content/cryptomator/cryptomator/antkit-${TRAVIS_TAG}.zip on: repo: cryptomator/cryptomator tags: true -- provider: script - script: "curl -X POST -u cryptobot:${BINTRAY_API_KEY} -H 'Content-Type: application/json' -d '{\"name\": \"${TRAVIS_TAG}\", \"vcs_tag\": \"${TRAVIS_TAG}\"}' https://api.bintray.com/packages/cryptomator/cryptomator/cryptomator-osx/versions" - on: - repo: cryptomator/cryptomator - tags: true -after_script: -- jdk_switcher use oraclejdk8 -- curl -o ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.1/codacy-coverage-reporter-4.0.1-assembly.jar -- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial -- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/keychain/target/site/jacoco/jacoco.xml --partial -- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial -- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial -- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter-assembly-latest.jar final diff --git a/34C80F11.gpg b/34C80F11.gpg deleted file mode 100644 index e40ebc7fe..000000000 --- a/34C80F11.gpg +++ /dev/null @@ -1,57 +0,0 @@ ------BEGIN PGP PRIVATE KEY BLOCK----- -Version: GnuPG v1 - -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 -=BRSB ------END PGP PRIVATE KEY BLOCK----- \ No newline at end of file diff --git a/main/ant-kit/pom.xml b/main/ant-kit/pom.xml index 24c4898d1..2675a5cae 100644 --- a/main/ant-kit/pom.xml +++ b/main/ant-kit/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 ant-kit pom diff --git a/main/commons/pom.xml b/main/commons/pom.xml index b3223aa0c..8494a78f6 100644 --- a/main/commons/pom.xml +++ b/main/commons/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 commons Cryptomator Commons diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java b/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java index 634f528f4..e475ff0d9 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VolumeImpl.java @@ -5,7 +5,7 @@ import java.util.Arrays; public enum VolumeImpl { WEBDAV("WebDAV"), FUSE("FUSE"), - DOKANY("DOKANY"); + DOKANY("Dokany"); private String displayName; diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index 211a29688..0683abbf4 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 keychain System Keychain Access diff --git a/main/launcher/pom.xml b/main/launcher/pom.xml index a3e8ca84b..80e54ea67 100644 --- a/main/launcher/pom.xml +++ b/main/launcher/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 launcher Cryptomator Launcher diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java b/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java index f0aeb4704..c62f624c4 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/MainApplication.java @@ -5,25 +5,23 @@ *******************************************************************************/ package org.cryptomator.launcher; +import javafx.application.Application; +import javafx.stage.Stage; import org.cryptomator.ui.controllers.MainController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javafx.application.Application; -import javafx.application.Platform; -import javafx.fxml.FXMLLoader; -import javafx.stage.Stage; - public class MainApplication extends Application { private static final Logger LOG = LoggerFactory.getLogger(MainApplication.class); private Stage primaryStage; @Override - public void start(Stage primaryStage) throws Exception { + public void start(Stage primaryStage) { LOG.info("JavaFX application started."); this.primaryStage = primaryStage; - setupFXMLClassLoader(); + primaryStage.setMinWidth(652.0); + primaryStage.setMinHeight(440.0); LauncherModule launcherModule = new LauncherModule(this, primaryStage); LauncherComponent launcherComponent = DaggerLauncherComponent.builder() // @@ -34,30 +32,14 @@ public class MainApplication extends Application { MainController mainCtrl = launcherComponent.fxmlLoader().load("/fxml/main.fxml"); mainCtrl.initStage(primaryStage); - primaryStage.show(); } @Override - public void stop() throws Exception { + public void stop() { assert primaryStage != null; primaryStage.hide(); LOG.info("JavaFX application stopped."); } - // fix discussed in https://github.com/cryptomator/cryptomator/pull/29 - private void setupFXMLClassLoader() { - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - FXMLLoader.setDefaultClassLoader(contextClassLoader); - Platform.runLater(() -> { - /* - * This fixes a bug on OSX where the magic file open handler leads to no context class loader being set in the AppKit (event) - * thread if the application is not started opening a file. - */ - if (Thread.currentThread().getContextClassLoader() == null) { - Thread.currentThread().setContextClassLoader(contextClassLoader); - } - }); - } - } diff --git a/main/pom.xml b/main/pom.xml index f909bfe57..6e55ed1bb 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 pom Cryptomator @@ -24,20 +24,20 @@ UTF-8 - 1.2.0 - 1.5.2 + 1.2.1 + 1.6.0 2.0.0 - 0.1.5 - 0.1.2 - 1.0.4 + 1.0.0 + 1.0.0 + 1.0.5 2.5 3.6 1.0.3 - 25.1-jre - 2.16 + 26.0-jre + 2.17 2.8.5 1.7.25 @@ -45,7 +45,7 @@ 4.12 4.12.1 - 2.19.0 + 2.23.0 1.3 @@ -288,7 +288,7 @@ org.jacoco jacoco-maven-plugin - 0.8.1 + 0.8.2 prepare-agent @@ -315,15 +315,11 @@ maven-compiler-plugin - 3.7.0 + 3.8.0 10 10 10 - - --add-modules - jdk.incubator.httpclient - com.google.dagger diff --git a/main/uber-jar/pom.xml b/main/uber-jar/pom.xml index 6b87edde7..6c1cfba5f 100644 --- a/main/uber-jar/pom.xml +++ b/main/uber-jar/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 uber-jar Single über jar with all dependencies diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 96f74d750..bdfdcf34d 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -4,7 +4,7 @@ org.cryptomator main - 1.4.0-beta2 + 1.4.0-beta3 ui Cryptomator GUI diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java index e0e4d70e5..fc5019162 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java @@ -217,7 +217,22 @@ public class MainController implements ViewController { private void gracefulShutdown() { vaults.filtered(Vault.NOT_LOCKED).forEach(Vault::prepareForShutdown); - Platform.runLater(Platform::exit); + if (!vaults.filtered(Vault.NOT_LOCKED).isEmpty()) { + ButtonType tryAgainButtonType = new ButtonType(localization.getString("main.gracefulShutdown.button.tryAgain")); + ButtonType forceShutdownButtonType = new ButtonType(localization.getString("main.gracefulShutdown.button.forceShutdown")); + Alert gracefulShutdownDialog = DialogBuilderUtil.buildGracefulShutdownDialog( + localization.getString("main.gracefulShutdown.dialog.title"), localization.getString("main.gracefulShutdown.dialog.header"), localization.getString("main.gracefulShutdown.dialog.content"), + forceShutdownButtonType, forceShutdownButtonType, tryAgainButtonType); + + Optional choice = gracefulShutdownDialog.showAndWait(); + choice.ifPresent(btnType -> { + if (tryAgainButtonType.equals(btnType)) { + gracefulShutdown(); + } else if (forceShutdownButtonType.equals(btnType)) { + Platform.runLater(Platform::exit); + } + }); + } } private void loadFont(String resourcePath) { 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 0cc884943..8c1454404 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 @@ -8,17 +8,13 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; -import java.util.Optional; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import com.google.common.base.CharMatcher; import com.google.common.base.Strings; +import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.Group; import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; @@ -26,13 +22,18 @@ import javafx.scene.control.ChoiceBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.input.KeyEvent; -import javafx.scene.layout.GridPane; import javafx.scene.layout.VBox; import javafx.util.StringConverter; import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.common.settings.VolumeImpl; import org.cryptomator.common.settings.Settings; +import org.cryptomator.common.settings.VolumeImpl; import org.cryptomator.ui.l10n.Localization; +import org.cryptomator.ui.model.Volume; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import java.util.Optional; @Singleton public class SettingsController implements ViewController { @@ -48,16 +49,13 @@ public class SettingsController implements ViewController { this.localization = localization; this.settings = settings; this.applicationVersion = applicationVersion; + this.webdavSettings = new Group(); } @FXML private CheckBox checkForUpdatesCheckbox; - @FXML - private GridPane webdavVolume; - - @FXML - private GridPane fuseVolume; + private Group webdavSettings; @FXML private Label portFieldLabel; @@ -93,18 +91,21 @@ public class SettingsController implements ViewController { checkForUpdatesCheckbox.setSelected(settings.checkForUpdates().get() && !areUpdatesManagedExternally()); //NIOADAPTER - volume.getItems().addAll(getSupportedAdapters()); + volume.getItems().addAll(Volume.getCurrentSupportedAdapters()); volume.setValue(settings.preferredVolumeImpl().get()); volume.setConverter(new NioAdapterImplStringConverter()); + volume.valueProperty().addListener(this::setVisibilityGvfsElements); //WEBDAV - webdavVolume.visibleProperty().bind(volume.valueProperty().isEqualTo(VolumeImpl.WEBDAV)); - webdavVolume.managedProperty().bind(webdavVolume.visibleProperty()); - prefGvfsScheme.managedProperty().bind(webdavVolume.visibleProperty()); - prefGvfsSchemeLabel.managedProperty().bind(webdavVolume.visibleProperty()); - portFieldLabel.managedProperty().bind(webdavVolume.visibleProperty()); - changePortButton.managedProperty().bind(webdavVolume.visibleProperty()); - portField.managedProperty().bind(webdavVolume.visibleProperty()); + webdavSettings.visibleProperty().bind(volume.valueProperty().isEqualTo(VolumeImpl.WEBDAV)); + webdavSettings.managedProperty().bind(webdavSettings.visibleProperty()); + prefGvfsScheme.managedProperty().bind(webdavSettings.visibleProperty()); + prefGvfsSchemeLabel.managedProperty().bind(webdavSettings.visibleProperty()); + portFieldLabel.managedProperty().bind(webdavSettings.visibleProperty()); + portFieldLabel.visibleProperty().bind(webdavSettings.visibleProperty()); + changePortButton.managedProperty().bind(webdavSettings.visibleProperty()); + portField.managedProperty().bind(webdavSettings.visibleProperty()); + portField.visibleProperty().bind(webdavSettings.visibleProperty()); portField.setText(String.valueOf(settings.port().intValue())); portField.addEventFilter(KeyEvent.KEY_TYPED, this::filterNumericKeyEvents); changePortButton.visibleProperty().bind(settings.port().asString().isNotEqualTo(portField.textProperty())); @@ -115,10 +116,6 @@ public class SettingsController implements ViewController { prefGvfsSchemeLabel.setVisible(SystemUtils.IS_OS_LINUX); prefGvfsScheme.setVisible(SystemUtils.IS_OS_LINUX); - //FUSE - fuseVolume.visibleProperty().bind(volume.valueProperty().isEqualTo(VolumeImpl.FUSE)); - fuseVolume.managedProperty().bind(fuseVolume.visibleProperty()); - debugModeCheckbox.setSelected(settings.debugMode().get()); settings.checkForUpdates().bind(checkForUpdatesCheckbox.selectedProperty()); @@ -127,11 +124,6 @@ public class SettingsController implements ViewController { settings.debugMode().bind(debugModeCheckbox.selectedProperty()); } - private VolumeImpl[] getSupportedAdapters() { - // TODO: filter depending on supported drivers - return VolumeImpl.values(); - } - @Override public Parent getRoot() { return root; @@ -167,6 +159,11 @@ public class SettingsController implements ViewController { } } + private void setVisibilityGvfsElements(Observable obs, Object oldValue, Object newValue) { + prefGvfsSchemeLabel.setVisible(SystemUtils.IS_OS_LINUX && ((VolumeImpl) newValue).getDisplayName().equals("WebDAV")); + prefGvfsScheme.setVisible(SystemUtils.IS_OS_LINUX && ((VolumeImpl) newValue).getDisplayName().equals("WebDAV")); + } + private boolean areUpdatesManagedExternally() { return Boolean.parseBoolean(System.getProperty("cryptomator.updatesManagedExternally", "false")); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java index 2001e50b6..9584bfc81 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java @@ -9,10 +9,6 @@ package org.cryptomator.ui.controllers; import javax.inject.Inject; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; @@ -22,7 +18,6 @@ import java.util.concurrent.ExecutorService; import com.google.common.base.CharMatcher; import com.google.common.base.Strings; import javafx.application.Application; -import javafx.beans.binding.Bindings; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; @@ -39,7 +34,6 @@ import javafx.scene.control.ProgressIndicator; import javafx.scene.control.TextField; import javafx.scene.input.KeyEvent; import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; import javafx.scene.text.Text; import javafx.util.StringConverter; import org.apache.commons.lang3.CharUtils; @@ -51,6 +45,7 @@ import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; import org.cryptomator.frontend.webdav.ServerLifecycleException; import org.cryptomator.keychain.KeychainAccess; +import org.cryptomator.ui.model.InvalidSettingsException; import org.cryptomator.ui.controls.SecPasswordField; import org.cryptomator.ui.l10n.Localization; import org.cryptomator.ui.model.Vault; @@ -122,18 +117,12 @@ public class UnlockController implements ViewController { @FXML private CheckBox useOwnMountPath; - @FXML - private HBox mountPathBox; - @FXML private Label mountPathLabel; @FXML private TextField mountPath; - @FXML - private Button changeMountPathButton; - @FXML private ProgressIndicator progressIndicator; @@ -161,13 +150,10 @@ public class UnlockController implements ViewController { savePassword.setDisable(!keychainAccess.isPresent()); unlockAfterStartup.disableProperty().bind(savePassword.disabledProperty().or(savePassword.selectedProperty().not())); - mountPathLabel.setVisible(false); - mountPathBox.visibleProperty().bind(mountPathLabel.visibleProperty()); - mountPathBox.managedProperty().bind(mountPathLabel.managedProperty()); - mountPath.visibleProperty().bind(mountPathLabel.visibleProperty()); - mountPath.managedProperty().bind(mountPathLabel.managedProperty()); - changeMountPathButton.visibleProperty().bind(mountPathLabel.visibleProperty()); - changeMountPathButton.managedProperty().bind(mountPathLabel.managedProperty()); + mountPathLabel.visibleProperty().bind(useOwnMountPath.selectedProperty()); + mountPath.visibleProperty().bind(useOwnMountPath.selectedProperty()); + mountPath.managedProperty().bind(useOwnMountPath.selectedProperty()); + mountPath.textProperty().addListener(this::mountPathDidChange); if (SystemUtils.IS_OS_WINDOWS) { winDriveLetter.setConverter(new WinDriveLetterLabelConverter()); @@ -175,7 +161,7 @@ public class UnlockController implements ViewController { useOwnMountPath.setManaged(false); mountPathLabel.setManaged(false); //dirty cheat - mountPathBox.setMouseTransparent(true); + mountPath.setMouseTransparent(true); } else { winDriveLetterLabel.setVisible(false); winDriveLetterLabel.setManaged(false); @@ -187,10 +173,9 @@ public class UnlockController implements ViewController { mountPathLabel.setManaged(false); } } - changeMountPathButton.disableProperty().bind(Bindings.createBooleanBinding(this::isDirVaild, mountPath.textProperty()).not()); - } + @Override public Parent getRoot() { return root; @@ -252,11 +237,8 @@ public class UnlockController implements ViewController { vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), vaultSettings.revealAfterMount()::set)); vaultSubs = vaultSubs.and(EasyBind.subscribe(useOwnMountPath.selectedProperty(), vaultSettings.usesIndividualMountPath()::set)); - changeMountPathButton.visibleProperty().bind( - vaultSettings.individualMountPath().isNotEqualTo(mountPath.textProperty()) - ); + mountPath.textProperty().setValue(vaultSettings.individualMountPath().getValueSafe()); - mountPathLabel.visibleProperty().bind(useOwnMountPath.selectedProperty()); } @@ -284,28 +266,6 @@ public class UnlockController implements ViewController { } } - @FXML - private void didClickchangeMountPathButton(ActionEvent event) { - assert isDirVaild(); - vault.setMountPath(mountPath.getText()); - } - - private boolean isDirVaild() { - try { - if (!mountPath.textProperty().isEmpty().get()) { - Path p = Paths.get(mountPath.textProperty().get()); - return Files.isDirectory(p) && Files.isReadable(p) && Files.isWritable(p) && Files.isExecutable(p); - } else { - return false; - } - - } catch (InvalidPathException e) { - LOG.info("Invalid path"); - return false; - } - } - - private void filterAlphanumericKeyEvents(KeyEvent t) { if (!Strings.isNullOrEmpty(t.getCharacter()) && !ALPHA_NUMERIC_MATCHER.matchesAllOf(t.getCharacter())) { t.consume(); @@ -321,6 +281,10 @@ public class UnlockController implements ViewController { } } + private void mountPathDidChange(ObservableValue property, String oldValue, String newValue) { + vault.setIndividualMountPath(newValue); + } + /** * Converts 'C' to "C:" to translate between model and GUI. */ @@ -420,6 +384,7 @@ public class UnlockController implements ViewController { @FXML private void didClickUnlockButton(ActionEvent event) { advancedOptions.setDisable(true); + advancedOptions.setVisible(false); progressIndicator.setVisible(true); CharSequence password = passwordField.getCharacters(); @@ -432,6 +397,10 @@ public class UnlockController implements ViewController { messageText.setText(null); downloadsPageLink.setVisible(false); listener.ifPresent(lstnr -> lstnr.didUnlock(vault)); + }).onError(InvalidSettingsException.class, e -> { + messageText.setText(localization.getString("unlock.errorMessage.invalidMountPath")); + advancedOptions.setVisible(true); + mountPath.setStyle("-fx-border-color: red;"); }).onError(InvalidPassphraseException.class, e -> { messageText.setText(localization.getString("unlock.errorMessage.wrongPassword")); passwordField.selectAll(); @@ -451,14 +420,17 @@ public class UnlockController implements ViewController { LOG.error("Unlock failed for technical reasons.", e); messageText.setText(localization.getString("unlock.errorMessage.unlockFailed")); }).onError(Exception.class, e -> { - LOG.error("Unlock failed for technical reasons.", e); - messageText.setText(localization.getString("unlock.errorMessage.unlockFailed")); + LOG.error("Unlock failed for technical reasons.", e); + messageText.setText(localization.getString("unlock.errorMessage.unlockFailed")); }).andFinally(() -> { if (!savePassword.isSelected()) { passwordField.swipe(); } advancedOptions.setDisable(false); progressIndicator.setVisible(false); + if (advancedOptions.isVisible()) { //dirty programming, but otherwise the focus is wrong + mountPath.requestFocus(); + } }).runOnce(executor); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java b/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java index 792a62364..f986b6e3f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/DokanyVolume.java @@ -1,13 +1,16 @@ package org.cryptomator.ui.model; import javax.inject.Inject; -import java.util.Iterator; +import java.nio.file.Paths; +import java.util.Set; import java.util.concurrent.ExecutorService; +import com.google.common.collect.Sets; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; import org.cryptomator.frontend.dokany.Mount; import org.cryptomator.frontend.dokany.MountFactory; +import org.cryptomator.frontend.dokany.MountFailedException; public class DokanyVolume implements Volume { @@ -28,7 +31,7 @@ public class DokanyVolume implements Volume { @Override public boolean isSupported() { - return MountFactory.isApplicable(); + return DokanyVolume.isSupportedStatic(); } //TODO: Drive letter 'A' as mount point is invalid in dokany. maybe we should do already here something against it @@ -39,22 +42,21 @@ public class DokanyVolume implements Volume { driveLetter = vaultSettings.winDriveLetter().get().charAt(0); } else { //auto assign drive letter - //TODO: can we assume the we have at least one free drive letter? - - //this is a temporary fix for 'A' being an invalid drive letter - if(!windowsDriveLetters.getAvailableDriveLetters().isEmpty()){ - Iterator winDriveLetterIt = windowsDriveLetters.getAvailableDriveLetters().iterator(); - do{ - driveLetter = winDriveLetterIt.next(); - }while (winDriveLetterIt.hasNext() && driveLetter == 65); -// if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) { + if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) { + //this is a temporary fix for 'A' being an invalid drive letter + Set availableLettersWithoutA = Sets.difference(windowsDriveLetters.getAvailableDriveLetters(), Set.of('A')); + driveLetter = availableLettersWithoutA.iterator().next(); // driveLetter = windowsDriveLetters.getAvailableDriveLetters().iterator().next(); } else { throw new VolumeException("No free drive letter available."); } } String mountName = vaultSettings.mountName().get(); - this.mount = mountFactory.mount(fs.getPath("/"), driveLetter, mountName, FS_TYPE_NAME); + try { + this.mount = mountFactory.mount(fs.getPath("/"), Paths.get(driveLetter + ":\\") , mountName, FS_TYPE_NAME); + } catch (MountFailedException e) { + throw new VolumeException("Unable to mount Filesystem", e); + } } @Override @@ -69,4 +71,8 @@ public class DokanyVolume implements Volume { public void unmount() { mount.close(); } + + public static boolean isSupportedStatic() { + return MountFactory.isApplicable(); + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java b/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java index 0249a198d..ec63da443 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/FuseVolume.java @@ -60,11 +60,10 @@ public class FuseVolume implements Volume { private String createDirIfNotExist(String prefix, String dirName) throws IOException { Path p = Paths.get(prefix, dirName + vaultSettings.getId()); if (Files.isDirectory(p)) { - try(DirectoryStream emptyCheck = Files.newDirectoryStream(p)){ - if(emptyCheck.iterator().hasNext()){ + try (DirectoryStream emptyCheck = Files.newDirectoryStream(p)) { + if (emptyCheck.iterator().hasNext()) { throw new DirectoryNotEmptyException("Mount point is not empty."); - } - else { + } else { LOG.info("Directory already exists and is empty. Using it as mount point."); return p.toString(); } @@ -119,6 +118,10 @@ public class FuseVolume implements Volume { @Override public boolean isSupported() { + return FuseVolume.isSupportedStatic(); + } + + public static boolean isSupportedStatic() { return (SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_LINUX) && FuseMountFactory.isFuseSupported(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/InvalidSettingsException.java b/main/ui/src/main/java/org/cryptomator/ui/model/InvalidSettingsException.java new file mode 100644 index 000000000..ed9b39040 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/InvalidSettingsException.java @@ -0,0 +1,5 @@ +package org.cryptomator.ui.model; + +public class InvalidSettingsException extends RuntimeException { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java index 3c9e6aa2e..cb0981d52 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java @@ -5,8 +5,8 @@ *******************************************************************************/ package org.cryptomator.ui.model; -import static java.nio.charset.StandardCharsets.UTF_8; - +import javax.inject.Inject; +import javax.inject.Singleton; import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; @@ -19,11 +19,7 @@ import java.util.EnumSet; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.apache.commons.codec.binary.Base32; -import org.apache.commons.codec.binary.BaseNCodec; +import com.google.common.io.BaseEncoding; import org.apache.commons.lang3.StringUtils; import org.cryptomator.cryptolib.Cryptors; import org.cryptomator.cryptolib.api.Cryptor; @@ -32,6 +28,8 @@ import org.cryptomator.ui.l10n.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Contains the collective knowledge of all creatures who were alive during the development of vault format 3. * This class uses no external classes from the crypto or shortening layer by purpose, so we don't need legacy code inside these. @@ -50,7 +48,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy { private static final String NEW_FOLDER_PREFIX = "0"; private final MessageDigest sha1 = MessageDigestSupplier.SHA1.get(); - private final BaseNCodec base32 = new Base32(); + private final BaseEncoding base32 = BaseEncoding.base32(); @Inject public UpgradeVersion3to4(Localization localization) { @@ -155,7 +153,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy { String oldLongName = new String(Files.readAllBytes(oldMetadataFile), UTF_8); if (oldLongName.endsWith(OLD_FOLDER_SUFFIX)) { String newLongName = NEW_FOLDER_PREFIX + StringUtils.removeEnd(oldLongName, OLD_FOLDER_SUFFIX); - String newCanonicalBase32 = base32.encodeAsString(sha1.digest(newLongName.getBytes(UTF_8))); + String newCanonicalBase32 = base32.encode(sha1.digest(newLongName.getBytes(UTF_8))); String newCanonicalName = newCanonicalBase32 + LONG_FILENAME_EXT; Path newMetadataFile = metadataDir.resolve(newCanonicalName.substring(0, 2)).resolve(newCanonicalName.substring(2, 4)).resolve(newCanonicalName); String newName = newCanonicalBase32 + oldNameSuffix + LONG_FILENAME_EXT; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 5e2622024..cf0e6d7cc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -27,7 +27,6 @@ import javafx.beans.binding.Binding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.StringProperty; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.LazyInitializer; @@ -99,9 +98,12 @@ public class Vault { CryptoFileSystemProvider.changePassphrase(getPath(), MASTERKEY_FILENAME, oldPassphrase, newPassphrase); } - public synchronized void unlock(CharSequence passphrase) throws CryptoException, IOException, Volume.VolumeException { + public synchronized void unlock(CharSequence passphrase) throws InvalidSettingsException, CryptoException, IOException, Volume.VolumeException { Platform.runLater(() -> state.set(State.PROCESSING)); try { + if (vaultSettings.usesIndividualMountPath().and(vaultSettings.individualMountPath().isEmpty()).get()) { + throw new InvalidSettingsException(); + } CryptoFileSystem fs = getCryptoFileSystem(passphrase); volume = volumeProvider.get(); volume.mount(fs); @@ -239,11 +241,11 @@ public class Vault { return vaultSettings.mountName().get(); } - public StringProperty getMountPathProperty() { - return vaultSettings.individualMountPath(); + public String getIndividualMountPath() { + return vaultSettings.individualMountPath().getValueSafe(); } - public void setMountPath(String mountPath) { + public void setIndividualMountPath(String mountPath) { vaultSettings.individualMountPath().set(mountPath); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Volume.java b/main/ui/src/main/java/org/cryptomator/ui/model/Volume.java index 399e765da..73f8d666b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Volume.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Volume.java @@ -1,8 +1,10 @@ package org.cryptomator.ui.model; +import org.cryptomator.common.settings.VolumeImpl; import org.cryptomator.cryptofs.CryptoFileSystem; import java.io.IOException; +import java.util.stream.Stream; /** * Takes a Volume and usess it to mount an unlocked vault @@ -11,12 +13,12 @@ public interface Volume { /** * Checks in constant time whether this volume type is supported on the system running Cryptomator. + * * @return true if this volume can be mounted */ boolean isSupported(); /** - * * @param fs * @throws IOException */ @@ -36,6 +38,21 @@ public interface Volume { throw new VolumeException("Operation not supported."); } + static VolumeImpl[] getCurrentSupportedAdapters() { + return Stream.of(VolumeImpl.values()).filter(impl -> { + switch (impl) { + case WEBDAV: + return WebDavVolume.isSupportedStatic(); + case DOKANY: + return DokanyVolume.isSupportedStatic(); + case FUSE: + return FuseVolume.isSupportedStatic(); + default: + return false;//throw new IllegalStateException("Adapter not implemented."); + } + }).toArray(VolumeImpl[]::new); + } + /** * Exception thrown when a volume-specific command such as mount/unmount/reveal failed. */ diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/WebDavVolume.java b/main/ui/src/main/java/org/cryptomator/ui/model/WebDavVolume.java index 6d1138c90..2161e388d 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/WebDavVolume.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/WebDavVolume.java @@ -116,11 +116,16 @@ public class WebDavVolume implements Volume { @Override public boolean isSupported() { - return true; + return WebDavVolume.isSupportedStatic(); } @Override public boolean supportsForcedUnmount() { return mount != null && mount.forced().isPresent(); } + + + public static boolean isSupportedStatic() { + return true; + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java b/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java index 59741e2f2..744c37cff 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/DialogBuilderUtil.java @@ -38,6 +38,10 @@ public class DialogBuilderUtil { return buildDialog(title, header, content, Alert.AlertType.CONFIRMATION, defaultButton, ButtonType.YES, ButtonType.NO); } + public static Alert buildGracefulShutdownDialog(String title, String header, String content, ButtonType defaultButton, ButtonType... buttons) { + return buildDialog(title, header, content, Alert.AlertType.WARNING, defaultButton, buttons); + } + private static Alert buildDialog(String title, String header, String content, Alert.AlertType type, ButtonType defaultButton, ButtonType... buttons) { Text contentText = new Text(content); contentText.setWrappingWidth(360.0); diff --git a/main/ui/src/main/resources/fxml/settings.fxml b/main/ui/src/main/resources/fxml/settings.fxml index 794181cf5..5748a0668 100644 --- a/main/ui/src/main/resources/fxml/settings.fxml +++ b/main/ui/src/main/resources/fxml/settings.fxml @@ -7,7 +7,6 @@ Contributors: Sebastian Stenzel - initial API and implementation --> - @@ -45,21 +44,15 @@ - -