diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 31b43f7cd..c38d20dc5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -4,25 +4,24 @@ on:
[push]
jobs:
- test:
- name: Run Tests
+ build:
+ name: Build and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - name: Set up JDK 14
- uses: actions/setup-java@v1
+ - uses: actions/setup-java@v1
with:
java-version: 14
- uses: actions/cache@v1
with:
path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ github.run_id }}
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Ensure to use tagged version
run: mvn versions:set --file main/pom.xml -DnewVersion=${GITHUB_REF##*/} # use shell parameter expansion to strip of 'refs/tags'
if: startsWith(github.ref, 'refs/tags/')
- - name: Build with Maven
+ - name: Build and Test
run: mvn -B install --file main/pom.xml -Pcoverage
- name: Run Codacy Coverage Reporter
run: |
@@ -34,25 +33,7 @@ jobs:
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar final
env:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
-
- assemble-build-kit:
- name: Assemble Build Kit
- runs-on: ubuntu-latest
- needs: test
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 14
- uses: actions/setup-java@v1
- with:
- java-version: 14
- - uses: actions/cache@v1
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ github.run_id }}
- - name: Ensure to use tagged version
- run: mvn versions:set --file main/pom.xml -DnewVersion=${GITHUB_REF##*/} # use shell parameter expansion to strip of 'refs/tags'
- if: startsWith(github.ref, 'refs/tags/')
- - name: Build with Maven
+ - name: Assemble Buildkit
run: mvn -B package -DskipTests --file main/pom.xml --resume-from=buildkit -Prelease
- name: Upload buildkit-linux.zip
uses: actions/upload-artifact@v1
@@ -70,10 +51,10 @@ jobs:
name: buildkit-win.zip
path: main/buildkit/target/buildkit-win.zip
- github-release:
+ release:
name: Draft a Release on GitHub Releases
runs-on: ubuntu-latest
- needs: assemble-build-kit
+ needs: build
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Download buildkit-linux.zip
@@ -91,7 +72,8 @@ jobs:
with:
name: buildkit-win.zip
path: .
- - id: create_release
+ - name: Create Release
+ id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -99,9 +81,9 @@ jobs:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: |
- TODO
+ :construction: Work in Progress
draft: true
- prerelease: true
+ prerelease: false
- name: Upload buildkit-linux.zip to GitHub Releases
uses: actions/upload-release-asset@v1.0.1
env:
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index d6a3de953..1c7121872 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -32,9 +32,9 @@
+
-
diff --git a/.idea/runConfigurations/Cryptomator_macOS.xml b/.idea/runConfigurations/Cryptomator_macOS.xml
index 3d824a536..235887653 100644
--- a/.idea/runConfigurations/Cryptomator_macOS.xml
+++ b/.idea/runConfigurations/Cryptomator_macOS.xml
@@ -1,5 +1,8 @@
+
+
+
diff --git a/README.md b/README.md
index a8a7248cd..091b6af8c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
[](https://cryptomator.org/)
-[](https://travis-ci.org/cryptomator/cryptomator)
+[](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
[](https://snyk.io/test/github/cryptomator/cryptomator?targetFile=main%2Fpom.xml)
[](https://www.codacy.com/app/cryptomator/cryptomator?utm_source=github.com&utm_medium=referral&utm_content=cryptomator/cryptomator&utm_campaign=Badge_Grade)
[](http://twitter.com/Cryptomator)
@@ -41,7 +41,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
- File names get encrypted
- Folder structure gets obfuscated
- Use as many vaults in your Dropbox as you want, each having individual passwords
-- One thousand commits for the security of your data!! :tada:
+- Two thousand commits for the security of your data!! :tada:
### Privacy
@@ -65,7 +65,7 @@ For more information on the security details visit [cryptomator.org](https://doc
### Dependencies
-* JDK 11 (we recommend to use the latest version)
+* JDK 14 (e.g. adoptopenjdk)
* Maven 3
* Optional: OS-dependent build tools for native packaging (see [Windows](https://github.com/cryptomator/cryptomator-win), [OS X](https://github.com/cryptomator/cryptomator-osx), [Linux](https://github.com/cryptomator/builder-containers))
diff --git a/main/buildkit/pom.xml b/main/buildkit/pom.xml
index b29cb977d..e8cc24058 100644
--- a/main/buildkit/pom.xml
+++ b/main/buildkit/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.5.1
+ 1.5.2
buildkit
pom
diff --git a/main/commons/pom.xml b/main/commons/pom.xml
index fd6b0aea0..e8e0d078b 100644
--- a/main/commons/pom.xml
+++ b/main/commons/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.5.1
+ 1.5.2
commons
Cryptomator Commons
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
index 3d91b38f7..04dd2b447 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java
@@ -9,23 +9,20 @@ import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.apache.commons.lang3.StringUtils;
import org.fxmisc.easybind.EasyBind;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
-import java.util.Base64;
-import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
-import java.util.UUID;
/**
* The settings specific to a single vault.
@@ -38,6 +35,7 @@ public class VaultSettings {
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
public static final boolean DEFAULT_USES_READONLY_MODE = false;
public static final String DEFAULT_MOUNT_FLAGS = "";
+ public static final int DEFAULT_FILENAME_LENGTH_LIMIT = -1;
private static final Random RNG = new Random();
@@ -51,6 +49,7 @@ public class VaultSettings {
private final StringProperty individualMountPath = new SimpleStringProperty();
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS);
+ private final IntegerProperty filenameLengthLimit = new SimpleIntegerProperty(DEFAULT_FILENAME_LENGTH_LIMIT);
public VaultSettings(String id) {
this.id = Objects.requireNonNull(id);
@@ -59,7 +58,7 @@ public class VaultSettings {
}
Observable[] observables() {
- return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags};
+ return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit};
}
private void deriveMountNameFromPath(Path path) {
@@ -146,6 +145,10 @@ public class VaultSettings {
public StringProperty mountFlags() {
return mountFlags;
}
+
+ public IntegerProperty filenameLengthLimit() {
+ return filenameLengthLimit;
+ }
/* Hashcode/Equals */
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
index e5130cdb0..8e87a16e7 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java
@@ -29,6 +29,7 @@ class VaultSettingsJsonAdapter {
out.name("individualMountPath").value(value.individualMountPath().get());
out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get());
out.name("mountFlags").value(value.mountFlags().get());
+ out.name("filenameLengthLimit").value(value.filenameLengthLimit().get());
out.endObject();
}
@@ -43,6 +44,7 @@ class VaultSettingsJsonAdapter {
boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
+ int filenameLengthLimit = VaultSettings.DEFAULT_FILENAME_LENGTH_LIMIT;
in.beginObject();
while (in.hasNext()) {
@@ -78,6 +80,9 @@ class VaultSettingsJsonAdapter {
case "mountFlags":
mountFlags = in.nextString();
break;
+ case "filenameLengthLimit":
+ filenameLengthLimit = in.nextInt();
+ break;
default:
LOG.warn("Unsupported vault setting found in JSON: " + name);
in.skipValue();
@@ -96,6 +101,7 @@ class VaultSettingsJsonAdapter {
vaultSettings.individualMountPath().set(individualMountPath);
vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode);
vaultSettings.mountFlags().set(mountFlags);
+ vaultSettings.filenameLengthLimit().set(filenameLengthLimit);
return vaultSettings;
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java
index e9e0fbd6d..5b0fd3bd6 100644
--- a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java
+++ b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java
@@ -21,6 +21,8 @@ import org.cryptomator.cryptofs.CryptoFileSystem;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
+import org.cryptomator.cryptofs.common.Constants;
+import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.slf4j.Logger;
@@ -101,10 +103,19 @@ public class Vault {
if (vaultSettings.usesReadOnlyMode().get()) {
flags.add(FileSystemFlags.READONLY);
}
+ if (vaultSettings.filenameLengthLimit().get() == -1) {
+ LOG.debug("Determining file name length limitations...");
+ int limit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(getPath());
+ vaultSettings.filenameLengthLimit().set(limit);
+ LOG.info("Storing file name length limit of {}", limit);
+ }
+ assert vaultSettings.filenameLengthLimit().get() > 0;
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
.withPassphrase(passphrase) //
.withFlags(flags) //
.withMasterkeyFilename(MASTERKEY_FILENAME) //
+ .withMaxPathLength(vaultSettings.filenameLengthLimit().get() + Constants.MAX_ADDITIONAL_PATH_LENGTH) //
+ .withMaxNameLength(vaultSettings.filenameLengthLimit().get()) //
.build();
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
index 09bd60c77..72f88a02c 100644
--- a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
+++ b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
@@ -51,15 +51,16 @@ public class VaultListManager {
}
public Vault add(Path pathToVault) throws NoSuchFileException {
- if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
- throw new NoSuchFileException(pathToVault.toString(), null, "Not a vault directory");
+ Path normalizedPathToVault = pathToVault.normalize().toAbsolutePath();
+ if (!CryptoFileSystemProvider.containsVault(normalizedPathToVault, MASTERKEY_FILENAME)) {
+ throw new NoSuchFileException(normalizedPathToVault.toString(), null, "Not a vault directory");
}
- Optional alreadyExistingVault = get(pathToVault);
+ Optional alreadyExistingVault = get(normalizedPathToVault);
if (alreadyExistingVault.isPresent()) {
return alreadyExistingVault.get();
} else {
VaultSettings vaultSettings = VaultSettings.withRandomId();
- vaultSettings.path().set(pathToVault);
+ vaultSettings.path().set(normalizedPathToVault);
Vault newVault = create(vaultSettings);
vaultList.add(newVault);
return newVault;
@@ -72,13 +73,11 @@ public class VaultListManager {
}
private Optional get(Path vaultPath) {
- return vaultList.stream().filter(v -> {
- try {
- return Files.isSameFile(vaultPath, v.getPath());
- } catch (IOException e) {
- return false;
- }
- }).findAny();
+ assert vaultPath.isAbsolute();
+ assert vaultPath.normalize().equals(vaultPath);
+ return vaultList.stream() //
+ .filter(v -> vaultPath.equals(v.getPath())) //
+ .findAny();
}
private Vault create(VaultSettings vaultSettings) {
diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java
index c5062e6f3..69564b876 100644
--- a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java
+++ b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultStats.java
@@ -41,16 +41,13 @@ public class VaultStats {
}
private void vaultStateChanged(@SuppressWarnings("unused") Observable observable) {
- switch (state.get()) {
- case UNLOCKED:
- assert fs.get() != null;
- LOG.debug("start recording stats");
- updateService.restart();
- break;
- default:
- LOG.debug("stop recording stats");
- updateService.cancel();
- break;
+ if (VaultState.UNLOCKED.equals(state.get())) {
+ assert fs.get() != null;
+ LOG.debug("start recording stats");
+ updateService.restart();
+ } else {
+ LOG.debug("stop recording stats");
+ updateService.cancel();
}
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java
index 05efa5ef9..a0aa11be8 100644
--- a/main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java
+++ b/main/commons/src/main/java/org/cryptomator/common/vaults/Volume.java
@@ -43,17 +43,10 @@ public interface Volume {
}
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.");
- }
+ return Stream.of(VolumeImpl.values()).filter(impl -> switch (impl) {
+ case WEBDAV -> WebDavVolume.isSupportedStatic();
+ case DOKANY -> DokanyVolume.isSupportedStatic();
+ case FUSE -> FuseVolume.isSupportedStatic();
}).toArray(VolumeImpl[]::new);
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java b/main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java
index c873e9f3f..016c39a3a 100644
--- a/main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java
+++ b/main/commons/src/main/java/org/cryptomator/common/vaults/WindowsDriveLetters.java
@@ -7,8 +7,6 @@ package org.cryptomator.common.vaults;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.SystemUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -22,12 +20,11 @@ import java.util.stream.StreamSupport;
@Singleton
public final class WindowsDriveLetters {
- private static final Logger LOG = LoggerFactory.getLogger(WindowsDriveLetters.class);
- private static final Set A_TO_Z;
+ private static final Set C_TO_Z;
static {
- try (IntStream stream = IntStream.rangeClosed('A', 'Z')) {
- A_TO_Z = stream.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.toSet());
+ try (IntStream stream = IntStream.rangeClosed('C', 'Z')) {
+ C_TO_Z = stream.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.toSet());
}
}
@@ -36,7 +33,7 @@ public final class WindowsDriveLetters {
}
public Set getAllDriveLetters() {
- return A_TO_Z;
+ return C_TO_Z;
}
public Set getOccupiedDriveLetters() {
@@ -44,12 +41,12 @@ public final class WindowsDriveLetters {
return Set.of();
} else {
Iterable rootDirs = FileSystems.getDefault().getRootDirectories();
- return StreamSupport.stream(rootDirs.spliterator(), false).map(p -> p.toString().substring(0,1)).collect(Collectors.toSet());
+ return StreamSupport.stream(rootDirs.spliterator(), false).map(p -> p.toString().substring(0, 1)).collect(Collectors.toSet());
}
}
public Set getAvailableDriveLetters() {
- return Sets.difference(A_TO_Z, getOccupiedDriveLetters());
+ return Sets.difference(C_TO_Z, getOccupiedDriveLetters());
}
}
diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml
index 7b99f1730..242c41b84 100644
--- a/main/keychain/pom.xml
+++ b/main/keychain/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.5.1
+ 1.5.2
keychain
System Keychain Access
diff --git a/main/launcher/pom.xml b/main/launcher/pom.xml
index ef3d74d4c..642dcfe98 100644
--- a/main/launcher/pom.xml
+++ b/main/launcher/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.5.1
+ 1.5.2
launcher
Cryptomator Launcher
diff --git a/main/pom.xml b/main/pom.xml
index dbb5c18eb..fc9e8e3f5 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.cryptomator
main
- 1.5.1
+ 1.5.2
pom
Cryptomator
@@ -24,11 +24,11 @@
UTF-8
- 1.9.7
+ 1.9.9
2.2.2
1.2.3
- 1.1.13
- 1.0.10
+ 1.1.14
+ 1.0.11
14
diff --git a/main/ui/pom.xml b/main/ui/pom.xml
index 364d66d62..d305cbee9 100644
--- a/main/ui/pom.xml
+++ b/main/ui/pom.xml
@@ -4,7 +4,7 @@
org.cryptomator
main
- 1.5.1
+ 1.5.2
ui
Cryptomator GUI
diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java
index 9798a9a0f..262af2283 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java
@@ -13,6 +13,7 @@ public enum FxmlFile {
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
MAIN_WINDOW("/fxml/main_window.fxml"), //
MIGRATION_CAPABILITY_ERROR("/fxml/migration_capability_error.fxml"), //
+ MIGRATION_IMPOSSIBLE("/fxml/migration_impossible.fxml"),
MIGRATION_RUN("/fxml/migration_run.fxml"), //
MIGRATION_START("/fxml/migration_start.fxml"), //
MIGRATION_SUCCESS("/fxml/migration_success.fxml"), //
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java b/main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java
index 24cb8b8e9..f5aa6dbd5 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java
@@ -22,6 +22,8 @@ import javafx.scene.control.TextField;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCodeCombination;
+import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
@@ -43,6 +45,7 @@ public class SecurePasswordField extends TextField {
private static final int GROW_BUFFER_SIZE = 50;
private static final String DEFAULT_PLACEHOLDER = "●";
private static final String STYLE_CLASS = "secure-password-field";
+ private static final KeyCodeCombination SHORTCUT_BACKSPACE = new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCombination.SHORTCUT_DOWN);
private final String placeholderChar;
private final BooleanProperty capsLocked = new SimpleBooleanProperty();
@@ -74,12 +77,10 @@ public class SecurePasswordField extends TextField {
}
public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
- switch(attribute) {
- case TEXT:
- return null;
- default:
- return super.queryAccessibleAttribute(attribute, parameters);
- }
+ return switch (attribute) {
+ case TEXT -> null;
+ default -> super.queryAccessibleAttribute(attribute, parameters);
+ };
}
private void handleDragOver(DragEvent event) {
@@ -101,6 +102,8 @@ public class SecurePasswordField extends TextField {
private void handleKeyEvent(KeyEvent e) {
if (e.getCode() == KeyCode.CAPS) {
updateCapsLocked();
+ } else if (SHORTCUT_BACKSPACE.match(e)) {
+ swipe();
}
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
index 7f25bdf62..36a746039 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
@@ -31,16 +31,12 @@ public class VaultDetailController implements FxController {
}
private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
- switch (state) {
- case LOCKED:
- return FontAwesome5Icon.LOCK;
- case PROCESSING:
- return FontAwesome5Icon.SPINNER;
- case UNLOCKED:
- return FontAwesome5Icon.LOCK_OPEN;
- default:
- return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
- }
+ return switch (state) {
+ case LOCKED -> FontAwesome5Icon.LOCK;
+ case PROCESSING -> FontAwesome5Icon.SPINNER;
+ case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
+ case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ };
}
@FXML
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
index ec553c329..6703ec674 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
@@ -3,9 +3,9 @@ package org.cryptomator.ui.mainwindow;
import javafx.beans.binding.Binding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
+import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
-import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.fxmisc.easybind.EasyBind;
@@ -23,16 +23,12 @@ public class VaultListCellController implements FxController {
}
private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
- switch (state) {
- case LOCKED:
- return FontAwesome5Icon.LOCK;
- case PROCESSING:
- return FontAwesome5Icon.SPINNER;
- case UNLOCKED:
- return FontAwesome5Icon.LOCK_OPEN;
- default:
- return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
- }
+ return switch (state) {
+ case LOCKED -> FontAwesome5Icon.LOCK;
+ case PROCESSING -> FontAwesome5Icon.SPINNER;
+ case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
+ case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ };
}
/* Getter/Setter */
diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
index 625a10e65..de39719bc 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
@@ -66,9 +66,7 @@ public class VaultListController implements FxController {
}
VaultState reportedState = newValue.getState();
switch (reportedState) {
- case LOCKED:
- case NEEDS_MIGRATION:
- case MISSING:
+ case LOCKED, NEEDS_MIGRATION, MISSING:
try {
VaultState determinedState = VaultListManager.determineVaultState(newValue.getPath());
newValue.setState(determinedState);
@@ -78,11 +76,8 @@ public class VaultListController implements FxController {
newValue.setLastKnownException(e);
}
break;
- case ERROR:
- case UNLOCKED:
- case PROCESSING:
- default:
- // no-op
+ case ERROR, UNLOCKED, PROCESSING:
+ break; // no-op
}
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java
new file mode 100644
index 000000000..76d462113
--- /dev/null
+++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java
@@ -0,0 +1,46 @@
+package org.cryptomator.ui.migration;
+
+import javafx.fxml.FXML;
+import javafx.stage.Stage;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.fxapp.FxApplication;
+
+import javax.inject.Inject;
+
+public class MigrationImpossibleController implements FxController {
+
+ private static final String HELP_URI = "https://docs.cryptomator.org/en/1.5/help/manual-migration/";
+
+ private final FxApplication fxApplication;
+ private final Stage window;
+ private final Vault vault;
+
+ @Inject
+ MigrationImpossibleController(FxApplication fxApplication, @MigrationWindow Stage window, @MigrationWindow Vault vault) {
+ this.fxApplication = fxApplication;
+ this.window = window;
+ this.vault = vault;
+ }
+
+ @FXML
+ public void close() {
+ window.close();
+ }
+
+ @FXML
+ public void getMigrationHelp() {
+ fxApplication.getHostServices().showDocument(HELP_URI);
+ }
+
+ /* Getter/Setters */
+
+ public Vault getVault() {
+ return vault;
+ }
+
+ public String getHelpUri() {
+ return HELP_URI;
+ }
+
+}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java
index 508777364..0c36818a2 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java
@@ -83,6 +83,13 @@ abstract class MigrationModule {
return fxmlLoaders.createScene("/fxml/migration_capability_error.fxml");
}
+ @Provides
+ @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE)
+ @MigrationScoped
+ static Scene provideMigrationImpossibleScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
+ return fxmlLoaders.createScene("/fxml/migration_impossible.fxml");
+ }
+
// ------------------
@Binds
@@ -104,5 +111,9 @@ abstract class MigrationModule {
@IntoMap
@FxControllerKey(MigrationCapabilityErrorController.class)
abstract FxController bindMigrationCapabilityErrorController(MigrationCapabilityErrorController controller);
-
+
+ @Binds
+ @IntoMap
+ @FxControllerKey(MigrationImpossibleController.class)
+ abstract FxController bindMigrationImpossibleController(MigrationImpossibleController controller);
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
index d7340618d..aad1914d7 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
@@ -16,8 +16,10 @@ import javafx.scene.control.ContentDisplay;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
+import org.cryptomator.cryptofs.FileNameTooLongException;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptofs.migration.Migrators;
+import org.cryptomator.cryptofs.migration.api.MigrationContinuationListener;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.keychain.KeychainAccess;
@@ -58,6 +60,7 @@ public class MigrationRunController implements FxController {
private final ErrorComponent.Builder errorComponent;
private final Lazy startScene;
private final Lazy successScene;
+ private final Lazy impossibleScene;
private final ObjectBinding migrateButtonContentDisplay;
private final Lazy capabilityErrorScene;
private final BooleanProperty migrationButtonDisabled;
@@ -66,7 +69,8 @@ public class MigrationRunController implements FxController {
public NiceSecurePasswordField passwordField;
@Inject
- public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional keychainAccess, @Named("capabilityErrorCause") ObjectProperty missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy capabilityErrorScene, ErrorComponent.Builder errorComponent) {
+ public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional keychainAccess, @Named("capabilityErrorCause") ObjectProperty missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy impossibleScene, ErrorComponent.Builder errorComponent) {
+
this.window = window;
this.vault = vault;
this.executor = executor;
@@ -80,6 +84,7 @@ public class MigrationRunController implements FxController {
this.capabilityErrorScene = capabilityErrorScene;
this.migrationButtonDisabled = new SimpleBooleanProperty();
this.migrationProgress = new SimpleDoubleProperty(volatileMigrationProgress);
+ this.impossibleScene = impossibleScene;
}
public void initialize() {
@@ -107,7 +112,7 @@ public class MigrationRunController implements FxController {
}, 0, MIGRATION_PROGRESS_UPDATE_MILLIS, TimeUnit.MILLISECONDS);
Tasks.create(() -> {
Migrators migrators = Migrators.get();
- migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password, this::migrationProgressChanged);
+ migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password, this::migrationProgressChanged, this::migrationRequiresInput);
return migrators.needsMigration(vault.getPath(), MASTERKEY_FILENAME);
}).onSuccess(needsAnotherMigration -> {
if (needsAnotherMigration) {
@@ -127,9 +132,14 @@ public class MigrationRunController implements FxController {
vault.setState(VaultState.NEEDS_MIGRATION);
}).onError(FileSystemCapabilityChecker.MissingCapabilityException.class, e -> {
LOG.error("Underlying file system not supported.", e);
- vault.setState(VaultState.ERROR);
+ vault.setState(VaultState.NEEDS_MIGRATION);
missingCapability.set(e.getMissingCapability());
window.setScene(capabilityErrorScene.get());
+ }).onError(FileNameTooLongException.class, e -> {
+ LOG.error("Migration failed because the underlying file system does not support long filenames.", e);
+ vault.setState(VaultState.NEEDS_MIGRATION);
+ errorComponent.cause(e).window(window).returnToScene(startScene.get()).build().showErrorScene();
+ window.setScene(impossibleScene.get());
}).onError(Exception.class, e -> { // including RuntimeExceptions
LOG.error("Migration failed for technical reasons.", e);
vault.setState(VaultState.NEEDS_MIGRATION);
@@ -142,19 +152,18 @@ public class MigrationRunController implements FxController {
// Called by a background task. We can not directly modify observable properties from here
private void migrationProgressChanged(MigrationProgressListener.ProgressState state, double progress) {
- switch (state) {
- case INITIALIZING:
- volatileMigrationProgress = -1.0;
- break;
- case MIGRATING:
- volatileMigrationProgress = progress;
- break;
- case FINALIZING:
- volatileMigrationProgress = 1.0;
- break;
- default:
- throw new IllegalStateException("Unexpted state " + state);
- }
+ volatileMigrationProgress = switch (state) {
+ case INITIALIZING -> -1.0;
+ case MIGRATING -> progress;
+ case FINALIZING -> 1.0;
+ };
+ }
+
+ private MigrationContinuationListener.ContinuationResult migrationRequiresInput(MigrationContinuationListener.ContinuationEvent event) {
+ //TODO: creating a new scene seems a little over the top, maybe stick to this scene
+ // my suggestion is to make this quick and dirty by setting some elements unmanaged and invisible and afterwards activate them again
+ // otherwise: We need a more abstract runController which has two subviews (run and halted), see mainWindow for example
+ return MigrationContinuationListener.ContinuationResult.PROCEED;
}
private void loadStoredPassword() {
@@ -194,12 +203,10 @@ public class MigrationRunController implements FxController {
}
public ContentDisplay getMigrateButtonContentDisplay() {
- switch (vault.getState()) {
- case PROCESSING:
- return ContentDisplay.LEFT;
- default:
- return ContentDisplay.TEXT_ONLY;
- }
+ return switch (vault.getState()) {
+ case PROCESSING -> ContentDisplay.LEFT;
+ default -> ContentDisplay.TEXT_ONLY;
+ };
}
public ReadOnlyDoubleProperty migrationProgressProperty() {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java
index ea525cc90..2b58eda30 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/PreferencesController.java
@@ -49,21 +49,14 @@ public class PreferencesController implements FxController {
}
private Tab getTabToSelect(SelectedPreferencesTab selectedTab) {
- switch (selectedTab) {
- case UPDATES:
- return updatesTab;
- case VOLUME:
- return volumeTab;
- case DONATION_KEY:
- return donationKeyTab;
- case GENERAL:
- return generalTab;
- case ABOUT:
- return aboutTab;
- case ANY:
- default:
- return updateAvailable.get() ? updatesTab : generalTab;
- }
+ return switch (selectedTab) {
+ case UPDATES -> updatesTab;
+ case VOLUME -> volumeTab;
+ case DONATION_KEY -> donationKeyTab;
+ case GENERAL -> generalTab;
+ case ABOUT -> aboutTab;
+ case ANY -> updateAvailable.get() ? updatesTab : generalTab;
+ };
}
private void selectedTabChanged() {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java
index 7d5031937..a76c8b1e3 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java
@@ -29,12 +29,10 @@ class TrayImageFactory {
MacApplicationUiInterfaceStyle interfaceStyle = macFunctions.map(MacFunctions::uiAppearance) //
.map(MacApplicationUiAppearance::getCurrentInterfaceStyle) //
.orElse(MacApplicationUiInterfaceStyle.LIGHT);
- switch (interfaceStyle) {
- case DARK:
- return "/tray_icon_mac_white.png";
- default:
- return "/tray_icon_mac_black.png";
- }
+ return switch (interfaceStyle) {
+ case DARK -> "/tray_icon_mac_white.png";
+ case LIGHT -> "/tray_icon_mac_black.png";
+ };
}
private String getWinOrLinuxResourceName() {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
index d725fd0ea..6f754b4c1 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
@@ -73,7 +73,7 @@ public class UnlockController implements FxController {
if (keychainAccess.isPresent()) {
loadStoredPassword();
} else {
- savePassword.setDisable(true);
+ savePassword.setSelected(false);
}
unlockButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.LOCKED).or(passwordField.textProperty().isEmpty()));
}
@@ -174,12 +174,10 @@ public class UnlockController implements FxController {
}
public ContentDisplay getUnlockButtonState() {
- switch (vault.getState()) {
- case PROCESSING:
- return ContentDisplay.LEFT;
- default:
- return ContentDisplay.TEXT_ONLY;
- }
+ return switch (vault.getState()) {
+ case PROCESSING -> ContentDisplay.LEFT;
+ default -> ContentDisplay.TEXT_ONLY;
+ };
}
public ReadOnlyBooleanProperty unlockButtonDisabledProperty() {
@@ -189,4 +187,8 @@ public class UnlockController implements FxController {
public boolean isUnlockButtonDisabled() {
return unlockButtonDisabled.get();
}
+
+ public boolean isKeychainAccessAvailable() {
+ return keychainAccess.isPresent();
+ }
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
index 8cca1c1cc..a6e5202d8 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
@@ -8,6 +8,7 @@ import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
+import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FXMLLoaderFactory;
import org.cryptomator.ui.common.FxController;
@@ -35,9 +36,9 @@ abstract class UnlockModule {
@Provides
@UnlockWindow
@UnlockScoped
- static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcons") List windowIcons) {
+ static Stage provideStage(@UnlockWindow Vault vault, @Named("windowIcons") List windowIcons) {
Stage stage = new Stage();
- stage.setTitle(resourceBundle.getString("unlock.title"));
+ stage.setTitle(vault.getDisplayableName());
stage.setResizable(false);
stage.initModality(Modality.APPLICATION_MODAL);
stage.getIcons().addAll(windowIcons);
diff --git a/main/ui/src/main/resources/css/dark_theme.css b/main/ui/src/main/resources/css/dark_theme.css
index 4a4e0c302..f9b113c77 100644
--- a/main/ui/src/main/resources/css/dark_theme.css
+++ b/main/ui/src/main/resources/css/dark_theme.css
@@ -854,7 +854,7 @@
.progress-bar > .bar {
-fx-background-color: CONTROL_PRIMARY_BG_NORMAL;
-fx-background-radius: 4px;
- -fx-padding: 0.5em;
+ -fx-padding: 1em 0.5em;
}
.progress-bar:indeterminate > .bar {
diff --git a/main/ui/src/main/resources/css/light_theme.css b/main/ui/src/main/resources/css/light_theme.css
index f020582ce..0170b32d7 100644
--- a/main/ui/src/main/resources/css/light_theme.css
+++ b/main/ui/src/main/resources/css/light_theme.css
@@ -853,7 +853,7 @@
.progress-bar > .bar {
-fx-background-color: CONTROL_PRIMARY_BG_NORMAL;
-fx-background-radius: 4px;
- -fx-padding: 0.5em;
+ -fx-padding: 1em 0.5em;
}
.progress-bar:indeterminate > .bar {
diff --git a/main/ui/src/main/resources/fxml/migration_impossible.fxml b/main/ui/src/main/resources/fxml/migration_impossible.fxml
new file mode 100644
index 000000000..46c1fb94f
--- /dev/null
+++ b/main/ui/src/main/resources/fxml/migration_impossible.fxml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main/ui/src/main/resources/fxml/migration_run.fxml b/main/ui/src/main/resources/fxml/migration_run.fxml
index 27164c643..03be9a140 100644
--- a/main/ui/src/main/resources/fxml/migration_run.fxml
+++ b/main/ui/src/main/resources/fxml/migration_run.fxml
@@ -3,6 +3,7 @@
+
@@ -19,17 +20,20 @@
-
+
-
+
+
+
+
-
+