diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml new file mode 100644 index 000000000..aab954476 --- /dev/null +++ b/.github/workflows/appimage.yml @@ -0,0 +1,151 @@ +name: Build AppImage + +on: + release: + types: [published] + workflow_dispatch: + +env: + JAVA_VERSION: 17 + +jobs: + build: + name: Build AppImage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + - id: versions + name: Apply version information + run: | + if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR=${GITHUB_REF##*/} + mvn versions:set -DnewVersion=${SEM_VER_STR} + else + SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` + fi + SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` + REVCOUNT=`git rev-list --count HEAD` + echo "::set-output name=semVerStr::${SEM_VER_STR}" + echo "::set-output name=semVerNum::${SEM_VER_NUM}" + echo "::set-output name=revNum::${REVCOUNT}" + - name: Validate Version + uses: skymatic/semver-validation-action@v1 + with: + version: ${{ steps.versions.outputs.semVerStr }} + - name: Run maven + run: mvn -B clean package -Pdependency-check,linux -DskipTests + - name: Patch target dir + run: | + cp LICENSE.txt target + cp dist/linux/launcher.sh target + cp target/cryptomator-*.jar target/mods + - name: Run jlink + run: > + ${JAVA_HOME}/bin/jlink + --verbose + --output runtime + --module-path "${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,jdk.management.jfr + --no-header-files + --no-man-pages + --strip-debug + --compress=1 + - name: Run jpackage + run: > + ${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 appdir + --name Cryptomator + --vendor "Skymatic GmbH" + --copyright "(C) 2016 - 2022 Skymatic GmbH" + --app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}" + --java-options "-Xss5m" + --java-options "-Xmx256m" + --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\"" + --java-options "-Dfile.encoding=\"utf-8\"" + --java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" + --java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" + --java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" + --java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" + --java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" + --java-options "-Dcryptomator.showTrayIcon=false" + --java-options "-Dcryptomator.buildNumber=\"appimage-${{ steps.versions.outputs.revNum }}\"" + --resource-dir dist/linux/resources + - name: Patch Cryptomator.AppDir + run: | + mv appdir/Cryptomator Cryptomator.AppDir + cp -r dist/linux/appimage/resources/AppDir/* Cryptomator.AppDir/ + envsubst '${REVISION_NO} ${SEMVER_STR}' < dist/linux/appimage/resources/AppDir/bin/cryptomator.sh > Cryptomator.AppDir/bin/cryptomator.sh + cp dist/linux/common/org.cryptomator.Cryptomator256.png Cryptomator.AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png + cp dist/linux/common/org.cryptomator.Cryptomator512.png Cryptomator.AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png + cp dist/linux/common/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg + cp dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.metainfo.xml + cp dist/linux/common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop + cp dist/linux/common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml + ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg + ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg + ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon + ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop + ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun + env: + REVISION_NO: ${{ steps.versions.outputs.revNum }} + SEMVER_STR: ${{ steps.versions.outputs.semVerStr }} + - name: Extract libjffi.so # workaround for https://github.com/cryptomator/cryptomator-linux/issues/27 + run: | + JFFI_NATIVE_JAR=`ls lib/app/ | grep -e 'jffi-[1-9]\.[0-9]\{1,2\}.[0-9]\{1,2\}-native.jar'` + ${JAVA_HOME}/bin/jar -xf lib/app/${JFFI_NATIVE_JAR} /jni/x86_64-Linux/ + mv jni/x86_64-Linux/* lib/app/libjffi.so + working-directory: Cryptomator.AppDir + - name: Download AppImageKit + run: | + curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o appimagetool.AppImage + chmod +x appimagetool.AppImage + ./appimagetool.AppImage --appimage-extract + - name: Prepare GPG-Agent for signing with key 615D449FE6E6A235 + run: | + echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import + echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --dry-run --sign README.md + env: + GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - name: Build AppImage + run: > + ./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ steps.versions.outputs.semVerStr }}-x86_64.AppImage + -u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync' + --sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback" + - name: Create detached GPG signatures + run: | + gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage + gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage.zsync + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: appimage + path: | + cryptomator-*.AppImage + cryptomator-*.AppImage.zsync + cryptomator-*.asc + if-no-files-found: error + - name: Publish AppImage on GitHub Releases + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + fail_on_unmatched_files: true + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + files: | + cryptomator-*.AppImage + cryptomator-*.zsync + cryptomator-*.asc \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 750b64826..40d2b2e1b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,4 +48,16 @@ jobs: run: bash <(curl -Ls https://coverage.codacy.com/get.sh) env: CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} - continue-on-error: true \ No newline at end of file + continue-on-error: true + - name: Draft a release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + draft: true + discussion_category_name: releases + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + generate_release_notes: true + body: |- + :construction: Work in Progress + + --- diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml new file mode 100644 index 000000000..f7893bbaa --- /dev/null +++ b/.github/workflows/debian.yml @@ -0,0 +1,118 @@ +name: Build Debian Package + +on: + release: + types: [published] + workflow_dispatch: + inputs: + dput: + description: 'Upload to PPA' + required: true + default: false + type: boolean + +env: + JAVA_VERSION: 17 + +jobs: + build: + name: Build Debian Package + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get install debhelper devscripts dput + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + - id: versions + name: Apply version information + run: | + if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR=${GITHUB_REF##*/} + mvn versions:set -DnewVersion=${SEM_VER_STR} + else + SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` + fi + SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` + REVCOUNT=`git rev-list --count HEAD` + echo "::set-output name=semVerStr::${SEM_VER_STR}" + echo "::set-output name=semVerNum::${SEM_VER_NUM}" + echo "::set-output name=revNum::${REVCOUNT}" + echo "::set-output name=ppaVerStr::${SEM_VER_STR/-/\~}-${REVCOUNT}" + - name: Validate Version + uses: skymatic/semver-validation-action@v1 + with: + version: ${{ steps.versions.outputs.semVerStr }} + - name: Run maven + run: mvn -B clean package -Pdependency-check,linux -DskipTests + - name: Create orig.tar.gz with common/ libs/ mods/ + run: | + mkdir pkgdir + cp -r target/libs pkgdir + cp -r target/mods pkgdir + cp -r dist/linux/common/ pkgdir + cp target/cryptomator-*.jar pkgdir/mods + tar -cJf cryptomator_${{ steps.versions.outputs.ppaVerStr }}.orig.tar.xz -C pkgdir . + - name: Patch and rename pkgdir + run: | + cp -r dist/linux/debian/ pkgdir + export RFC2822_TIMESTAMP=`date --rfc-2822` + envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM}' < dist/linux/debian/rules > pkgdir/debian/rules + envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog + find . -name "*.jar" >> pkgdir/debian/source/include-binaries + mv pkgdir cryptomator_${{ steps.versions.outputs.ppaVerStr }} + env: + SEMVER_STR: ${{ steps.versions.outputs.semVerStr }} + VERSION_NUM: ${{ steps.versions.outputs.semVerNum }} + REVISION_NUM: ${{ steps.versions.outputs.revNum }} + PPA_VERSION: ${{ steps.versions.outputs.ppaVerStr }}-0ppa1 + - name: Prepare GPG-Agent for signing with key 615D449FE6E6A235 + run: | + echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import + echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --dry-run --sign README.md + env: + GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - name: debuild + run: | + debuild -S -sa -d + debuild -b -sa -d + env: + DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback + DEBSIGN_KEYID: 615D449FE6E6A235 + working-directory: cryptomator_${{ steps.versions.outputs.ppaVerStr }} + - name: Create detached GPG signatures + run: | + gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: linux-deb-package + path: | + cryptomator_*.dsc + cryptomator_*.orig.tar.xz + cryptomator_*.debian.tar.xz + cryptomator_*_source.buildinfo + cryptomator_*_source.changes + cryptomator_*_amd64.deb + cryptomator_*.asc + - name: Publish on PPA + if: startsWith(github.ref, 'refs/tags/') || github.event.inputs.dput == 'true' + run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes + - name: Publish Debian package on GitHub Releases + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + fail_on_unmatched_files: true + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + files: | + cryptomator_*_amd64.deb + cryptomator_*.asc \ No newline at end of file diff --git a/.github/workflows/mac-dmg.yml b/.github/workflows/mac-dmg.yml new file mode 100644 index 000000000..66af92d6d --- /dev/null +++ b/.github/workflows/mac-dmg.yml @@ -0,0 +1,232 @@ +name: Build macOS .dmg + +on: + release: + types: [published] + workflow_dispatch: + +env: + JAVA_VERSION: 17 + +jobs: + build: + name: Build Cryptomator.app + runs-on: macos-11 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + - id: versions + name: Apply version information + run: | + if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR=${GITHUB_REF##*/} + mvn versions:set -DnewVersion=${SEM_VER_STR} + else + SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` + fi + SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` + REVCOUNT=`git rev-list --count HEAD` + echo "::set-output name=semVerStr::${SEM_VER_STR}" + echo "::set-output name=semVerNum::${SEM_VER_NUM}" + echo "::set-output name=revNum::${REVCOUNT}" + - name: Validate Version + uses: skymatic/semver-validation-action@v1 + with: + version: ${{ steps.versions.outputs.semVerStr }} + - name: Run maven + run: mvn -B clean package -Pdependency-check,mac -DskipTests + - name: Patch target dir + run: | + cp LICENSE.txt target + cp dist/mac/launcher.sh target + cp target/cryptomator-*.jar target/mods + - name: Run jlink + run: > + ${JAVA_HOME}/bin/jlink + --verbose + --output runtime + --module-path "${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,jdk.management.jfr + --strip-native-commands + --no-header-files + --no-man-pages + --strip-debug + --compress=1 + - name: Run jpackage + run: > + ${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 appdir + --name Cryptomator + --vendor "Skymatic GmbH" + --copyright "(C) 2016 - 2022 Skymatic GmbH" + --app-version "${{ steps.versions.outputs.semVerNum }}" + --java-options "-Xss5m" + --java-options "-Xmx256m" + --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\"" + --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\"" + --java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\"" + --java-options "-Dcryptomator.showTrayIcon=true" + --java-options "-Dcryptomator.buildNumber=\"dmg-${{ steps.versions.outputs.revNum }}\"" + --mac-package-identifier org.cryptomator + --resource-dir dist/mac/resources + - name: Patch Cryptomator.app + run: | + mv appdir/Cryptomator.app Cryptomator.app + mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/ + sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist + sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist + env: + VERSION_NO: ${{ steps.versions.outputs.semVerNum }} + REVISION_NO: ${{ steps.versions.outputs.revNum }} + - name: Install codesign certificate + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain-db + + # import certificate and provisioning profile from secrets + echo -n "$CODESIGN_P12_BASE64" | base64 --decode --output $CERTIFICATE_PATH + + # create temporary keychain + security create-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH + security set-keychain-settings -lut 900 $KEYCHAIN_PATH + security unlock-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH + + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$CODESIGN_P12_PW" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + env: + CODESIGN_P12_BASE64: ${{ secrets.MACOS_CODESIGN_P12_BASE64 }} + CODESIGN_P12_PW: ${{ secrets.MACOS_CODESIGN_P12_PW }} + CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }} + - name: Codesign + run: | + find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do + if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then + JAR_FILENAME=$(basename ${JAR_PATH}) + OUTPUT_PATH=${JAR_PATH%.*} + echo "Codesigning libs in ${JAR_FILENAME}..." + unzip -q ${JAR_PATH} -d ${OUTPUT_PATH} + find ${OUTPUT_PATH} -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + find ${OUTPUT_PATH} -name '*.jnilib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + rm ${JAR_PATH} + pushd ${OUTPUT_PATH} > /dev/null + zip -qr ../${JAR_FILENAME} * + popd > /dev/null + rm -r ${OUTPUT_PATH} + fi + done + echo "Codesigning Cryptomator.app..." + codesign --force --deep --entitlements dist/mac/Cryptomator.entitlements -o runtime -s ${CODESIGN_IDENTITY} Cryptomator.app + env: + CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} + - name: Prepare .dmg contents + run: | + mkdir dmg + mv Cryptomator.app dmg + cp dist/mac/dmg/resources/macFUSE.webloc dmg + ls -l dmg + - name: Install create-dmg + run: | + brew install create-dmg + create-dmg --help + - name: Create .dmg + run: > + create-dmg + --volname Cryptomator + --volicon "dist/mac/dmg/resources/Cryptomator-Volume.icns" + --background "dist/mac/dmg/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 "dist/mac/dmg/resources/license.rtf" + --icon ".background" 128 758 + --icon ".fseventsd" 320 758 + --icon ".VolumeIcon.icns" 512 758 + Cryptomator-${VERSION_NO}.dmg dmg + env: + VERSION_NO: ${{ steps.versions.outputs.semVerNum }} + - name: Install notarization credentials + if: startsWith(github.ref, 'refs/tags/') + run: | + # create temporary keychain + KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db + security create-keychain -p "${NOTARIZATION_TMP_KEYCHAIN_PW}" ${KEYCHAIN_PATH} + security set-keychain-settings -lut 900 ${KEYCHAIN_PATH} + security unlock-keychain -p "${NOTARIZATION_TMP_KEYCHAIN_PW}" ${KEYCHAIN_PATH} + + # import credentials from secrets + sudo xcode-select -s /Applications/Xcode_13.0.app + xcrun notarytool store-credentials "${NOTARIZATION_KEYCHAIN_PROFILE}" --apple-id "${NOTARIZATION_APPLE_ID}" --password "${NOTARIZATION_PW}" --team-id "${NOTARIZATION_TEAM_ID}" --keychain "${KEYCHAIN_PATH}" + env: + NOTARIZATION_KEYCHAIN_PROFILE: ${{ secrets.MACOS_NOTARIZATION_KEYCHAIN_PROFILE }} + NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }} + NOTARIZATION_PW: ${{ secrets.MACOS_NOTARIZATION_PW }} + NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} + NOTARIZATION_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_NOTARIZATION_TMP_KEYCHAIN_PW }} + - name: Notarize .dmg + if: startsWith(github.ref, 'refs/tags/') + run: | + KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db + sudo xcode-select -s /Applications/Xcode_13.0.app + xcrun notarytool submit Cryptomator-*.dmg --keychain-profile "${NOTARIZATION_KEYCHAIN_PROFILE}" --keychain "${KEYCHAIN_PATH}" --wait + xcrun stapler staple Cryptomator-*.dmg + env: + NOTARIZATION_KEYCHAIN_PROFILE: ${{ secrets.MACOS_NOTARIZATION_KEYCHAIN_PROFILE }} + - name: Add possible alpha/beta tags to installer name + run: mv Cryptomator-*.dmg Cryptomator-${{ steps.versions.outputs.semVerStr }}.dmg + - name: Create detached GPG signature with key 615D449FE6E6A235 + run: | + echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import + echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a Cryptomator-*.dmg + env: + GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - name: Clean up codesign certificate + if: ${{ always() }} + run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db + continue-on-error: true + - name: Clean up notarization credentials + if: ${{ always() }} + run: security delete-keychain $RUNNER_TEMP/notarization.keychain-db + continue-on-error: true + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: dmg + path: Cryptomator-*.dmg + if-no-files-found: error + - name: Publish dmg on GitHub Releases + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + fail_on_unmatched_files: true + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + files: | + Cryptomator-*.dmg + Cryptomator-*.asc + + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 630d5bbf2..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,630 +0,0 @@ -name: Installers and Release - -on: - workflow_dispatch: - inputs: - semver: - description: 'SemVer' - required: true - default: '0.99.99-SNAPSHOT' - push: - tags: # see https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet - - '[0-9]+.[0-9]+.[0-9]+' - - '[0-9]+.[0-9]+.[0-9]+-*' - -env: - JAVA_VERSION: 17 - -defaults: - run: - shell: bash - -jobs: - -# -# Buildkit -# - buildkit: - name: Build ${{ matrix.profile }}-buildkit - runs-on: ${{ matrix.os }} - strategy: - fail-fast: true - matrix: - include: - - os: ubuntu-latest - profile: linux - - os: windows-latest - profile: win - - os: macos-latest - profile: mac - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: ${{ env.JAVA_VERSION }} - 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/') - - name: Build and Test - run: mvn -B clean package -Pdependency-check,${{ matrix.profile }} - - name: Patch buildkit - run: | - cp LICENSE.txt target - cp dist/${{ matrix.profile }}/launcher* target - cp target/cryptomator-*.jar target/mods - - name: Upload ${{ matrix.profile }}-buildkit - uses: actions/upload-artifact@v2 - with: - name: ${{ matrix.profile }}-buildkit - path: | - target/libs - target/mods - target/LICENSE.txt - target/launcher* - if-no-files-found: error - -# -# Release Metadata -# - metadata: - name: Determine Version Metadata - runs-on: ubuntu-latest - outputs: - semVerNum: ${{ steps.versions.outputs.semVerNum }} - semVerStr: ${{ steps.versions.outputs.semVerStr }} - ppaVerStr: ${{ steps.versions.outputs.ppaVerStr }} - revNum: ${{ steps.versions.outputs.revNum }} - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - id: versions - run: | - if [[ $GITHUB_REF == refs/tags/* ]]; then - SEM_VER_STR=${GITHUB_REF##*/} - else - SEM_VER_STR=${{ github.event.inputs.semver }} - fi - SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` - REVCOUNT=`git rev-list --count HEAD` - echo "::set-output name=semVerStr::${SEM_VER_STR}" - echo "::set-output name=semVerNum::${SEM_VER_NUM}" - echo "::set-output name=ppaVerStr::${SEM_VER_STR/-/\~}-${REVCOUNT}" - echo "::set-output name=revNum::${REVCOUNT}" - - uses: skymatic/semver-validation-action@v1 - with: - version: ${{ steps.versions.outputs.semVerStr }} - -# -# Application Directory -# - appdir: - name: Create ${{ matrix.profile }}-appdir - needs: [buildkit, metadata] - runs-on: ${{ matrix.os }} - strategy: - fail-fast: true - matrix: - include: - - os: ubuntu-latest - profile: linux - jpackageoptions: > - --app-version "${{ needs.metadata.outputs.semVerNum }}.${{ needs.metadata.outputs.revNum }}" - --java-options "-Dfile.encoding=\"utf-8\"" - --java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" - --java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" - --java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" - --java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" - --java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" - --java-options "-Dcryptomator.showTrayIcon=false" - --java-options "-Dcryptomator.buildNumber=\"appimage-${{ needs.metadata.outputs.revNum }}\"" - --resource-dir dist/linux/resources - - os: windows-latest - profile: win - jpackageoptions: > - --app-version "${{ needs.metadata.outputs.semVerNum }}.${{ needs.metadata.outputs.revNum }}" - --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-${{ needs.metadata.outputs.revNum }}\"" - --resource-dir dist/win/resources - --icon dist/win/resources/Cryptomator.ico - - os: macos-latest - profile: mac - jpackageoptions: > - --app-version "${{ needs.metadata.outputs.semVerNum }}" - --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\"" - --java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\"" - --java-options "-Dcryptomator.showTrayIcon=true" - --java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.metadata.outputs.revNum }}\"" - --mac-package-identifier org.cryptomator - --resource-dir dist/mac/resources - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: ${{ env.JAVA_VERSION }} - - name: Download ${{ matrix.profile }}-buildkit - uses: actions/download-artifact@v2 - with: - name: ${{ matrix.profile }}-buildkit - path: buildkit - - name: Create Runtime Image - run: > - ${JAVA_HOME}/bin/jlink - --verbose - --output runtime - --module-path "${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 - - name: Create App Directory - run: > - ${JAVA_HOME}/bin/jpackage - --verbose - --type app-image - --runtime-image runtime - --input buildkit/libs - --module-path buildkit/mods - --module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator - --dest appdir - --name Cryptomator - --vendor "Skymatic GmbH" - --copyright "(C) 2016 - 2022 Skymatic GmbH" - --java-options "-Xss5m" - --java-options "-Xmx256m" - --java-options "-Dcryptomator.appVersion=\"${{ needs.metadata.outputs.semVerStr }}\"" - ${{ matrix.jpackageoptions }} - - name: Create appdir.tar - run: tar -cvf appdir.tar appdir - - name: Upload ${{ matrix.profile }}-appdir - uses: actions/upload-artifact@v2 - with: - name: ${{ matrix.profile }}-appdir - path: appdir.tar - if-no-files-found: error - -# -# Linux PPA Source Package -# - ppa: - name: Upload source package to PPA - needs: [buildkit, metadata] - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - name: install build tools - run: | - sudo apt-get update - sudo apt-get install debhelper devscripts dput - - name: Download linux-buildkit - uses: actions/download-artifact@v2 - with: - name: linux-buildkit - path: pkgdir - - name: create orig.tar.gz - run: tar -cJf cryptomator_${{ needs.metadata.outputs.ppaVerStr }}.orig.tar.xz -C pkgdir . - - name: patch and rename pkgdir - run: | - cp -r dist/linux/debian/ pkgdir - cp -r dist/linux/resources/ pkgdir - export RFC2822_TIMESTAMP=`date --rfc-2822` - envsubst '${VERSION_STR} ${VERSION_NUM} ${REVISION_NUM}' < dist/linux/debian/rules > pkgdir/debian/rules - envsubst '${VERSION_STR}' < dist/linux/debian/org.cryptomator.Cryptomator.desktop > pkgdir/debian/org.cryptomator.Cryptomator.desktop - envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog - find . -name "*.jar" >> pkgdir/debian/source/include-binaries - mv pkgdir cryptomator_${{ needs.metadata.outputs.ppaVerStr }} - env: - VERSION_STR: ${{ needs.metadata.outputs.semVerStr }} - VERSION_NUM: ${{ needs.metadata.outputs.semVerNum }} - REVISION_NUM: ${{ needs.metadata.outputs.revNum }} - PPA_VERSION: ${{ needs.metadata.outputs.ppaVerStr }}-0ppa1 - - name: import gpg key 615D449FE6E6A235 - run: | - echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import - echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --dry-run --sign dist/linux/debian/rules - env: - GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} - GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} - - name: debuild - run: debuild -S -sa -d - env: - DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback - DEBSIGN_KEYID: 615D449FE6E6A235 - working-directory: cryptomator_${{ needs.metadata.outputs.ppaVerStr }} - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - name: linux-deb-source-package - path: | - cryptomator_*.dsc - cryptomator_*.orig.tar.xz - cryptomator_*.debian.tar.xz - cryptomator_*_source.changes - cryptomator_*_source.buildinfo - - name: dput to beta repo - run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_${PPA_VERSION}_source.changes - env: - PPA_VERSION: ${{ needs.metadata.outputs.ppaVerStr }}-0ppa1 - -# -# Linux Cryptomator.AppImage -# - linux-appimage: - name: Build Cryptomator.AppImage - runs-on: ubuntu-latest - needs: [appdir, metadata] - steps: - - uses: actions/checkout@v2 - - name: Download linux-appdir - uses: actions/download-artifact@v2 - with: - name: linux-appdir - - name: Untar appdir.tar - run: | - tar -xvf appdir.tar - - name: Patch Cryptomator.AppDir - run: | - mv appdir/Cryptomator Cryptomator.AppDir - cp -r dist/linux/appimage/resources/AppDir/* Cryptomator.AppDir/ - envsubst '${REVISION_NO} ${SEMVER_STR}' < dist/linux/appimage/resources/AppDir/bin/cryptomator.sh > Cryptomator.AppDir/bin/cryptomator.sh - ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg - ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg - ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon - ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop - ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun - env: - REVISION_NO: ${{ needs.metadata.outputs.revNum }} - SEMVER_STR: ${{ needs.metadata.outputs.semVerStr }} - - name: Extract libjffi.so # workaround for https://github.com/cryptomator/cryptomator-linux/issues/27 - run: | - JFFI_NATIVE_JAR=`ls lib/app/ | grep -e 'jffi-[1-9]\.[0-9]\{1,2\}.[0-9]\{1,2\}-native.jar'` - ${JAVA_HOME}/bin/jar -xf lib/app/${JFFI_NATIVE_JAR} /jni/x86_64-Linux/ - mv jni/x86_64-Linux/* lib/app/libjffi.so - working-directory: Cryptomator.AppDir - - name: Download AppImageKit - run: | - curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o appimagetool.AppImage - chmod +x appimagetool.AppImage - ./appimagetool.AppImage --appimage-extract - - name: Prepare GPG-Agent for signing with key 615D449FE6E6A235 - run: | - echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import - echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --dry-run --sign Cryptomator.AppDir/AppRun - env: - GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} - GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} - - name: Build AppImage - run: > - ./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.metadata.outputs.semVerStr }}-x86_64.AppImage - -u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync' - --sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback" - - name: Upload AppImage - uses: actions/upload-artifact@v2 - with: - name: linux-appimage - path: | - cryptomator-*.AppImage - cryptomator-*.AppImage.zsync - if-no-files-found: error - -# -# macOS Cryptomator.app -# - mac-app: - name: Build Cryptomator.app - runs-on: macos-latest - needs: [appdir, metadata] - steps: - - uses: actions/checkout@v2 - - name: Download mac-appdir - uses: actions/download-artifact@v2 - with: - name: mac-appdir - - name: Untar appdir.tar - run: tar -xvf appdir.tar - - name: Patch Cryptomator.app - run: | - mv appdir/Cryptomator.app Cryptomator.app - mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/ - sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist - sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist - env: - VERSION_NO: ${{ needs.metadata.outputs.semVerNum }} - REVISION_NO: ${{ needs.metadata.outputs.revNum }} - - name: Install codesign certificate - env: - CODESIGN_P12_BASE64: ${{ secrets.MACOS_CODESIGN_P12_BASE64 }} - CODESIGN_P12_PW: ${{ secrets.MACOS_CODESIGN_P12_PW }} - CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }} - run: | - # create variables - CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12 - KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain-db - - # import certificate and provisioning profile from secrets - echo -n "$CODESIGN_P12_BASE64" | base64 --decode --output $CERTIFICATE_PATH - - # create temporary keychain - security create-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH - security set-keychain-settings -lut 900 $KEYCHAIN_PATH - security unlock-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH - - # import certificate to keychain - security import $CERTIFICATE_PATH -P "$CODESIGN_P12_PW" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH - security list-keychain -d user -s $KEYCHAIN_PATH - - name: Codesign - env: - CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} - run: | - find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; - for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do - if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then - JAR_FILENAME=$(basename ${JAR_PATH}) - OUTPUT_PATH=${JAR_PATH%.*} - echo "Codesigning libs in ${JAR_FILENAME}..." - unzip -q ${JAR_PATH} -d ${OUTPUT_PATH} - find ${OUTPUT_PATH} -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; - find ${OUTPUT_PATH} -name '*.jnilib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; - rm ${JAR_PATH} - pushd ${OUTPUT_PATH} > /dev/null - zip -qr ../${JAR_FILENAME} * - popd > /dev/null - rm -r ${OUTPUT_PATH} - fi - done - echo "Codesigning Cryptomator.app..." - codesign --force --deep --entitlements dist/mac/Cryptomator.entitlements -o runtime -s ${CODESIGN_IDENTITY} Cryptomator.app - - name: Clean up codesign certificate - if: ${{ always() }} - run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db - - name: Create app.tar - run: tar -cvf app.tar Cryptomator.app - - name: Upload mac-app - uses: actions/upload-artifact@v2 - with: - name: mac-app - path: app.tar - if-no-files-found: error - -# -# macOS Cryptomator.dmg -# - mac-dmg: - name: Build Cryptomator.dmg - runs-on: macos-11 - needs: [mac-app, metadata] - steps: - - uses: actions/checkout@v2 - - name: Download mac-appdir - uses: actions/download-artifact@v2 - with: - name: mac-app - - name: Untar app.tar - run: tar -xvf app.tar - - name: Prepare .dmg contents - run: | - mkdir dmg - mv Cryptomator.app dmg - cp dist/mac/dmg/resources/macFUSE.webloc dmg - ls -l dmg - - name: Install create-dmg - run: | - brew install create-dmg - create-dmg --help - - name: Create .dmg - run: > - create-dmg - --volname Cryptomator - --volicon "dist/mac/dmg/resources/Cryptomator-Volume.icns" - --background "dist/mac/dmg/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 "dist/mac/dmg/resources/license.rtf" - --icon ".background" 128 758 - --icon ".fseventsd" 320 758 - --icon ".VolumeIcon.icns" 512 758 - Cryptomator-${VERSION_NO}.dmg dmg - env: - VERSION_NO: ${{ needs.metadata.outputs.semVerNum }} - - name: Install notarization credentials - env: - NOTARIZATION_KEYCHAIN_PROFILE: ${{ secrets.MACOS_NOTARIZATION_KEYCHAIN_PROFILE }} - NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }} - NOTARIZATION_PW: ${{ secrets.MACOS_NOTARIZATION_PW }} - NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} - NOTARIZATION_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_NOTARIZATION_TMP_KEYCHAIN_PW }} - run: | - # create temporary keychain - KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db - security create-keychain -p "${NOTARIZATION_TMP_KEYCHAIN_PW}" ${KEYCHAIN_PATH} - security set-keychain-settings -lut 900 ${KEYCHAIN_PATH} - security unlock-keychain -p "${NOTARIZATION_TMP_KEYCHAIN_PW}" ${KEYCHAIN_PATH} - - # import credentials from secrets - sudo xcode-select -s /Applications/Xcode_13.0.app - xcrun notarytool store-credentials "${NOTARIZATION_KEYCHAIN_PROFILE}" --apple-id "${NOTARIZATION_APPLE_ID}" --password "${NOTARIZATION_PW}" --team-id "${NOTARIZATION_TEAM_ID}" --keychain "${KEYCHAIN_PATH}" - - name: Notarize .dmg - env: - NOTARIZATION_KEYCHAIN_PROFILE: ${{ secrets.MACOS_NOTARIZATION_KEYCHAIN_PROFILE }} - run: | - KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db - sudo xcode-select -s /Applications/Xcode_13.0.app - xcrun notarytool submit Cryptomator-*.dmg --keychain-profile "${NOTARIZATION_KEYCHAIN_PROFILE}" --keychain "${KEYCHAIN_PATH}" --wait - xcrun stapler staple Cryptomator-*.dmg - - name: Clean up notarization credentials - if: ${{ always() }} - run: security delete-keychain $RUNNER_TEMP/notarization.keychain-db - - name: Add possible alpha/beta tags to installer name - run: mv Cryptomator-*.dmg Cryptomator-${{ needs.metadata.outputs.semVerStr }}.dmg - - name: Upload mac-dmg - uses: actions/upload-artifact@v2 - with: - name: mac-dmg - path: Cryptomator-*.dmg - if-no-files-found: error - -# -# MSI package -# - win-msi: - name: Build Cryptomator.msi - runs-on: windows-latest - needs: [appdir, metadata] - steps: - - uses: actions/checkout@v2 - - name: Download win-appdir - uses: actions/download-artifact@v2 - with: - name: win-appdir - - name: Untar appdir.tar - run: tar -xvf appdir.tar - - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: ${{ env.JAVA_VERSION }} - - name: Patch Application Directory - run: | - cp dist/win/contrib/* appdir/Cryptomator - - name: Fix permissions - run: attrib -r appdir/Cryptomator/Cryptomator.exe - shell: pwsh - - name: Codesign - uses: skymatic/code-sign-action@v1 - with: - certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} - password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B - description: Cryptomator - timestampUrl: 'http://timestamp.digicert.com' - folder: appdir/Cryptomator - recursive: true - - name: Create MSI - run: > - ${JAVA_HOME}/bin/jpackage - --verbose - --type msi - --win-upgrade-uuid bda45523-42b1-4cae-9354-a45475ed4775 - --app-image appdir/Cryptomator - --dest installer - --name Cryptomator - --vendor "Skymatic GmbH" - --copyright "(C) 2016 - 2022 Skymatic GmbH" - --app-version "${{ needs.metadata.outputs.semVerNum }}" - --win-menu - --win-dir-chooser - --win-shortcut-prompt - --win-update-url "https:\\cryptomator.org" - --win-menu-group Cryptomator - --resource-dir dist/win/resources - --license-file dist/win/resources/license.rtf - --file-associations dist/win/resources/FAvaultFile.properties - env: - JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs - - name: Codesign MSI - uses: skymatic/code-sign-action@v1 - with: - certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} - password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B - description: Cryptomator Installer - timestampUrl: 'http://timestamp.digicert.com' - folder: installer - - name: Add possible alpha/beta tags to installer name - run: mv installer/Cryptomator-*.msi installer/Cryptomator-${{ needs.metadata.outputs.semVerStr }}-x64.msi - - name: Upload win-msi - uses: actions/upload-artifact@v2 - with: - name: win-msi - path: installer/*.msi - if-no-files-found: error - -# -# Release -# - release: - name: Draft a release on Github - runs-on: ubuntu-latest - needs: [metadata,linux-appimage,mac-dmg,win-msi,ppa] - if: startsWith(github.ref, 'refs/tags/') && github.repository == 'cryptomator/cryptomator' - steps: - - uses: actions/checkout@v2 - - name: Create tarball - run: git archive --prefix="cryptomator-${{ needs.metadata.outputs.semVerStr }}/" -o "cryptomator-${{ needs.metadata.outputs.semVerStr }}.tar.gz" ${{ github.ref }} - - name: Download linux appimage - uses: actions/download-artifact@v2 - with: - name: linux-appimage - - name: Download macOS dmg - uses: actions/download-artifact@v2 - with: - name: mac-dmg - - name: Download Windows msi - uses: actions/download-artifact@v2 - with: - name: win-msi - - name: Create detached GPG signature for all release files with key 615D449FE6E6A235 - run: | - echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import - for FILE in `find . -name "*.AppImage" -o -name "*.dmg" -o -name "*.msi" -o -name "*.zsync" -o -name "*.tar.gz"`; do - echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a ${FILE} - done - env: - GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} - GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} - - name: Compute SHA256 checksums of release artifacts - run: | - SHA256_SUMS=`find . -name "*.AppImage" -o -name "*.dmg" -o -name "*.msi" -o -name "*.tar.gz" | xargs sha256sum` - echo "SHA256_SUMS<> $GITHUB_ENV - echo "${SHA256_SUMS}" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - continue-on-error: true - - name: Create release draft - uses: softprops/action-gh-release@v1 - with: - draft: true - fail_on_unmatched_files: true - discussion_category_name: releases - token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} - files: | - *.AppImage - *.zsync - *.asc - *.dmg - *.msi - body: |- - :construction: Work in Progress - ## What's New - ## Bugfixes - ## Misc - - --- - - :scroll: A complete list of closed issues is available [here](LINK). - - --- - - :floppy_disk: SHA-256 checksums of release artifacts: - ``` - ${{ env.SHA256_SUMS }} - ``` diff --git a/.github/workflows/win-exe.yml b/.github/workflows/win-exe.yml new file mode 100644 index 000000000..f024d7347 --- /dev/null +++ b/.github/workflows/win-exe.yml @@ -0,0 +1,255 @@ +name: Build Windows Installer + +on: + release: + types: [published] + workflow_dispatch: + +env: + JAVA_VERSION: 17 + WINFSP_MSI: https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi + +defaults: + run: + shell: bash + +jobs: + build-msi: + name: Build .msi Installer + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + - id: versions + name: Apply version information + run: | + if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR=${GITHUB_REF##*/} + mvn versions:set -DnewVersion=${SEM_VER_STR} + else + SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` + fi + SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` + REVCOUNT=`git rev-list --count HEAD` + echo "::set-output name=semVerStr::${SEM_VER_STR}" + echo "::set-output name=semVerNum::${SEM_VER_NUM}" + echo "::set-output name=revNum::${REVCOUNT}" + - name: Validate Version + uses: skymatic/semver-validation-action@v1 + with: + version: ${{ steps.versions.outputs.semVerStr }} + - name: Run maven + run: mvn -B clean package -Pdependency-check,win -DskipTests + - name: Patch target dir + run: | + cp LICENSE.txt target + cp dist/linux/launcher.sh target + cp target/cryptomator-*.jar target/mods + - name: Run jlink + run: > + ${JAVA_HOME}/bin/jlink + --verbose + --output runtime + --module-path "${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,jdk.management.jfr + --strip-native-commands + --no-header-files + --no-man-pages + --strip-debug + --compress=1 + - name: Run jpackage + run: > + ${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 appdir + --name Cryptomator + --vendor "Skymatic GmbH" + --copyright "(C) 2016 - 2022 Skymatic GmbH" + --app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}" + --java-options "-Xss5m" + --java-options "-Xmx256m" + --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-${{ steps.versions.outputs.revNum }}\"" + --resource-dir dist/win/resources + --icon dist/win/resources/Cryptomator.ico + - name: Patch Application Directory + run: | + cp dist/win/contrib/* appdir/Cryptomator + - name: Fix permissions + run: attrib -r appdir/Cryptomator/Cryptomator.exe + shell: pwsh + - name: Codesign + uses: skymatic/code-sign-action@v1 + with: + certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} + password: ${{ secrets.WIN_CODESIGN_P12_PW }} + certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + description: Cryptomator + timestampUrl: 'http://timestamp.digicert.com' + folder: appdir/Cryptomator + recursive: true + - name: Generate license + run: > + mvn -B license:add-third-party + "-Dlicense.thirdPartyFilename=license.rtf" + "-Dlicense.fileTemplate=dist/win/resources/licenseTemplate.ftl" + "-Dlicense.outputDirectory=dist/win/resources" + - name: Create MSI + run: > + ${JAVA_HOME}/bin/jpackage + --verbose + --type msi + --win-upgrade-uuid bda45523-42b1-4cae-9354-a45475ed4775 + --app-image appdir/Cryptomator + --dest installer + --name Cryptomator + --vendor "Skymatic GmbH" + --copyright "(C) 2016 - 2022 Skymatic GmbH" + --app-version "${{ steps.versions.outputs.semVerNum }}" + --win-menu + --win-dir-chooser + --win-shortcut-prompt + --win-update-url "https:\\cryptomator.org" + --win-menu-group Cryptomator + --resource-dir dist/win/resources + --license-file dist/win/resources/license.rtf + --file-associations dist/win/resources/FAvaultFile.properties + env: + JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs + - name: Codesign MSI + uses: skymatic/code-sign-action@v1 + with: + certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} + password: ${{ secrets.WIN_CODESIGN_P12_PW }} + certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + description: Cryptomator Installer + timestampUrl: 'http://timestamp.digicert.com' + folder: installer + - name: Add possible alpha/beta tags to installer name + run: mv installer/Cryptomator-*.msi Cryptomator-${{ steps.versions.outputs.semVerStr }}-x64.msi + - name: Create detached GPG signature with key 615D449FE6E6A235 + run: | + echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import + echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a Cryptomator-*.msi + env: + GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: msi + path: | + Cryptomator-*.msi + Cryptomator-*.asc + if-no-files-found: error + - name: Publish .msi on GitHub Releases + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + fail_on_unmatched_files: true + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + files: | + *.msi + *.asc + outputs: + semVerNum: ${{ steps.versions.outputs.semVerNum }} + semVerStr: ${{ steps.versions.outputs.semVerStr }} + revNum: ${{ steps.versions.outputs.revNum }} + + build-exe: + name: Build .exe installer + runs-on: windows-latest + needs: [build-msi] + steps: + - uses: actions/checkout@v2 + - name: Download .msi + uses: actions/download-artifact@v2 + with: + name: msi + path: dist/win/bundle/resources + - name: Strip version info from msi file name + run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi + - uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + - name: Generate license + run: > + mvn -B license:add-third-party + "-Dlicense.thirdPartyFilename=license.rtf" + "-Dlicense.fileTemplate=dist/win/bundle/resources/licenseTemplate.ftl" + "-Dlicense.outputDirectory=dist/win/bundle/resources" + - name: Download WinFsp + run: + curl --output dist/win/bundle/resources/winfsp.msi -L ${{ env.WINFSP_MSI }} + - name: Compile to wixObj file + run: > + "${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs + -ext WixBalExtension + -out dist/win/bundle/ + -dBundleVersion="${{ needs.build-msi.outputs.semVerNum }}.${{ needs.build-msi.outputs.revNum }}" + -dBundleVendor="Skymatic GmbH" + -dBundleCopyright="(C) 2016 - 2022 Skymatic GmbH" + -dAboutUrl="https://cryptomator.org" + -dHelpUrl="https://cryptomator.org/contact" + -dUpdateUrl="https://cryptomator.org/downloads/" + - name: Create executable with linker + run: > + "${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj + -ext WixBalExtension + -out installer/Cryptomator.exe + - name: Codesign EXE + uses: skymatic/code-sign-action@v1 + with: + certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} + password: ${{ secrets.WIN_CODESIGN_P12_PW }} + certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + description: Cryptomator Installer + timestampUrl: 'http://timestamp.digicert.com' + folder: installer + - name: Add possible alpha/beta tags to installer name + run: mv installer/Cryptomator.exe Cryptomator-${{ needs.build-msi.outputs.semVerStr }}-x64.exe + - name: Create detached GPG signature with key 615D449FE6E6A235 + run: | + echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import + echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a Cryptomator-*.exe + env: + GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: exe + path: | + Cryptomator-*.exe + Cryptomator-*.asc + if-no-files-found: error + - name: Publish .msi on GitHub Releases + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + fail_on_unmatched_files: true + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + files: | + Cryptomator-*.exe + Cryptomator-*.asc \ No newline at end of file diff --git a/.gitignore b/.gitignore index be67207df..8e239b35e 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ pom.xml.versionsBackup .idea/jarRepositories.xml .idea/uiDesigner.xml .idea/**/libraries/ -*.iml \ No newline at end of file +*.iml + +hs_err_pid*.log \ No newline at end of file diff --git a/dist/linux/appimage/build.sh b/dist/linux/appimage/build.sh index 335532cba..6dd670df2 100755 --- a/dist/linux/appimage/build.sh +++ b/dist/linux/appimage/build.sh @@ -9,6 +9,7 @@ command -v mvn >/dev/null 2>&1 || { echo >&2 "mvn not found."; exit 1; } command -v curl >/dev/null 2>&1 || { echo >&2 "curl not found."; exit 1; } VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout) +SEMVER_STR=${VERSION} # compile mvn -B -f ../../../pom.xml clean package -DskipTests -Plinux @@ -18,7 +19,7 @@ cp ../../../target/cryptomator-*.jar ../../../target/mods ${JAVA_HOME}/bin/jlink \ --output runtime \ --module-path "${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 \ + --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,jdk.management.jfr \ --no-header-files \ --no-man-pages \ --strip-debug \ @@ -54,6 +55,12 @@ mv Cryptomator Cryptomator.AppDir cp -r resources/AppDir/* Cryptomator.AppDir/ chmod +x Cryptomator.AppDir/lib/runtime/bin/java envsubst '${REVISION_NO}' < resources/AppDir/bin/cryptomator.sh > Cryptomator.AppDir/bin/cryptomator.sh +cp ../common/org.cryptomator.Cryptomator256.png Cryptomator.AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png +cp ../common/org.cryptomator.Cryptomator512.png Cryptomator.AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png +cp ../common/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg +cp ../common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop +cp ../common/org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.metainfo.xml +cp ../common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon diff --git a/dist/linux/appimage/resources/AppDir/usr/share/applications/.gitkeep b/dist/linux/appimage/resources/AppDir/usr/share/applications/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/256x256/apps/.gitkeep b/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/256x256/apps/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/512x512/apps/.gitkeep b/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/512x512/apps/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/scalable/apps/.gitkeep b/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/scalable/apps/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg b/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg deleted file mode 100644 index b2e12a3c3..000000000 --- a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/linux/appimage/resources/AppDir/usr/share/metainfo/.gitkeep b/dist/linux/appimage/resources/AppDir/usr/share/metainfo/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/dist/linux/appimage/resources/AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml b/dist/linux/appimage/resources/AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml deleted file mode 100644 index ad4af6c70..000000000 --- a/dist/linux/appimage/resources/AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - org.cryptomator.Cryptomator - FSFAP - GPL-3.0-or-later - Cryptomator - Multi-platform client-side encryption tool optimized for cloud storages - -

- Cryptomator offers multi-platform transparent client-side encryption of your files in the cloud. -

-

- Features: -

    -
  • Works with Dropbox, Google Drive, OneDrive, ownCloud, Nextcloud and any other cloud storage service which synchronizes with a local directory
  • -
  • Open Source means: No backdoors, control is better than trust
  • -
  • Client-side: No accounts, no data shared with any online service
  • -
  • Totally transparent: Just work on the virtual drive as if it were a USB flash drive
  • -
  • AES encryption with 256-bit key length
  • -
  • 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:
  • -
-

-

- Privacy: -

    -
  • 256-bit keys (unlimited strength policy bundled with native binaries)
  • -
  • Scrypt key derivation
  • -
  • Cryptographically secure random numbers for salts, IVs and the masterkey of course
  • -
  • Sensitive data is wiped from the heap asap
  • -
  • Lightweight: Complexity kills security
  • -
-

-

- Consistency: -

    -
  • HMAC over file contents to recognize changed ciphertext before decryption
  • -
  • I/O operations are transactional and atomic, if the filesystems support it
  • -
  • Each file contains all information needed for decryption (except for the key of course), no common metadata means no Single Point of Failure
  • -
-

-
- - Office - Security - FileTools - Java - - http://cryptomator.org - https://github.com/cryptomator/cryptomator/issues - https://community.cryptomator.org/c/kb/faq - https://community.cryptomator.org/ - https://cryptomator.org/ - - none - none - none - none - mild - - Cryptomator - - cryptomator - - org.cryptomator.Cryptomator.desktop -
diff --git a/dist/linux/appimage/resources/AppDir/usr/share/mime/packages/.gitkeep b/dist/linux/appimage/resources/AppDir/usr/share/mime/packages/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/dist/linux/debian/cryptomator-vault.xml b/dist/linux/common/application-vnd.cryptomator.vault.xml similarity index 77% rename from dist/linux/debian/cryptomator-vault.xml rename to dist/linux/common/application-vnd.cryptomator.vault.xml index eeb4bc537..3b602f230 100644 --- a/dist/linux/debian/cryptomator-vault.xml +++ b/dist/linux/common/application-vnd.cryptomator.vault.xml @@ -1,6 +1,6 @@ - + Cryptomator Vault Metadata diff --git a/dist/linux/appimage/resources/AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop b/dist/linux/common/org.cryptomator.Cryptomator.desktop similarity index 71% rename from dist/linux/appimage/resources/AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop rename to dist/linux/common/org.cryptomator.Cryptomator.desktop index 3e1b34830..1872b9f38 100644 --- a/dist/linux/appimage/resources/AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop +++ b/dist/linux/common/org.cryptomator.Cryptomator.desktop @@ -6,5 +6,6 @@ Icon=org.cryptomator.Cryptomator Terminal=false Type=Application Categories=Utility;Security;FileTools; +StartupNotify=true StartupWMClass=org.cryptomator.launcher.Cryptomator -MimeType=application/vnd.cryptomator.encrypted;application/x-vnd.cryptomator.vault-metadata; +MimeType=application/vnd.cryptomator.encrypted;application/vnd.cryptomator.vault; diff --git a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml new file mode 100644 index 000000000..bdd0e178e --- /dev/null +++ b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml @@ -0,0 +1,71 @@ + + + + org.cryptomator.Cryptomator + FSFAP + GPL-3.0-or-later + Cryptomator + Multi-platform client-side encryption tool optimized for cloud storages + + +

+ Cryptomator provides transparent, client-side encryption for your cloud. Protect your documents from unauthorized + access. Cryptomator is free and open source software, so you can rest assured there are no backdoors. +

+

+ Cryptomator encrypts file contents and names using AES. Your passphrase is protected against bruteforcing attempts + using scrypt. Directory structures get obfuscated. The only thing which cannot be encrypted without breaking your + cloud synchronization is the modification date of your files. +

+

+ Cryptomator is a free and open source software licensed under the GPLv3. This allows anyone to check our code. It + is impossible to introduce backdoors for third parties. Also we cannot hide vulnerabilities. And the best thing + is: There is no need to trust us, as you can control us! +

+

+ Vendor lock-ins are impossible. Even if we decided to stop development: The source code is already cloned by + hundreds of other developers. As you don't need an account, you will never stand in front of locked doors. +

+
+ + + Office + Security + FileTools + + + org.cryptomator.Cryptomator.desktop + + cryptomator + application/vnd.cryptomator.vault + application/vnd.cryptomator.encrypted + + + + + Light theme + https://user-images.githubusercontent.com/11858409/156986109-6e58f59c-8b8c-4501-b33b-bb1e33007cea.png + + + Dark theme + https://user-images.githubusercontent.com/11858409/156986113-6c5d7801-86e0-4643-bc2f-aff9d95d3ce0.png + + + + https://cryptomator.org/ + https://github.com/cryptomator/cryptomator/issues/ + https://cryptomator.org/donate + https://community.cryptomator.org/c/kb/faq + https://community.cryptomator.org/ + https://translate.cryptomator.org + + Skymatic GmbH + + + mild + + + + + +
diff --git a/dist/linux/debian/org.cryptomator.Cryptomator.svg b/dist/linux/common/org.cryptomator.Cryptomator.svg similarity index 99% rename from dist/linux/debian/org.cryptomator.Cryptomator.svg rename to dist/linux/common/org.cryptomator.Cryptomator.svg index 19d80d49c..c76d99fb9 100644 --- a/dist/linux/debian/org.cryptomator.Cryptomator.svg +++ b/dist/linux/common/org.cryptomator.Cryptomator.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png b/dist/linux/common/org.cryptomator.Cryptomator256.png similarity index 100% rename from dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png rename to dist/linux/common/org.cryptomator.Cryptomator256.png diff --git a/dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png b/dist/linux/common/org.cryptomator.Cryptomator512.png similarity index 100% rename from dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png rename to dist/linux/common/org.cryptomator.Cryptomator512.png diff --git a/dist/linux/debian/cryptomator.install b/dist/linux/debian/cryptomator.install index 0d5e0b31c..d3ff8cf1f 100644 --- a/dist/linux/debian/cryptomator.install +++ b/dist/linux/debian/cryptomator.install @@ -1,7 +1,8 @@ cryptomator usr/lib debian/cryptomator.sh usr/lib/cryptomator/bin -debian/org.cryptomator.Cryptomator.desktop usr/share/applications -debian/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps -debian/org.cryptomator.Cryptomator.png usr/share/icons/hicolor/512x512/apps -debian/org.cryptomator.Cryptomator.appdata.xml usr/share/metainfo -debian/cryptomator-vault.xml usr/share/mime/packages \ No newline at end of file +common/org.cryptomator.Cryptomator.desktop usr/share/applications +common/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps +common/org.cryptomator.Cryptomator256.png usr/share/icons/hicolor/256x256/apps +common/org.cryptomator.Cryptomator512.png usr/share/icons/hicolor/512x512/apps +common/org.cryptomator.Cryptomator.metainfo.xml usr/share/metainfo +common/application-vnd.cryptomator.vault.xml usr/share/mime/packages \ No newline at end of file diff --git a/dist/linux/debian/org.cryptomator.Cryptomator.appdata.xml b/dist/linux/debian/org.cryptomator.Cryptomator.appdata.xml deleted file mode 100644 index ad4af6c70..000000000 --- a/dist/linux/debian/org.cryptomator.Cryptomator.appdata.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - org.cryptomator.Cryptomator - FSFAP - GPL-3.0-or-later - Cryptomator - Multi-platform client-side encryption tool optimized for cloud storages - -

- Cryptomator offers multi-platform transparent client-side encryption of your files in the cloud. -

-

- Features: -

    -
  • Works with Dropbox, Google Drive, OneDrive, ownCloud, Nextcloud and any other cloud storage service which synchronizes with a local directory
  • -
  • Open Source means: No backdoors, control is better than trust
  • -
  • Client-side: No accounts, no data shared with any online service
  • -
  • Totally transparent: Just work on the virtual drive as if it were a USB flash drive
  • -
  • AES encryption with 256-bit key length
  • -
  • 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:
  • -
-

-

- Privacy: -

    -
  • 256-bit keys (unlimited strength policy bundled with native binaries)
  • -
  • Scrypt key derivation
  • -
  • Cryptographically secure random numbers for salts, IVs and the masterkey of course
  • -
  • Sensitive data is wiped from the heap asap
  • -
  • Lightweight: Complexity kills security
  • -
-

-

- Consistency: -

    -
  • HMAC over file contents to recognize changed ciphertext before decryption
  • -
  • I/O operations are transactional and atomic, if the filesystems support it
  • -
  • Each file contains all information needed for decryption (except for the key of course), no common metadata means no Single Point of Failure
  • -
-

-
- - Office - Security - FileTools - Java - - http://cryptomator.org - https://github.com/cryptomator/cryptomator/issues - https://community.cryptomator.org/c/kb/faq - https://community.cryptomator.org/ - https://cryptomator.org/ - - none - none - none - none - mild - - Cryptomator - - cryptomator - - org.cryptomator.Cryptomator.desktop -
diff --git a/dist/linux/debian/org.cryptomator.Cryptomator.desktop b/dist/linux/debian/org.cryptomator.Cryptomator.desktop deleted file mode 100644 index d8a5925bd..000000000 --- a/dist/linux/debian/org.cryptomator.Cryptomator.desktop +++ /dev/null @@ -1,11 +0,0 @@ -[Desktop Entry] -Name=Cryptomator -Version=${VERSION_STR} -Comment=Cloud Storage Encryption Utility -Exec=/usr/bin/cryptomator %f -Icon=org.cryptomator.Cryptomator -Terminal=false -Type=Application -Categories=Utility;Security;FileTools; -StartupWMClass=org.cryptomator.launcher.Cryptomator -MimeType=application/vnd.cryptomator.encrypted;application/x-vnd.cryptomator.vault-metadata; \ No newline at end of file diff --git a/dist/linux/debian/org.cryptomator.Cryptomator.png b/dist/linux/debian/org.cryptomator.Cryptomator.png deleted file mode 100644 index 9c8635111..000000000 Binary files a/dist/linux/debian/org.cryptomator.Cryptomator.png and /dev/null differ diff --git a/dist/linux/debian/postinst b/dist/linux/debian/postinst index 2af574c6b..5668a5e29 100644 --- a/dist/linux/debian/postinst +++ b/dist/linux/debian/postinst @@ -24,7 +24,7 @@ case "$1" in mkdir -p /usr/share/desktop-directories fi xdg-desktop-menu install --novendor /usr/share/applications/org.cryptomator.Cryptomator.desktop - xdg-mime install /usr/share/mime/packages/cryptomator-vault.xml + xdg-mime install /usr/share/mime/packages/application-vnd.cryptomator.vault.xml ;; abort-upgrade|abort-remove|abort-deconfigure) diff --git a/dist/linux/debian/prerm b/dist/linux/debian/prerm index cace6816e..41a54cf33 100644 --- a/dist/linux/debian/prerm +++ b/dist/linux/debian/prerm @@ -22,7 +22,7 @@ case "$1" in echo Removing shortcut xdg-desktop-menu uninstall --novendor /usr/share/applications/org.cryptomator.Cryptomator.desktop - xdg-mime uninstall /usr/share/mime/packages/cryptomator-vault.xml + xdg-mime uninstall /usr/share/mime/packages/application-vnd.cryptomator.vault.xml ;; failed-upgrade) diff --git a/dist/linux/debian/rules b/dist/linux/debian/rules index fc237107e..e4f824394 100755 --- a/dist/linux/debian/rules +++ b/dist/linux/debian/rules @@ -11,11 +11,14 @@ override_dh_auto_clean: rm -rf runtime rm -rf cryptomator rm -rf debian/cryptomator + rm -rf resources override_dh_auto_build: + mkdir resources + ln -s ../common/org.cryptomator.Cryptomator512.png resources/cryptomator.png jlink \ --output runtime \ - --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 \ + --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,jdk.management.jfr \ --no-header-files \ --no-man-pages \ --strip-debug \ @@ -39,8 +42,8 @@ override_dh_auto_build: --java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \ --java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \ --java-options "-Dcryptomator.showTrayIcon=false" \ - --java-options "-Dcryptomator.buildNumber=\"ppa-${REVISION_NUM}\"" \ - --java-options "-Dcryptomator.appVersion=\"${VERSION_STR}\"" \ + --java-options "-Dcryptomator.buildNumber=\"deb-${REVISION_NUM}\"" \ + --java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\"" \ --app-version "${VERSION_NUM}.${REVISION_NUM}" \ --resource-dir resources \ --verbose diff --git a/dist/linux/debian/source/include-binaries b/dist/linux/debian/source/include-binaries index adc7cabd8..8b9254c65 100644 --- a/dist/linux/debian/source/include-binaries +++ b/dist/linux/debian/source/include-binaries @@ -1,2 +1,2 @@ -debian/org.cryptomator.Cryptomator.png -resources/cryptomator.png +common/org.cryptomator.Cryptomator256.png +common/org.cryptomator.Cryptomator512.png diff --git a/dist/mac/dmg/.gitignore b/dist/mac/dmg/.gitignore index c186170c9..b8ef35283 100644 --- a/dist/mac/dmg/.gitignore +++ b/dist/mac/dmg/.gitignore @@ -1,4 +1,5 @@ # created during build +Cryptomator.app/ runtime/ dmg/ -*.dmg +*.dmg \ No newline at end of file diff --git a/dist/mac/dmg/build.sh b/dist/mac/dmg/build.sh index ebec045bc..c90411acb 100755 --- a/dist/mac/dmg/build.sh +++ b/dist/mac/dmg/build.sh @@ -22,8 +22,8 @@ VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q # 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; } +command -v mvn >/dev/null 2>&1 || { echo >&2 "mvn not found. Fix by 'brew install maven'."; exit 1; } +command -v create-dmg >/dev/null 2>&1 || { echo >&2 "create-dmg not found. Fix by 'brew install create-dmg'."; 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 @@ -37,7 +37,7 @@ cp ../../../target/cryptomator-*.jar ../../../target/mods ${JAVA_HOME}/bin/jlink \ --output runtime \ --module-path "${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 \ + --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,jdk.management.jfr \ --no-header-files \ --no-man-pages \ --strip-debug \ diff --git a/dist/win/.gitignore b/dist/win/.gitignore index 2b66ddbed..9cce929df 100644 --- a/dist/win/.gitignore +++ b/dist/win/.gitignore @@ -1,3 +1,7 @@ runtime Cryptomator -installer \ No newline at end of file +installer +*.wixobj +*.pdb +*.msi +license.rtf \ No newline at end of file diff --git a/dist/win/build.ps1 b/dist/win/build.ps1 index eb33c2462..0b0e953bc 100644 --- a/dist/win/build.ps1 +++ b/dist/win/build.ps1 @@ -1,11 +1,14 @@ +# check parameters +$clean = $args[0] -eq "fresh" + # check preconditions -if ((Get-Command "git" -ErrorAction SilentlyContinue) -eq $null) -{ +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) -{ +if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null) +{ Write-Host "Unable to find mvn.cmd in your PATH (try: choco install maven)" exit 1 } @@ -21,21 +24,34 @@ Write-Output "`$revisionNo=$revisionNo" Write-Output "`$buildDir=$buildDir" Write-Output "`$Env:JAVA_HOME=$Env:JAVA_HOME" +$vendor = "Skymatic GmbH" +$copyright = "(C) 2016 - 2022 Skymatic GmbH" + # compile &mvn -B -f $buildDir/../../pom.xml clean package -DskipTests -Pwin Copy-Item "$buildDir\..\..\target\cryptomator-*.jar" -Destination "$buildDir\..\..\target\mods" # add runtime +$runtimeImagePath = '.\runtime' +if ($clean -and (Test-Path -Path $runtimeImagePath)) { + Remove-Item -Path $runtimeImagePath -Force -Recurse +} + & "$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 ` + --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,jdk.management.jfr ` --no-header-files ` --no-man-pages ` --strip-debug ` --compress=1 +$appPath = '.\Cryptomator' +if ($clean -and (Test-Path -Path $appPath)) { + Remove-Item -Path $appPath -Force -Recurse +} + # create app dir & "$Env:JAVA_HOME\bin\jpackage" ` --verbose ` @@ -46,8 +62,8 @@ Copy-Item "$buildDir\..\..\target\cryptomator-*.jar" -Destination "$buildDir\..\ --module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator ` --dest . ` --name Cryptomator ` - --vendor "Skymatic GmbH" ` - --copyright "(C) 2016 - 2022 Skymatic GmbH" ` + --vendor $vendor ` + --copyright $copyright ` --java-options "-Xss5m" ` --java-options "-Xmx256m" ` --java-options "-Dcryptomator.appVersion=`"$semVerNo`"" ` @@ -64,11 +80,21 @@ Copy-Item "$buildDir\..\..\target\cryptomator-*.jar" -Destination "$buildDir\..\ --resource-dir resources ` --icon resources/Cryptomator.ico +#Create RTF license for msi +&mvn -B -f $buildDir/../../pom.xml license:add-third-party ` + "-Dlicense.thirdPartyFilename=license.rtf" ` + "-Dlicense.fileTemplate=$buildDir\resources\licenseTemplate.ftl" ` + "-Dlicense.outputDirectory=$buildDir\resources\" + # patch app dir Copy-Item "contrib\*" -Destination "Cryptomator" attrib -r "Cryptomator\Cryptomator.exe" -# create .msi bundle +$aboutUrl="https://cryptomator.org" +$updateUrl="https://cryptomator.org/downloads/" +$helpUrl="https://cryptomator.org/contact/" + +# create .msi $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources" & "$Env:JAVA_HOME\bin\jpackage" ` --verbose ` @@ -77,14 +103,41 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources" --app-image Cryptomator ` --dest installer ` --name Cryptomator ` - --vendor "Skymatic GmbH" ` - --copyright "(C) 2016 - 2022 Skymatic GmbH" ` + --vendor $vendor ` + --copyright $copyright ` --app-version "$semVerNo" ` --win-menu ` --win-dir-chooser ` --win-shortcut-prompt ` - --win-update-url "https:\\cryptomator.org" ` + --win-update-url $updateUrl ` --win-menu-group Cryptomator ` --resource-dir resources ` + --about-url $aboutUrl ` --license-file resources/license.rtf ` --file-associations resources/FAvaultFile.properties + +#Create RTF license for bundle +&mvn -B -f $buildDir/../../pom.xml license:add-third-party ` + "-Dlicense.thirdPartyFilename=license.rtf" ` + "-Dlicense.fileTemplate=$buildDir\bundle\resources\licenseTemplate.ftl" ` + "-Dlicense.outputDirectory=$buildDir\bundle\resources\" + +# download Winfsp +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s +$winfspMsiUrl = "https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi" +Write-Output "Downloading ${winfspMsiUrl}..." +Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default + +# copy MSI to bundle resources +Copy-Item ".\installer\Cryptomator-*.msi" -Destination ".\bundle\resources\Cryptomator.msi" + +# create bundle including winfsp +& "$env:WIX\bin\candle.exe" .\bundle\bundleWithWinfsp.wxs -ext WixBalExtension -out bundle\ ` + -dBundleVersion="$semVerNo.$revisionNo" ` + -dBundleVendor="$vendor" ` + -dBundleCopyright="$copyright" ` + -dAboutUrl="$aboutUrl" ` + -dHelpUrl="$helpUrl" ` + -dUpdateUrl="$updateUrl" +& "$env:WIX\bin\light.exe" -b . .\bundle\BundlewithWinfsp.wixobj -ext WixBalExtension -out installer\CryptomatorBundle.exe \ No newline at end of file diff --git a/dist/win/bundle/bundleWithWinfsp.wxs b/dist/win/bundle/bundleWithWinfsp.wxs new file mode 100644 index 000000000..91093df7d --- /dev/null +++ b/dist/win/bundle/bundleWithWinfsp.wxs @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/win/bundle/customBootstrapperTheme.wxl b/dist/win/bundle/customBootstrapperTheme.wxl new file mode 100644 index 000000000..cc464ce9c --- /dev/null +++ b/dist/win/bundle/customBootstrapperTheme.wxl @@ -0,0 +1,64 @@ + + + + + + [WixBundleName] Setup + [WixBundleName] + Welcome + This Setup will install [WixBundleName] and additional dependencies on your computer. + Version [WixBundleVersion] + Are you sure you want to cancel? + Previous version + Setup Help + /install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or + creates a complete local copy of the bundle in directory. Install is the default. + +/passive | /quiet - displays minimal UI with no prompts or displays no UI and + no prompts. By default UI and all prompts are displayed. + +/norestart - suppress any attempts to restart. By default UI will prompt before restart. +/log log.txt - logs to a specific file. By default a log file is created in %TEMP%. + &Close + [WixBundleName] <a href="#">license terms</a>. + I &agree to the license terms and conditions + &Options + &Install + &Close + Setup Options + Install location: + &Browse + &OK + &Cancel + Setup Progress + Processing: + Initializing... + &Cancel + Modify Setup + &Repair + &Uninstall + &Close + Repair Successfully Completed + Uninstall Successfully Completed + Installation Successfully Completed + Setup Successful + &Launch + You must restart your computer before you can use the software. + &Restart + &Close + Setup Failed + Setup Failed + Uninstall Failed + Repair Failed + One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>. + You must restart your computer to complete the rollback of the software. + &Restart + &Close + Files In Use + The following applications are using files that need to be updated: + Close the &applications and attempt to restart them. + &Do not close applications. A reboot will be required. + &OK + &Cancel + No action was taken as a system reboot is required. + diff --git a/dist/win/bundle/customBootstrapperTheme.xml b/dist/win/bundle/customBootstrapperTheme.xml new file mode 100644 index 000000000..792f51a35 --- /dev/null +++ b/dist/win/bundle/customBootstrapperTheme.xml @@ -0,0 +1,90 @@ + + + + + + + #(loc.Caption) + Segoe UI + Segoe UI + Segoe UI + Segoe UI + Segoe UI + + + #(loc.Title) + + + + #(loc.Title) + #(loc.HelpHeader) + #(loc.HelpText) + + + + #(loc.Title) + + #(loc.InstallHeader) + #(loc.InstallMessage) + + #(loc.InstallAcceptCheckbox) + #(loc.InstallVersion) + + + + + + #(loc.Title) + #(loc.FilesInUseHeader) + #(loc.FilesInUseLabel) + A + + + + + + + + + #(loc.Title) + + #(loc.ProgressHeader) + #(loc.ProgressLabel) + #(loc.OverallProgressPackageText) + + + + + + #(loc.Title) + #(loc.ModifyHeader) + + + + + + #(loc.Title) + + #(loc.SuccessHeader) + #(loc.SuccessInstallHeader) + #(loc.SuccessRepairHeader) + #(loc.SuccessUninstallHeader) + + #(loc.SuccessRestartText) + + + + + #(loc.Title) + + #(loc.FailureHeader) + #(loc.FailureInstallHeader) + #(loc.FailureUninstallHeader) + #(loc.FailureRepairHeader) + #(loc.FailureHyperlinkLogText) + + #(loc.FailureRestartText) + + + + diff --git a/dist/win/bundle/resources/Cryptomator.ico b/dist/win/bundle/resources/Cryptomator.ico new file mode 100644 index 000000000..7d1d8be88 Binary files /dev/null and b/dist/win/bundle/resources/Cryptomator.ico differ diff --git a/dist/win/bundle/resources/licenseTemplate.ftl b/dist/win/bundle/resources/licenseTemplate.ftl new file mode 100644 index 000000000..bd137a1a1 --- /dev/null +++ b/dist/win/bundle/resources/licenseTemplate.ftl @@ -0,0 +1,41 @@ +<#function artifactFormat p> + <#if p.name?index_of('Unnamed') > -1> + <#return p.artifactId + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + " - {{\\field{\\*\\fldinst{HYPERLINK " + (p.url!"no url defined") + "}}{\\fldrslt{" + (p.url!"no url defined") + "\\ul0\\cf0}}}}\\f0\\fs16 ) "> + <#else> + <#return p.name + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + " - {{\\field{\\*\\fldinst{HYPERLINK " + (p.url!"no url defined") + "}}{\\fldrslt{" + (p.url!"no url defined") + "\\ul0\\cf0}}}}\\f0\\fs16 ) "> + + +{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}} +{\colortbl ;\red0\green0\blue255;} +\viewkind4\uc1 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par +\par +\b\'a9 2016 \endash 2022 Skymatic GmbH\b0\par +\par +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par +\par +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\par +\par +You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par +\par + +\b Cryptomator uses ${dependencyMap?size} third-party dependencies under the following licenses:\b0\par +<#list licenseMap as e> +<#assign license = e.getKey()/> +<#assign projects = e.getValue()/> +<#if projects?size > 0> +\tab ${license}:\par +<#list projects as project> +\tab\tab- ${artifactFormat(project)}\par + + + +\par +\b Cryptomator uses other third-party assets under the following licenses:\b0\par +\tab SIL OFL 1.1 License:\par +\tab\tab - Font Awesome 5.12.0 ({{\field{\*\fldinst{HYPERLINK https://fontawesome.com/ }}{\fldrslt{https://fontawesome.com/\ul0\cf0}}}}\f0\fs16 )\b\par +\par +\b Cryptomator dynamically links to third-party libraries under the following license:\b0\par +\tab Uncategorized License:\par +\tab\tab - WinFsp - Windows File System Proxy, Copyright (C) Bill Zissimopoulos ({{\field{\*\fldinst{HYPERLINK https://github.com/billziss-gh/winfsp }}{\fldrslt{https://github.com/billziss-gh/winfsp\ul0\cf0}}}}\f0\fs16 )\b\par +} \ No newline at end of file diff --git a/dist/win/bundle/resources/logo.png b/dist/win/bundle/resources/logo.png new file mode 100644 index 000000000..fdfdd6235 Binary files /dev/null and b/dist/win/bundle/resources/logo.png differ diff --git a/dist/win/bundle/resources/logoSide.png b/dist/win/bundle/resources/logoSide.png new file mode 100644 index 000000000..e1629e8d6 Binary files /dev/null and b/dist/win/bundle/resources/logoSide.png differ diff --git a/dist/win/resources/license.rtf b/dist/win/resources/license.rtf deleted file mode 100644 index 28956ed42..000000000 --- a/dist/win/resources/license.rtf +++ /dev/null @@ -1,84 +0,0 @@ -{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}} -{\colortbl ;\red0\green0\blue255;} -{\*\generator Riched20 10.0.17134}\viewkind4\uc1 -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par -\par -\b\'a9 2016 \endash 2022 Skymatic GmbH\b0\par -\par -This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par -\par -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\par -\par -You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par -\par -\b Cryptomator uses 40 third-party dependencies under the following licenses:\b0\par -\tab Apache License v2.0:\par -\tab\tab - jffi (com.github.jnr:jffi:1.2.23 - {{\field{\*\fldinst{HYPERLINK http://github.com/jnr/jffi }}{\fldrslt{http://github.com/jnr/jffi\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - {{\field{\*\fldinst{HYPERLINK http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm }}{\fldrslt{http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - jnr-constants (com.github.jnr:jnr-constants:0.9.15 - {{\field{\*\fldinst{HYPERLINK http://github.com/jnr/jnr-constants }}{\fldrslt{http://github.com/jnr/jnr-constants\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - {{\field{\*\fldinst{HYPERLINK http://github.com/jnr/jnr-ffi }}{\fldrslt{http://github.com/jnr/jnr-ffi\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Gson (com.google.code.gson:gson:2.8.7 - {{\field{\*\fldinst{HYPERLINK https://github.com/google/gson/gson }}{\fldrslt{https://github.com/google/gson/gson\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Dagger (com.google.dagger:dagger:2.38.1 - {{\field{\*\fldinst{HYPERLINK https://github.com/google/dagger }}{\fldrslt{https://github.com/google/dagger\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - {{\field{\*\fldinst{HYPERLINK https://github.com/google/guava/failureaccess }}{\fldrslt{https://github.com/google/guava/failureaccess\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Guava: Google Core Libraries for Java (com.google.guava:guava:30.1.1-jre - {{\field{\*\fldinst{HYPERLINK https://github.com/google/guava/guava }}{\fldrslt{https://github.com/google/guava/guava\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Apache Commons CLI (commons-cli:commons-cli:1.4 - {{\field{\*\fldinst{HYPERLINK http://commons.apache.org/proper/commons-cli/ }}{\fldrslt{http://commons.apache.org/proper/commons-cli/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - javax.inject (javax.inject:javax.inject:1 - {{\field{\*\fldinst{HYPERLINK http://code.google.com/p/atinject/ }}{\fldrslt{http://code.google.com/p/atinject/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Java Native Access (net.java.dev.jna:jna:5.7.0 - {{\field{\*\fldinst{HYPERLINK https://github.com/java-native-access/jna }}{\fldrslt{https://github.com/java-native-access/jna\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Java Native Access Platform (net.java.dev.jna:jna-platform:5.7.0 - {{\field{\*\fldinst{HYPERLINK https://github.com/java-native-access/jna }}{\fldrslt{https://github.com/java-native-access/jna\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Apache Commons Lang (org.apache.commons:commons-lang3:3.12.0 - {{\field{\*\fldinst{HYPERLINK https://commons.apache.org/proper/commons-lang/ }}{\fldrslt{https://commons.apache.org/proper/commons-lang/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.14 - {{\field{\*\fldinst{HYPERLINK http://hc.apache.org/httpcomponents-core-ga }}{\fldrslt{http://hc.apache.org/httpcomponents-core-ga\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.5 - {{\field{\*\fldinst{HYPERLINK http://jackrabbit.apache.org/jackrabbit-webdav/ }}{\fldrslt{http://jackrabbit.apache.org/jackrabbit-webdav/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-http }}{\fldrslt{https://eclipse.org/jetty/jetty-http\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-io }}{\fldrslt{https://eclipse.org/jetty/jetty-io\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-security }}{\fldrslt{https://eclipse.org/jetty/jetty-security\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-server }}{\fldrslt{https://eclipse.org/jetty/jetty-server\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-servlet }}{\fldrslt{https://eclipse.org/jetty/jetty-servlet\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-util }}{\fldrslt{https://eclipse.org/jetty/jetty-util\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-servlet-api }}{\fldrslt{https://eclipse.org/jetty/jetty-servlet-api\ul0\cf0}}}}\f0\fs16 )\par -\tab BSD:\par -\tab\tab - asm (org.ow2.asm:asm:7.1 - {{\field{\*\fldinst{HYPERLINK http://asm.ow2.org/ }}{\fldrslt{http://asm.ow2.org/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - asm-analysis (org.ow2.asm:asm-analysis:7.1 - {{\field{\*\fldinst{HYPERLINK http://asm.ow2.org/ }}{\fldrslt{http://asm.ow2.org/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - asm-commons (org.ow2.asm:asm-commons:7.1 - {{\field{\*\fldinst{HYPERLINK http://asm.ow2.org/ }}{\fldrslt{http://asm.ow2.org/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - asm-tree (org.ow2.asm:asm-tree:7.1 - {{\field{\*\fldinst{HYPERLINK http://asm.ow2.org/ }}{\fldrslt{http://asm.ow2.org/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - asm-util (org.ow2.asm:asm-util:7.1 - {{\field{\*\fldinst{HYPERLINK http://asm.ow2.org/ }}{\fldrslt{http://asm.ow2.org/\ul0\cf0}}}}\f0\fs16 )\par -\tab Eclipse Public License - Version 1.0:\par -\tab\tab - Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-servlet-api }}{\fldrslt{https://eclipse.org/jetty/jetty-servlet-api\ul0\cf0}}}}\f0\fs16 )\par -\tab Eclipse Public License - Version 2.0:\par -\tab\tab - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-http }}{\fldrslt{https://eclipse.org/jetty/jetty-http\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-io }}{\fldrslt{https://eclipse.org/jetty/jetty-io\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-security }}{\fldrslt{https://eclipse.org/jetty/jetty-security\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-server }}{\fldrslt{https://eclipse.org/jetty/jetty-server\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-servlet }}{\fldrslt{https://eclipse.org/jetty/jetty-servlet\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.6 - {{\field{\*\fldinst{HYPERLINK https://eclipse.org/jetty/jetty-util }}{\fldrslt{https://eclipse.org/jetty/jetty-util\ul0\cf0}}}}\f0\fs16 )\par -\tab Eclipse Public License - v 1.0:\par -\tab\tab - Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - {{\field{\*\fldinst{HYPERLINK http://logback.qos.ch/logback-classic }}{\fldrslt{http://logback.qos.ch/logback-classic\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Logback Core Module (ch.qos.logback:logback-core:1.2.3 - {{\field{\*\fldinst{HYPERLINK http://logback.qos.ch/logback-core }}{\fldrslt{http://logback.qos.ch/logback-core\ul0\cf0}}}}\f0\fs16 )\par -\tab Eclipse Public License - v 2.0:\par -\tab\tab - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - {{\field{\*\fldinst{HYPERLINK http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix }}{\fldrslt{http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix\ul0\cf0}}}}\f0\fs16 )\par -\tab GNU Lesser General Public License:\par -\tab\tab - Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - {{\field{\*\fldinst{HYPERLINK http://logback.qos.ch/logback-classic }}{\fldrslt{http://logback.qos.ch/logback-classic\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Logback Core Module (ch.qos.logback:logback-core:1.2.3 - {{\field{\*\fldinst{HYPERLINK http://logback.qos.ch/logback-core }}{\fldrslt{http://logback.qos.ch/logback-core\ul0\cf0}}}}\f0\fs16 )\par -\tab GPLv2:\par -\tab\tab - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - {{\field{\*\fldinst{HYPERLINK http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix }}{\fldrslt{http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix\ul0\cf0}}}}\f0\fs16 )\par -\tab GPLv2+CE:\par -\tab\tab - javafx-base (org.openjfx:javafx-base:16 - {{\field{\*\fldinst{HYPERLINK https://openjdk.java.net/projects/openjfx/javafx-base/ }}{\fldrslt{https://openjdk.java.net/projects/openjfx/javafx-base/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - javafx-controls (org.openjfx:javafx-controls:16 - {{\field{\*\fldinst{HYPERLINK https://openjdk.java.net/projects/openjfx/javafx-controls/ }}{\fldrslt{https://openjdk.java.net/projects/openjfx/javafx-controls/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - javafx-fxml (org.openjfx:javafx-fxml:16 - {{\field{\*\fldinst{HYPERLINK https://openjdk.java.net/projects/openjfx/javafx-fxml/ }}{\fldrslt{https://openjdk.java.net/projects/openjfx/javafx-fxml/\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - javafx-graphics (org.openjfx:javafx-graphics:16 - {{\field{\*\fldinst{HYPERLINK https://openjdk.java.net/projects/openjfx/javafx-graphics/ }}{\fldrslt{https://openjdk.java.net/projects/openjfx/javafx-graphics/\ul0\cf0}}}}\f0\fs16 )\par -\tab LGPL 2.1:\par -\tab\tab - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - {{\field{\*\fldinst{HYPERLINK http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix }}{\fldrslt{http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Java Native Access (net.java.dev.jna:jna:5.7.0 - {{\field{\*\fldinst{HYPERLINK https://github.com/java-native-access/jna }}{\fldrslt{https://github.com/java-native-access/jna\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - Java Native Access Platform (net.java.dev.jna:jna-platform:5.7.0 - {{\field{\*\fldinst{HYPERLINK https://github.com/java-native-access/jna }}{\fldrslt{https://github.com/java-native-access/jna\ul0\cf0}}}}\f0\fs16 )\par -\tab MIT License:\par -\tab\tab - java jwt (com.auth0:java-jwt:3.18.1 - {{\field{\*\fldinst{HYPERLINK https://github.com/auth0/java-jwt }}{\fldrslt{https://github.com/auth0/java-jwt\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - {{\field{\*\fldinst{HYPERLINK http://github.com/jnr/jnr-x86asm }}{\fldrslt{http://github.com/jnr/jnr-x86asm\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - jnr-fuse (com.github.serceman:jnr-fuse:0.5.5 - {{\field{\*\fldinst{HYPERLINK https://github.com/SerCeMan/jnr-fuse }}{\fldrslt{https://github.com/SerCeMan/jnr-fuse\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - zxcvbn4j (com.nulab-inc:zxcvbn:1.5.2 - {{\field{\*\fldinst{HYPERLINK https://github.com/nulab/zxcvbn4j }}{\fldrslt{https://github.com/nulab/zxcvbn4j\ul0\cf0}}}}\f0\fs16 )\par -\tab\tab - SLF4J API Module (org.slf4j:slf4j-api:1.7.31 - {{\field{\*\fldinst{HYPERLINK http://www.slf4j.org }}{\fldrslt{http://www.slf4j.org\ul0\cf0}}}}\f0\fs16 )\par -\tab The BSD 2-Clause License:\par -\tab\tab - EasyBind (com.tobiasdiez:easybind:2.2 - {{\field{\*\fldinst{HYPERLINK https://github.com/tobiasdiez/EasyBind }}{\fldrslt{https://github.com/tobiasdiez/EasyBind\ul0\cf0}}}}\f0\fs16 )\par -\par -\b Cryptomator uses other third-party assets under the following licenses:\b0\par -\tab SIL OFL 1.1 License:\par -\tab\tab - Font Awesome 5.12.0 ({{\field{\*\fldinst{HYPERLINK https://fontawesome.com/ }}{\fldrslt{https://fontawesome.com/\ul0\cf0}}}}\f0\fs16 )\b\par -} diff --git a/dist/win/resources/licenseTemplate.ftl b/dist/win/resources/licenseTemplate.ftl new file mode 100644 index 000000000..d442e6538 --- /dev/null +++ b/dist/win/resources/licenseTemplate.ftl @@ -0,0 +1,37 @@ +<#function artifactFormat p> + <#if p.name?index_of('Unnamed') > -1> + <#return p.artifactId + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + " - {{\\field{\\*\\fldinst{HYPERLINK " + (p.url!"no url defined") + "}}{\\fldrslt{" + (p.url!"no url defined") + "\\ul0\\cf0}}}}\\f0\\fs16 ) "> + <#else> + <#return p.name + " (" + p.groupId + ":" + p.artifactId + ":" + p.version + " - {{\\field{\\*\\fldinst{HYPERLINK " + (p.url!"no url defined") + "}}{\\fldrslt{" + (p.url!"no url defined") + "\\ul0\\cf0}}}}\\f0\\fs16 ) "> + + +{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}} +{\colortbl ;\red0\green0\blue255;} +\viewkind4\uc1 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par +\par +\b\'a9 2016 \endash 2022 Skymatic GmbH\b0\par +\par +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par +\par +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\par +\par +You should have received a copy of the GNU General Public License along with this program. If not, see {{\field{\*\fldinst{HYPERLINK http://www.gnu.org/licenses/ }}{\fldrslt{http://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs16 .\par +\par + +\b Cryptomator uses ${dependencyMap?size} third-party dependencies under the following licenses:\b0\par +<#list licenseMap as e> +<#assign license = e.getKey()/> +<#assign projects = e.getValue()/> +<#if projects?size > 0> +\tab ${license}:\par +<#list projects as project> +\tab\tab- ${artifactFormat(project)}\par + + + +\par +\b Cryptomator uses other third-party assets under the following licenses:\b0\par +\tab SIL OFL 1.1 License:\par +\tab\tab - Font Awesome 5.12.0 ({{\field{\*\fldinst{HYPERLINK https://fontawesome.com/ }}{\fldrslt{https://fontawesome.com/\ul0\cf0}}}}\f0\fs16 )\b\par +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6f0243597..469ab6398 100644 --- a/pom.xml +++ b/pom.xml @@ -37,9 +37,9 @@ 1.2.6 - 17.0.1 + 17.0.2 3.12.0 - 3.18.2 + 3.18.3 2.2 31.0-jre 2.40.3 @@ -52,6 +52,10 @@ 5.8.1 3.12.4 2.2 + + + 7.0.0 + 0.8.7 @@ -228,7 +232,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.10.1 org.apache.maven.plugins @@ -238,7 +242,7 @@ org.apache.maven.plugins maven-dependency-plugin - 3.2.0 + 3.3.0 org.apache.maven.plugins @@ -253,17 +257,17 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.0 + 3.2.2 org.jacoco jacoco-maven-plugin - 0.8.7 + ${jacoco.version} org.owasp dependency-check-maven - 6.3.1 + ${dependency-check.version} diff --git a/src/main/java/org/cryptomator/common/mountpoint/CustomDriveLetterChooser.java b/src/main/java/org/cryptomator/common/mountpoint/CustomDriveLetterChooser.java index 1a42aa5ad..02f75d4a1 100644 --- a/src/main/java/org/cryptomator/common/mountpoint/CustomDriveLetterChooser.java +++ b/src/main/java/org/cryptomator/common/mountpoint/CustomDriveLetterChooser.java @@ -5,6 +5,9 @@ import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.vaults.Volume; import javax.inject.Inject; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; @@ -27,4 +30,13 @@ class CustomDriveLetterChooser implements MountPointChooser { public Optional chooseMountPoint(Volume caller) { return this.vaultSettings.getWinDriveLetter().map(letter -> letter.charAt(0) + ":\\").map(Paths::get); } + + @Override + public boolean prepare(Volume caller, Path driveLetter) throws InvalidMountPointException { + if (!Files.notExists(driveLetter, LinkOption.NOFOLLOW_LINKS)) { + //Drive already exists OR can't be determined + throw new InvalidMountPointException(new FileAlreadyExistsException(driveLetter.toString())); + } + return false; + } } diff --git a/src/main/java/org/cryptomator/common/mountpoint/CustomMountPointChooser.java b/src/main/java/org/cryptomator/common/mountpoint/CustomMountPointChooser.java index 5f1a7fedd..80c5b067b 100644 --- a/src/main/java/org/cryptomator/common/mountpoint/CustomMountPointChooser.java +++ b/src/main/java/org/cryptomator/common/mountpoint/CustomMountPointChooser.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.Environment; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.settings.VolumeImpl; +import org.cryptomator.common.vaults.MountPointRequirement; import org.cryptomator.common.vaults.Volume; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,10 +12,10 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; import java.io.IOException; import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.DirectoryStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; import java.nio.file.NotDirectoryException; import java.nio.file.Path; import java.nio.file.Paths; @@ -22,6 +23,9 @@ import java.util.Optional; class CustomMountPointChooser implements MountPointChooser { + private static final String HIDEAWAY_PREFIX = ".~$"; + private static final String HIDEAWAY_SUFFIX = ".tmp"; + private static final String WIN_HIDDEN = "dos:hidden"; private static final Logger LOG = LoggerFactory.getLogger(CustomMountPointChooser.class); private final VaultSettings vaultSettings; @@ -35,7 +39,6 @@ class CustomMountPointChooser implements MountPointChooser { @Override public boolean isApplicable(Volume caller) { - //Disable if useExperimentalFuse is required (Win + Fuse), but set to false return caller.getImplementationType() != VolumeImpl.FUSE || !SystemUtils.IS_OS_WINDOWS || environment.useExperimentalFuse(); } @@ -47,49 +50,102 @@ class CustomMountPointChooser implements MountPointChooser { @Override public boolean prepare(Volume caller, Path mountPoint) throws InvalidMountPointException { - switch (caller.getMountPointRequirement()) { - case PARENT_NO_MOUNT_POINT -> prepareParentNoMountPoint(mountPoint); - case EMPTY_MOUNT_POINT -> prepareEmptyMountPoint(mountPoint); - case NONE -> { - //Requirement "NONE" doesn't make any sense here. - //No need to prepare/verify a Mountpoint without requiring one... + return switch (caller.getMountPointRequirement()) { + case PARENT_NO_MOUNT_POINT -> { + prepareParentNoMountPoint(mountPoint); + LOG.debug("Successfully checked custom mount point: {}", mountPoint); + yield true; + } + case EMPTY_MOUNT_POINT -> { + prepareEmptyMountPoint(mountPoint); + LOG.debug("Successfully checked custom mount point: {}", mountPoint); + yield false; + } + case NONE, UNUSED_ROOT_DIR, PARENT_OPT_MOUNT_POINT -> { throw new InvalidMountPointException(new IllegalStateException("Illegal MountPointRequirement")); } - default -> { - //Currently the case for "PARENT_OPT_MOUNT_POINT" - throw new InvalidMountPointException(new IllegalStateException("Not implemented")); - } - } - LOG.debug("Successfully checked custom mount point: {}", mountPoint); - return false; + }; } - private void prepareParentNoMountPoint(Path mountPoint) throws InvalidMountPointException { - //This the case on Windows when using FUSE - //See https://github.com/billziss-gh/winfsp/issues/320 - Path parent = mountPoint.getParent(); - if (!Files.isDirectory(parent)) { - throw new InvalidMountPointException(new NotDirectoryException(parent.toString())); - } - //We must use #notExists() here because notExists =/= !exists (see docs) - if (!Files.notExists(mountPoint, LinkOption.NOFOLLOW_LINKS)) { - //File exists OR can't be determined - throw new InvalidMountPointException(new FileAlreadyExistsException(mountPoint.toString())); + //This is case on Windows when using FUSE + //See https://github.com/billziss-gh/winfsp/issues/320 + void prepareParentNoMountPoint(Path mountPoint) throws InvalidMountPointException { + Path hideaway = getHideaway(mountPoint); + var mpExists = Files.exists(mountPoint, LinkOption.NOFOLLOW_LINKS); + var hideExists = Files.exists(hideaway, LinkOption.NOFOLLOW_LINKS); + + //TODO: possible improvement by just deleting an _empty_ hideaway + if (mpExists && hideExists) { //both resources exist (whatever type) + throw new InvalidMountPointException(new FileAlreadyExistsException(hideaway.toString())); + } else if (!mpExists && !hideExists) { //neither mountpoint nor hideaway exist + throw new InvalidMountPointException(new NoSuchFileException(mountPoint.toString())); + } else if (!mpExists) { //only hideaway exists + checkIsDirectory(hideaway); + LOG.info("Mountpoint {} for winfsp mount seems to be not properly cleaned up. Will be fixed on unmount.", mountPoint); + try { + if (SystemUtils.IS_OS_WINDOWS) { + Files.setAttribute(hideaway, WIN_HIDDEN, true, LinkOption.NOFOLLOW_LINKS); + } + } catch (IOException e) { + throw new InvalidMountPointException(e); + } + } else { //only mountpoint exists + try { + checkIsDirectory(mountPoint); + checkIsEmpty(mountPoint); + + Files.move(mountPoint, hideaway); + if (SystemUtils.IS_OS_WINDOWS) { + Files.setAttribute(hideaway, WIN_HIDDEN, true, LinkOption.NOFOLLOW_LINKS); + } + } catch (IOException e) { + throw new InvalidMountPointException(e); + } } } private void prepareEmptyMountPoint(Path mountPoint) throws InvalidMountPointException { //This is the case for Windows when using Dokany and for Linux and Mac - if (!Files.isDirectory(mountPoint)) { - throw new InvalidMountPointException(new NotDirectoryException(mountPoint.toString())); - } - try (DirectoryStream ds = Files.newDirectoryStream(mountPoint)) { - if (ds.iterator().hasNext()) { - throw new InvalidMountPointException(new DirectoryNotEmptyException(mountPoint.toString())); - } + checkIsDirectory(mountPoint); + try { + checkIsEmpty(mountPoint); } catch (IOException exception) { throw new InvalidMountPointException("IOException while checking folder content", exception); } } + @Override + public void cleanup(Volume caller, Path mountPoint) { + if (caller.getMountPointRequirement() == MountPointRequirement.PARENT_NO_MOUNT_POINT) { + Path hideaway = getHideaway(mountPoint); + try { + Files.move(hideaway, mountPoint); + if (SystemUtils.IS_OS_WINDOWS) { + Files.setAttribute(mountPoint, WIN_HIDDEN, false); + } + } catch (IOException e) { + LOG.error("Unable to clean up mountpoint {} for Winfsp mounting.", mountPoint, e); + } + } + } + + private void checkIsDirectory(Path toCheck) throws InvalidMountPointException { + if (!Files.isDirectory(toCheck, LinkOption.NOFOLLOW_LINKS)) { + throw new InvalidMountPointException(new NotDirectoryException(toCheck.toString())); + } + } + + private void checkIsEmpty(Path toCheck) throws InvalidMountPointException, IOException { + try (var dirStream = Files.list(toCheck)) { + if (dirStream.findFirst().isPresent()) { + throw new InvalidMountPointException(new DirectoryNotEmptyException(toCheck.toString())); + } + } + } + + //visible for testing + Path getHideaway(Path mountPoint) { + return mountPoint.resolveSibling(HIDEAWAY_PREFIX + mountPoint.getFileName().toString() + HIDEAWAY_SUFFIX); + } + } diff --git a/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java b/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java index eb1d8d0b1..bcda3d8f2 100644 --- a/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java +++ b/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java @@ -65,7 +65,7 @@ class TemporaryMountPointChooser implements MountPointChooser { throw new InvalidMountPointException(new IllegalStateException("Illegal MountPointRequirement")); } default -> { - //Currently the case for "PARENT_OPT_MOUNT_POINT" + //Currently the case for "UNUSED_ROOT_DIR, PARENT_OPT_MOUNT_POINT" throw new InvalidMountPointException(new IllegalStateException("Not implemented")); } } diff --git a/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java b/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java index c998761d0..c08642073 100644 --- a/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java +++ b/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java @@ -86,7 +86,7 @@ public class DokanyVolume extends AbstractVolume { @Override public MountPointRequirement getMountPointRequirement() { - return MountPointRequirement.EMPTY_MOUNT_POINT; + return this.vaultSettings.getWinDriveLetter().isPresent() ? MountPointRequirement.UNUSED_ROOT_DIR : MountPointRequirement.EMPTY_MOUNT_POINT; } public static boolean isSupportedStatic() { diff --git a/src/main/java/org/cryptomator/common/vaults/FuseVolume.java b/src/main/java/org/cryptomator/common/vaults/FuseVolume.java index a1579fdaf..0321cfa0f 100644 --- a/src/main/java/org/cryptomator/common/vaults/FuseVolume.java +++ b/src/main/java/org/cryptomator/common/vaults/FuseVolume.java @@ -4,6 +4,7 @@ import com.google.common.collect.Iterators; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.mountpoint.InvalidMountPointException; import org.cryptomator.common.mountpoint.MountPointChooser; +import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.settings.VolumeImpl; import org.cryptomator.cryptofs.CryptoFileSystem; import org.cryptomator.frontend.fuse.mount.EnvironmentVariables; @@ -28,11 +29,14 @@ public class FuseVolume extends AbstractVolume { private static final Logger LOG = LoggerFactory.getLogger(FuseVolume.class); private static final Pattern NON_WHITESPACE_OR_QUOTED = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"); // Thanks to https://stackoverflow.com/a/366532 + private final VaultSettings vaultSettings; + private Mount mount; @Inject - public FuseVolume(@Named("orderedMountPointChoosers") Iterable choosers) { + public FuseVolume(VaultSettings vaultSettings, @Named("orderedMountPointChoosers") Iterable choosers) { super(choosers); + this.vaultSettings = vaultSettings; } @Override @@ -50,7 +54,7 @@ public class FuseVolume extends AbstractVolume { .withFileNameTranscoder(mounter.defaultFileNameTranscoder()) // .build(); this.mount = mounter.mount(root, envVars, onExitAction); - } catch ( FuseMountException | FuseNotSupportedException e) { + } catch (FuseMountException | FuseNotSupportedException e) { throw new VolumeException("Unable to mount Filesystem", e); } } @@ -119,7 +123,10 @@ public class FuseVolume extends AbstractVolume { @Override public MountPointRequirement getMountPointRequirement() { - return SystemUtils.IS_OS_WINDOWS ? MountPointRequirement.PARENT_NO_MOUNT_POINT : MountPointRequirement.EMPTY_MOUNT_POINT; + if (!SystemUtils.IS_OS_WINDOWS) { + return MountPointRequirement.EMPTY_MOUNT_POINT; + } + return this.vaultSettings.getWinDriveLetter().isPresent() ? MountPointRequirement.UNUSED_ROOT_DIR : MountPointRequirement.PARENT_NO_MOUNT_POINT; } public static boolean isSupportedStatic() { diff --git a/src/main/java/org/cryptomator/common/vaults/MountPointRequirement.java b/src/main/java/org/cryptomator/common/vaults/MountPointRequirement.java index 84a798e59..deec61e1a 100644 --- a/src/main/java/org/cryptomator/common/vaults/MountPointRequirement.java +++ b/src/main/java/org/cryptomator/common/vaults/MountPointRequirement.java @@ -6,6 +6,11 @@ package org.cryptomator.common.vaults; */ public enum MountPointRequirement { + /** + * The Mountpoint needs to be a filesystem root and must not exist. + */ + UNUSED_ROOT_DIR, + /** * No Mountpoint on the local filesystem required. (e.g. WebDAV) */ diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java index 35f2be069..1fd463432 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java @@ -35,14 +35,13 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ResourceBundle; -import java.util.UUID; @AddVaultWizardScoped public class CreateNewVaultLocationController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultLocationController.class); private static final Path DEFAULT_CUSTOM_VAULT_PATH = Paths.get(System.getProperty("user.home")); - private static final String TEMP_FILE_FORMAT = "cryptomator-%s.tmp"; + private static final String TEMP_FILE_FORMAT = ".locationTest.cryptomator.tmp"; private final Stage window; private final Lazy chooseNameScene; @@ -112,7 +111,7 @@ public class CreateNewVaultLocationController implements FxController { } private boolean isActuallyWritable(Path p) { - Path tmpFile = p.resolve(String.format(TEMP_FILE_FORMAT, UUID.randomUUID())); + Path tmpFile = p.resolve(TEMP_FILE_FORMAT); try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) { return true; } catch (IOException e) { diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java b/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java index fd85db988..234bac65b 100644 --- a/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java +++ b/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.unlock; +import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.vaults.MountPointRequirement; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; @@ -32,12 +33,24 @@ public class UnlockInvalidMountPointController implements FxController { return vault.getVaultSettings().getCustomMountPath().orElse("AUTO"); } - public boolean getMustExist() { - MountPointRequirement requirement = vault.getVolume().orElseThrow(() -> new IllegalStateException("Invalid Mountpoint without a Volume?!")).getMountPointRequirement(); - assert requirement != MountPointRequirement.NONE; //An invalid MountPoint with no required MountPoint doesn't seem sensible - assert requirement != MountPointRequirement.PARENT_OPT_MOUNT_POINT; //Not implemented anywhere (yet) - - return requirement == MountPointRequirement.EMPTY_MOUNT_POINT; + public boolean getNotExisting() { + return getMountPointRequirement() == MountPointRequirement.EMPTY_MOUNT_POINT; } -} + public boolean getExisting() { + return getMountPointRequirement() == MountPointRequirement.PARENT_NO_MOUNT_POINT; + } + + public boolean getDriveLetterOccupied() { + return getMountPointRequirement() == MountPointRequirement.UNUSED_ROOT_DIR; + } + + private MountPointRequirement getMountPointRequirement() { + var requirement = vault.getVolume().orElseThrow(() -> new IllegalStateException("Invalid Mountpoint without a Volume?!")).getMountPointRequirement(); + assert requirement != MountPointRequirement.NONE; //An invalid MountPoint with no required MountPoint doesn't seem sensible + assert requirement != MountPointRequirement.PARENT_OPT_MOUNT_POINT; //Not implemented anywhere (yet) + assert requirement != MountPointRequirement.UNUSED_ROOT_DIR || SystemUtils.IS_OS_WINDOWS; //Not implemented anywhere, but on Windows + + return requirement; + } +} \ No newline at end of file diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java b/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java index 073258d80..6964c3c86 100644 --- a/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java +++ b/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java @@ -2,6 +2,7 @@ package org.cryptomator.ui.unlock; import com.google.common.base.Throwables; import dagger.Lazy; +import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.mountpoint.InvalidMountPointException; import org.cryptomator.common.vaults.MountPointRequirement; import org.cryptomator.common.vaults.Vault; @@ -79,9 +80,10 @@ public class UnlockWorkflow extends Task { } private void handleInvalidMountPoint(InvalidMountPointException impExc) { - MountPointRequirement requirement = vault.getVolume().orElseThrow(() -> new IllegalStateException("Invalid Mountpoint without a Volume?!", impExc)).getMountPointRequirement(); + var requirement = vault.getVolume().orElseThrow(() -> new IllegalStateException("Invalid Mountpoint without a Volume?!", impExc)).getMountPointRequirement(); assert requirement != MountPointRequirement.NONE; //An invalid MountPoint with no required MountPoint doesn't seem sensible assert requirement != MountPointRequirement.PARENT_OPT_MOUNT_POINT; //Not implemented anywhere (yet) + assert requirement != MountPointRequirement.UNUSED_ROOT_DIR || SystemUtils.IS_OS_WINDOWS; //Not implemented anywhere, but on Windows Throwable cause = impExc.getCause(); // TODO: apply https://openjdk.java.net/jeps/8213076 in future JDK versions @@ -93,7 +95,11 @@ public class UnlockWorkflow extends Task { } showInvalidMountPointScene(); } else if (cause instanceof FileAlreadyExistsException) { - LOG.error("Unlock failed. Mountpoint already exists: {}", cause.getMessage()); + if (requirement == MountPointRequirement.UNUSED_ROOT_DIR) { + LOG.error("Unlock failed. Drive Letter already in use: {}", cause.getMessage()); + } else { + LOG.error("Unlock failed. Mountpoint already exists: {}", cause.getMessage()); + } showInvalidMountPointScene(); } else if (cause instanceof DirectoryNotEmptyException) { LOG.error("Unlock failed. Mountpoint not an empty directory: {}", cause.getMessage()); diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 8739be791..3be38568d 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -11,9 +11,6 @@ import org.cryptomator.ui.common.FxController; import javax.inject.Inject; import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; @@ -32,18 +29,15 @@ import java.nio.file.Path; import java.util.ResourceBundle; import java.util.Set; -/** - * TODO: if WebDav is selected on a windows system, custom mount directory is _not_ supported. This is currently not indicated/shown/etc in the ui - */ @VaultOptionsScoped public class MountOptionsController implements FxController { private final Stage window; private final Vault vault; - private final BooleanProperty osIsWindows = new SimpleBooleanProperty(SystemUtils.IS_OS_WINDOWS); - private final BooleanBinding webDavAndWindows; + private final VolumeImpl usedVolumeImpl; private final WindowsDriveLetters windowsDriveLetters; private final ResourceBundle resourceBundle; + public CheckBox readOnlyCheckbox; public CheckBox customMountFlagsCheckbox; public TextField mountFlags; @@ -53,20 +47,13 @@ public class MountOptionsController implements FxController { public RadioButton mountPointCustomDir; public ChoiceBox driveLetterSelection; - //FUSE + Windows -> Disable some (experimental) features for the user because they are unstable - //Use argument Dfuse.experimental="true" to override - private final BooleanBinding restrictToStableFuseOnWindows; - @Inject MountOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, Settings settings, WindowsDriveLetters windowsDriveLetters, ResourceBundle resourceBundle, Environment environment) { this.window = window; this.vault = vault; - this.webDavAndWindows = settings.preferredVolumeImpl().isEqualTo(VolumeImpl.WEBDAV).and(osIsWindows); + this.usedVolumeImpl = settings.preferredVolumeImpl().get(); this.windowsDriveLetters = windowsDriveLetters; this.resourceBundle = resourceBundle; - - BooleanBinding isFuseOnWindows = settings.preferredVolumeImpl().isEqualTo(VolumeImpl.FUSE).and(osIsWindows); - this.restrictToStableFuseOnWindows = isFuseOnWindows.and(new SimpleBooleanProperty(!environment.useExperimentalFuse())); //Is FUSE on Win and is NOT experimental fuse enabled } @FXML @@ -74,10 +61,11 @@ public class MountOptionsController implements FxController { // readonly: readOnlyCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().usesReadOnlyMode()); - if (getRestrictToStableFuseOnWindows()) { + //TODO: support this feature on Windows + if (usedVolumeImpl == VolumeImpl.FUSE && isOsWindows()) { readOnlyCheckbox.setSelected(false); // to prevent invalid states + readOnlyCheckbox.setDisable(true); } - readOnlyCheckbox.disableProperty().bind(customMountFlagsCheckbox.selectedProperty().or(restrictToStableFuseOnWindows)); // custom mount flags: mountFlags.disableProperty().bind(customMountFlagsCheckbox.selectedProperty().not()); @@ -95,9 +83,7 @@ public class MountOptionsController implements FxController { driveLetterSelection.setConverter(new WinDriveLetterLabelConverter(windowsDriveLetters, resourceBundle)); driveLetterSelection.setValue(vault.getVaultSettings().winDriveLetter().get()); - if (vault.getVaultSettings().useCustomMountPath().get() - && vault.getVaultSettings().getCustomMountPath().isPresent() - && !getRestrictToStableFuseOnWindows() /* to prevent invalid states */) { + if (vault.getVaultSettings().useCustomMountPath().get() && vault.getVaultSettings().getCustomMountPath().isPresent()) { mountPoint.selectToggle(mountPointCustomDir); } else if (!Strings.isNullOrEmpty(vault.getVaultSettings().winDriveLetter().get())) { mountPoint.selectToggle(mountPointWinDriveLetter); @@ -188,32 +174,28 @@ public class MountOptionsController implements FxController { // Getter & Setter - public BooleanProperty osIsWindowsProperty() { - return osIsWindows; + public boolean isOsWindows() { + return SystemUtils.IS_OS_WINDOWS; } - public boolean getOsIsWindows() { - return osIsWindows.get(); + public boolean isCustomMountPointSupported() { + return !(usedVolumeImpl == VolumeImpl.WEBDAV && isOsWindows()); } - public BooleanBinding webDavAndWindowsProperty() { - return webDavAndWindows; - } - - public boolean isWebDavAndWindows() { - return webDavAndWindows.get(); + public boolean isReadOnlySupported() { + return !(usedVolumeImpl == VolumeImpl.FUSE && isOsWindows()); } public StringProperty customMountPathProperty() { return vault.getVaultSettings().customMountPath(); } + public boolean isCustomMountOptionsSupported() { + return usedVolumeImpl != VolumeImpl.WEBDAV; + } + public String getCustomMountPath() { return vault.getVaultSettings().customMountPath().get(); } - public Boolean getRestrictToStableFuseOnWindows() { - return restrictToStableFuseOnWindows.get(); - } - } diff --git a/src/main/resources/fxml/unlock_invalid_mount_point.fxml b/src/main/resources/fxml/unlock_invalid_mount_point.fxml index 253ff5704..062981304 100644 --- a/src/main/resources/fxml/unlock_invalid_mount_point.fxml +++ b/src/main/resources/fxml/unlock_invalid_mount_point.fxml @@ -29,8 +29,9 @@ - - + + + diff --git a/src/main/resources/fxml/vault_options_mount.fxml b/src/main/resources/fxml/vault_options_mount.fxml index a96784020..48b1fc7cd 100644 --- a/src/main/resources/fxml/vault_options_mount.fxml +++ b/src/main/resources/fxml/vault_options_mount.fxml @@ -24,7 +24,7 @@ - + @@ -38,19 +38,19 @@ - + - - + + - + diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties index 63e2bbecf..36932b877 100644 --- a/src/main/resources/i18n/strings.properties +++ b/src/main/resources/i18n/strings.properties @@ -116,6 +116,7 @@ unlock.error.heading=Unable to unlock vault ### Invalid Mount Point unlock.error.invalidMountPoint.notExisting=Mount point "%s" is not a directory, not empty or does not exist. unlock.error.invalidMountPoint.existing=Mount point "%s" already exists or parent folder is missing. +unlock.error.invalidMountPoint.driveLetterOccupied=Drive Letter "%s" is already in use. # Lock ## Force diff --git a/src/main/resources/license/THIRD-PARTY.txt b/src/main/resources/license/THIRD-PARTY.txt index ba4310dd5..9c9d92c7d 100644 --- a/src/main/resources/license/THIRD-PARTY.txt +++ b/src/main/resources/license/THIRD-PARTY.txt @@ -62,10 +62,10 @@ Cryptomator uses 40 third-party dependencies under the following licenses: GPLv2: - jnr-posix (com.github.jnr:jnr-posix:3.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix) GPLv2+CE: - - javafx-base (org.openjfx:javafx-base:17.0.1 - https://openjdk.java.net/projects/openjfx/javafx-base/) - - javafx-controls (org.openjfx:javafx-controls:17.0.1 - https://openjdk.java.net/projects/openjfx/javafx-controls/) - - javafx-fxml (org.openjfx:javafx-fxml:17.0.1 - https://openjdk.java.net/projects/openjfx/javafx-fxml/) - - javafx-graphics (org.openjfx:javafx-graphics:17.0.1 - https://openjdk.java.net/projects/openjfx/javafx-graphics/) + - javafx-base (org.openjfx:javafx-base:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-base/) + - javafx-controls (org.openjfx:javafx-controls:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-controls/) + - javafx-fxml (org.openjfx:javafx-fxml:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-fxml/) + - javafx-graphics (org.openjfx:javafx-graphics:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-graphics/) LGPL 2.1: - jnr-posix (com.github.jnr:jnr-posix:3.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix) LGPL-2.1-or-later: diff --git a/src/test/java/org/cryptomator/common/mountpoint/CustomMountPointChooserTest.java b/src/test/java/org/cryptomator/common/mountpoint/CustomMountPointChooserTest.java new file mode 100644 index 000000000..da2e0fde0 --- /dev/null +++ b/src/test/java/org/cryptomator/common/mountpoint/CustomMountPointChooserTest.java @@ -0,0 +1,187 @@ +package org.cryptomator.common.mountpoint; + +import org.cryptomator.common.Environment; +import org.cryptomator.common.settings.VaultSettings; +import org.cryptomator.common.vaults.MountPointRequirement; +import org.cryptomator.common.vaults.Volume; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CustomMountPointChooserTest { + + //--- Mocks --- + VaultSettings vaultSettings; + Environment environment; + Volume volume; + + CustomMountPointChooser customMpc; + + + @BeforeEach + public void init() { + this.volume = Mockito.mock(Volume.class); + this.vaultSettings = Mockito.mock(VaultSettings.class); + this.environment = Mockito.mock(Environment.class); + this.customMpc = new CustomMountPointChooser(vaultSettings, environment); + } + + @Nested + public class WinfspPreperations { + + @Test + @DisplayName("Hideaway name for PARENT_NO_MOUNTPOINT is not the same as mountpoint") + public void testGetHideaway() { + //prepare + Path mntPoint = Path.of("/foo/bar"); + //execute + var hideaway = customMpc.getHideaway(mntPoint); + //eval + Assertions.assertNotEquals(hideaway.getFileName(), mntPoint.getFileName()); + Assertions.assertEquals(hideaway.getParent(), mntPoint.getParent()); + Assertions.assertTrue(hideaway.getFileName().toString().contains(mntPoint.getFileName().toString())); + } + + @Test + @DisplayName("PARENT_NO_MOUNTPOINT preparations succeeds, if only mountpoint is present") + public void testPrepareParentNoMountpointOnlyMountpoint(@TempDir Path tmpDir) throws IOException { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + Files.createDirectory(mntPoint); + + //execute + Assertions.assertDoesNotThrow(() -> customMpc.prepareParentNoMountPoint(mntPoint)); + + //evaluate + Assertions.assertTrue(Files.notExists(mntPoint)); + + Path hideaway = customMpc.getHideaway(mntPoint); + Assertions.assertTrue(Files.exists(hideaway)); + + if(OS.WINDOWS.isCurrentOs()) { + Assertions.assertTrue((Boolean) Files.getAttribute(hideaway, "dos:hidden")); + } + } + + @Test + @DisplayName("PARENT_NO_MOUNTPOINT preparations fail, if only non-empty mountpoint is present") + public void testPrepareParentNoMountpointOnlyNonEmptyMountpoint(@TempDir Path tmpDir) throws IOException { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + Files.createDirectory(mntPoint); + Files.createFile(mntPoint.resolve("foo")); + + //execute + Assertions.assertThrows(InvalidMountPointException.class, () -> customMpc.prepareParentNoMountPoint(mntPoint)); + + //evaluate + Assertions.assertTrue(Files.exists(mntPoint.resolve("foo"))); + } + + @Test + @DisplayName("PARENT_NO_MOUNTPOINT preparation succeeds, if for any reason only hideaway dir is present") + public void testPrepareParentNoMountpointOnlyHideaway(@TempDir Path tmpDir) throws IOException { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + var hideaway = customMpc.getHideaway(mntPoint); + Files.createDirectory(hideaway); //we explicitly do not set the file attributes here + + //execute + Assertions.assertDoesNotThrow(() -> customMpc.prepareParentNoMountPoint(mntPoint)); + + //evaluate + Assertions.assertTrue(Files.exists(hideaway)); + + if(OS.WINDOWS.isCurrentOs()) { + Assertions.assertTrue((Boolean) Files.getAttribute(hideaway, "dos:hidden")); + } + } + + @Test + @DisplayName("PARENT_NO_MOUNTPOINT preparation fails, if mountpoint and hideaway dirs are present") + public void testPrepareParentNoMountpointMountPointAndHideaway(@TempDir Path tmpDir) throws IOException { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + var hideaway = customMpc.getHideaway(mntPoint); + Files.createDirectory(hideaway); //we explicitly do not set the file attributes here + Files.createDirectory(mntPoint); + + //execute + Assertions.assertThrows(InvalidMountPointException.class, () -> customMpc.prepareParentNoMountPoint(mntPoint)); + + //evaluate + Assertions.assertTrue(Files.exists(hideaway)); + Assertions.assertTrue(Files.exists(mntPoint)); + + if(OS.WINDOWS.isCurrentOs()) { + Assertions.assertFalse((Boolean) Files.getAttribute(hideaway, "dos:hidden")); + } + } + + @Test + @DisplayName("PARENT_NO_MOUNTPOINT preparation fails, if neither mountpoint nor hideaway dir is present") + public void testPrepareParentNoMountpointNothing(@TempDir Path tmpDir) { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + var hideaway = customMpc.getHideaway(mntPoint); + + //execute + Assertions.assertThrows(InvalidMountPointException.class, () -> customMpc.prepareParentNoMountPoint(mntPoint)); + + //evaluate + Assertions.assertTrue(Files.notExists(hideaway)); + Assertions.assertTrue(Files.notExists(mntPoint)); + } + + @Test + @DisplayName("Normal Cleanup for PARENT_NO_MOUNTPOINT") + public void testCleanupSuccess(@TempDir Path tmpDir) throws IOException { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + var hideaway = customMpc.getHideaway(mntPoint); + + Files.createDirectory(hideaway); + Mockito.when(volume.getMountPointRequirement()).thenReturn(MountPointRequirement.PARENT_NO_MOUNT_POINT); + + //execute + Assertions.assertDoesNotThrow(() -> customMpc.cleanup(volume, mntPoint)); + + //evaluate + Assertions.assertTrue(Files.exists(mntPoint)); + Assertions.assertTrue(Files.notExists(hideaway)); + + if(OS.WINDOWS.isCurrentOs()) { + Assertions.assertFalse((Boolean) Files.getAttribute(mntPoint, "dos:hidden")); + } + } + + @Test + @DisplayName("On IOException cleanup for PARENT_NO_MOUNTPOINT exits normally") + public void testCleanupIOFailure(@TempDir Path tmpDir) throws IOException { + //prepare + var mntPoint = tmpDir.resolve("mntPoint"); + var hideaway = customMpc.getHideaway(mntPoint); + + Files.createDirectory(hideaway); + Mockito.when(volume.getMountPointRequirement()).thenReturn(MountPointRequirement.PARENT_NO_MOUNT_POINT); + try (MockedStatic filesMock = Mockito.mockStatic(Files.class)) { + filesMock.when(() -> Files.move(Mockito.any(), Mockito.any(), Mockito.any())).thenThrow(new IOException("error")); + //execute + Assertions.assertDoesNotThrow(() -> customMpc.cleanup(volume, mntPoint)); + } + } + + } + + +} diff --git a/suppression.xml b/suppression.xml index c747f92a7..ccd1a1cdf 100644 --- a/suppression.xml +++ b/suppression.xml @@ -25,4 +25,23 @@ org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 .* + + + + ^org\.cryptomator:.*$ + cpe:/a:cryptomator:cryptomator + CVE-2022-25366 + + + + + ^commons\-cli:commons\-cli:.*$ + cpe:/a:apache:james + + cpe:/a:spirit-project:spirit + \ No newline at end of file