diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 521edeedd..26111c518 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -52,7 +52,6 @@ jobs: java-version: ${{ env.JAVA_VERSION }} check-latest: true cache: 'maven' - - name: Download OpenJFX jmods id: download-jmods run: | @@ -194,3 +193,68 @@ jobs: cryptomator-*.AppImage cryptomator-*.zsync cryptomator-*.asc + + create-aur-bin-pr: + name: Create PR for aur-bin repo + needs: [build, get-version] + runs-on: ubuntu-latest + if: github.event_name == 'release' + steps: + - name: Download AppImages + uses: actions/download-artifact@v4 + with: + path: downloads/ + merge-multiple: true + - name: Compute sha256 hash of AppImages + id: checksums + run: | + X64_SHA256=$(sha256sum downloads/cryptomator-*-x86_64.AppImage | cut -d ' ' -f1) + echo "x64-sha256sum=${X64_SHA256}" >> "$GITHUB_OUTPUT" + AARCH64_SHA256=$(sha256sum downloads/cryptomator-*-aarch64.AppImage | cut -d ' ' -f1) + echo "aarch64-sha256sum=${AARCH64_SHA256}" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v4 + with: + repository: 'cryptomator/aur-bin' + token: ${{ secrets.CRYPTOBOT_PR_TOKEN }} + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install makepkg pacman-package-manager + - name: Checkout release branch + run: | + git checkout -b release/${{ needs.get-version.outputs.semVerStr }} + - name: Update build file + run: | + sed -i -e 's|^pkgver=.*$|pkgver=${{ needs.get-version.outputs.semVerStr }}|' PKGBUILD + sed -i -e 's|^pkgrel=.*$|pkgrel=1|' PKGBUILD + sed -i -e "s|^sha256sums_x86_64=.*$|sha256sums_x86_64=('${{ steps.checksums.outputs.x64-sha256sum }}'|" PKGBUILD + sed -i -e "s|^sha256sums_aarch64=.*$|sha256sums_aarch64=('${{ steps.checksums.outputs.aarch64-sha256sum}}'|" PKGBUILD + makepkg --printsrcinfo > .SRCINFO + - name: Commit and push + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" + git config push.autoSetupRemote true + git stage . + git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}" + git push + - name: Create pull request + id: create-pr + run: | + printf "> [!IMPORTANT]\n> Todos:\n> - [ ] Update build instructions\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md + URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md) + echo "PR_URL=$URL" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }} + - name: Slack Notification + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_USERNAME: 'Cryptobot' + SLACK_ICON: false + SLACK_ICON_EMOJI: ':bot:' + SLACK_CHANNEL: 'cryptomator-desktop' + SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created." + SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.PR_URL }}|PR> on how to proceed." + SLACK_FOOTER: false + MSG_MINIMAL: true diff --git a/.github/workflows/aur.yml b/.github/workflows/aur.yml new file mode 100644 index 000000000..e290be872 --- /dev/null +++ b/.github/workflows/aur.yml @@ -0,0 +1,93 @@ +name: Create PR for AUR + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: 'Release tag' + required: true + +jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: ${{ inputs.tag }} + tarball: + name: Determines tarball url and compute checksum + runs-on: ubuntu-latest + needs: [get-version] + if: github.event_name == 'workflow_dispatch' || needs.get-version.outputs.versionType == 'stable' + outputs: + url: ${{ steps.url.outputs.url}} + sha256: ${{ steps.sha256.outputs.sha256}} + steps: + - name: Determine tarball url + id: url + run: | + URL=""; + if [[ -n "${{ inputs.tag }}" ]]; then + URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ inputs.tag }}.tar.gz" + else + URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz" + fi + echo "url=${URL}" >> "$GITHUB_OUTPUT" + - name: Download source tarball and compute checksum + id: sha256 + run: | + curl --silent --fail-with-body -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz + TARBALL_SHA256=$(sha256sum cryptomator.tar.gz | cut -d ' ' -f1) + echo "sha256=${TARBALL_SHA256}" >> "$GITHUB_OUTPUT" + aur: + name: Create PR for AUR + runs-on: ubuntu-latest + needs: [tarball, get-version] + env: + AUR_PR_URL: tbd + steps: + - uses: actions/checkout@v4 + with: + repository: 'cryptomator/aur' + token: ${{ secrets.CRYPTOBOT_PR_TOKEN }} + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install makepkg pacman-package-manager + - name: Checkout release branch + run: | + git checkout -b release/${{ needs.get-version.outputs.semVerStr }} + - name: Update build file + run: | + sed -i -e 's|^pkgver=.*$|pkgver=${{ needs.get-version.outputs.semVerStr }}|' PKGBUILD + sed -i -e 's|^pkgrel=.*$|pkgrel=1|' PKGBUILD + sed -i -e "s|^sha256sums=.*$|sha256sums=('${{ needs.tarball.outputs.sha256 }}'|" PKGBUILD + makepkg --printsrcinfo > .SRCINFO + - name: Commit and push + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" + git config push.autoSetupRemote true + git stage . + git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}" + git push + - name: Create pull request + run: | + printf "> [!IMPORTANT]\n> Todos:\n> - [ ] Update build instructions\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md + PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md) + echo "AUR_PR_URL=$PR_URL" >> "$GITHUB_ENV" + env: + GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }} + - name: Slack Notification + uses: rtCamp/action-slack-notify@v2 + if: github.event_name == 'release' + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_USERNAME: 'Cryptobot' + SLACK_ICON: false + SLACK_ICON_EMOJI: ':bot:' + SLACK_CHANNEL: 'cryptomator-desktop' + SLACK_TITLE: "AUR release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created." + SLACK_MESSAGE: "See <${{ env.AUR_PR_URL }}|PR> on how to proceed." + SLACK_FOOTER: false + MSG_MINIMAL: true \ No newline at end of file diff --git a/.github/workflows/flathub.yml b/.github/workflows/flathub.yml index da8f6c77f..85e2cb435 100644 --- a/.github/workflows/flathub.yml +++ b/.github/workflows/flathub.yml @@ -49,7 +49,7 @@ jobs: - uses: actions/checkout@v4 with: repository: 'flathub/org.cryptomator.Cryptomator' - token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }} + token: ${{ secrets.CRYPTOBOT_PR_TOKEN }} - name: Checkout release branch run: | git checkout -b release/${{ needs.get-version.outputs.semVerStr }} @@ -72,7 +72,7 @@ jobs: PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md) echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV" env: - GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }} + GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }} - name: Slack Notification uses: rtCamp/action-slack-notify@v2 if: github.event_name == 'release' diff --git a/.github/workflows/win-exe.yml b/.github/workflows/win-exe.yml index cfbbc05a7..2045fc6da 100644 --- a/.github/workflows/win-exe.yml +++ b/.github/workflows/win-exe.yml @@ -12,6 +12,11 @@ on: description: 'Build debug version with console output' type: boolean default: false + sign: + description: 'Sign binaries' + required: false + type: boolean + default: false push: branches-ignore: - 'dependabot/**' @@ -126,9 +131,6 @@ jobs: --no-man-pages --strip-debug --compress zip-0 - - name: Change win-console flag if debug is active - if: ${{ inputs.isDebug }} - run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV - name: Run jpackage run: > ${JAVA_HOME}/bin/jpackage @@ -166,7 +168,7 @@ jobs: --java-options "-Djavafx.verbose=${{ inputs.isDebug }}" --resource-dir dist/win/resources --icon dist/win/resources/Cryptomator.ico - ${WIN_CONSOLE_FLAG} + --add-launcher "Cryptomator (Debug)=dist/win/debug-launcher.properties" - name: Patch Application Directory run: | cp dist/win/contrib/* appdir/Cryptomator @@ -181,7 +183,9 @@ jobs: exit 1 } - name: Fix permissions - run: attrib -r appdir/Cryptomator/Cryptomator.exe + run: | + attrib -r appdir/Cryptomator/Cryptomator.exe + attrib -r "appdir/Cryptomator/Cryptomator (Debug).exe" shell: pwsh - name: Extract jars with DLLs for Codesigning shell: pwsh @@ -206,16 +210,17 @@ jobs: New-Item -Path appdir/jpackage-jmod -ItemType Directory & $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod" Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir" - - name: Codesign - uses: skymatic/code-sign-action@v3 + - name: Sign DLLs with Actalis CodeSigner + if: inputs.sign || github.event_name == 'release' + uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f with: - certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} - password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A - description: Cryptomator - timestampUrl: 'http://timestamp.digicert.com' - folder: appdir + base-dir: 'appdir' + file-extensions: 'dll,exe,ps1' recursive: true + sign-description: 'Cryptomator' + sign-url: 'https://cryptomator.org' + username: ${{ secrets.WIN_CODESIGN_USERNAME }} + password: ${{ secrets.WIN_CODESIGN_PW }} - name: Replace DLLs inside jars with signed ones shell: pwsh run: | @@ -264,15 +269,16 @@ jobs: env: JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir - - name: Codesign MSI - uses: skymatic/code-sign-action@v3 + - name: Sign msi with Actalis CodeSigner + if: inputs.sign || github.event_name == 'release' + uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f with: - certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} - password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A - description: Cryptomator Installer - timestampUrl: 'http://timestamp.digicert.com' - folder: installer + base-dir: 'installer' + file-extensions: 'msi' + sign-description: 'Cryptomator Installer' + sign-url: 'https://cryptomator.org' + username: ${{ secrets.WIN_CODESIGN_USERNAME }} + password: ${{ secrets.WIN_CODESIGN_PW }} - name: Add possible alpha/beta tags and architecture to installer name run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.arch }}.msi - name: Create detached GPG signature with key 615D449FE6E6A235 @@ -375,27 +381,29 @@ jobs: - name: Detach burn engine in preparation to sign run: > wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe - - name: Codesign burn engine - uses: skymatic/code-sign-action@v3 + - name: Sign burn engine with Actalis CodeSigner + if: inputs.sign || github.event_name == 'release' + uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f with: - certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} - password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A - description: Cryptomator Installer - timestampUrl: 'http://timestamp.digicert.com' - folder: tmp + base-dir: 'tmp' + file-extensions: 'exe' + sign-description: 'Cryptomator Bundle Installer' + sign-url: 'https://cryptomator.org' + username: ${{ secrets.WIN_CODESIGN_USERNAME }} + password: ${{ secrets.WIN_CODESIGN_PW }} - name: Reattach signed burn engine to installer run: > wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe - - name: Codesign EXE - uses: skymatic/code-sign-action@v3 + - name: Sign installer with Actalis CodeSigner + if: inputs.sign || github.event_name == 'release' + uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f with: - certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} - password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A - description: Cryptomator Installer - timestampUrl: 'http://timestamp.digicert.com' - folder: installer + base-dir: 'installer' + file-extensions: 'exe' + sign-description: 'Cryptomator Bundle Installer' + sign-url: 'https://cryptomator.org' + username: ${{ secrets.WIN_CODESIGN_USERNAME }} + password: ${{ secrets.WIN_CODESIGN_PW }} - name: Add possible alpha/beta tags to installer name run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.executable-suffix }}.exe - name: Create detached GPG signature with key 615D449FE6E6A235 diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml index 476e409e3..0beb75544 100644 --- a/.github/workflows/winget.yml +++ b/.github/workflows/winget.yml @@ -16,7 +16,7 @@ jobs: run: | gh repo sync cryptomator/winget-pkgs -b master --force env: - GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }} + GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }} - name: Submit package uses: vedantmgoyal2009/winget-releaser@main with: @@ -24,4 +24,4 @@ jobs: version: ${{ inputs.tag }} release-tag: ${{ inputs.tag }} installers-regex: '-x64\.msi$' - token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }} \ No newline at end of file + token: ${{ secrets.CRYPTOBOT_PR_TOKEN }} \ No newline at end of file diff --git a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml index 16e2ba876..e986431a8 100644 --- a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml +++ b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml @@ -83,6 +83,12 @@ + + https://github.com/cryptomator/cryptomator/releases/1.17.1 + + + https://github.com/cryptomator/cryptomator/releases/1.17.0 + https://github.com/cryptomator/cryptomator/releases/1.16.2 diff --git a/dist/win/.gitignore b/dist/win/.gitignore index 7b2faa4b5..a9cb10372 100644 --- a/dist/win/.gitignore +++ b/dist/win/.gitignore @@ -4,7 +4,8 @@ installer *.wixobj *.pdb *.msi +*Debug.properties *.exe *.jmod resources/jfxJmods.zip -license.rtf \ No newline at end of file +license.rtf diff --git a/dist/win/build.bat b/dist/win/build.bat index 3532a69fd..c8f23a82b 100644 --- a/dist/win/build.bat +++ b/dist/win/build.bat @@ -11,6 +11,10 @@ SET HELP_URL="https://cryptomator.org/contact/" SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator" SET LOOPBACK_ALIAS="cryptomator-vault" +:: read clean parameter from command line +SET CLEAN=0 +IF "%~1"=="clean" SET CLEAN=1 + pwsh -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^ -AppName %APPNAME%^ -MainJarGlob "%MAIN_JAR_GLOB%"^ @@ -22,4 +26,4 @@ pwsh -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^ -HelpUrl "%HELP_URL%"^ -UpdateUrl "%UPDATE_URL%"^ -LoopbackAlias "%LOOPBACK_ALIAS%"^ - -Clean 1 \ No newline at end of file + -Clean %CLEAN% \ No newline at end of file diff --git a/dist/win/build.ps1 b/dist/win/build.ps1 index a861cf40d..b1706a28e 100644 --- a/dist/win/build.ps1 +++ b/dist/win/build.ps1 @@ -9,9 +9,15 @@ Param( [Parameter(Mandatory, HelpMessage="Please provide an update url")][string] $UpdateUrl, [Parameter(Mandatory, HelpMessage="Please provide an about url")][string] $AboutUrl, [Parameter(Mandatory, HelpMessage="Please provide an alias for localhost")][string] $LoopbackAlias, - [bool] $clean + [bool] $clean = $false # if true, cleans up previous build artifacts ) +# ============================ +# Function Definitions Section +# ============================ + +function Main { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s @@ -50,11 +56,11 @@ $version = $(mvn -f $buildDir/../../pom.xml help:evaluate -Dexpression="project. $semVerNo = $version -replace '(\d+\.\d+\.\d+).*','$1' $revisionNo = $(git rev-list --count HEAD) -Write-Output "`$version=$version" -Write-Output "`$semVerNo=$semVerNo" -Write-Output "`$revisionNo=$revisionNo" -Write-Output "`$buildDir=$buildDir" -Write-Output "`$Env:JAVA_HOME=$Env:JAVA_HOME" +Write-Host "`$version=$version" +Write-Host "`$semVerNo=$semVerNo" +Write-Host "`$revisionNo=$revisionNo" +Write-Host "`$buildDir=$buildDir" +Write-Host "`$Env:JAVA_HOME=$Env:JAVA_HOME" $copyright = "(C) $CopyrightStartYear - $((Get-Date).Year) $Vendor" @@ -71,7 +77,7 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) { ## download jfx jmods for X64, while they are part of the Arm64 JDK $archCode = (Get-CimInstance Win32_Processor).Architecture $archName = switch ($archCode) { - 9 { "x64 (AMD64)" } + 9 { "x64" } 12 { "ARM64" } default { "WMI Win32_Processor.Architecture code ($archCode)" } } @@ -86,14 +92,14 @@ switch ($archName) { $jmodPaths = "$Env:JAVA_HOME/jmods" } - 'x64 (AMD64)' { + 'x64' { $javaFxVersion='24.0.1' $javaFxJmodsUrl = "https://download2.gluonhq.com/openjfx/${javaFxVersion}/openjfx-${javaFxVersion}_windows-x64_bin-jmods.zip" $javaFxJmodsSHA256 = 'f13d17c7caf88654fc835f1b4e75a9b0f34a888eb8abef381796c0002e63b03f' $javaFxJmods = '.\resources\jfxJmods.zip' if( !(Test-Path -Path $javaFxJmods) ) { - Write-Output "Downloading ${javaFxJmodsUrl}..." + Write-Host "Downloading ${javaFxJmodsUrl}..." Invoke-WebRequest $javaFxJmodsUrl -OutFile $javaFxJmods # redirects are followed by default } @@ -139,6 +145,29 @@ if ($clean -and (Test-Path -Path $appPath)) { Remove-Item -Path $appPath -Force -Recurse } + +$javaOptions = @( +"--java-options", "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win" +"--java-options", "-Xss5m" +"--java-options", "-Xmx256m" +"--java-options", "-Dcryptomator.appVersion=`"$semVerNo`"" +"--java-options", "-Dfile.encoding=`"utf-8`"" +"--java-options", "-Djava.net.useSystemProxies=true" +"--java-options", "-Dcryptomator.logDir=`"@{localappdata}/$AppName`"" +"--java-options", "-Dcryptomator.pluginDir=`"@{appdata}/$AppName/Plugins`"" +"--java-options", "-Dcryptomator.settingsPath=`"@{appdata}/$AppName/settings.json;@{userhome}/AppData/Roaming/$AppName/settings.json`"" +"--java-options", "-Dcryptomator.ipcSocketPath=`"@{localappdata}/$AppName/ipc.socket`"" +"--java-options", "-Dcryptomator.p12Path=`"@{appdata}/$AppName/key.p12;@{userhome}/AppData/Roaming/$AppName/key.p12`"" +"--java-options", "-Dcryptomator.mountPointsDir=`"@{userhome}/$AppName`"" +"--java-options", "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`"" +"--java-options", "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" +"--java-options", "-Dcryptomator.integrationsWin.keychainPaths=`"@{appdata}/$AppName/keychain.json;@{userhome}/AppData/Roaming/$AppName/keychain.json`"" +"--java-options", "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=`"@{appdata}/$AppName/windowsHelloKeychain.json`"" +"--java-options", "-Dcryptomator.showTrayIcon=true" +"--java-options", "-Dcryptomator.buildNumber=`"msi-$revisionNo`"" +) + + # create app dir & "$Env:JAVA_HOME\bin\jpackage" ` --verbose ` @@ -151,28 +180,16 @@ if ($clean -and (Test-Path -Path $appPath)) { --name $AppName ` --vendor $Vendor ` --copyright $copyright ` - --java-options "--enable-preview" ` - --java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win" ` - --java-options "-Xss5m" ` - --java-options "-Xmx256m" ` - --java-options "-Dcryptomator.appVersion=`"$semVerNo`"" ` --app-version "$semVerNo.$revisionNo" ` - --java-options "-Dfile.encoding=`"utf-8`"" ` - --java-options "-Djava.net.useSystemProxies=true" ` - --java-options "-Dcryptomator.logDir=`"@{localappdata}/$AppName`"" ` - --java-options "-Dcryptomator.pluginDir=`"@{appdata}/$AppName/Plugins`"" ` - --java-options "-Dcryptomator.settingsPath=`"@{appdata}/$AppName/settings.json;@{userhome}/AppData/Roaming/$AppName/settings.json`"" ` - --java-options "-Dcryptomator.ipcSocketPath=`"@{localappdata}/$AppName/ipc.socket`"" ` - --java-options "-Dcryptomator.p12Path=`"@{appdata}/$AppName/key.p12;@{userhome}/AppData/Roaming/$AppName/key.p12`"" ` - --java-options "-Dcryptomator.mountPointsDir=`"@{userhome}/$AppName`"" ` - --java-options "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`"" ` - --java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" ` - --java-options "-Dcryptomator.integrationsWin.keychainPaths=`"@{appdata}/$AppName/keychain.json;@{userhome}/AppData/Roaming/$AppName/keychain.json`"" ` - --java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=`"@{appdata}/$AppName/windowsHelloKeychain.json`"" ` - --java-options "-Dcryptomator.showTrayIcon=true" ` - --java-options "-Dcryptomator.buildNumber=`"msi-$revisionNo`"" ` --resource-dir resources ` - --icon resources/$AppName.ico + --icon resources/$AppName.ico ` + --add-launcher "${AppName} (Debug)=$buildDir\debug-launcher.properties" ` + @javaOptions + +if ($LASTEXITCODE -ne 0) { + Write-Error "jpackage Appimage failed with exit code $LASTEXITCODE" + return 1; +} #Create RTF license for msi &mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" ` @@ -187,6 +204,7 @@ if ($clean -and (Test-Path -Path $appPath)) { # patch app dir Copy-Item "contrib\*" -Destination "$AppName" attrib -r "$AppName\$AppName.exe" +attrib -r "$AppName\${AppName} (Debug).exe" # patch batch script to set hostfile $webDAVPatcher = "$AppName\patchWebDAV.bat" try { @@ -237,7 +255,7 @@ if ($LASTEXITCODE -ne 0) { # download Winfsp $winfspMsiUrl= 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi' $winfspMsiHash = '073A70E00F77423E34BED98B86E600DEF93393BA5822204FAC57A29324DB9F7A' -Write-Output "Downloading ${winfspMsiUrl}..." +Write-Host "Downloading ${winfspMsiUrl}..." Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default $computedHash = $(Get-FileHash -Path '.\bundle\resources\winfsp.msi' -Algorithm SHA256).Hash if (! $computedHash.Equals($winfspMsiHash)) { @@ -251,7 +269,7 @@ if (! $computedHash.Equals($winfspMsiHash)) { # download legacy-winfsp uninstaller $winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe' -Write-Output "Downloading ${winfspUninstaller}..." +Write-Host "Downloading ${winfspUninstaller}..." Invoke-WebRequest $winfspUninstaller -OutFile ".\bundle\resources\winfsp-uninstaller.exe" # redirects are followed by default # copy MSI to bundle resources @@ -271,4 +289,18 @@ Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName .\bundle\bundleWithWinfsp.wxs ` -out "installer\$AppName-Installer.exe" -Write-Output "Created EXE installer .\installer\$AppName-Installer.exe" +Write-Host "Created EXE installer .\installer\$AppName-Installer.exe" +return 0; +} + +# ============================ +# Script Execution Starts Here +# ============================ +if ($clean) { + Write-Host "Cleaning up previous build artifacts..." + Remove-Item -Path ".\runtime" -Force -Recurse -ErrorAction Ignore + Remove-Item -Path ".\$AppName" -Force -Recurse -ErrorAction Ignore + Remove-Item -Path ".\installer" -Force -Recurse -ErrorAction Ignore +} +return Main + diff --git a/dist/win/debug-launcher.properties b/dist/win/debug-launcher.properties new file mode 100644 index 000000000..d8789ab7a --- /dev/null +++ b/dist/win/debug-launcher.properties @@ -0,0 +1,4 @@ +win-console=true +win-shortcut=false +win-menu=false +description=Debug Launcher with Console for Cryptomator \ No newline at end of file diff --git a/dist/win/launcher.bat b/dist/win/launcher.bat deleted file mode 100644 index 0e6ec7042..000000000 --- a/dist/win/launcher.bat +++ /dev/null @@ -1,15 +0,0 @@ -@echo off -java ^ - -p "mods" ^ - -cp "libs/*" ^ - -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" ^ - -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" ^ - -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" ^ - -Dcryptomator.mountPointsDir="~/Cryptomator" ^ - -Dcryptomator.integrationsWin.keychainPaths="~/AppData/Roaming/Cryptomator/keychain.json" ^ - -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="~/AppData/Roaming/Cryptomator/windowsHelloKeychain.json" ^ - -Xss20m ^ - -Xmx512m ^ - --enable-preview ` - --enable-native-access=org.cryptomator.jfuse.win ` - -m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator diff --git a/pom.xml b/pom.xml index 79d93f583..caba8e342 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.cryptomator cryptomator - 1.17.0-SNAPSHOT + 1.18.0-SNAPSHOT Cryptomator Desktop App diff --git a/src/main/java/org/cryptomator/common/settings/Settings.java b/src/main/java/org/cryptomator/common/settings/Settings.java index b382cd1ac..a711e6536 100644 --- a/src/main/java/org/cryptomator/common/settings/Settings.java +++ b/src/main/java/org/cryptomator/common/settings/Settings.java @@ -25,6 +25,8 @@ import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.NodeOrientation; + +import java.nio.file.Path; import java.time.Instant; import java.util.function.Consumer; @@ -75,6 +77,7 @@ public class Settings { public final BooleanProperty checkForUpdates; public final ObjectProperty lastUpdateCheckReminder; public final ObjectProperty lastSuccessfulUpdateCheck; + public final ObjectProperty previouslyUsedVaultDirectory; private Consumer saveCmd; @@ -114,6 +117,7 @@ public class Settings { this.checkForUpdates = new SimpleBooleanProperty(this, "checkForUpdates", json.checkForUpdatesEnabled); this.lastUpdateCheckReminder = new SimpleObjectProperty<>(this, "lastUpdateCheckReminder", json.lastReminderForUpdateCheck); this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck); + this.previouslyUsedVaultDirectory = new SimpleObjectProperty<>(this, "previouslyUsedVaultDirectory", json.previouslyUsedVaultDirectory); this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList()); @@ -143,6 +147,7 @@ public class Settings { checkForUpdates.addListener(this::somethingChanged); lastUpdateCheckReminder.addListener(this::somethingChanged); lastSuccessfulUpdateCheck.addListener(this::somethingChanged); + previouslyUsedVaultDirectory.addListener(this::somethingChanged); } @SuppressWarnings("deprecation") @@ -204,6 +209,7 @@ public class Settings { json.checkForUpdatesEnabled = checkForUpdates.get(); json.lastReminderForUpdateCheck = lastUpdateCheckReminder.get(); json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get(); + json.previouslyUsedVaultDirectory = previouslyUsedVaultDirectory.get(); return json; } diff --git a/src/main/java/org/cryptomator/common/settings/SettingsJson.java b/src/main/java/org/cryptomator/common/settings/SettingsJson.java index 15f5f2790..feb8a0bf2 100644 --- a/src/main/java/org/cryptomator/common/settings/SettingsJson.java +++ b/src/main/java/org/cryptomator/common/settings/SettingsJson.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import java.nio.file.Path; import java.time.Instant; import java.util.List; @@ -92,4 +93,7 @@ class SettingsJson { @JsonProperty("quickAccessService") String quickAccessService = Settings.DEFAULT_QUICKACCESS_SERVICE; + + @JsonProperty("previouslyUsedVaultDirectory") + Path previouslyUsedVaultDirectory; } diff --git a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java index 63cbcc3e0..3301d461c 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java @@ -8,6 +8,18 @@ *******************************************************************************/ package org.cryptomator.common.vaults; +import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.recovery.BackupRestorer; +import org.cryptomator.common.settings.Settings; +import org.cryptomator.common.settings.VaultSettings; +import org.cryptomator.cryptofs.CryptoFileSystemProvider; +import org.cryptomator.cryptofs.DirStructure; +import org.cryptomator.cryptofs.migration.Migrators; +import org.cryptomator.integrations.mount.MountService; +import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.inject.Inject; import javax.inject.Singleton; import javafx.collections.ObservableList; @@ -25,18 +37,6 @@ import static org.cryptomator.common.Constants.MASTERKEY_FILENAME; import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME; import static org.cryptomator.common.vaults.VaultState.Value.*; -import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.common.Constants; -import org.cryptomator.common.recovery.BackupRestorer; -import org.cryptomator.common.settings.Settings; -import org.cryptomator.common.settings.VaultSettings; -import org.cryptomator.cryptofs.CryptoFileSystemProvider; -import org.cryptomator.cryptofs.DirStructure; -import org.cryptomator.cryptofs.migration.Migrators; -import org.cryptomator.integrations.mount.MountService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - @Singleton public class VaultListManager { @@ -137,7 +137,7 @@ public class VaultListManager { vaultSettings.lastKnownKeyLoader.set(keyIdScheme); } } else if (vaultState == NEEDS_MIGRATION) { - vaultSettings.lastKnownKeyLoader.set(Constants.DEFAULT_KEY_ID.toString()); + vaultSettings.lastKnownKeyLoader.set(MasterkeyFileLoadingStrategy.SCHEME); } if (vaultState != VAULT_CONFIG_MISSING) { diff --git a/src/main/java/org/cryptomator/ipc/Server.java b/src/main/java/org/cryptomator/ipc/Server.java index 770373681..193a2ff6b 100644 --- a/src/main/java/org/cryptomator/ipc/Server.java +++ b/src/main/java/org/cryptomator/ipc/Server.java @@ -53,18 +53,26 @@ class Server implements IpcCommunicator { @Override public void listen(IpcMessageListener listener, Executor executor) { executor.execute(() -> { + int errorCount = 0; while (serverSocketChannel.isOpen()) { try (var ch = serverSocketChannel.accept()) { while (ch.isConnected()) { var msg = IpcMessage.receive(ch); listener.handleMessage(msg); } + errorCount = 0; } catch (AsynchronousCloseException e) { + LOG.info("Closing server socket due to closed channel."); return; // serverSocketChannel closed or listener interrupted } catch (EOFException | ClosedChannelException e) { // continue with next connected client } catch (IOException e) { + errorCount++; LOG.error("Failed to read IPC message", e); + if(errorCount > 100) { //apparently something is broken, prevent log spam + LOG.info("Closing server socket due to too many failed requests."); + return; + } } } }); diff --git a/src/main/java/org/cryptomator/logging/LogbackConfigurator.java b/src/main/java/org/cryptomator/logging/LogbackConfigurator.java index 3b77993cc..7e8b9e6c4 100644 --- a/src/main/java/org/cryptomator/logging/LogbackConfigurator.java +++ b/src/main/java/org/cryptomator/logging/LogbackConfigurator.java @@ -90,6 +90,9 @@ public class LogbackConfigurator extends ContextAwareBase implements Configurato // configure fuse file locking logger: Logger fuseLocking = context.getLogger("org.cryptomator.frontend.fuse.locks"); fuseLocking.setLevel(Level.OFF); + //deactivate kwallet unsettling message + Logger kdeWallet = context.getLogger("org.purejava.kwallet.freedesktop.dbus.handlers"); + kdeWallet.setLevel(Level.OFF); } return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY; } diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultExpertSettingsController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultExpertSettingsController.java index a35bcdebe..9ca557366 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultExpertSettingsController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultExpertSettingsController.java @@ -26,7 +26,7 @@ public class CreateNewVaultExpertSettingsController implements FxController { public static final int MAX_SHORTENING_THRESHOLD = 220; public static final int MIN_SHORTENING_THRESHOLD = 36; - private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/security/architecture/#name-shortening"; + private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/security/vault/#name-shortening"; private final Stage window; private final Lazy application; diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java index c8b7bee22..78a2771df 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java @@ -4,6 +4,7 @@ import dagger.Lazy; import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.locationpresets.LocationPreset; import org.cryptomator.common.locationpresets.LocationPresetsProvider; +import org.cryptomator.common.settings.Settings; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; @@ -38,6 +39,7 @@ import javafx.stage.WindowEvent; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; @@ -64,6 +66,7 @@ public class CreateNewVaultLocationController implements FxController { private final BooleanProperty loadingPresetLocations = new SimpleBooleanProperty(false); private final ObservableList radioButtons; private final ObservableList sortedRadioButtons; + private final Settings settings; private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH; @@ -82,6 +85,7 @@ public class CreateNewVaultLocationController implements FxController { @FxmlScene(FxmlFile.ADDVAULT_NEW_EXPERT_SETTINGS) Lazy chooseExpertSettingsScene, // ObjectProperty vaultPath, // @Named("vaultName") StringProperty vaultName, // + Settings settings, // ExecutorService backgroundExecutor, ResourceBundle resourceBundle) { this.window = window; this.chooseNameScene = chooseNameScene; @@ -96,6 +100,18 @@ public class CreateNewVaultLocationController implements FxController { this.usePresetPath = new SimpleBooleanProperty(); this.radioButtons = FXCollections.observableArrayList(); this.sortedRadioButtons = radioButtons.sorted(this::compareLocationPresets); + this.settings = settings; + + Path previouslyUsedDirectory = settings.previouslyUsedVaultDirectory.get(); + if (previouslyUsedDirectory != null) { + try { + if (Files.exists(previouslyUsedDirectory) && Files.isDirectory(previouslyUsedDirectory) && isActuallyWritable(previouslyUsedDirectory)) { + this.customVaultPath = previouslyUsedDirectory; + } + } catch (InvalidPathException | NullPointerException e) { + LOG.warn("Invalid previously used vault directory path: {}", previouslyUsedDirectory, e); + } + } } private VaultPathStatus validatePath(Path p) throws NullPointerException { @@ -196,6 +212,12 @@ public class CreateNewVaultLocationController implements FxController { @FXML public void next() { if (validVaultPath.getValue()) { + if (this.getVaultPath() != null) { + Path parentPath = this.getVaultPath().getParent(); + if (parentPath != null) { + this.settings.previouslyUsedVaultDirectory.setValue(parentPath); + } + } window.setScene(chooseExpertSettingsScene.get()); } } diff --git a/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingStrategy.java b/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingStrategy.java index b9af0f4a3..eb6ecbfa3 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingStrategy.java +++ b/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingStrategy.java @@ -46,15 +46,16 @@ public interface KeyLoadingStrategy extends MasterkeyLoader { /** * Determines whether the provided key loader scheme corresponds to a Masterkey File Vault. *

- * This method checks if the {@code keyLoader} parameter matches the known Masterkey File Vault scheme + * This method checks if the {@code keyLoader} parameter starts with the known Masterkey File Vault scheme * {@link MasterkeyFileLoadingStrategy#SCHEME}. + * This allows identifying not only exact matches but also variants or extended schemes based on the Masterkey scheme. *

* * @param keyLoader A string representing the key loader scheme to be checked. - * @return {@code true} if the given key loader scheme represents a Masterkey File Vault; {@code false} otherwise. + * @return {@code true} if the given key loader scheme starts with the Masterkey File Vault scheme; {@code false} otherwise. */ static boolean isMasterkeyFileVault(String keyLoader) { - return MasterkeyFileLoadingStrategy.SCHEME.equals(keyLoader); + return keyLoader.startsWith(MasterkeyFileLoadingStrategy.SCHEME); } /** diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java index 859c9e38d..93fb298ed 100644 --- a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java +++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java @@ -19,7 +19,7 @@ public class ShareVaultController implements FxController { private static final String SCHEME_PREFIX = "hub+"; private static final String VISIT_HUB_URL = "https://cryptomator.org/hub/"; - private static final String BEST_PRACTICES_URL = "https://docs.cryptomator.org/en/latest/security/best-practices/#sharing-of-vaults"; + private static final String BEST_PRACTICES_URL = "https://docs.cryptomator.org/security/best-practices/#sharing-of-vaults"; private final Stage window; private final Lazy application; diff --git a/src/main/resources/i18n/strings_ar.properties b/src/main/resources/i18n/strings_ar.properties index 4e4b34095..f69f4b67c 100644 --- a/src/main/resources/i18n/strings_ar.properties +++ b/src/main/resources/i18n/strings_ar.properties @@ -62,9 +62,9 @@ addvaultwizard.new.locationIsOk=الموقع المناسب للمخزن الخ addvaultwizard.new.invalidName=اسم المخزن غير صالح addvaultwizard.new.validName=اسم المخزن صالح addvaultwizard.new.validCharacters.message=قد يحتوي اسم المخزن على الأحرف التالية: -addvaultwizard.new.validCharacters.chars=أحرف الكلمات (أمثلة: a, ж, 수) -addvaultwizard.new.validCharacters.numbers=الأعداد -addvaultwizard.new.validCharacters.dashes=الشرطة (%s) أو الشرطة السفلية (%s) +addvaultwizard.new.validCharacters.chars=أحرف لكن دون علامات (#, $, !, @...) +addvaultwizard.new.validCharacters.numbers=الأرقام +addvaultwizard.new.validCharacters.dashes=ناقص (%s) أو شِرْطَةٌ سفلية (%s) ### Expert Settings addvaultwizard.new.expertSettings.enableExpertSettingsCheckbox=تمكين إعدادات الخبراء addvaultwizard.new.expertSettings.shorteningThreshold.invalid=أدخل قيمة بين 36 و 220 (الافتراضي 220) @@ -319,7 +319,7 @@ preferences.volume.feature.readOnly=تحميل للقراءة فقط ## Updates preferences.updates=تحديثات preferences.updates.currentVersion=الإصدار الحالي: %s -preferences.updates.autoUpdateCheck=تحقق من التحديثات اوتوماتيكيا +preferences.updates.autoUpdateCheck=التحقق من وجود تحديثات تلقائياً preferences.updates.checkNowBtn=تحقق الان preferences.updates.updateAvailable=التحديث إلى الإصدار %s متاح. preferences.updates.lastUpdateCheck=آخر فحص: %s @@ -395,6 +395,7 @@ main.vaultlist.contextMenu.vaultoptions=إظهار خيارات المخزن main.vaultlist.contextMenu.reveal=اظهار القرص main.vaultlist.addVaultBtn.menuItemNew=إنشاء مخزن جديد... main.vaultlist.addVaultBtn.menuItemExisting=افتح مخزن موجود... +main.vaultlist.showEventsButton.tooltip=عرض الإشعارات ##Notificaition main.notification.updateAvailable=هناك تحديث متاح. main.notification.support=دعم Cryptomator. @@ -423,7 +424,9 @@ main.vaultDetail.stats=إحصائيات الخزنة main.vaultDetail.locateEncryptedFileBtn=تحديد موقع الملف المشفر main.vaultDetail.locateEncryptedFileBtn.tooltip=اختر ملف من خزانتك لتحديد مكان نظيره المشفر main.vaultDetail.encryptedPathsCopied=تم نسخ مسارات الملفات إلى الحافظة! +main.vaultDetail.locateEncrypted.filePickerTitle=اختر الملَف من الخزنة main.vaultDetail.decryptName.buttonLabel=فك تشفير اسم الملف +main.vaultDetail.decryptName.tooltip=اختر ملَف مشفر لفك تشفير اسمه ### Missing main.vaultDetail.missing.info=لم يتمكن Cryptomator من العثور على خزنة في هذا المسار. main.vaultDetail.missing.recheck=إعادة الفحص @@ -473,7 +476,7 @@ vaultOptions.mount.mountPoint.custom=استخدام المجلد المختار vaultOptions.mount.mountPoint.directoryPickerButton=اختر… vaultOptions.mount.mountPoint.directoryPickerTitle=إختر مجلد vaultOptions.mount.volumeType.default=الافتراضي (%s) -vaultOptions.mount.volumeType.restartRequired=لاستخدام هذا النوع ‮من وحدة التخزين يحتاج Cryptomator إلى إعادة تشغيله. +vaultOptions.mount.volumeType.restartRequired=لاستخدام هذا النوع من وحدة التخزين يحتاج Cryptomator إلى إعادة تشغيل. vaultOptions.mount.volume.tcp.port=منفذ TCP vaultOptions.mount.volume.type=‮نوع وحدة التخزين ## Master Key @@ -580,7 +583,40 @@ shareVault.hub.instruction.2=2. امنح الوصول لعضو الفريق في shareVault.hub.openHub=زيارة Cryptomator Hub # Decrypt File Names +decryptNames.title=فك تشفير اسم الملَف +decryptNames.filePicker.title=اختر ملَف مشفر +decryptNames.filePicker.extensionDescription=ملف مشفر +decryptNames.copyTable.tooltip=نسخ الجدول +decryptNames.clearTable.tooltip=مسح الجدول +decryptNames.copyHint=نسخ محتوى الخلية مع %s +decryptNames.dropZone.message=إسقاط الملفات أو انقر لتحديد +decryptNames.dropZone.error.vaultInternalFiles=مخزن الملفات الداخلية مع عدم تحديد اسم قابل للتشفير +decryptNames.dropZone.error.foreignFiles=الملفات لا تنتمي إلى مخزن "%s" +decryptNames.dropZone.error.noDirIdBackup=مسار الملفات المحددة لا يحتوي على ملَف dirId.c9r +decryptNames.dropZone.error.generic=فشل فك تشفير أسماء الملفات # Event View +eventView.title=أحداث +eventView.filter.allVaults=الكل +eventView.clearListButton.tooltip=تفريغ القائمة ## event list entries +eventView.entry.vaultLocked.description=فتح "%s" للحصول على التفاصيل +eventView.entry.conflictResolved.message=تم حل التضارب +eventView.entry.conflictResolved.showDecrypted=إظهار الملف غير المشفر +eventView.entry.conflictResolved.copyDecrypted=نسخ المسار غير المشفر +eventView.entry.conflict.message=فشل حل التضارب +eventView.entry.conflict.showDecrypted=إظهار الملَف غير المشفر الأصلي +eventView.entry.conflict.copyDecrypted=نسخ المسار غير المشفر والأصلي +eventView.entry.conflict.showEncrypted=إظهار ملف متضارب ومشفر +eventView.entry.conflict.copyEncrypted=نسخ مسار التشفير المتعارض +eventView.entry.decryptionFailed.message=فشل فك التشفير +eventView.entry.decryptionFailed.showEncrypted=عرض ملَف المشفر +eventView.entry.decryptionFailed.copyEncrypted=نسخ مسار المشفر +eventView.entry.brokenDirFile.message=رابط الدليل المكسور +eventView.entry.brokenDirFile.showEncrypted=إظهار الرابط المكسور، المشفر +eventView.entry.brokenDirFile.copyEncrypted=نسخ مسار الرابط المكسور +eventView.entry.brokenFileNode.message=عقدة ملفات النظام التافلة +eventView.entry.brokenFileNode.showEncrypted=عرض العقدة المشفّرة التافلة +eventView.entry.brokenFileNode.copyEncrypted=نسخ مسار العقدة المشفّرة التافلة +eventView.entry.brokenFileNode.copyDecrypted=نسخ المسار غير المشفر diff --git a/src/main/resources/i18n/strings_pt.properties b/src/main/resources/i18n/strings_pt.properties index e123071b0..bb048b2cf 100644 --- a/src/main/resources/i18n/strings_pt.properties +++ b/src/main/resources/i18n/strings_pt.properties @@ -424,9 +424,9 @@ main.vaultDetail.stats=Estatísticas do Cofre main.vaultDetail.locateEncryptedFileBtn=Localizar Ficheiro Encriptado main.vaultDetail.locateEncryptedFileBtn.tooltip=Escolha um ficheiro do seu cofre para localizar a sua contraparte encriptada main.vaultDetail.encryptedPathsCopied=Caminhos copiados para a área de transferência! -main.vaultDetail.locateEncrypted.filePickerTitle=Selecionar ficheiro dentro do cofre -main.vaultDetail.decryptName.buttonLabel=Desencriptar nome do ficheiro -main.vaultDetail.decryptName.tooltip=Escolha um ficheiro de cofre encriptado para desencriptar o seu nome +main.vaultDetail.locateEncrypted.filePickerTitle=Selecione o ficheiro no cofre +main.vaultDetail.decryptName.buttonLabel=Descriptografar o nome do ficheiro +main.vaultDetail.decryptName.tooltip=Escolha um ficheiro encriptado do cofre para desencriptar o seu nome ### Missing main.vaultDetail.missing.info=O Cryptomator não conseguiu encontrar um cofre neste diretório. main.vaultDetail.missing.recheck=Verificar novamente @@ -583,17 +583,17 @@ shareVault.hub.instruction.2=2. Conceder acesso ao membro da equipe no Hub Crypt shareVault.hub.openHub=Abrir Hub do Cryptomator # Decrypt File Names -decryptNames.title=Desencriptar nomes de ficheiros +decryptNames.title=Desencriptar os nomes dos ficheiros decryptNames.filePicker.title=Selecione o ficheiro encriptado -decryptNames.filePicker.extensionDescription=Ficheiro encriptado do Cryptomator -decryptNames.copyTable.tooltip=Copiar tabela -decryptNames.clearTable.tooltip=Limpar tabela -decryptNames.copyHint=Copiar conteúdo da célula com %s -decryptNames.dropZone.message=Solte os ficheiros ou clique para selecionar -decryptNames.dropZone.error.vaultInternalFiles=Ficheiros internos do cofre sem nome decifrável selecionado -decryptNames.dropZone.error.foreignFiles=Ficheiros não pertencem ao cofre "%s" +decryptNames.filePicker.extensionDescription=Ficheiro encriptado pelo Criptomator +decryptNames.copyTable.tooltip=Copiar a tabela +decryptNames.clearTable.tooltip=Limpar a tabela +decryptNames.copyHint=Copiar o conteúdo da célula com %s +decryptNames.dropZone.message=Largue os ficheiros ou clique para selecionar +decryptNames.dropZone.error.vaultInternalFiles=Ficheiros internos do coftre sem nome desencriptável selecionado +decryptNames.dropZone.error.foreignFiles=Os ficheiros não pertencem ao cofre "%s" decryptNames.dropZone.error.noDirIdBackup=O diretório dos ficheiros selecionados não contém o ficheiro dirId.c9r -decryptNames.dropZone.error.generic=Falha ao desencriptar nomes de ficheiros +decryptNames.dropZone.error.generic=Falha ao desencriptar os nomes dos ficheiros # Event View @@ -603,20 +603,20 @@ eventView.clearListButton.tooltip=Limpar lista ## event list entries eventView.entry.vaultLocked.description=Desbloquear "%s" para detalhes eventView.entry.conflictResolved.message=Conflito resolvido -eventView.entry.conflictResolved.showDecrypted=Mostrar ficheiro desencriptado -eventView.entry.conflictResolved.copyDecrypted=Copiar caminho desencriptado -eventView.entry.conflict.message=Resolução de conflito falhou -eventView.entry.conflict.showDecrypted=Mostrar ficheiro original desencriptado -eventView.entry.conflict.copyDecrypted=Copie caminho original desencriptado -eventView.entry.conflict.showEncrypted=Mostrar ficheiro encriptado conflitante -eventView.entry.conflict.copyEncrypted=Copiar caminho encriptado conflituante -eventView.entry.decryptionFailed.message=Falha na desencriptação +eventView.entry.conflictResolved.showDecrypted=Mostrar o ficheiro desencriptado +eventView.entry.conflictResolved.copyDecrypted=Copiar o caminho desencriptado +eventView.entry.conflict.message=A resolução do conflito falhou +eventView.entry.conflict.showDecrypted=Mostrar o ficheiro original desencriptado +eventView.entry.conflict.copyDecrypted=Copie o caminho original desencriptado +eventView.entry.conflict.showEncrypted=Mostrar o ficheiro encriptado em conflito +eventView.entry.conflict.copyEncrypted=Copiar o caminho encriptado em conflito +eventView.entry.decryptionFailed.message=A desencriptação falhou eventView.entry.decryptionFailed.showEncrypted=Mostrar ficheiro encriptado -eventView.entry.decryptionFailed.copyEncrypted=Copiar caminho de encriptação +eventView.entry.decryptionFailed.copyEncrypted=Copiar o caminho encriptado eventView.entry.brokenDirFile.message=Link de diretório quebrado -eventView.entry.brokenDirFile.showEncrypted=Mostrar link quebrado e encriptado +eventView.entry.brokenDirFile.showEncrypted=Mostrar o link quebrado e encriptado eventView.entry.brokenDirFile.copyEncrypted=Copiar caminho do link quebrado eventView.entry.brokenFileNode.message=Nó do sistema de ficheiros avariado -eventView.entry.brokenFileNode.showEncrypted=Mostrar nó encriptado quebrado +eventView.entry.brokenFileNode.showEncrypted=Mostrar nó encriptado e danificado eventView.entry.brokenFileNode.copyEncrypted=Copiar o caminho do nó encriptado e danificado -eventView.entry.brokenFileNode.copyDecrypted=Copiar caminho desencriptado +eventView.entry.brokenFileNode.copyDecrypted=Copiar o caminho desencriptado