diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ea7d5fd42..8ea663cc1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -39,15 +39,11 @@ jobs:
profile: mac
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/setup-java@v2
with:
+ distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
- - uses: actions/cache@v2
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+ cache: 'maven'
- name: Ensure to use tagged version
run: mvn versions:set -DnewVersion=${GITHUB_REF##*/} # use shell parameter expansion to strip of 'refs/tags'
if: startsWith(github.ref, 'refs/tags/')
@@ -159,8 +155,9 @@ jobs:
--resource-dir dist/mac/resources
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/setup-java@v2
with:
+ distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
- name: Download ${{ matrix.profile }}-buildkit
uses: actions/download-artifact@v2
@@ -210,7 +207,7 @@ jobs:
ppa:
name: Upload source package to PPA
needs: [buildkit, metadata]
- runs-on: ubuntu-latest
+ runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: install build tools
@@ -505,8 +502,9 @@ jobs:
name: win-appdir
- name: Untar appdir.tar
run: tar -xvf appdir.tar
- - uses: actions/setup-java@v1
+ - uses: actions/setup-java@v2
with:
+ distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
- name: Patch Application Directory
run: |
diff --git a/README.md b/README.md
index 4e29763ba..7ffb1fba1 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,14 @@ Cryptomator is provided free of charge as an open-source project despite the hig
### Silver Sponsors
+
+
+
+  |
+
+
+
+
- [Jameson Lopp](https://www.lopp.net/)
---
diff --git a/dist/linux/debian/changelog b/dist/linux/debian/changelog
index 84a9756f9..2c7606733 100644
--- a/dist/linux/debian/changelog
+++ b/dist/linux/debian/changelog
@@ -1,4 +1,4 @@
-cryptomator (${PPA_VERSION}) focal; urgency=low
+cryptomator (${PPA_VERSION}) bionic; urgency=low
* Full changelog can be found on https://github.com/cryptomator/cryptomator/releases
diff --git a/dist/mac/dmg/.gitignore b/dist/mac/dmg/.gitignore
index 738927994..c186170c9 100644
--- a/dist/mac/dmg/.gitignore
+++ b/dist/mac/dmg/.gitignore
@@ -1,3 +1,4 @@
# created during build
runtime/
-*.app/
+dmg/
+*.dmg
diff --git a/dist/mac/dmg/build.sh b/dist/mac/dmg/build.sh
index 6051e6f4c..b8d17cbe0 100755
--- a/dist/mac/dmg/build.sh
+++ b/dist/mac/dmg/build.sh
@@ -16,13 +16,14 @@ shift "$((OPTIND-1))"
# prepare working dir and variables
cd $(dirname $0)
-rm -rf runtime *.app
+rm -rf runtime dmg
REVISION_NO=`git rev-list --count HEAD`
VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout | sed -rn 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'`
# check preconditions
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
command -v mvn >/dev/null 2>&1 || { echo >&2 "mvn not found."; exit 1; }
+command -v create-dmg >/dev/null 2>&1 || { echo >&2 "create-dmg not found."; exit 1; }
if [ -n "${CODESIGN_IDENTITY}" ]; then
command -v codesign >/dev/null 2>&1 || { echo >&2 "codesign not found. Fix by 'xcode-select --install'."; exit 1; }
if [[ ! `security find-identity -v -p codesigning | grep -w "${CODESIGN_IDENTITY}"` ]]; then echo "Given codesign identity is invalid."; exit 1; fi
@@ -59,6 +60,7 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
--app-version "${VERSION_NO}" \
--java-options "-Dfile.encoding=\"utf-8\"" \
+ --java-options "-Dapple.awt.enableTemplateImages=true" \
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\"" \
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\"" \
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\"" \
@@ -94,3 +96,27 @@ if [ -n "${CODESIGN_IDENTITY}" ]; then
echo "Codesigning Cryptomator.app..."
codesign --force --deep --entitlements ../Cryptomator.entitlements -o runtime -s ${CODESIGN_IDENTITY} Cryptomator.app
fi
+
+# prepare dmg contents
+mkdir dmg
+mv Cryptomator.app dmg
+cp resources/macFUSE.webloc dmg
+
+# create dmg
+create-dmg \
+ --volname Cryptomator \
+ --volicon "resources/Cryptomator-Volume.icns" \
+ --background "resources/Cryptomator-background.tiff" \
+ --window-pos 400 100 \
+ --window-size 640 694 \
+ --icon-size 128 \
+ --icon "Cryptomator.app" 128 245 \
+ --hide-extension "Cryptomator.app" \
+ --icon "macFUSE.webloc" 320 501 \
+ --hide-extension "macFUSE.webloc" \
+ --app-drop-link 512 245 \
+ --eula "resources/license.rtf" \
+ --icon ".background" 128 758 \
+ --icon ".fseventsd" 320 758 \
+ --icon ".VolumeIcon.icns" 512 758 \
+ Cryptomator-${VERSION_NO}.dmg dmg
diff --git a/dist/win/.gitignore b/dist/win/.gitignore
new file mode 100644
index 000000000..2b66ddbed
--- /dev/null
+++ b/dist/win/.gitignore
@@ -0,0 +1,3 @@
+runtime
+Cryptomator
+installer
\ No newline at end of file
diff --git a/dist/win/build.bat b/dist/win/build.bat
new file mode 100644
index 000000000..ebfe2aa0b
--- /dev/null
+++ b/dist/win/build.bat
@@ -0,0 +1,2 @@
+@echo off
+powershell -NoExit -ExecutionPolicy Unrestricted -Command .\build.ps1
\ No newline at end of file
diff --git a/dist/win/build.ps1 b/dist/win/build.ps1
new file mode 100644
index 000000000..e4024d46d
--- /dev/null
+++ b/dist/win/build.ps1
@@ -0,0 +1,91 @@
+# check preconditions
+if ((Get-Command "git" -ErrorAction SilentlyContinue) -eq $null)
+{
+ Write-Host "Unable to find git.exe in your PATH (try: choco install git)"
+ exit 1
+}
+if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null)
+{
+ Write-Host "Unable to find mvn.cmd in your PATH (try: choco install maven)"
+ exit 1
+}
+
+$buildDir = Split-Path -Parent $PSCommandPath
+$version = $(mvn -f $buildDir/../../pom.xml help:evaluate -Dexpression="project.version" -q -DforceStdout)
+$semVerNo = $version -replace '(\d\.\d\.\d).*','$1'
+$revisionNo = $(git rev-list --count HEAD)
+
+Write-Output "`$version=$version"
+Write-Output "`$semVerNo=$semVerNo"
+Write-Output "`$revisionNo=$revisionNo"
+Write-Output "`$buildDir=$buildDir"
+Write-Output "`$Env:JAVA_HOME=$Env:JAVA_HOME"
+
+# compile
+&mvn -B -f $buildDir/../../pom.xml clean package -DskipTests -Pwin
+Copy-Item "$buildDir\..\..\target\cryptomator-*.jar" -Destination "$buildDir\..\..\target\mods"
+
+# add runtime
+& "$Env:JAVA_HOME\bin\jlink" `
+ --verbose `
+ --output runtime `
+ --module-path "$Env:JAVA_HOME/jmods" `
+ --add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility `
+ --no-header-files `
+ --no-man-pages `
+ --strip-debug `
+ --compress=1
+
+# create app dir
+& "$Env:JAVA_HOME\bin\jpackage" `
+ --verbose `
+ --type app-image `
+ --runtime-image runtime `
+ --input ../../target/libs `
+ --module-path ../../target/mods `
+ --module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator `
+ --dest . `
+ --name Cryptomator `
+ --vendor "Skymatic GmbH" `
+ --copyright "(C) 2016 - 2021 Skymatic GmbH" `
+ --java-options "-Xss5m" `
+ --java-options "-Xmx256m" `
+ --java-options "-Dcryptomator.appVersion=`"$semVerNo`"" `
+ --app-version "$semVerNo.$revisionNo" `
+ --java-options "-Dfile.encoding=`"utf-8`"" `
+ --java-options "-Dcryptomator.logDir=`"~/AppData/Roaming/Cryptomator`"" `
+ --java-options "-Dcryptomator.pluginDir=`"~/AppData/Roaming/Cryptomator/Plugins`"" `
+ --java-options "-Dcryptomator.settingsPath=`"~/AppData/Roaming/Cryptomator/settings.json`"" `
+ --java-options "-Dcryptomator.ipcSocketPath=`"~/AppData/Roaming/Cryptomator/ipc.socket`"" `
+ --java-options "-Dcryptomator.keychainPath=`"~/AppData/Roaming/Cryptomator/keychain.json`"" `
+ --java-options "-Dcryptomator.mountPointsDir=`"~/Cryptomator`"" `
+ --java-options "-Dcryptomator.showTrayIcon=true" `
+ --java-options "-Dcryptomator.buildNumber=`"msi-$revisionNo`"" `
+ --resource-dir resources `
+ --icon resources/Cryptomator.ico
+
+# patch app dir
+Copy-Item "contrib\*" -Destination "Cryptomator"
+attrib -r "Cryptomator\Cryptomator.exe"
+
+
+# create .msi bundle
+$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
+& "$Env:JAVA_HOME\bin\jpackage" `
+ --verbose `
+ --type msi `
+ --win-upgrade-uuid bda45523-42b1-4cae-9354-a45475ed4775 `
+ --app-image Cryptomator `
+ --dest installer `
+ --name Cryptomator `
+ --vendor "Skymatic GmbH" `
+ --copyright "(C) 2016 - 2021 Skymatic GmbH" `
+ --app-version "$semVerNo" `
+ --win-menu `
+ --win-dir-chooser `
+ --win-shortcut-prompt `
+ --win-update-url "https:\\cryptomator.org" `
+ --win-menu-group Cryptomator `
+ --resource-dir resources `
+ --license-file resources/license.rtf `
+ --file-associations resources/FAvaultFile.properties
\ No newline at end of file
diff --git a/src/main/java/org/cryptomator/ui/common/UserInteractionLock.java b/src/main/java/org/cryptomator/ui/common/UserInteractionLock.java
index f0c199648..4eba62552 100644
--- a/src/main/java/org/cryptomator/ui/common/UserInteractionLock.java
+++ b/src/main/java/org/cryptomator/ui/common/UserInteractionLock.java
@@ -16,7 +16,11 @@ public class UserInteractionLock {
private volatile E state;
public UserInteractionLock(E initialValue) {
- state = initialValue;
+ this.state = initialValue;
+ }
+
+ public synchronized void reset(E value) {
+ this.state = value;
}
public void interacted(E result) {
diff --git a/src/main/java/org/cryptomator/ui/lock/LockForcedController.java b/src/main/java/org/cryptomator/ui/lock/LockForcedController.java
index 8d4ce32d3..c3a452acc 100644
--- a/src/main/java/org/cryptomator/ui/lock/LockForcedController.java
+++ b/src/main/java/org/cryptomator/ui/lock/LockForcedController.java
@@ -35,7 +35,13 @@ public class LockForcedController implements FxController {
}
@FXML
- public void confirmForcedLock() {
+ public void retry() {
+ forceLockDecisionLock.interacted(LockModule.ForceLockDecision.RETRY);
+ window.close();
+ }
+
+ @FXML
+ public void force() {
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.FORCE);
window.close();
}
@@ -54,4 +60,8 @@ public class LockForcedController implements FxController {
return vault.getDisplayName();
}
+ public boolean isForceSupported() {
+ return vault.supportsForcedUnmount();
+ }
+
}
diff --git a/src/main/java/org/cryptomator/ui/lock/LockModule.java b/src/main/java/org/cryptomator/ui/lock/LockModule.java
index 160dcf6fb..d1eb5f189 100644
--- a/src/main/java/org/cryptomator/ui/lock/LockModule.java
+++ b/src/main/java/org/cryptomator/ui/lock/LockModule.java
@@ -28,6 +28,7 @@ abstract class LockModule {
enum ForceLockDecision {
CANCEL,
+ RETRY,
FORCE;
}
diff --git a/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java
index 73b4844b9..00b25c507 100644
--- a/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java
+++ b/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java
@@ -51,20 +51,26 @@ public class LockWorkflow extends Task {
@Override
protected Void call() throws Volume.VolumeException, InterruptedException, LockNotCompletedException {
- try {
- vault.lock(false);
- } catch (Volume.VolumeException | LockNotCompletedException e) {
- LOG.debug("Regular lock of {} failed.", vault.getDisplayName(), e);
- var decision = askUserForAction();
- switch (decision) {
- case FORCE -> vault.lock(true);
- case CANCEL -> cancel(false);
- }
- }
+ lock(false);
return null;
}
+ private void lock(boolean forced) throws InterruptedException {
+ try {
+ vault.lock(forced);
+ } catch (Volume.VolumeException | LockNotCompletedException e) {
+ LOG.info("Locking {} failed (forced: {}).", vault.getDisplayName(), forced, e);
+ var decision = askUserForAction();
+ switch (decision) {
+ case RETRY -> lock(false);
+ case FORCE -> lock(true);
+ case CANCEL -> cancel(false);
+ }
+ }
+ }
+
private LockModule.ForceLockDecision askUserForAction() throws InterruptedException {
+ forceLockDecisionLock.reset(null);
// show forcedLock dialogue ...
Platform.runLater(() -> {
lockWindow.setScene(lockForcedScene.get());
diff --git a/src/main/java/org/cryptomator/ui/preferences/SupporterCertificateController.java b/src/main/java/org/cryptomator/ui/preferences/SupporterCertificateController.java
index 02b8bab91..db2554d67 100644
--- a/src/main/java/org/cryptomator/ui/preferences/SupporterCertificateController.java
+++ b/src/main/java/org/cryptomator/ui/preferences/SupporterCertificateController.java
@@ -34,10 +34,10 @@ public class SupporterCertificateController implements FxController {
public void initialize() {
supporterCertificateField.setText(licenseHolder.getLicenseKey().orElse(null));
supporterCertificateField.textProperty().addListener(this::registrationKeyChanged);
- supporterCertificateField.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength));
+ supporterCertificateField.setTextFormatter(new TextFormatter<>(this::removeWhitespaces));
}
- private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) {
+ private TextFormatter.Change removeWhitespaces(TextFormatter.Change change) {
if (change.isContentChange()) {
var strippedText = CharMatcher.whitespace().removeFrom(change.getText());
change.setText(strippedText);
diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java
index a35b108d9..633797820 100644
--- a/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java
+++ b/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java
@@ -47,7 +47,7 @@ public class GeneralVaultOptionsController implements FxController {
public void initialize() {
vaultName.textProperty().set(vault.getVaultSettings().displayName().get());
vaultName.focusedProperty().addListener(this::trimVaultNameOnFocusLoss);
- vaultName.setTextFormatter(new TextFormatter<>(this::removeWhitespaces));
+ vaultName.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength));
unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup());
actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
@@ -63,7 +63,7 @@ public class GeneralVaultOptionsController implements FxController {
}
}
- private TextFormatter.Change removeWhitespaces(TextFormatter.Change change) {
+ private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) {
if (change.isContentChange() && change.getControlNewText().length() > VAULTNAME_TRUNCATE_THRESHOLD) {
return null; // reject any change that would lead to a text exceeding threshold
} else {
diff --git a/src/main/resources/fxml/lock_forced.fxml b/src/main/resources/fxml/lock_forced.fxml
index 4596af119..b0b5baa63 100644
--- a/src/main/resources/fxml/lock_forced.fxml
+++ b/src/main/resources/fxml/lock_forced.fxml
@@ -33,11 +33,11 @@
-
+
-
-
+
+
diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties
index 1cb5eb0b8..7b17fa791 100644
--- a/src/main/resources/i18n/strings.properties
+++ b/src/main/resources/i18n/strings.properties
@@ -118,9 +118,10 @@ unlock.error.invalidMountPoint.existing=Mount point "%s" already exists or paren
# Lock
## Force
-lock.forced.heading=Graceful lock failed
+lock.forced.heading=Lock failed
lock.forced.message=Locking "%s" was blocked by pending operations or open files. You can force lock this vault, however interrupting I/O may result in the loss of unsaved data.
-lock.forced.confirmBtn=Force Lock
+lock.forced.retryBtn=Retry
+lock.forced.forceBtn=Force Lock
## Failure
lock.fail.heading=Locking vault failed.
lock.fail.message=Vault "%s" could not be locked. Ensure unsaved work is saved elsewhere and important Read/Write operations are finished. In order to close the vault, kill the Cryptomator process.