mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-24 00:44:21 +00:00
Compare commits
181
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b042fec29d | ||
|
|
a653fc3627 | ||
|
|
db31fcad98 | ||
|
|
b82c73f789 | ||
|
|
70d3507e5d | ||
|
|
518b45d149 | ||
|
|
65f2eea6c9 | ||
|
|
12a4a8218a | ||
|
|
76dd4f079c | ||
|
|
b35fb011e0 | ||
|
|
fa1e9c7ca7 | ||
|
|
75bb64b333 | ||
|
|
1f40045b41 | ||
|
|
1951e5e82c | ||
|
|
0be39c5b7d | ||
|
|
6886188ff4 | ||
|
|
3a2de81369 | ||
|
|
4de3ea2892 | ||
|
|
0beb2e3334 | ||
|
|
537d79f3c2 | ||
|
|
10d5f4f530 | ||
|
|
ab0e7e1ea9 | ||
|
|
967a3aa10b | ||
|
|
821649c821 | ||
|
|
7cf75e9dba | ||
|
|
dfe126f827 | ||
|
|
80ce98991c | ||
|
|
579d42ec74 | ||
|
|
047108683f | ||
|
|
830c9196e7 | ||
|
|
7208f23da1 | ||
|
|
b0a4a0bcfa | ||
|
|
f7b13dd121 | ||
|
|
a5ccfa01d2 | ||
|
|
62bf4c5b45 | ||
|
|
7168d7e31d | ||
|
|
3c633f8a34 | ||
|
|
b606a4ee8e | ||
|
|
1af094692f | ||
|
|
c86d8ac6b8 | ||
|
|
b06d65ab43 | ||
|
|
390bdc33e0 | ||
|
|
2284d1fcee | ||
|
|
62a439e10e | ||
|
|
ddad663489 | ||
|
|
f08e7d9b92 | ||
|
|
6c2865a09d | ||
|
|
5a0d15c937 | ||
|
|
53757dab93 | ||
|
|
e1d4d3e85b | ||
|
|
859fe238b8 | ||
|
|
23df40796b | ||
|
|
b98b1326b2 | ||
|
|
2f8831b561 | ||
|
|
4948b9b586 | ||
|
|
838018e72e | ||
|
|
d5433e7a3f | ||
|
|
194e19bf5e | ||
|
|
1358e7098d | ||
|
|
4be327608a | ||
|
|
929ef37ded | ||
|
|
6fce1807f0 | ||
|
|
c1d72650cc | ||
|
|
dab368e44b | ||
|
|
7548174e4f | ||
|
|
b513060744 | ||
|
|
311a9ef70b | ||
|
|
7331144f9d | ||
|
|
d576b36f7b | ||
|
|
7a6340aac6 | ||
|
|
6b82abcd80 | ||
|
|
97bde05422 | ||
|
|
3bc50eee47 | ||
|
|
b95a220de7 | ||
|
|
2896e18429 | ||
|
|
29db91f976 | ||
|
|
1e3dfe3de1 | ||
|
|
dcb1f5e80f | ||
|
|
5c75eeab27 | ||
|
|
8e4bff8c19 | ||
|
|
e066f155b2 | ||
|
|
c3c7a23ccd | ||
|
|
c816411644 | ||
|
|
f752490624 | ||
|
|
d196b66b4e | ||
|
|
d803a1d71e | ||
|
|
c75430cde2 | ||
|
|
f44c3531c7 | ||
|
|
596829bc77 | ||
|
|
096aeb0c54 | ||
|
|
1a12684557 | ||
|
|
998664acc3 | ||
|
|
c52b3fc4ad | ||
|
|
1fde3650ca | ||
|
|
57614f59e4 | ||
|
|
a95883f98b | ||
|
|
6cf18c33a1 | ||
|
|
232e6fbf71 | ||
|
|
d15731d5a4 | ||
|
|
45d7421e4f | ||
|
|
4d0aabfe6e | ||
|
|
db0e266fde | ||
|
|
6281561ab4 | ||
|
|
b981f0dc19 | ||
|
|
bc41429982 | ||
|
|
a31621cfde | ||
|
|
aa68224d63 | ||
|
|
b8413a21a3 | ||
|
|
af59196f19 | ||
|
|
3a58f560fc | ||
|
|
a2cca0b624 | ||
|
|
0c4ba94f10 | ||
|
|
0f8b6a8f51 | ||
|
|
8ca6946fe6 | ||
|
|
e583b70931 | ||
|
|
6f6d0d8771 | ||
|
|
9d3d67b605 | ||
|
|
8da27e36d6 | ||
|
|
1123fa28a3 | ||
|
|
be3ecc536a | ||
|
|
94c8dd911b | ||
|
|
7e888b0e3b | ||
|
|
a066afe37d | ||
|
|
21c8cbf709 | ||
|
|
ea236d45a3 | ||
|
|
fab5ac3726 | ||
|
|
57666a620c | ||
|
|
e49fe23b35 | ||
|
|
254a7696c8 | ||
|
|
62bd43ef9b | ||
|
|
b73510ec0f | ||
|
|
3fba62ef72 | ||
|
|
7daca70a15 | ||
|
|
90228a1d5c | ||
|
|
4090413290 | ||
|
|
29bfbdc524 | ||
|
|
688090095e | ||
|
|
98db9649c3 | ||
|
|
7a4c8f113e | ||
|
|
50f6a87788 | ||
|
|
d601088948 | ||
|
|
4d62f2303d | ||
|
|
792734b486 | ||
|
|
f884861373 | ||
|
|
da3c5e901f | ||
|
|
f7ccc326de | ||
|
|
246eb19c3c | ||
|
|
c073b26d8f | ||
|
|
227a3258ec | ||
|
|
3279df68c7 | ||
|
|
bf6598302b | ||
|
|
dccb4ef072 | ||
|
|
cbae2413ae | ||
|
|
113ab66a49 | ||
|
|
34eb336e5f | ||
|
|
2cab0c59a1 | ||
|
|
3822136e69 | ||
|
|
1fa4d42d27 | ||
|
|
d5bc0914f4 | ||
|
|
ee5165320d | ||
|
|
84a966993f | ||
|
|
3fb0e9328f | ||
|
|
eb369ba5bd | ||
|
|
738bd56270 | ||
|
|
5e29f08d2b | ||
|
|
b3a5265b98 | ||
|
|
d7d439947d | ||
|
|
2eda795219 | ||
|
|
18ce7d333d | ||
|
|
f32d0c463f | ||
|
|
7275ec9a61 | ||
|
|
0fa34dba33 | ||
|
|
49f070977a | ||
|
|
35f39a9eaf | ||
|
|
b9d21b1b7a | ||
|
|
2e698317e5 | ||
|
|
9c88fbab5e | ||
|
|
1a51642eb1 | ||
|
|
fdaf5d1c36 | ||
|
|
00e824a1ba | ||
|
|
9c5ab7e311 |
@@ -14,6 +14,9 @@ updates:
|
|||||||
versions: ["2.0.1.MR"]
|
versions: ["2.0.1.MR"]
|
||||||
- dependency-name: "org.openjfx:*"
|
- dependency-name: "org.openjfx:*"
|
||||||
update-types: ["version-update:semver-major"]
|
update-types: ["version-update:semver-major"]
|
||||||
|
# due to https://github.com/fabriciorby/maven-surefire-junit5-tree-reporter/issues/68
|
||||||
|
- dependency-name: "org.apache.maven.plugins:maven-surefire-plugin"
|
||||||
|
versions: [ "3.5.4", "3.5.5" ]
|
||||||
groups:
|
groups:
|
||||||
java-test-dependencies:
|
java-test-dependencies:
|
||||||
patterns:
|
patterns:
|
||||||
|
|||||||
@@ -3,11 +3,17 @@ name: Build AppImage
|
|||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 23 20 * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'Version'
|
description: 'Version'
|
||||||
required: false
|
required: false
|
||||||
|
create-pr:
|
||||||
|
description: 'Create a PR for aur-bin repo'
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- 'dependabot/**'
|
- 'dependabot/**'
|
||||||
@@ -31,18 +37,24 @@ jobs:
|
|||||||
name: Build AppImage
|
name: Build AppImage
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [get-version]
|
needs: [get-version]
|
||||||
|
env:
|
||||||
|
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
|
SEMVER_NUM: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
REV_NUM: ${{ needs.get-version.outputs.revNum }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
appimage-suffix: x86_64
|
arch: x86_64
|
||||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-x64_bin-jmods.zip'
|
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-x64_bin-jmods.zip'
|
||||||
openjfx-sha: 'e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b'
|
openjfx-sha: 'e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b'
|
||||||
|
appimagetool-sha: 'ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0'
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
appimage-suffix: aarch64
|
arch: aarch64
|
||||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-aarch64_bin-jmods.zip'
|
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-aarch64_bin-jmods.zip'
|
||||||
openjfx-sha: 'c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646'
|
openjfx-sha: 'c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646'
|
||||||
|
appimagetool-sha: 'f0837e7448a0c1e4e650a93bb3e85802546e60654ef287576f46c71c126a9158'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
@@ -55,7 +67,7 @@ jobs:
|
|||||||
- name: Download OpenJFX jmods
|
- name: Download OpenJFX jmods
|
||||||
id: download-jmods
|
id: download-jmods
|
||||||
run: |
|
run: |
|
||||||
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
curl --silent --fail-with-body --proto "=https" -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
||||||
echo "${{ matrix.openjfx-sha }} openjfx-jmods.zip" | shasum -a256 --check
|
echo "${{ matrix.openjfx-sha }} openjfx-jmods.zip" | shasum -a256 --check
|
||||||
mkdir -p openjfx-jmods
|
mkdir -p openjfx-jmods
|
||||||
unzip -j openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
unzip -j openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||||
@@ -73,7 +85,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: Set version
|
- name: Set version
|
||||||
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
run : mvn versions:set -DnewVersion="$SEMVER_STR"
|
||||||
- name: Run maven
|
- name: Run maven
|
||||||
run: mvn -B clean package -Plinux -DskipTests
|
run: mvn -B clean package -Plinux -DskipTests
|
||||||
- name: Patch target dir
|
- name: Patch target dir
|
||||||
@@ -94,13 +106,15 @@ jobs:
|
|||||||
${JAVA_HOME}/bin/jlink
|
${JAVA_HOME}/bin/jlink
|
||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${{ steps.jep-493-check.outputs.jmod_paths }}"
|
--module-path "${JMOD_PATHS}"
|
||||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
--no-man-pages
|
--no-man-pages
|
||||||
--strip-debug
|
--strip-debug
|
||||||
--compress zip-0
|
--compress zip-0
|
||||||
|
env:
|
||||||
|
JMOD_PATHS: ${{ steps.jep-493-check.outputs.jmod_paths }}
|
||||||
- name: Run jpackage
|
- name: Run jpackage
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jpackage
|
${JAVA_HOME}/bin/jpackage
|
||||||
@@ -114,12 +128,12 @@ jobs:
|
|||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
||||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
--app-version "${SEMVER_NUM}.${REV_NUM}"
|
||||||
--java-options "--enable-preview"
|
--java-options "--enable-preview"
|
||||||
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\""
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
--java-options "-Djava.net.useSystemProxies=true"
|
--java-options "-Djava.net.useSystemProxies=true"
|
||||||
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\""
|
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\""
|
||||||
@@ -130,8 +144,9 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\""
|
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\""
|
||||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||||
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\""
|
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\""
|
||||||
--java-options "-Dcryptomator.buildNumber=\"appimage-${{ needs.get-version.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"appimage-${REV_NUM}\""
|
||||||
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\""
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\""
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
|
||||||
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
|
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
|
||||||
--resource-dir dist/linux/resources
|
--resource-dir dist/linux/resources
|
||||||
- name: Patch Cryptomator.AppDir
|
- name: Patch Cryptomator.AppDir
|
||||||
@@ -155,7 +170,8 @@ jobs:
|
|||||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||||
- name: Download AppImageKit
|
- name: Download AppImageKit
|
||||||
run: |
|
run: |
|
||||||
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
|
curl --silent --fail-with-body --proto "=https" -L "https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-${{ matrix.arch }}.AppImage" -o appimagetool.AppImage
|
||||||
|
echo "${{ matrix.appimagetool-sha }} appimagetool.AppImage" | shasum -a256 --check
|
||||||
chmod +x appimagetool.AppImage
|
chmod +x appimagetool.AppImage
|
||||||
./appimagetool.AppImage --appimage-extract
|
./appimagetool.AppImage --appimage-extract
|
||||||
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
||||||
@@ -167,17 +183,17 @@ jobs:
|
|||||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||||
- name: Build AppImage
|
- name: Build AppImage
|
||||||
run: >
|
run: >
|
||||||
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.appimage-suffix }}.AppImage
|
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${SEMVER_STR}-${{ matrix.arch }}.AppImage
|
||||||
-u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.appimage-suffix }}.AppImage.zsync"
|
-u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.arch }}.AppImage.zsync"
|
||||||
--sign --sign-key=615D449FE6E6A235
|
--sign --sign-key=615D449FE6E6A235
|
||||||
- name: Create detached GPG signatures
|
- name: Create detached GPG signatures
|
||||||
run: |
|
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
|
||||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage.zsync
|
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage.zsync
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: appimage-${{ matrix.appimage-suffix }}
|
name: appimage-${{ matrix.arch }}
|
||||||
path: |
|
path: |
|
||||||
cryptomator-*.AppImage
|
cryptomator-*.AppImage
|
||||||
cryptomator-*.AppImage.zsync
|
cryptomator-*.AppImage.zsync
|
||||||
@@ -196,65 +212,77 @@ jobs:
|
|||||||
|
|
||||||
create-aur-bin-pr:
|
create-aur-bin-pr:
|
||||||
name: Create PR for aur-bin repo
|
name: Create PR for aur-bin repo
|
||||||
needs: [build, get-version]
|
if: github.event_name == 'workflow_dispatch' && inputs.create-pr || github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
|
needs: [build, get-version]
|
||||||
|
container:
|
||||||
|
image: archlinux:base-devel
|
||||||
|
env:
|
||||||
|
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
|
PKGDEST: ${{ github.workspace }}/pkgdest
|
||||||
|
SRCDEST: ${{ github.workspace }}/srcdest
|
||||||
steps:
|
steps:
|
||||||
- name: Download AppImages
|
- name: Prepare pacman
|
||||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
|
||||||
with:
|
|
||||||
path: downloads/
|
|
||||||
merge-multiple: true
|
|
||||||
- name: Compute sha256 hash of AppImages
|
|
||||||
id: checksums
|
|
||||||
run: |
|
run: |
|
||||||
X64_SHA256=$(sha256sum downloads/cryptomator-*-x86_64.AppImage | cut -d ' ' -f1)
|
pacman-key --init
|
||||||
echo "x64-sha256sum=${X64_SHA256}" >> "$GITHUB_OUTPUT"
|
pacman-key --populate archlinux
|
||||||
AARCH64_SHA256=$(sha256sum downloads/cryptomator-*-aarch64.AppImage | cut -d ' ' -f1)
|
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl pacman-contrib
|
||||||
echo "aarch64-sha256sum=${AARCH64_SHA256}" >> "$GITHUB_OUTPUT"
|
- name: Checkout cryptomator/aur-bin
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
repository: 'cryptomator/aur-bin'
|
repository: 'cryptomator/aur-bin'
|
||||||
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
- name: Install dependencies
|
- name: Create build user
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
useradd -m builder
|
||||||
sudo apt-get -y install makepkg pacman-package-manager
|
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
|
||||||
|
chown -R builder:builder "$GITHUB_WORKSPACE"
|
||||||
|
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
|
||||||
|
- name: Import Cryptomator release signing key
|
||||||
|
# try first ubuntu. on failure try openpgp keyservers
|
||||||
|
run: >
|
||||||
|
sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|
||||||
|
|| sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|
||||||
- name: Checkout release branch
|
- name: Checkout release branch
|
||||||
run: |
|
run: |
|
||||||
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
|
git config --global safe.directory '*'
|
||||||
|
git checkout -b "release/${SEMVER_STR}"
|
||||||
- name: Update build file
|
- name: Update build file
|
||||||
run: |
|
run: |
|
||||||
sed -i -e 's|^pkgver=.*$|pkgver=${{ needs.get-version.outputs.semVerStr }}|' PKGBUILD
|
sed -i -e "s|^pkgver=.*$|pkgver=${SEMVER_STR}|" PKGBUILD
|
||||||
sed -i -e 's|^pkgrel=.*$|pkgrel=1|' 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
|
sudo -u builder updpkgsums
|
||||||
sed -i -e "s|^sha256sums_aarch64=.*$|sha256sums_aarch64=('${{ steps.checksums.outputs.aarch64-sha256sum}}'|" PKGBUILD
|
sudo -u builder makepkg --printsrcinfo > .SRCINFO
|
||||||
makepkg --printsrcinfo > .SRCINFO
|
- name: Build package with makepkg
|
||||||
|
run: >
|
||||||
|
sudo -u builder
|
||||||
|
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
|
||||||
|
makepkg --syncdeps --cleanbuild --noconfirm --log
|
||||||
- name: Commit and push
|
- name: Commit and push
|
||||||
run: |
|
run: |
|
||||||
git config user.name "${{ github.actor }}"
|
git config user.name "cryptobot"
|
||||||
git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
|
git config user.email "cryptobot@users.noreply.github.com"
|
||||||
git config push.autoSetupRemote true
|
git config push.autoSetupRemote true
|
||||||
git stage .
|
git stage PKGBUILD .SRCINFO
|
||||||
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
|
git commit -m "Prepare release ${SEMVER_STR}"
|
||||||
git push
|
git push
|
||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
id: create-pr
|
id: create-pr
|
||||||
run: |
|
run: |
|
||||||
printf "> [!IMPORTANT]\n> Todos:\n> - [ ] Update build instructions\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md
|
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
|
||||||
URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
|
PR_URL=$(gh pr create --title "Release ${SEMVER_STR}" --body-file pr_body.md)
|
||||||
echo "PR_URL=$URL" >> "$GITHUB_OUTPUT"
|
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
- name: Slack Notification
|
- name: Slack Notification
|
||||||
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
|
||||||
SLACK_USERNAME: 'Cryptobot'
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
SLACK_ICON: false
|
SLACK_ICON: false
|
||||||
SLACK_ICON_EMOJI: ':bot:'
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
SLACK_CHANNEL: 'cryptomator-desktop'
|
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||||
SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
|
SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ needs.get-version.outputs.semVerStr }} created."
|
||||||
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.PR_URL }}|PR> on how to proceed."
|
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
|
||||||
SLACK_FOOTER: false
|
SLACK_FOOTER: false
|
||||||
MSG_MINIMAL: true
|
MSG_MINIMAL: true
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
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'
|
|
||||||
env:
|
|
||||||
INPUT_TAG: ${{ inputs.tag }}
|
|
||||||
outputs:
|
|
||||||
url: ${{ steps.url.outputs.url}}
|
|
||||||
sha256: ${{ steps.sha256.outputs.sha256}}
|
|
||||||
steps:
|
|
||||||
- name: Determine tarball url
|
|
||||||
id: url
|
|
||||||
run: |
|
|
||||||
URL="";
|
|
||||||
if [[ -n "${INPUT_TAG}" ]]; then
|
|
||||||
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${INPUT_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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
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
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
|
||||||
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
|
|
||||||
@@ -49,9 +49,9 @@ jobs:
|
|||||||
url="${INPUT_URL}"
|
url="${INPUT_URL}"
|
||||||
echo "fileName=${url##*/}" >> $GITHUB_OUTPUT
|
echo "fileName=${url##*/}" >> $GITHUB_OUTPUT
|
||||||
- name: Download file
|
- name: Download file
|
||||||
run: curl "${INPUT_URL}" -L -o "${{steps.extractName.outputs.fileName}}" --fail-with-body
|
run: curl --silent --fail-with-body --proto "=https" -L "${INPUT_URL}" -o "${{steps.extractName.outputs.fileName}}"
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.extractName.outputs.fileName }}
|
name: ${{ steps.extractName.outputs.fileName }}
|
||||||
path: ${{ steps.extractName.outputs.fileName }}
|
path: ${{ steps.extractName.outputs.fileName }}
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
if: inputs.kaspersky
|
if: inputs.kaspersky
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.download-file.outputs.fileName }}
|
name: ${{ needs.download-file.outputs.fileName }}
|
||||||
path: upload
|
path: upload
|
||||||
@@ -83,7 +83,7 @@ jobs:
|
|||||||
if: inputs.avast
|
if: inputs.avast
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.download-file.outputs.fileName }}
|
name: ${{ needs.download-file.outputs.fileName }}
|
||||||
path: upload
|
path: upload
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
### Other Changes 📎
|
### Other Changes 📎
|
||||||
END REPLACE-->
|
END REPLACE-->
|
||||||
|
|
||||||
Feel free to also read our [CHANGELOG.md](https://github.com/cryptomator/cryptomator/blob/develop/CHANGELOG.md).
|
For a comprehensive view of changes, read the [CHANGELOG](https://github.com/cryptomator/cryptomator/blob/develop/CHANGELOG.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
name: Build Debian Package
|
name: Build Debian Package
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 22 20 * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
semver:
|
semver:
|
||||||
@@ -71,11 +73,11 @@ jobs:
|
|||||||
- name: Download OpenJFX jmods
|
- name: Download OpenJFX jmods
|
||||||
id: download-jmods
|
id: download-jmods
|
||||||
run: |
|
run: |
|
||||||
curl -L ${{ env.OPENJFX_JMODS_AMD64 }} -o openjfx-amd64.zip
|
curl --silent --fail-with-body --proto "=https" -L ${{ env.OPENJFX_JMODS_AMD64 }} -o openjfx-amd64.zip
|
||||||
echo "${{ env.OPENJFX_JMODS_AMD64_HASH }} openjfx-amd64.zip" | shasum -a256 --check
|
echo "${{ env.OPENJFX_JMODS_AMD64_HASH }} openjfx-amd64.zip" | shasum -a256 --check
|
||||||
mkdir -p jmods/amd64
|
mkdir -p jmods/amd64
|
||||||
unzip -j openjfx-amd64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/amd64
|
unzip -j openjfx-amd64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/amd64
|
||||||
curl -L ${{ env.OPENJFX_JMODS_AARCH64 }} -o openjfx-aarch64.zip
|
curl --silent --fail-with-body --proto "=https" -L ${{ env.OPENJFX_JMODS_AARCH64 }} -o openjfx-aarch64.zip
|
||||||
echo "${{ env.OPENJFX_JMODS_AARCH64_HASH }} openjfx-aarch64.zip" | shasum -a256 --check
|
echo "${{ env.OPENJFX_JMODS_AARCH64_HASH }} openjfx-aarch64.zip" | shasum -a256 --check
|
||||||
mkdir -p jmods/aarch64
|
mkdir -p jmods/aarch64
|
||||||
unzip -j openjfx-aarch64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/aarch64
|
unzip -j openjfx-aarch64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/aarch64
|
||||||
@@ -143,7 +145,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: linux-deb-package
|
name: linux-deb-package
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
name: Create PR for flathub
|
|
||||||
|
|
||||||
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}}
|
|
||||||
sha512: ${{ steps.sha512.outputs.sha512}}
|
|
||||||
steps:
|
|
||||||
- name: Determine tarball url
|
|
||||||
id: url
|
|
||||||
run: |
|
|
||||||
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${TAG}.tar.gz"
|
|
||||||
echo "url=${URL}" >> "$GITHUB_OUTPUT"
|
|
||||||
env:
|
|
||||||
TAG: ${{ inputs.tag || github.event.release.tag_name}}
|
|
||||||
- name: Download source tarball and compute checksum
|
|
||||||
id: sha512
|
|
||||||
run: |
|
|
||||||
curl --silent --fail-with-body -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz
|
|
||||||
TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
|
|
||||||
echo "sha512=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
|
|
||||||
flathub:
|
|
||||||
name: Create PR for flathub
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [tarball, get-version]
|
|
||||||
env:
|
|
||||||
FLATHUB_PR_URL: tbd
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
repository: 'flathub/org.cryptomator.Cryptomator'
|
|
||||||
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
|
||||||
- name: Checkout release branch
|
|
||||||
run: |
|
|
||||||
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
|
|
||||||
- name: Update build file
|
|
||||||
run: |
|
|
||||||
sed -i -e 's/VERSION: [0-9]\+\.[0-9]\+\.[0-9]\+.*/VERSION: ${{ needs.get-version.outputs.semVerStr }}/g' org.cryptomator.Cryptomator.yaml
|
|
||||||
sed -i -e 's/sha512: [0-9A-Za-z_\+-]\{128\} #CRYPTOMATOR/sha512: ${{ needs.tarball.outputs.sha512 }} #CRYPTOMATOR/g' org.cryptomator.Cryptomator.yaml
|
|
||||||
sed -i -e 's;url: https://github.com/cryptomator/cryptomator/archive/refs/tags/[^[:blank:]]\+;url: ${{ needs.tarball.outputs.url }};g' org.cryptomator.Cryptomator.yaml
|
|
||||||
- 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 maven dependencies\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 "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
|
||||||
- name: Slack Notification
|
|
||||||
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
|
||||||
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: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
|
|
||||||
SLACK_MESSAGE: "See <${{ env.FLATHUB_PR_URL }}|PR> on how to proceed.>."
|
|
||||||
SLACK_FOOTER: false
|
|
||||||
MSG_MINIMAL: true
|
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
name: Build flatpak
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
src-tag:
|
||||||
|
description: 'Source or Release tag'
|
||||||
|
required: false
|
||||||
|
create-pr:
|
||||||
|
description: 'Create Flathub PR'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- 'dependabot/**'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/get-version.yml'
|
||||||
|
- '.github/workflows/linux-flatpak.yml'
|
||||||
|
- 'dist/linux/flatpak/**'
|
||||||
|
- 'dist/linux/common/**'
|
||||||
|
- 'dist/linux/resources/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-version:
|
||||||
|
uses: ./.github/workflows/get-version.yml
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.src-tag }}
|
||||||
|
|
||||||
|
build-flatpak:
|
||||||
|
name: "Build flatpak"
|
||||||
|
needs: [get-version]
|
||||||
|
container:
|
||||||
|
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08
|
||||||
|
options: --privileged
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
variant:
|
||||||
|
- arch: x86_64
|
||||||
|
runner: ubuntu-24.04
|
||||||
|
- arch: aarch64
|
||||||
|
runner: ubuntu-24.04-arm
|
||||||
|
runs-on: ${{ matrix.variant.runner }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
env:
|
||||||
|
SRC_GIT_SHA: ${{ inputs.src-tag || github.sha}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
repository: flathub/org.cryptomator.Cryptomator
|
||||||
|
submodules: true
|
||||||
|
- name: Checkout build script
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
path: build-scripts
|
||||||
|
- name: Checkout app source
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
path: cryptomator
|
||||||
|
ref: ${{ env.SRC_GIT_SHA }}
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Prepare build files
|
||||||
|
# using envsubst instead of yq to keep linebreaks
|
||||||
|
run: |
|
||||||
|
cp -r -f build-scripts/dist/linux/flatpak/* .
|
||||||
|
envsubst '$FLATPAK_VERSION $FLATPAK_REVISION $CRYPTOMATOR_SOURCE' < org.cryptomator.Cryptomator.TEMPLATE.yaml > org.cryptomator.Cryptomator.yaml
|
||||||
|
env:
|
||||||
|
FLATPAK_VERSION: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
FLATPAK_REVISION: 1
|
||||||
|
CRYPTOMATOR_SOURCE: |-
|
||||||
|
type: git
|
||||||
|
path: cryptomator
|
||||||
|
commit: ${{ env.SRC_GIT_SHA }}
|
||||||
|
- name: Copy build script for upload
|
||||||
|
run: cp org.cryptomator.Cryptomator.yaml org.cryptomator.Cryptomator.${{matrix.variant.arch}}.yaml
|
||||||
|
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
|
with:
|
||||||
|
archive: false
|
||||||
|
if-no-files-found: error
|
||||||
|
path: |
|
||||||
|
org.cryptomator.Cryptomator.${{matrix.variant.arch}}.yaml
|
||||||
|
- uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb # SNAPSHOT due to using keep-build-dirs
|
||||||
|
with:
|
||||||
|
bundle: cryptomator.flatpak
|
||||||
|
manifest-path: org.cryptomator.Cryptomator.yaml
|
||||||
|
cache-key: flatpak-builder-${{ env.SRC_GIT_SHA }}
|
||||||
|
arch: ${{ matrix.variant.arch }}
|
||||||
|
keep-build-dirs: true
|
||||||
|
- name: Collect maven dependencies
|
||||||
|
working-directory: .flatpak-builder/build/cryptomator-1/.m2/repository/
|
||||||
|
run: |
|
||||||
|
find * -type f \( -iname '*.jar' -o -iname '*.pom' \) | sort -V > /tmp/maven-dependency-files.txt
|
||||||
|
grep -v '^org/openjfx/javafx-' /tmp/maven-dependency-files.txt > maven-dependency-files-common.txt
|
||||||
|
grep '^org/openjfx/javafx-' /tmp/maven-dependency-files.txt > maven-dependency-files-javafx.txt
|
||||||
|
- name: Update arch independent maven dependencies
|
||||||
|
run: |
|
||||||
|
(
|
||||||
|
cd .flatpak-builder/build/cryptomator-1/.m2/repository/
|
||||||
|
|
||||||
|
while IFS= read -r dependencyPath; do
|
||||||
|
dependencyName=$(dirname "$dependencyPath")
|
||||||
|
dependencySha=$(sha256sum "$dependencyPath" | cut -c 1-64)
|
||||||
|
cat <<EOF
|
||||||
|
- type: file
|
||||||
|
dest: .m2/repository/${dependencyName}
|
||||||
|
url: https://repo.maven.apache.org/maven2/${dependencyPath}
|
||||||
|
sha256: ${dependencySha}
|
||||||
|
EOF
|
||||||
|
done < maven-dependency-files-common.txt
|
||||||
|
) > maven-dependencies.yaml
|
||||||
|
- name: Update arch specific maven dependencies
|
||||||
|
run: |
|
||||||
|
(
|
||||||
|
cd .flatpak-builder/build/cryptomator-1/.m2/repository/
|
||||||
|
|
||||||
|
while IFS= read -r dependencyPath; do
|
||||||
|
dependencyName=$(dirname "$dependencyPath")
|
||||||
|
dependencySha=$(sha256sum "$dependencyPath" | cut -c 1-64)
|
||||||
|
cat <<EOF
|
||||||
|
- type: file
|
||||||
|
dest: .m2/repository/${dependencyName}
|
||||||
|
url: https://repo.maven.apache.org/maven2/${dependencyPath}
|
||||||
|
sha256: ${dependencySha}
|
||||||
|
only-arches: [${{ matrix.variant.arch }}]
|
||||||
|
EOF
|
||||||
|
done < maven-dependency-files-javafx.txt
|
||||||
|
) > javafx-maven-dependencies-${{ matrix.variant.arch }}.yaml
|
||||||
|
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
|
with:
|
||||||
|
name: maven-sources-${{ matrix.variant.arch }}
|
||||||
|
if-no-files-found: error
|
||||||
|
path: |
|
||||||
|
maven-dependencies.yaml
|
||||||
|
javafx-maven-dependencies-${{ matrix.variant.arch }}.yaml
|
||||||
|
|
||||||
|
verify-maven-sources:
|
||||||
|
name: Verify maven sources
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build-flatpak]
|
||||||
|
permissions:
|
||||||
|
contents: none
|
||||||
|
steps:
|
||||||
|
- name: Download updated maven aarch64 dependencies
|
||||||
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
|
with:
|
||||||
|
name: maven-sources-aarch64
|
||||||
|
path: mvn-src-aarch64
|
||||||
|
- name: Download updated maven x86_64 dependencies
|
||||||
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
|
with:
|
||||||
|
name: maven-sources-x86_64
|
||||||
|
path: mvn-src-x64
|
||||||
|
- name: Verify arch independent maven dependencies
|
||||||
|
run: cmp --silent mvn-src-aarch64/maven-dependencies.yaml mvn-src-x64/maven-dependencies.yaml
|
||||||
|
|
||||||
|
create-pr:
|
||||||
|
name: Create PR for flathub
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [get-version, verify-maven-sources]
|
||||||
|
if: (github.event_name == 'workflow_dispatch' && inputs.create-pr ) || (github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable')
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
env:
|
||||||
|
TARBALL_URL: 'https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name || inputs.src-tag }}.tar.gz'
|
||||||
|
steps:
|
||||||
|
- name: Check that input "src-tag" is actually a tag
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
if [ -z "$SRC_TAG" ]; then
|
||||||
|
echo '::error::Input "src-tag" must be set to create a Flathub PR'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
SRC_TAG: ${{ inputs.src-tag }}
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
repository: flathub/org.cryptomator.Cryptomator
|
||||||
|
submodules: true #TODO: Update submodule!
|
||||||
|
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
|
- name: Checkout release branch
|
||||||
|
run: |
|
||||||
|
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
path: cryptomator
|
||||||
|
- name: Download source tarball and compute checksum
|
||||||
|
id: sha512
|
||||||
|
run: |
|
||||||
|
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" ${TARBALL_URL} --output cryptomator.tar.gz
|
||||||
|
TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
|
||||||
|
echo "value=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
|
||||||
|
- name: Download updated maven aarch64 dependencies
|
||||||
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
|
with:
|
||||||
|
name: maven-sources-aarch64
|
||||||
|
path: mvn-src-aarch64
|
||||||
|
- name: Download updated maven x86_64 dependencies
|
||||||
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
|
with:
|
||||||
|
name: maven-sources-x86_64
|
||||||
|
path: mvn-src-x64
|
||||||
|
- name: Determine revision
|
||||||
|
id: revision
|
||||||
|
run: |
|
||||||
|
CURRENT_VERSION="$(yq '(.modules[] | select(.name == "cryptomator") | .build-options.env.VERSION)' org.cryptomator.Cryptomator.yaml)"
|
||||||
|
CURRENT_REVISION="$(yq '(.modules[] | select(.name == "cryptomator") | .build-options.env.REVISION_NO)' org.cryptomator.Cryptomator.yaml)"
|
||||||
|
|
||||||
|
if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" && "$CURRENT_REVISION" =~ ^[0-9]+$ ]]; then
|
||||||
|
NEXT_REVISION=$((CURRENT_REVISION + 1))
|
||||||
|
else
|
||||||
|
NEXT_REVISION=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "value=${NEXT_REVISION}" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
TARGET_VERSION: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
|
- name: Update build files
|
||||||
|
run: |
|
||||||
|
cp -r -f cryptomator/dist/linux/flatpak/* .
|
||||||
|
cp -r -f mvn-src-x64/* .
|
||||||
|
cp -r -f mvn-src-aarch64/* .
|
||||||
|
envsubst '$FLATPAK_VERSION $FLATPAK_REVISION $CRYPTOMATOR_SOURCE' < org.cryptomator.Cryptomator.TEMPLATE.yaml > org.cryptomator.Cryptomator.yaml
|
||||||
|
yq -i 'del(.modules[] | select(.name == "cryptomator") | .build-options.build-args)' org.cryptomator.Cryptomator.yaml
|
||||||
|
yq -i '(.modules[] | select(.name == "cryptomator") | .sources) += ["maven-dependencies.yaml", "javafx-maven-dependencies-x86_64.yaml", "javafx-maven-dependencies-aarch64.yaml"]' org.cryptomator.Cryptomator.yaml
|
||||||
|
env:
|
||||||
|
FLATPAK_VERSION: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
FLATPAK_REVISION: ${{ steps.revision.outputs.value}}
|
||||||
|
CRYPTOMATOR_SOURCE: |-
|
||||||
|
type: archive
|
||||||
|
sha512: ${{steps.sha512.outputs.value}}
|
||||||
|
url: ${{ env.TARBALL_URL }}
|
||||||
|
- name: Commit and push
|
||||||
|
run: |
|
||||||
|
git config user.name "cryptobot"
|
||||||
|
git config user.email "cryptobot@users.noreply.github.com"
|
||||||
|
git config push.autoSetupRemote true
|
||||||
|
git stage org.cryptomator.Cryptomator.yaml maven-dependencies.yaml javafx-maven-dependencies-aarch64.yaml javafx-maven-dependencies-x86_64.yaml
|
||||||
|
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
|
||||||
|
git push
|
||||||
|
- name: Create pull request
|
||||||
|
id: create-pr
|
||||||
|
run: |
|
||||||
|
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
|
||||||
|
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
|
||||||
|
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
|
- name: Slack Notification
|
||||||
|
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
|
||||||
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
|
SLACK_ICON: false
|
||||||
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
|
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||||
|
SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
|
||||||
|
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.FLATHUB_PR_URL }}|PR> on how to proceed."
|
||||||
|
SLACK_FOOTER: false
|
||||||
|
MSG_MINIMAL: true
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
name: Build Arch package
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 21 20 * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version'
|
||||||
|
required: false
|
||||||
|
create-pr:
|
||||||
|
description: 'Create a PR for aur repo'
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- 'dependabot/**'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/linux-makepkg.yml'
|
||||||
|
- 'dist/linux/makepkg/**'
|
||||||
|
- 'dist/linux/common/**'
|
||||||
|
- 'dist/linux/resources/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-version:
|
||||||
|
uses: ./.github/workflows/get-version.yml
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.version }}
|
||||||
|
|
||||||
|
makepkg:
|
||||||
|
name: Build with makepkg
|
||||||
|
needs: [get-version]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: archlinux:base-devel
|
||||||
|
env:
|
||||||
|
PKGDEST: ${{ github.workspace }}/pkgdest
|
||||||
|
SRCDEST: ${{ github.workspace }}/srcdest
|
||||||
|
steps:
|
||||||
|
- name: Prepare pacman
|
||||||
|
run: |
|
||||||
|
pacman-key --init
|
||||||
|
pacman-key --populate archlinux
|
||||||
|
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
path: cryptomator
|
||||||
|
- name: Create build user
|
||||||
|
run: |
|
||||||
|
useradd -m builder
|
||||||
|
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
|
||||||
|
chown -R builder:builder "$GITHUB_WORKSPACE"
|
||||||
|
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
|
||||||
|
- name: Prepare PKGBUILD
|
||||||
|
# cannot use github.workspace due to https://github.com/actions/runner/issues/2058
|
||||||
|
run: |
|
||||||
|
export SOURCES="${SOURCES_1}${GITHUB_WORKSPACE}${SOURCES_2}"
|
||||||
|
envsubst '$PKG_VERSION $PKG_RELEASE $SOURCES $SOURCES_SHA' < cryptomator/dist/linux/makepkg/PKGBUILD.template > PKGBUILD
|
||||||
|
env:
|
||||||
|
PKG_VERSION: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
PKG_RELEASE: 1
|
||||||
|
SOURCES_1: '"${_src_app_dir}::git+file://'
|
||||||
|
SOURCES_2: '/cryptomator"'
|
||||||
|
SOURCES_SHA: "'SKIP'"
|
||||||
|
- name: Build package with makepkg
|
||||||
|
run: >
|
||||||
|
sudo -u builder
|
||||||
|
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
|
||||||
|
makepkg --syncdeps --cleanbuild --noconfirm --log
|
||||||
|
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
|
with:
|
||||||
|
name: arch-package
|
||||||
|
if-no-files-found: error
|
||||||
|
path: |
|
||||||
|
${{ env.PKGDEST }}/*.pkg.tar.zst
|
||||||
|
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
|
with:
|
||||||
|
name: pkgbuild-file
|
||||||
|
if-no-files-found: error
|
||||||
|
path: |
|
||||||
|
cryptomator/dist/linux/makepkg/PKGBUILD.template
|
||||||
|
|
||||||
|
create-pr:
|
||||||
|
name: Create PR for aur repo
|
||||||
|
if: github.event_name == 'workflow_dispatch' && inputs.create-pr || github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [get-version, makepkg]
|
||||||
|
container:
|
||||||
|
image: archlinux:base-devel
|
||||||
|
env:
|
||||||
|
PKGDEST: ${{ github.workspace }}/pkgdest
|
||||||
|
SRCDEST: ${{ github.workspace }}/srcdest
|
||||||
|
steps:
|
||||||
|
- name: Prepare pacman
|
||||||
|
run: |
|
||||||
|
pacman-key --init
|
||||||
|
pacman-key --populate archlinux
|
||||||
|
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl
|
||||||
|
- name: Download source tarball and compute checksum
|
||||||
|
id: sha256
|
||||||
|
run: |
|
||||||
|
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${TAG}.tar.gz"
|
||||||
|
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" ${URL} --output cryptomator.tar.gz
|
||||||
|
TARBALL_SHA256=$(sha256sum cryptomator.tar.gz | cut -d ' ' -f1)
|
||||||
|
echo "value=${TARBALL_SHA256}" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
TAG: ${{ needs.get-version.outputs.semVerStr || github.event.release.tag_name }}
|
||||||
|
- name: Checkout cryptomator/aur repo
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
repository: 'cryptomator/aur'
|
||||||
|
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
|
- name: Create build user
|
||||||
|
run: |
|
||||||
|
useradd -m builder
|
||||||
|
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
|
||||||
|
chown -R builder:builder "$GITHUB_WORKSPACE"
|
||||||
|
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
|
||||||
|
- name: Import Cryptomator release signing key
|
||||||
|
# try first ubuntu. on failure try openpgp keyservers
|
||||||
|
run: >
|
||||||
|
sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|
||||||
|
|| sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|
||||||
|
- name: Checkout release branch
|
||||||
|
run: |
|
||||||
|
git config --global safe.directory '*'
|
||||||
|
git checkout -b release/${VERSION}
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
|
- name: Determine pkgrel
|
||||||
|
id: pkgrel
|
||||||
|
run: |
|
||||||
|
TARGET_VERSION='${{ needs.get-version.outputs.semVerStr }}'
|
||||||
|
CURRENT_VERSION="$(sed -nE 's/^pkgver=(.*)$/\1/p' PKGBUILD | head -n1)"
|
||||||
|
CURRENT_REL="$(sed -nE 's/^pkgrel=([0-9]+).*$/\1/p' PKGBUILD | head -n1)"
|
||||||
|
|
||||||
|
if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" && "$CURRENT_REL" =~ ^[0-9]+$ ]]; then
|
||||||
|
NEXT_REL=$((CURRENT_REL + 1))
|
||||||
|
else
|
||||||
|
NEXT_REL=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "value=${NEXT_REL}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "dist-version=${VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
|
- name: Download PKGBUILD template
|
||||||
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
|
with:
|
||||||
|
name: pkgbuild-file
|
||||||
|
- name: Prepare PKGBUILD
|
||||||
|
run: |
|
||||||
|
envsubst '$PKG_VERSION $PKG_RELEASE $SOURCES $SOURCES_SHA' < PKGBUILD.template > PKGBUILD
|
||||||
|
sudo -u builder makepkg --printsrcinfo > .SRCINFO
|
||||||
|
env:
|
||||||
|
PKG_VERSION: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
PKG_RELEASE: ${{ steps.pkgrel.outputs.value }}
|
||||||
|
SOURCES: |-
|
||||||
|
"cryptomator-${pkgver//_/-}.tar.gz::https://github.com/cryptomator/cryptomator/archive/refs/tags/${pkgver//_/-}.tar.gz"
|
||||||
|
"cryptomator-${pkgver//_/-}.tar.gz.asc::https://github.com/cryptomator/cryptomator/releases/download/${pkgver//_/-}/cryptomator-${pkgver//_/-}.tar.gz.asc"
|
||||||
|
SOURCES_SHA: |-
|
||||||
|
'${{steps.sha256.outputs.value}}'
|
||||||
|
'SKIP'
|
||||||
|
- name: Build package with makepkg
|
||||||
|
run: >
|
||||||
|
sudo -u builder
|
||||||
|
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
|
||||||
|
makepkg --syncdeps --cleanbuild --noconfirm --log
|
||||||
|
- name: Commit and push
|
||||||
|
run: |
|
||||||
|
git config user.name "cryptobot"
|
||||||
|
git config user.email "cryptobot@users.noreply.github.com"
|
||||||
|
git config push.autoSetupRemote true
|
||||||
|
git stage PKGBUILD .SRCINFO
|
||||||
|
git commit -m "Prepare release ${DIST_VERSION}"
|
||||||
|
git push
|
||||||
|
env:
|
||||||
|
DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }}
|
||||||
|
- name: Create pull request
|
||||||
|
id: create-pr
|
||||||
|
run: |
|
||||||
|
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
|
||||||
|
PR_URL=$(gh pr create --title "Release $DIST_VERSION" --body-file pr_body.md)
|
||||||
|
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }}
|
||||||
|
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
|
- name: Slack Notification
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
|
||||||
|
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 }} ${{ steps.pkgrel.outputs.dist-version }} ."
|
||||||
|
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
|
||||||
|
SLACK_FOOTER: false
|
||||||
|
MSG_MINIMAL: true
|
||||||
@@ -11,6 +11,8 @@ name: Build macOS .dmg for x64
|
|||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 20 20 * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
@@ -59,7 +61,7 @@ jobs:
|
|||||||
- name: Download OpenJFX jmods
|
- name: Download OpenJFX jmods
|
||||||
id: download-jmods
|
id: download-jmods
|
||||||
run: |
|
run: |
|
||||||
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
curl --silent --fail-with-body --proto "=https" -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
||||||
echo "${{ matrix.openjfx-sha }} *openjfx-jmods.zip" | shasum -a256 --check
|
echo "${{ matrix.openjfx-sha }} *openjfx-jmods.zip" | shasum -a256 --check
|
||||||
mkdir -p openjfx-jmods/
|
mkdir -p openjfx-jmods/
|
||||||
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||||
@@ -125,7 +127,6 @@ jobs:
|
|||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
--java-options "-Djava.net.useSystemProxies=true"
|
--java-options "-Djava.net.useSystemProxies=true"
|
||||||
--java-options "-Dapple.awt.enableTemplateImages=true"
|
|
||||||
--java-options "-Dsun.java2d.metal=true"
|
--java-options "-Dsun.java2d.metal=true"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
|
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
|
||||||
@@ -138,12 +139,14 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||||
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
|
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
|
||||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
|
||||||
--mac-package-identifier org.cryptomator
|
--mac-package-identifier org.cryptomator
|
||||||
--resource-dir dist/mac/resources
|
--resource-dir dist/mac/resources
|
||||||
- name: Patch Cryptomator.app
|
- name: Patch Cryptomator.app
|
||||||
run: |
|
run: |
|
||||||
mv appdir/Cryptomator.app Cryptomator.app
|
mv appdir/Cryptomator.app Cryptomator.app
|
||||||
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
|
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
|
||||||
|
cp dist/mac/resources/Assets.car Cryptomator.app/Contents/Resources/
|
||||||
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
|
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
|
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
|
||||||
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
|
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
|
||||||
@@ -151,20 +154,6 @@ jobs:
|
|||||||
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
|
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
|
||||||
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
|
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
|
||||||
- name: Build and install DockTilePlugin
|
|
||||||
env:
|
|
||||||
DERIVED_DATA_PATH: dist/mac/DockTilePlugin/build
|
|
||||||
run: |
|
|
||||||
xcodebuild -project dist/mac/DockTilePlugin/DockTilePlugin.xcodeproj \
|
|
||||||
-scheme DockTilePlugin \
|
|
||||||
-configuration Release \
|
|
||||||
-destination "platform=macOS,arch=x86_64" \
|
|
||||||
-derivedDataPath ${DERIVED_DATA_PATH} \
|
|
||||||
-quiet \
|
|
||||||
clean build
|
|
||||||
mkdir -p Cryptomator.app/Contents/PlugIns
|
|
||||||
cp -R ${DERIVED_DATA_PATH}/Build/Products/Release/Cryptomator.docktileplugin Cryptomator.app/Contents/PlugIns/
|
|
||||||
rm -rf ${DERIVED_DATA_PATH}
|
|
||||||
- name: Generate license for dmg
|
- name: Generate license for dmg
|
||||||
run: >
|
run: >
|
||||||
mvn -B license:add-third-party
|
mvn -B license:add-third-party
|
||||||
@@ -261,7 +250,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
||||||
- name: Notarize .dmg
|
- name: Notarize .dmg
|
||||||
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize || github.event_name == 'schedule'
|
||||||
uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3
|
uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3
|
||||||
with:
|
with:
|
||||||
app-path: 'Cryptomator-*.dmg'
|
app-path: 'Cryptomator-*.dmg'
|
||||||
@@ -283,7 +272,7 @@ jobs:
|
|||||||
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
|
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: dmg-${{ matrix.output-suffix }}
|
name: dmg-${{ matrix.output-suffix }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ name: Build macOS .dmg for arm64
|
|||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 20 20 * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
@@ -57,7 +59,7 @@ jobs:
|
|||||||
- name: Download OpenJFX jmods
|
- name: Download OpenJFX jmods
|
||||||
id: download-jmods
|
id: download-jmods
|
||||||
run: |
|
run: |
|
||||||
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
curl --silent --fail-with-body --proto "=https" -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
||||||
echo "${{ matrix.openjfx-sha }} *openjfx-jmods.zip" | shasum -a256 --check
|
echo "${{ matrix.openjfx-sha }} *openjfx-jmods.zip" | shasum -a256 --check
|
||||||
mkdir -p openjfx-jmods/
|
mkdir -p openjfx-jmods/
|
||||||
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||||
@@ -123,7 +125,6 @@ jobs:
|
|||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
--java-options "-Djava.net.useSystemProxies=true"
|
--java-options "-Djava.net.useSystemProxies=true"
|
||||||
--java-options "-Dapple.awt.enableTemplateImages=true"
|
|
||||||
--java-options "-Dsun.java2d.metal=true"
|
--java-options "-Dsun.java2d.metal=true"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
|
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
|
||||||
@@ -137,12 +138,14 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
|
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
|
||||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
||||||
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
|
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
|
||||||
--mac-package-identifier org.cryptomator
|
--mac-package-identifier org.cryptomator
|
||||||
--resource-dir dist/mac/resources
|
--resource-dir dist/mac/resources
|
||||||
- name: Patch Cryptomator.app
|
- name: Patch Cryptomator.app
|
||||||
run: |
|
run: |
|
||||||
mv appdir/Cryptomator.app Cryptomator.app
|
mv appdir/Cryptomator.app Cryptomator.app
|
||||||
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
|
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
|
||||||
|
cp dist/mac/resources/Assets.car Cryptomator.app/Contents/Resources/
|
||||||
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
|
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
|
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
|
||||||
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
|
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
|
||||||
@@ -150,20 +153,6 @@ jobs:
|
|||||||
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
|
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
|
||||||
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
|
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
|
||||||
- name: Build and install DockTilePlugin
|
|
||||||
env:
|
|
||||||
DERIVED_DATA_PATH: dist/mac/DockTilePlugin/build
|
|
||||||
run: |
|
|
||||||
xcodebuild -project dist/mac/DockTilePlugin/DockTilePlugin.xcodeproj \
|
|
||||||
-scheme DockTilePlugin \
|
|
||||||
-configuration Release \
|
|
||||||
-destination "platform=macOS,arch=arm64" \
|
|
||||||
-derivedDataPath ${DERIVED_DATA_PATH} \
|
|
||||||
-quiet \
|
|
||||||
clean build
|
|
||||||
mkdir -p Cryptomator.app/Contents/PlugIns
|
|
||||||
cp -R ${DERIVED_DATA_PATH}/Build/Products/Release/Cryptomator.docktileplugin Cryptomator.app/Contents/PlugIns/
|
|
||||||
rm -rf ${DERIVED_DATA_PATH}
|
|
||||||
- name: Generate license for dmg
|
- name: Generate license for dmg
|
||||||
run: >
|
run: >
|
||||||
mvn -B license:add-third-party
|
mvn -B license:add-third-party
|
||||||
@@ -260,7 +249,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
||||||
- name: Notarize .dmg
|
- name: Notarize .dmg
|
||||||
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize || github.event_name == 'schedule'
|
||||||
uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3
|
uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3
|
||||||
with:
|
with:
|
||||||
app-path: 'Cryptomator-*.dmg'
|
app-path: 'Cryptomator-*.dmg'
|
||||||
@@ -282,7 +271,7 @@ jobs:
|
|||||||
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
|
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: dmg-${{ matrix.output-suffix }}
|
name: dmg-${{ matrix.output-suffix }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
|
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||||
with:
|
with:
|
||||||
days-before-stale: 14
|
days-before-stale: 14
|
||||||
days-before-close: 0
|
days-before-close: 0
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Download source tarball
|
- name: Download source tarball
|
||||||
run: |
|
run: |
|
||||||
curl -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
|
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
|
||||||
- name: Sign source tarball with key 615D449FE6E6A235
|
- name: Sign source tarball with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
- name: Slack Notification
|
- name: Slack Notification
|
||||||
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
|
||||||
SLACK_USERNAME: 'Cryptobot'
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
SLACK_ICON: false
|
SLACK_ICON: false
|
||||||
SLACK_ICON_EMOJI: ':bot:'
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: Validate release in org.cryptomator.Cryptomator.metainfo.xml file
|
- name: Validate release in org.cryptomator.Cryptomator.metainfo.xml file
|
||||||
|
if: ${{ ! (contains(github.event.head_commit.message, '[skip metadata check]') || contains(github.event.head_commit.message, '[metadata check skip]')) }}
|
||||||
run: |
|
run: |
|
||||||
if ! grep -q "<release date=\".*\" version=\"${{ steps.validate-pom-version.outputs.semVerStr }}\">" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then
|
if ! grep -q "<release date=\".*\" version=\"${{ steps.validate-pom-version.outputs.semVerStr }}\">" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then
|
||||||
echo "Release not set in dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml"
|
echo "Release not set in dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
|
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||||
with:
|
with:
|
||||||
days-before-stale: 365
|
days-before-stale: 365
|
||||||
days-before-close: 90
|
days-before-close: 90
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ name: Build Windows Installer
|
|||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 19 20 * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
@@ -72,7 +74,7 @@ jobs:
|
|||||||
if: matrix.arch == 'x64'
|
if: matrix.arch == 'x64'
|
||||||
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
|
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
|
||||||
run: |
|
run: |
|
||||||
curl --output openjfx-jmods.zip -L "${{ env.OPENJFX_JMODS_AMD64 }}"
|
curl --silent --fail-with-body --proto "=https" -L "${{ env.OPENJFX_JMODS_AMD64 }}" --output openjfx-jmods.zip
|
||||||
if(!(Get-FileHash -Path openjfx-jmods.zip -Algorithm SHA256).Hash.ToLower().equals("${{ env.OPENJFX_JMODS_AMD64_HASH }}")) {
|
if(!(Get-FileHash -Path openjfx-jmods.zip -Algorithm SHA256).Hash.ToLower().equals("${{ env.OPENJFX_JMODS_AMD64_HASH }}")) {
|
||||||
throw "Wrong checksum of JMOD archive downloaded from ${{ env.OPENJFX_JMODS_AMD64 }}.";
|
throw "Wrong checksum of JMOD archive downloaded from ${{ env.OPENJFX_JMODS_AMD64 }}.";
|
||||||
}
|
}
|
||||||
@@ -157,6 +159,7 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json\""
|
--java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json\""
|
||||||
--java-options "-Dcryptomator.disableUpdateCheck=false"
|
--java-options "-Dcryptomator.disableUpdateCheck=false"
|
||||||
--java-options "-XX:ErrorFile=C:/cryptomator/cryptomator_crash.log"
|
--java-options "-XX:ErrorFile=C:/cryptomator/cryptomator_crash.log"
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
|
||||||
--resource-dir dist/win/resources
|
--resource-dir dist/win/resources
|
||||||
--icon dist/win/resources/Cryptomator.ico
|
--icon dist/win/resources/Cryptomator.ico
|
||||||
--add-launcher "Cryptomator (Debug)=dist/win/debug-launcher.properties"
|
--add-launcher "Cryptomator (Debug)=dist/win/debug-launcher.properties"
|
||||||
@@ -192,7 +195,7 @@ jobs:
|
|||||||
& $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
|
& $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"
|
Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir"
|
||||||
- name: Sign DLLs with Azure Trusted Signing
|
- name: Sign DLLs with Azure Trusted Signing
|
||||||
if: inputs.sign || github.event_name == 'release'
|
if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule'
|
||||||
uses: ./.github/actions/win-sign-action
|
uses: ./.github/actions/win-sign-action
|
||||||
with:
|
with:
|
||||||
base-dir: ${{ github.workspace }}\appdir
|
base-dir: ${{ github.workspace }}\appdir
|
||||||
@@ -201,17 +204,6 @@ jobs:
|
|||||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||||
- name: Sign DLLs with Actalis CodeSigner
|
|
||||||
if: inputs.sign || github.event_name == 'release'
|
|
||||||
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
|
|
||||||
with:
|
|
||||||
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
|
- name: Replace DLLs inside jars with signed ones
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
@@ -261,7 +253,7 @@ jobs:
|
|||||||
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
|
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
|
||||||
JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
|
JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
|
||||||
- name: Sign MSI with Azure Trusted Signing
|
- name: Sign MSI with Azure Trusted Signing
|
||||||
if: inputs.sign || github.event_name == 'release'
|
if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule'
|
||||||
uses: ./.github/actions/win-sign-action
|
uses: ./.github/actions/win-sign-action
|
||||||
with:
|
with:
|
||||||
base-dir: ${{ github.workspace }}\installer
|
base-dir: ${{ github.workspace }}\installer
|
||||||
@@ -280,7 +272,7 @@ jobs:
|
|||||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: msi-${{ matrix.arch }}
|
name: msi-${{ matrix.arch }}
|
||||||
path: |
|
path: |
|
||||||
@@ -311,7 +303,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
WIX_VERSION: ${{ env.WIX_VERSION }}
|
WIX_VERSION: ${{ env.WIX_VERSION }}
|
||||||
- name: Download .msi
|
- name: Download .msi
|
||||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
with:
|
with:
|
||||||
name: msi-${{ matrix.arch }}
|
name: msi-${{ matrix.arch }}
|
||||||
path: dist/win/bundle/resources
|
path: dist/win/bundle/resources
|
||||||
@@ -338,7 +330,7 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Download WinFsp
|
- name: Download WinFsp
|
||||||
run: |
|
run: |
|
||||||
curl --output $env:WINFSP_PATH -L ${{ env.WINFSP_MSI }}
|
curl --silent --fail-with-body --proto "=https" -L ${{ env.WINFSP_MSI }} --output $env:WINFSP_PATH
|
||||||
$computedHash = (Get-FileHash -Path $env:WINFSP_PATH -Algorithm SHA256).Hash.ToLower()
|
$computedHash = (Get-FileHash -Path $env:WINFSP_PATH -Algorithm SHA256).Hash.ToLower()
|
||||||
if ($computedHash -ne "${{ env.WINFSP_MSI_HASH }}") {
|
if ($computedHash -ne "${{ env.WINFSP_MSI_HASH }}") {
|
||||||
throw "Checksum mismatch for $env:WINFSP_PATH (expected ${{ env.WINFSP_MSI_HASH }}, got $computedHash)."
|
throw "Checksum mismatch for $env:WINFSP_PATH (expected ${{ env.WINFSP_MSI_HASH }}, got $computedHash)."
|
||||||
@@ -348,7 +340,7 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Download Legacy-WinFsp uninstaller
|
- name: Download Legacy-WinFsp uninstaller
|
||||||
run: |
|
run: |
|
||||||
curl --output dist/win/bundle/resources/winfsp-uninstaller.exe -L ${{ env.WINFSP_UNINSTALLER }}
|
curl --silent --fail-with-body --proto "=https" -L ${{ env.WINFSP_UNINSTALLER }} --output dist/win/bundle/resources/winfsp-uninstaller.exe
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Create Wix Burn bundle
|
- name: Create Wix Burn bundle
|
||||||
working-directory: dist/win
|
working-directory: dist/win
|
||||||
@@ -369,7 +361,7 @@ jobs:
|
|||||||
run: >
|
run: >
|
||||||
wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe
|
wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe
|
||||||
- name: Sign WiX burn engine with Azure Trusted Signing
|
- name: Sign WiX burn engine with Azure Trusted Signing
|
||||||
if: inputs.sign || github.event_name == 'release'
|
if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule'
|
||||||
uses: ./.github/actions/win-sign-action
|
uses: ./.github/actions/win-sign-action
|
||||||
with:
|
with:
|
||||||
base-dir: ${{ github.workspace }}\tmp
|
base-dir: ${{ github.workspace }}\tmp
|
||||||
@@ -379,21 +371,11 @@ jobs:
|
|||||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||||
- name: Sign burn engine with Actalis CodeSigner
|
|
||||||
if: inputs.sign || github.event_name == 'release'
|
|
||||||
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
|
|
||||||
with:
|
|
||||||
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
|
- name: Reattach signed burn engine to installer
|
||||||
run: >
|
run: >
|
||||||
wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
|
wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
|
||||||
- name: Sign EXE installer with Azure Trusted Signing
|
- name: Sign EXE installer with Azure Trusted Signing
|
||||||
if: inputs.sign || github.event_name == 'release'
|
if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule'
|
||||||
uses: ./.github/actions/win-sign-action
|
uses: ./.github/actions/win-sign-action
|
||||||
with:
|
with:
|
||||||
base-dir: ${{ github.workspace }}\installer
|
base-dir: ${{ github.workspace }}\installer
|
||||||
@@ -403,16 +385,6 @@ jobs:
|
|||||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||||
- name: Sign installer with Actalis CodeSigner
|
|
||||||
if: inputs.sign || github.event_name == 'release'
|
|
||||||
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
|
|
||||||
with:
|
|
||||||
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
|
- 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
|
run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.executable-suffix }}.exe
|
||||||
- name: Create detached GPG signature with key 615D449FE6E6A235
|
- name: Create detached GPG signature with key 615D449FE6E6A235
|
||||||
@@ -423,7 +395,7 @@ jobs:
|
|||||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: exe-${{ matrix.executable-suffix }}
|
name: exe-${{ matrix.executable-suffix }}
|
||||||
path: |
|
path: |
|
||||||
@@ -441,7 +413,7 @@ jobs:
|
|||||||
download-url-exe-x64: ${{ fromJSON(steps.publish.outputs.assets)[2].browser_download_url }}
|
download-url-exe-x64: ${{ fromJSON(steps.publish.outputs.assets)[2].browser_download_url }}
|
||||||
steps:
|
steps:
|
||||||
- name: Download installers
|
- name: Download installers
|
||||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||||
with:
|
with:
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
- name: Publish installers on GitHub Releases
|
- name: Publish installers on GitHub Releases
|
||||||
@@ -479,7 +451,7 @@ jobs:
|
|||||||
- name: Slack Notification
|
- name: Slack Notification
|
||||||
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
|
||||||
SLACK_USERNAME: 'Cryptobot'
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
SLACK_ICON: false
|
SLACK_ICON: false
|
||||||
SLACK_ICON_EMOJI: ':bot:'
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.hub.enableTrustOnFirstUse=true -Dfuse.experimental="true" -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator" -Dcryptomator.pluginDir="@{appdata}/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator" -Dcryptomator.pluginDir="@{appdata}/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator-Dev" -Dcryptomator.pluginDir="@{appdata}/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator-Dev/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator-Dev" -Dcryptomator.pluginDir="@{appdata}/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator-Dev/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
</envs>
|
</envs>
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
</envs>
|
</envs>
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Library/Application Support/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Library/Application Support/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+48
-9
@@ -7,7 +7,44 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
The changelog starts with version 1.19.0.
|
The changelog starts with version 1.19.0.
|
||||||
Changes to prior versions can be found on the [Github release page](https://github.com/cryptomator/cryptomator/releases).
|
Changes to prior versions can be found on the [Github release page](https://github.com/cryptomator/cryptomator/releases).
|
||||||
|
|
||||||
## [Unreleased](https://github.com/cryptomator/cryptomator/compare/1.18.0...HEAD)
|
|
||||||
|
## [Unreleased](https://github.com/cryptomator/cryptomator/compare/1.19.1...HEAD)
|
||||||
|
|
||||||
|
No changes yet.
|
||||||
|
|
||||||
|
|
||||||
|
## [1.19.2](https://github.com/cryptomator/cryptomator/releases/1.19.2) - 2026-03-20
|
||||||
|
|
||||||
|
### Security
|
||||||
|
* Cryptomamtor Hub Vaults: Additional patch for (#4179, [GHSA-34rf-rwr3-7g43](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-34rf-rwr3-7g43))
|
||||||
|
|
||||||
|
|
||||||
|
## [1.19.1](https://github.com/cryptomator/cryptomator/releases/1.19.1) - 2026-03-12
|
||||||
|
|
||||||
|
### Security
|
||||||
|
* Cryptomamtor Hub Vaults: Fixed possible man-in-the-middle attack with tampered vault config (#4179, [GHSA-34rf-rwr3-7g43](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-34rf-rwr3-7g43))
|
||||||
|
* Disallow unencrypted http connections to hub by default ([CVE-2026-32309](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-vv33-h7qx-c264))
|
||||||
|
* Disallow loading of masterkey file from arbitrary paths (#4180, [CVE-2026-32310](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-5phc-5pfx-hr52))
|
||||||
|
* Fixed not-configured plugin directory does not disable plugin search ([#4176](https://github.com/cryptomator/cryptomator/pull/4176))
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Trust on first use, adding new config properties `cryptomator.hub.allowedHosts` and `cryptomator.hub.enableTrustOnFirstUse` (#4179)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Fixed Finder window opens twice when revealing vault on macOS ([#4177](https://github.com/cryptomator/cryptomator/pull/4177))
|
||||||
|
* Fixed app does not start due to secret service detection failure on Linux ([#4175](https://github.com/cryptomator/cryptomator/pull/4175))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Pin version of appimagetool([#4181](https://github.com/cryptomator/cryptomator/pull/4181))
|
||||||
|
* Updated translations
|
||||||
|
* Updated dependencies:
|
||||||
|
* `org.cryptomator:integrations-api` from 1.8.0-beta1 to 1.8.0
|
||||||
|
* `org.cryptomator:integrations-linux` from 1.7.0-beta4 to 1.7.0
|
||||||
|
* `org.cryptomator:integrations-mac` from 1.5.0-beta3 to 1.5.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [1.19.0](https://github.com/cryptomator/cryptomator/releases/tag/1.19.0) - 2026-03-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* Self-Update Mechanism ([#3948](https://github.com/cryptomator/cryptomator/pull/3948))
|
* Self-Update Mechanism ([#3948](https://github.com/cryptomator/cryptomator/pull/3948))
|
||||||
@@ -20,31 +57,33 @@ Changes to prior versions can be found on the [Github release page](https://gith
|
|||||||
* Support automatic app theme selection according to OS theme on Linux ([#4027](https://github.com/cryptomator/cryptomator/issues/4027))
|
* Support automatic app theme selection according to OS theme on Linux ([#4027](https://github.com/cryptomator/cryptomator/issues/4027))
|
||||||
* Admin configuration: Allow overwriting certain app properties by external config file ([#4105](https://github.com/cryptomator/cryptomator/pull/4105))
|
* Admin configuration: Allow overwriting certain app properties by external config file ([#4105](https://github.com/cryptomator/cryptomator/pull/4105))
|
||||||
* New keychain backend using [secret service API](https://specifications.freedesktop.org/secret-service/0.2) for Linux ([#4025](https://github.com/cryptomator/cryptomator/pull/4025))
|
* New keychain backend using [secret service API](https://specifications.freedesktop.org/secret-service/0.2) for Linux ([#4025](https://github.com/cryptomator/cryptomator/pull/4025))
|
||||||
|
* Liquid Glass icon for macOS ([#4166](https://github.com/cryptomator/cryptomator/pull/4166))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fixed password reset/show recovery possible for vaults without masterkey file ([#4120](https://github.com/cryptomator/cryptomator/pull/4120))
|
* Fixed password reset/show recovery possible for vaults without masterkey file ([#4120](https://github.com/cryptomator/cryptomator/pull/4120))
|
||||||
* Fixed restore vault config failed due to selecting a directory instead of file ([#4141](https://github.com/cryptomator/cryptomator/issues/4141))
|
* Fixed restore vault config failed due to selecting a directory instead of file ([#4141](https://github.com/cryptomator/cryptomator/issues/4141))
|
||||||
|
* Fixed leaking of cleartext paths into application log ([GHSA-j83j-mwhc-rcgw](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-j83j-mwhc-rcgw))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Disable user defined app start config on Windows ([#4132](https://github.com/cryptomator/cryptomator/issues/4132))
|
* Disable user defined app start config on Windows ([#4132](https://github.com/cryptomator/cryptomator/issues/4132))
|
||||||
* Disable plugin loading by default ([#4136](https://github.com/cryptomator/cryptomator/4136))
|
* Disable plugin loading by default ([#4136](https://github.com/cryptomator/cryptomator/4136))
|
||||||
* Use JDK 25 ([#4031](https://github.com/cryptomator/cryptomator/pull/4031))
|
* Use JDK 25 ([#4031](https://github.com/cryptomator/cryptomator/pull/4031))
|
||||||
* Update JavaFX to 25.0.2 ([#4145](https://github.com/cryptomator/cryptomator/pull/4145)))
|
* Update JavaFX to 25.0.2 ([#4145](https://github.com/cryptomator/cryptomator/pull/4145))
|
||||||
* Updated translations
|
* Updated translations
|
||||||
* Updated dependencies
|
* Updated dependencies
|
||||||
* `ch.qos.logback:*` from 1.5.19 to 1.5.31
|
* `ch.qos.logback:*` from 1.5.19 to 1.5.32
|
||||||
* `com.fasterxml.jackson.core:jackson-databind` from 2.20.0 to 2.21.0
|
* `com.fasterxml.jackson.core:jackson-databind` from 2.20.0 to 2.21.1
|
||||||
* `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.20.0 to 2.21.0
|
* `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.20.0 to 2.21.1
|
||||||
* `com.github.ben-manes.caffeine:caffeine` from 3.2.2 to 3.2.3
|
* `com.github.ben-manes.caffeine:caffeine` from 3.2.2 to 3.2.3
|
||||||
* `com.google.dagger:*` from 2.57.2 to 2.59.1
|
* `com.google.dagger:*` from 2.57.2 to 2.59.2
|
||||||
* `org.apache.commons:commons-lang3` from 3.19.0 to 3.20.0
|
* `org.apache.commons:commons-lang3` from 3.19.0 to 3.20.0
|
||||||
* `org.cryptomator:cryptofs` from 2.9.0 to 2.10.0-beta3
|
* `org.cryptomator:cryptofs` from 2.9.0 to 2.10.0
|
||||||
* `org.cryptomator:cryptolib` from 2.2.1 to 2.2.2
|
* `org.cryptomator:cryptolib` from 2.2.1 to 2.2.2
|
||||||
* `org.cryptomator:fuse-nio-adapter` from 5.1.0 to 6.0.0
|
* `org.cryptomator:fuse-nio-adapter` from 5.1.0 to 6.0.1
|
||||||
* `org.cryptomator:integrations-api` from 1.7.0 to 1.8.0-beta1
|
* `org.cryptomator:integrations-api` from 1.7.0 to 1.8.0-beta1
|
||||||
* `org.cryptomator:integrations-linux` from 1.6.1 to 1.7.0-beta4
|
* `org.cryptomator:integrations-linux` from 1.6.1 to 1.7.0-beta4
|
||||||
* `org.cryptomator:integrations-mac` from 1.4.1 to 1.5.0-beta3
|
* `org.cryptomator:integrations-mac` from 1.4.1 to 1.5.0-beta3
|
||||||
* `org.cryptomator:integrations-win` from 1.5.1 to 1.6.0
|
* `org.cryptomator:integrations-win` from 1.5.1 to 1.6.0
|
||||||
* `org.cryptomator:webdav-nio-adapter` from 3.0.0 to 3.0.1
|
* `org.cryptomator:webdav-nio-adapter` from 3.0.0 to 3.0.1
|
||||||
|
* `org.cryptomator:webdav-nio-adapter-servlet` to 1.2.12
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-1
@@ -99,6 +99,7 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
|
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
|
||||||
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
||||||
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log" \
|
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log" \
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
|
||||||
--resource-dir ../resources
|
--resource-dir ../resources
|
||||||
|
|
||||||
# transform AppDir
|
# transform AppDir
|
||||||
@@ -123,7 +124,7 @@ ln -s org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/meta
|
|||||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||||
|
|
||||||
# load AppImageTool
|
# load AppImageTool
|
||||||
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
|
curl -L https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
|
||||||
chmod +x /tmp/appimagetool.AppImage
|
chmod +x /tmp/appimagetool.AppImage
|
||||||
|
|
||||||
# create AppImage
|
# create AppImage
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
<url type="faq">https://community.cryptomator.org/c/kb/faq</url>
|
<url type="faq">https://community.cryptomator.org/c/kb/faq</url>
|
||||||
<url type="help">https://docs.cryptomator.org/</url>
|
<url type="help">https://docs.cryptomator.org/</url>
|
||||||
<url type="translate">https://translate.cryptomator.org</url>
|
<url type="translate">https://translate.cryptomator.org</url>
|
||||||
|
<url type="vcs-browser">https://github.com/cryptomator/cryptomator</url>
|
||||||
|
|
||||||
<developer id="de.skymatic">
|
<developer id="de.skymatic">
|
||||||
<name>Skymatic GmbH</name>
|
<name>Skymatic GmbH</name>
|
||||||
@@ -83,6 +84,15 @@
|
|||||||
</content_rating>
|
</content_rating>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release date="2026-03-20" version="1.19.2">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.19.2</url>
|
||||||
|
</release>
|
||||||
|
<release date="2026-03-12" version="1.19.1">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.19.1</url>
|
||||||
|
</release>
|
||||||
|
<release date="2026-03-09" version="1.19.0">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.19.0</url>
|
||||||
|
</release>
|
||||||
<release date="2025-11-12" version="1.18.0">
|
<release date="2025-11-12" version="1.18.0">
|
||||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.18.0</url>
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.18.0</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
Vendored
+1
@@ -64,6 +64,7 @@ override_dh_auto_build:
|
|||||||
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
|
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
|
||||||
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
|
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
|
||||||
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
|
||||||
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
||||||
--resource-dir resources \
|
--resource-dir resources \
|
||||||
--verbose
|
--verbose
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# From: https://gitlab.gnome.org/GNOME/gnome-builder/-/blob/main/build-aux/flatpak/fusermount-wrapper.sh
|
||||||
|
|
||||||
|
if [ -z "$_FUSE_COMMFD" ]; then
|
||||||
|
FD_ARGS=
|
||||||
|
else
|
||||||
|
FD_ARGS="--env=_FUSE_COMMFD=${_FUSE_COMMFD} --forward-fd=${_FUSE_COMMFD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e /proc/self/fd/3 ] && [ 3 != "$_FUSE_COMMFD" ]; then
|
||||||
|
FD_ARGS="$FD_ARGS --forward-fd=3"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec flatpak-spawn --host --forward-fd=1 --forward-fd=2 $FD_ARGS fusermount3 "$@"
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
app-id: org.cryptomator.Cryptomator
|
||||||
|
command: cryptomator
|
||||||
|
runtime: org.freedesktop.Platform
|
||||||
|
runtime-version: '25.08'
|
||||||
|
sdk: org.freedesktop.Sdk
|
||||||
|
separate-locales: false
|
||||||
|
finish-args:
|
||||||
|
# Required for FUSE, see https://github.com/flathub/org.cryptomator.Cryptomator/pull/68#issuecomment-1935136502
|
||||||
|
- --device=all
|
||||||
|
# Set the PATH environment variable in the application, as flatpak is resetting the shell's PATH
|
||||||
|
- --env=PATH=/app/bin/:/usr/bin/
|
||||||
|
# Allow filesystem access to the user's home dir
|
||||||
|
# Needed to manage vaults there
|
||||||
|
- --filesystem=home
|
||||||
|
# Reading system certificates
|
||||||
|
- --filesystem=host-etc:ro
|
||||||
|
# Allow access to the XDG data directory
|
||||||
|
# Needed to connect to KeePassXC's UNIX domain socket
|
||||||
|
- --filesystem=xdg-run/org.keepassxc.KeePassXC.BrowserServer
|
||||||
|
- --filesystem=xdg-run/app/org.keepassxc.KeePassXC/
|
||||||
|
# Share IPC namespace with the host, without it the X11 shared memory extension will not work
|
||||||
|
- --share=ipc
|
||||||
|
# Allow access to the network
|
||||||
|
- --share=network
|
||||||
|
# Show windows using X11
|
||||||
|
- --socket=x11
|
||||||
|
# Needed to reveal encrypted files
|
||||||
|
- --talk-name=org.freedesktop.FileManager1
|
||||||
|
# Run any command on the host
|
||||||
|
# Needed to spawn fusermount on the host
|
||||||
|
- --talk-name=org.freedesktop.Flatpak
|
||||||
|
# Allow desktop notifications
|
||||||
|
- --talk-name=org.freedesktop.Notifications
|
||||||
|
# Allow access to the GNOME secret service API and to talk to the GNOME keyring daemon
|
||||||
|
- --talk-name=org.freedesktop.secrets
|
||||||
|
- --talk-name=org.gnome.keyring
|
||||||
|
# Allow to talk to the KDE kwallet daemon
|
||||||
|
- --talk-name=org.kde.kwalletd5
|
||||||
|
- --talk-name=org.kde.kwalletd6
|
||||||
|
# Needed to talk to the gvfs daemons over D-Bus and list mounts using the GIO APIs
|
||||||
|
- --talk-name=org.gtk.vfs.*
|
||||||
|
# Allow access to appindicator icons
|
||||||
|
- --talk-name=org.ayatana
|
||||||
|
# Allow access to appindicator icons on KDE
|
||||||
|
- --talk-name=org.kde.StatusNotifierWatcher
|
||||||
|
cleanup:
|
||||||
|
- /include
|
||||||
|
- /lib/pkgconfig
|
||||||
|
modules:
|
||||||
|
- shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json
|
||||||
|
- name: libfuse
|
||||||
|
buildsystem: meson
|
||||||
|
config-opts:
|
||||||
|
- -Dexamples=false
|
||||||
|
- -Dinitscriptdir=
|
||||||
|
- -Duseroot=false
|
||||||
|
- -Dtests=false
|
||||||
|
# don't install rules on the host
|
||||||
|
- -Dudevrulesdir=/tmp/
|
||||||
|
sources:
|
||||||
|
- type: archive
|
||||||
|
url: https://github.com/libfuse/libfuse/releases/download/fuse-3.16.2/fuse-3.16.2.tar.gz
|
||||||
|
sha256: f797055d9296b275e981f5f62d4e32e089614fc253d1ef2985851025b8a0ce87
|
||||||
|
x-checker-data:
|
||||||
|
type: anitya
|
||||||
|
project-id: 861
|
||||||
|
url-template: https://github.com/libfuse/libfuse/releases/download/fuse-$version/fuse-$version.tar.gz
|
||||||
|
versions: {<: '3.17.0'}
|
||||||
|
- name: host-command-wrapper
|
||||||
|
buildsystem: simple
|
||||||
|
build-commands:
|
||||||
|
- install fusermount-wrapper.sh /app/bin/fusermount3
|
||||||
|
sources:
|
||||||
|
- type: file
|
||||||
|
path: build-aux/fusermount-wrapper.sh
|
||||||
|
- name: cryptomator
|
||||||
|
buildsystem: simple
|
||||||
|
build-options:
|
||||||
|
build-args:
|
||||||
|
- --share=network
|
||||||
|
env:
|
||||||
|
PATH: /app/bin:/usr/bin
|
||||||
|
MAVEN_OPTS: -Dmaven.repo.local=.m2/repository
|
||||||
|
JAVA_HOME: jdk
|
||||||
|
JMODS_PATH: jmods
|
||||||
|
VERSION: $FLATPAK_VERSION
|
||||||
|
REVISION_NO: '$FLATPAK_REVISION'
|
||||||
|
build-commands:
|
||||||
|
# Setup Java
|
||||||
|
- tar xvfz jdk.tar.gz --transform 's!^[^/]*!jdk!'
|
||||||
|
- mkdir jmods
|
||||||
|
- unzip -j openjfx.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods
|
||||||
|
# Setup Maven
|
||||||
|
- mkdir maven
|
||||||
|
- tar xf maven.tar.gz --strip-components=1 --exclude=jansi-native --directory=maven
|
||||||
|
# Build project
|
||||||
|
- maven/bin/mvn clean package -DskipTests -P"linux-$(uname -m)"
|
||||||
|
- cp target/cryptomator-*.jar target/mods
|
||||||
|
- cd target
|
||||||
|
- $JAVA_HOME/bin/jlink
|
||||||
|
--output runtime
|
||||||
|
--module-path $JMODS_PATH
|
||||||
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
|
||||||
|
--no-header-files
|
||||||
|
--no-man-pages
|
||||||
|
--strip-debug
|
||||||
|
--compress=zip-0
|
||||||
|
- $JAVA_HOME/bin/jpackage
|
||||||
|
--type app-image
|
||||||
|
--runtime-image runtime
|
||||||
|
--input target/libs
|
||||||
|
--module-path target/mods
|
||||||
|
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||||
|
--dest .
|
||||||
|
--name Cryptomator
|
||||||
|
--vendor 'Skymatic GmbH'
|
||||||
|
--copyright '(C) 2016 - 2025 Skymatic GmbH'
|
||||||
|
--java-options '--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator'
|
||||||
|
--java-options "--sun-misc-unsafe-memory-access=allow"
|
||||||
|
--java-options '-Xss5m'
|
||||||
|
--java-options '-Xmx256m'
|
||||||
|
--java-options '-Dfile.encoding='utf-8''
|
||||||
|
--java-options '-Djava.net.useSystemProxies=true'
|
||||||
|
--java-options "-Dcryptomator.appVersion='${VERSION}'"
|
||||||
|
--java-options "-Dcryptomator.buildNumber='flatpak-${REVISION_NO}'"
|
||||||
|
--java-options '-Dcryptomator.ipcSocketPath='@{userhome}/.config/Cryptomator/ipc.socket''
|
||||||
|
--java-options '-Dcryptomator.adminConfigPath='/run/host/etc/cryptomator/config.properties''
|
||||||
|
--java-options '-Dcryptomator.logDir='@{userhome}/.local/share/Cryptomator/logs''
|
||||||
|
--java-options '-Dcryptomator.mountPointsDir='@{userhome}/.local/share/Cryptomator/mnt''
|
||||||
|
--java-options '-Dcryptomator.pluginDir='@{userhome}/.local/share/Cryptomator/plugins''
|
||||||
|
--java-options '-Dcryptomator.p12Path='@{userhome}/.config/Cryptomator/key.p12''
|
||||||
|
--java-options '-Dcryptomator.settingsPath='@{userhome}/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json''
|
||||||
|
--java-options '-Dcryptomator.showTrayIcon=true'
|
||||||
|
--java-options '-Dcryptomator.updateMechanism=org.cryptomator.linux.update.FlatpakUpdater'
|
||||||
|
--java-options '-Dcryptomator.networking.truststore.p12Path='/run/host/etc/cryptomator/certs.p12''
|
||||||
|
--java-options '-Dcryptomator.hub.enableTrustOnFirstUse=true'
|
||||||
|
--app-version "${VERSION}.${REVISION_NO}"
|
||||||
|
--verbose
|
||||||
|
- cp -R Cryptomator /app/
|
||||||
|
- ln -s /app/Cryptomator/bin/Cryptomator /app/bin/cryptomator
|
||||||
|
- cp -R /app/lib/* /app/Cryptomator/lib/app/
|
||||||
|
- install -D -m0644 -t /app/share/applications/ dist/linux/common/org.cryptomator.Cryptomator.desktop
|
||||||
|
- install -D -m0644 -t /app/share/icons/hicolor/scalable/apps/ dist/linux/common/org.cryptomator.Cryptomator.svg
|
||||||
|
- install -D -m0644 -T dist/linux/common/org.cryptomator.Cryptomator.tray.svg /app/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg
|
||||||
|
- install -D -m0644 -T dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg /app/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg
|
||||||
|
- install -D -m0644 -t /app/share/metainfo/ dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
|
||||||
|
sources:
|
||||||
|
- $CRYPTOMATOR_SOURCE
|
||||||
|
- type: file
|
||||||
|
dest-filename: jdk.tar.gz
|
||||||
|
only-arches:
|
||||||
|
- x86_64
|
||||||
|
url: https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2%2B10/OpenJDK25U-jdk_x64_linux_hotspot_25.0.2_10.tar.gz
|
||||||
|
sha512: 29043fde119a031c2ca8d57aed445fedd9e7f74608fcdc7a809076ba84cfd1c31f08de2ecccf352e159fdcd1cae172395ed46363007552ff242057826c81ab3a
|
||||||
|
- type: file
|
||||||
|
dest-filename: jdk.tar.gz
|
||||||
|
only-arches:
|
||||||
|
- aarch64
|
||||||
|
url: https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2%2B10/OpenJDK25U-jdk_aarch64_linux_hotspot_25.0.2_10.tar.gz
|
||||||
|
sha512: f1d3ccec3e1f1bed9d632f14b9223709d6e5c2e0d922125d068870dd3016492a2ca8f08924d4a9d0dc5eb2159fa09efee366a748fd0093475baf29e5c70c781a
|
||||||
|
- type: file
|
||||||
|
dest-filename: openjfx.zip
|
||||||
|
only-arches:
|
||||||
|
- x86_64
|
||||||
|
url: https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-x64_bin-jmods.zip
|
||||||
|
sha512: 21f550217101c513f9eb1d7947eba30cb79618238e6539ce770e54e84b01574cdaeba40af602391145f163dd8e43e3794395467413152f13ffffeff948b0ca1b
|
||||||
|
- type: file
|
||||||
|
dest-filename: openjfx.zip
|
||||||
|
only-arches:
|
||||||
|
- aarch64
|
||||||
|
url: https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-aarch64_bin-jmods.zip
|
||||||
|
sha512: a9268409b3803e386490bf1319d0f0a14173cebe862c12254cd51b430ee0a297437d9e38d5ebeae0da8899be898b312b103330d09dcfd3e63c1e7d15f2f14311
|
||||||
|
- type: file
|
||||||
|
dest-filename: maven.tar.gz
|
||||||
|
url: https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.13/apache-maven-3.9.13-bin.tar.gz
|
||||||
|
sha512: d9ccd44ba2991586e359c29eb86780ae8ff4ec1b88b0b8af3af074803472690cf2017782a9c4401343c62cbcd056231db9612e1e551cbd9747c21746d732c015
|
||||||
|
x-checker-data:
|
||||||
|
type: anitya
|
||||||
|
project-id: 1894
|
||||||
|
stable-only: true
|
||||||
|
url-template: https://repo1.maven.org/maven2/org/apache/maven/apache-maven/$version/apache-maven-$version-bin.tar.gz
|
||||||
|
versions: {<: '4.0'}
|
||||||
Vendored
+119
@@ -0,0 +1,119 @@
|
|||||||
|
# Maintainer: Aaron Graves <linux@ajgraves.com>
|
||||||
|
# Contributor: Julian Raufelder <arch@raufelder.com>
|
||||||
|
# Contributor: Morten Linderud <morten@linderud.pw>
|
||||||
|
# Contributor: Sebastian Stenzel <sebastian.stenzel@gmail.com>
|
||||||
|
# Contributor: Armin Schrenk <armin.schrenk@skymatic.de>
|
||||||
|
|
||||||
|
pkgname=cryptomator
|
||||||
|
pkgver=$PKG_VERSION
|
||||||
|
pkgrel=$PKG_RELEASE
|
||||||
|
pkgdesc="Multiplatform transparent client-side encryption of your files in the cloud."
|
||||||
|
arch=('any')
|
||||||
|
url="https://cryptomator.org/"
|
||||||
|
license=('GPL3')
|
||||||
|
depends=('fuse3' 'alsa-lib' 'hicolor-icon-theme' 'libxtst' 'libnet' 'libxrender')
|
||||||
|
makedepends=('maven' 'unzip')
|
||||||
|
optdepends=('keepassxc-cryptomator: Use KeePassXC to store vault passwords' 'ttf-hanazono: Install this font when using Japanese system language')
|
||||||
|
_jdkver=25.0.2+10
|
||||||
|
_jfxver=25.0.2
|
||||||
|
_src_app_dir=cryptomator-${pkgver//_/-}
|
||||||
|
source=($SOURCES);
|
||||||
|
source_x86_64=("jdk-${_jdkver}.tar.gz::https://github.com/adoptium/temurin${_jdkver:0:2}-binaries/releases/download/jdk-${_jdkver//\+/%2B}/OpenJDK${_jdkver:0:2}U-jdk_x64_linux_hotspot_${_jdkver//\+/_}.tar.gz"
|
||||||
|
"openjfx-${_jfxver}.zip::https://download2.gluonhq.com/openjfx/${_jfxver}/openjfx-${_jfxver}_linux-x64_bin-jmods.zip")
|
||||||
|
source_aarch64=("jdk-${_jdkver}.tar.gz::https://github.com/adoptium/temurin${_jdkver:0:2}-binaries/releases/download/jdk-${_jdkver//\+/%2B}/OpenJDK${_jdkver:0:2}U-jdk_aarch64_linux_hotspot_${_jdkver//\+/_}.tar.gz"
|
||||||
|
"openjfx-${_jfxver}.zip::https://download2.gluonhq.com/openjfx/${_jfxver}/openjfx-${_jfxver}_linux-aarch64_bin-jmods.zip")
|
||||||
|
noextract=("jdk-${_jdkver}.tar.gz" "openjfx-${_jfxver}.zip")
|
||||||
|
sha256sums=($SOURCES_SHA)
|
||||||
|
sha256sums_x86_64=('987387933b64b9833846dee373b640440d3e1fd48a04804ec01a6dbf718e8ab8'
|
||||||
|
'e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b')
|
||||||
|
sha256sums_aarch64=('a9d73e711d967dc44896d4f430f73a68fd33590dabc29a7f2fb9f593425b854c'
|
||||||
|
'c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646')
|
||||||
|
options=('!strip')
|
||||||
|
|
||||||
|
validpgpkeys=('58117AFA1F85B3EEC154677D615D449FE6E6A235')
|
||||||
|
|
||||||
|
build() {
|
||||||
|
export JAVA_HOME="${srcdir}/jdk-${_jdkver}"
|
||||||
|
JMODS_PATH="${srcdir}/openjfx-${_jfxver}-jmods"
|
||||||
|
#JEP 493
|
||||||
|
if ! $(${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"); then
|
||||||
|
JMODS_PATH="${JMODS_PATH}:${JAVA_HOME}/jmods:"
|
||||||
|
fi
|
||||||
|
|
||||||
|
tar xfz "jdk-${_jdkver}.tar.gz"
|
||||||
|
|
||||||
|
mkdir "openjfx-${_jfxver}-jmods"
|
||||||
|
unzip -j "openjfx-${_jfxver}.zip" \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d "openjfx-${_jfxver}-jmods"
|
||||||
|
|
||||||
|
cd "${srcdir}/${_src_app_dir}"
|
||||||
|
|
||||||
|
mvn -B clean package -DskipTests -Plinux
|
||||||
|
|
||||||
|
cp LICENSE.txt target
|
||||||
|
cp target/cryptomator-*.jar target/mods
|
||||||
|
|
||||||
|
cd target
|
||||||
|
|
||||||
|
"$JAVA_HOME/bin/jlink" \
|
||||||
|
--output runtime \
|
||||||
|
--module-path "$JMODS_PATH" \
|
||||||
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler \
|
||||||
|
--strip-native-commands \
|
||||||
|
--no-header-files \
|
||||||
|
--no-man-pages \
|
||||||
|
--strip-debug \
|
||||||
|
--compress=zip-0
|
||||||
|
|
||||||
|
##Note: jpackage does not allow -beta suffixes, have to strip those
|
||||||
|
"$JAVA_HOME/bin/jpackage" \
|
||||||
|
--type app-image \
|
||||||
|
--runtime-image runtime \
|
||||||
|
--input libs \
|
||||||
|
--module-path mods \
|
||||||
|
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator \
|
||||||
|
--dest . \
|
||||||
|
--name cryptomator \
|
||||||
|
--vendor "Skymatic GmbH" \
|
||||||
|
--copyright "(C) 2016 - 2026 Skymatic GmbH" \
|
||||||
|
--java-options "--enable-preview" \
|
||||||
|
--java-options '--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator' \
|
||||||
|
--java-options "-Xss5m" \
|
||||||
|
--java-options "-Xmx256m" \
|
||||||
|
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||||
|
--java-options "-Djava.net.useSystemProxies=true" \
|
||||||
|
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\"" \
|
||||||
|
--java-options "-Dcryptomator.appVersion=\"${pkgver//_/-}\"" \
|
||||||
|
--java-options "-Dcryptomator.buildNumber=\"aur-${pkgrel}\"" \
|
||||||
|
--java-options "-Dcryptomator.disableUpdateCheck=true" \
|
||||||
|
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
|
||||||
|
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\"" \
|
||||||
|
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\"" \
|
||||||
|
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\"" \
|
||||||
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
||||||
|
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\"" \
|
||||||
|
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\"" \
|
||||||
|
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
|
||||||
|
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
|
||||||
|
--app-version "${pkgver//_*/}" \
|
||||||
|
--verbose
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/application-vnd.cryptomator.vault.xml" "${pkgdir}/usr/share/mime/packages/cryptomator-vault.xml"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.desktop" "${pkgdir}/usr/share/applications/org.cryptomator.Cryptomator.desktop"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator256.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator512.png" "${pkgdir}/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray.svg"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray-unlocked.svg"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray.svg" "${pkgdir}/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg" "${pkgdir}/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg"
|
||||||
|
|
||||||
|
mkdir -p "${pkgdir}/opt/cryptomator/"
|
||||||
|
cp -R "${srcdir}/${_src_app_dir}/target/cryptomator" "${pkgdir}/opt/"
|
||||||
|
install -Dm644 "${srcdir}/${_src_app_dir}/target/LICENSE.txt" -t "${pkgdir}/usr/share/licenses/${pkgname}"
|
||||||
|
|
||||||
|
mkdir -p "${pkgdir}/usr/bin"
|
||||||
|
ln -s "/opt/cryptomator/bin/cryptomator" "${pkgdir}/usr/bin/cryptomator"
|
||||||
|
}
|
||||||
@@ -1,2 +1 @@
|
|||||||
embedded.provisionprofile
|
embedded.provisionprofile
|
||||||
xcuserdata/
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
//
|
|
||||||
// CryptomatorDockTilePlugin.swift
|
|
||||||
// Integrations
|
|
||||||
//
|
|
||||||
// Created by Tobias Hagemann on 22.09.25.
|
|
||||||
// Copyright © 2025 Cryptomator. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import AppKit
|
|
||||||
|
|
||||||
class CryptomatorDockTilePlugin: NSObject, NSDockTilePlugIn {
|
|
||||||
func setDockTile(_ dockTile: NSDockTile?) {
|
|
||||||
guard let dockTile = dockTile, let image = Bundle(for: Self.self).image(forResource: "Cryptomator") else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dockTile.contentView = NSImageView(image: image)
|
|
||||||
dockTile.display()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 77;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
74E08DE12E8584DE007E665C /* CryptomatorDockTilePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08DE02E85847E007E665C /* CryptomatorDockTilePlugin.swift */; };
|
|
||||||
74E08DED2E858532007E665C /* Cryptomator.icns in Resources */ = {isa = PBXBuildFile; fileRef = 74E08DEC2E858532007E665C /* Cryptomator.icns */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
74E08DD92E858467007E665C /* Cryptomator.docktileplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Cryptomator.docktileplugin; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
74E08DE02E85847E007E665C /* CryptomatorDockTilePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptomatorDockTilePlugin.swift; sourceTree = "<group>"; };
|
|
||||||
74E08DEC2E858532007E665C /* Cryptomator.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = Cryptomator.icns; path = ../resources/Cryptomator.icns; sourceTree = SOURCE_ROOT; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
74E08DD62E858467007E665C /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
74E08DD02E858467007E665C = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
74E08DE02E85847E007E665C /* CryptomatorDockTilePlugin.swift */,
|
|
||||||
74E08DEC2E858532007E665C /* Cryptomator.icns */,
|
|
||||||
74E08DDA2E858467007E665C /* Products */,
|
|
||||||
);
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
74E08DDA2E858467007E665C /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
74E08DD92E858467007E665C /* Cryptomator.docktileplugin */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
74E08DD82E858467007E665C /* DockTilePlugin */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 74E08DDD2E858467007E665C /* Build configuration list for PBXNativeTarget "DockTilePlugin" */;
|
|
||||||
buildPhases = (
|
|
||||||
74E08DD52E858467007E665C /* Sources */,
|
|
||||||
74E08DD62E858467007E665C /* Frameworks */,
|
|
||||||
74E08DD72E858467007E665C /* Resources */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = DockTilePlugin;
|
|
||||||
packageProductDependencies = (
|
|
||||||
);
|
|
||||||
productName = DockTilePlugin;
|
|
||||||
productReference = 74E08DD92E858467007E665C /* Cryptomator.docktileplugin */;
|
|
||||||
productType = "com.apple.product-type.bundle";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
74E08DD12E858467007E665C /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
BuildIndependentTargetsInParallel = 1;
|
|
||||||
LastUpgradeCheck = 2600;
|
|
||||||
ORGANIZATIONNAME = Cryptomator;
|
|
||||||
TargetAttributes = {
|
|
||||||
74E08DD82E858467007E665C = {
|
|
||||||
CreatedOnToolsVersion = 26.0.1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = 74E08DD42E858467007E665C /* Build configuration list for PBXProject "DockTilePlugin" */;
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = 74E08DD02E858467007E665C;
|
|
||||||
minimizedProjectReferenceProxies = 1;
|
|
||||||
preferredProjectObjectVersion = 77;
|
|
||||||
productRefGroup = 74E08DDA2E858467007E665C /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
74E08DD82E858467007E665C /* DockTilePlugin */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
74E08DD72E858467007E665C /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
74E08DED2E858532007E665C /* Cryptomator.icns in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
74E08DD52E858467007E665C /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
74E08DE12E8584DE007E665C /* CryptomatorDockTilePlugin.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
74E08DDB2E858467007E665C /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
DEVELOPMENT_TEAM = YZQJQUHA3L;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.5;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
|
||||||
MTL_FAST_MATH = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
SDKROOT = macosx;
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
74E08DDC2E858467007E665C /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
DEVELOPMENT_TEAM = YZQJQUHA3L;
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.5;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
MTL_FAST_MATH = YES;
|
|
||||||
SDKROOT = macosx;
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
74E08DDE2E858467007E665C /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CODE_SIGN_STYLE = Manual;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
DEVELOPMENT_TEAM = "";
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Cryptomator. All rights reserved.";
|
|
||||||
INFOPLIST_KEY_NSPrincipalClass = CryptomatorDockTilePlugin;
|
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.cryptomator.DockTilePlugin;
|
|
||||||
PRODUCT_NAME = Cryptomator;
|
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
|
||||||
WRAPPER_EXTENSION = docktileplugin;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
74E08DDF2E858467007E665C /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
CODE_SIGN_STYLE = Manual;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
DEVELOPMENT_TEAM = "";
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Cryptomator. All rights reserved.";
|
|
||||||
INFOPLIST_KEY_NSPrincipalClass = CryptomatorDockTilePlugin;
|
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.cryptomator.DockTilePlugin;
|
|
||||||
PRODUCT_NAME = Cryptomator;
|
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
|
||||||
SKIP_INSTALL = YES;
|
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
|
||||||
WRAPPER_EXTENSION = docktileplugin;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
74E08DD42E858467007E665C /* Build configuration list for PBXProject "DockTilePlugin" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
74E08DDB2E858467007E665C /* Debug */,
|
|
||||||
74E08DDC2E858467007E665C /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
74E08DDD2E858467007E665C /* Build configuration list for PBXNativeTarget "DockTilePlugin" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
74E08DDE2E858467007E665C /* Debug */,
|
|
||||||
74E08DDF2E858467007E665C /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 74E08DD12E858467007E665C /* Project object */;
|
|
||||||
}
|
|
||||||
Generated
Vendored
-7
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
Vendored
-67
@@ -1,67 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "2600"
|
|
||||||
version = "1.7">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES"
|
|
||||||
buildArchitectures = "Automatic">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "74E08DD82E858467007E665C"
|
|
||||||
BuildableName = "Cryptomator.docktileplugin"
|
|
||||||
BlueprintName = "DockTilePlugin"
|
|
||||||
ReferencedContainer = "container:DockTilePlugin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
shouldAutocreateTestPlan = "YES">
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "74E08DD82E858467007E665C"
|
|
||||||
BuildableName = "Cryptomator.docktileplugin"
|
|
||||||
BlueprintName = "DockTilePlugin"
|
|
||||||
ReferencedContainer = "container:DockTilePlugin.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
Vendored
+2
-14
@@ -111,7 +111,6 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||||
--java-options "-Djava.net.useSystemProxies=true" \
|
--java-options "-Djava.net.useSystemProxies=true" \
|
||||||
--java-options "-Dapple.awt.enableTemplateImages=true" \
|
|
||||||
--java-options "-Dsun.java2d.metal=true" \
|
--java-options "-Dsun.java2d.metal=true" \
|
||||||
--java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
|
--java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
|
||||||
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\"" \
|
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\"" \
|
||||||
@@ -125,28 +124,17 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||||
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism" \
|
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism" \
|
||||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
||||||
|
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
|
||||||
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
|
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
|
||||||
--resource-dir ../resources
|
--resource-dir ../resources
|
||||||
|
|
||||||
# transform app dir
|
# transform app dir
|
||||||
cp ../resources/${APP_NAME}-Vault.icns ${APP_NAME}.app/Contents/Resources/
|
cp ../resources/${APP_NAME}-Vault.icns ${APP_NAME}.app/Contents/Resources/
|
||||||
|
cp ../resources/Assets.car ${APP_NAME}.app/Contents/Resources/
|
||||||
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" ${APP_NAME}.app/Contents/Info.plist
|
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" ${APP_NAME}.app/Contents/Info.plist
|
||||||
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" ${APP_NAME}.app/Contents/Info.plist
|
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" ${APP_NAME}.app/Contents/Info.plist
|
||||||
cp ../embedded.provisionprofile ${APP_NAME}.app/Contents/
|
cp ../embedded.provisionprofile ${APP_NAME}.app/Contents/
|
||||||
|
|
||||||
# build and install dock tile plugin
|
|
||||||
echo "Building and installing Cryptomator.docktileplugin..."
|
|
||||||
DERIVED_DATA_PATH=../DockTilePlugin/build
|
|
||||||
xcodebuild -project ../DockTilePlugin/DockTilePlugin.xcodeproj \
|
|
||||||
-scheme DockTilePlugin \
|
|
||||||
-configuration Release \
|
|
||||||
-derivedDataPath ${DERIVED_DATA_PATH} \
|
|
||||||
-quiet \
|
|
||||||
clean build
|
|
||||||
mkdir -p ${APP_NAME}.app/Contents/PlugIns
|
|
||||||
cp -R ${DERIVED_DATA_PATH}/Build/Products/Release/Cryptomator.docktileplugin ${APP_NAME}.app/Contents/PlugIns/
|
|
||||||
rm -rf ${DERIVED_DATA_PATH}
|
|
||||||
|
|
||||||
# generate license
|
# generate license
|
||||||
mvn -B -f../../../pom.xml license:add-third-party \
|
mvn -B -f../../../pom.xml license:add-third-party \
|
||||||
-Dlicense.thirdPartyFilename=license.rtf \
|
-Dlicense.thirdPartyFilename=license.rtf \
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
+2
-3
@@ -12,6 +12,8 @@
|
|||||||
<string>Cryptomator</string>
|
<string>Cryptomator</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>Cryptomator.icns</string>
|
<string>Cryptomator.icns</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>Cryptomator</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>org.cryptomator</string>
|
<string>org.cryptomator</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
@@ -117,8 +119,5 @@
|
|||||||
<!-- allow utilization of integrated GPU, see https://developer.apple.com/library/mac/qa/qa1734/_index.html -->
|
<!-- allow utilization of integrated GPU, see https://developer.apple.com/library/mac/qa/qa1734/_index.html -->
|
||||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||||
<true/>
|
<true/>
|
||||||
<!-- register dock tile plugin -->
|
|
||||||
<key>NSDockTilePlugIn</key>
|
|
||||||
<string>Cryptomator.docktileplugin</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
Vendored
+1
@@ -167,6 +167,7 @@ $javaOptions = @(
|
|||||||
"--java-options", "-Dcryptomator.showTrayIcon=true"
|
"--java-options", "-Dcryptomator.showTrayIcon=true"
|
||||||
"--java-options", "-Dcryptomator.buildNumber=`"msi-$revisionNo`""
|
"--java-options", "-Dcryptomator.buildNumber=`"msi-$revisionNo`""
|
||||||
"--java-options", "-Dcryptomator.disableUpdateCheck=false"
|
"--java-options", "-Dcryptomator.disableUpdateCheck=false"
|
||||||
|
"--java-options", "-Dcryptomator.hub.enableTrustOnFirstUse=true"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -109,7 +109,7 @@
|
|||||||
</ns0:CreateFolder>
|
</ns0:CreateFolder>
|
||||||
</ns0:Component>
|
</ns0:Component>
|
||||||
<ns0:Component Id="AdminConfigFile" NeverOverwrite="yes" Permanent="yes">
|
<ns0:Component Id="AdminConfigFile" NeverOverwrite="yes" Permanent="yes">
|
||||||
<ns0:File Id="EmptyAdminConfig" Source="$(env.JP_WIXWIZARD_RESOURCES)\..\..\common\cryptomator.config" Name="cryptomator.config" KeyPath="yes">
|
<ns0:File Id="EmptyAdminConfig" Source="$(env.JP_WIXWIZARD_RESOURCES)\..\..\common\config.properties" Name="config.properties" KeyPath="yes">
|
||||||
<util:PermissionEx User="SYSTEM" GenericAll="yes"/>
|
<util:PermissionEx User="SYSTEM" GenericAll="yes"/>
|
||||||
<util:PermissionEx User="Administrators" GenericAll="yes"/>
|
<util:PermissionEx User="Administrators" GenericAll="yes"/>
|
||||||
<util:PermissionEx User="Users" GenericRead="yes" GenericExecute="yes"/>
|
<util:PermissionEx User="Users" GenericRead="yes" GenericExecute="yes"/>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>cryptomator</artifactId>
|
<artifactId>cryptomator</artifactId>
|
||||||
<version>1.19.0</version>
|
<version>1.20.0-SNAPSHOT</version>
|
||||||
<name>Cryptomator Desktop App</name>
|
<name>Cryptomator Desktop App</name>
|
||||||
|
|
||||||
<organization>
|
<organization>
|
||||||
@@ -33,45 +33,46 @@
|
|||||||
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
|
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
|
||||||
|
|
||||||
<!-- cryptomator dependencies -->
|
<!-- cryptomator dependencies -->
|
||||||
<cryptomator.cryptofs.version>2.10.0-beta3</cryptomator.cryptofs.version>
|
<cryptomator.cryptofs.version>2.10.0</cryptomator.cryptofs.version>
|
||||||
<cryptomator.cryptolib.version>2.2.2</cryptomator.cryptolib.version>
|
<cryptomator.cryptolib.version>2.2.2</cryptomator.cryptolib.version>
|
||||||
<cryptomator.integrations.version>1.8.0-beta1</cryptomator.integrations.version>
|
<cryptomator.integrations.version>1.8.0</cryptomator.integrations.version>
|
||||||
<cryptomator.integrations.win.version>1.6.0</cryptomator.integrations.win.version>
|
<cryptomator.integrations.win.version>1.6.0</cryptomator.integrations.win.version>
|
||||||
<cryptomator.integrations.mac.version>1.5.0-beta3</cryptomator.integrations.mac.version>
|
<cryptomator.integrations.mac.version>1.5.0-SNAPSHOT</cryptomator.integrations.mac.version>
|
||||||
<cryptomator.integrations.linux.version>1.7.0-beta4</cryptomator.integrations.linux.version>
|
<cryptomator.integrations.linux.version>1.7.0</cryptomator.integrations.linux.version>
|
||||||
<cryptomator.fuse.version>6.0.0</cryptomator.fuse.version>
|
<cryptomator.fuse.version>6.0.1</cryptomator.fuse.version>
|
||||||
<cryptomator.webdav.version>3.0.1</cryptomator.webdav.version>
|
<cryptomator.webdav.version>3.0.1</cryptomator.webdav.version>
|
||||||
|
<cryptomator.webdav-servlet.version>1.2.12</cryptomator.webdav-servlet.version>
|
||||||
|
|
||||||
<!-- 3rd party dependencies -->
|
<!-- 3rd party dependencies -->
|
||||||
<caffeine.version>3.2.3</caffeine.version>
|
<caffeine.version>3.2.3</caffeine.version>
|
||||||
<commons-lang3.version>3.20.0</commons-lang3.version>
|
<commons-lang3.version>3.20.0</commons-lang3.version>
|
||||||
<dagger.version>2.59.1</dagger.version>
|
<dagger.version>2.59.2</dagger.version>
|
||||||
<easybind.version>2.2</easybind.version>
|
<easybind.version>2.2</easybind.version>
|
||||||
<jackson.version>2.21.0</jackson.version>
|
<jackson.version>2.21.1</jackson.version>
|
||||||
<javafx.version>25.0.2</javafx.version>
|
<javafx.version>25.0.2</javafx.version>
|
||||||
<jwt.version>4.5.0</jwt.version>
|
<jwt.version>4.5.1</jwt.version>
|
||||||
<nimbus-jose.version>10.5</nimbus-jose.version>
|
<nimbus-jose.version>10.5</nimbus-jose.version>
|
||||||
<logback.version>1.5.31</logback.version>
|
<logback.version>1.5.32</logback.version>
|
||||||
<slf4j.version>2.0.17</slf4j.version>
|
<slf4j.version>2.0.17</slf4j.version>
|
||||||
<tinyoauth2.version>0.8.1</tinyoauth2.version>
|
<tinyoauth2.version>0.8.1</tinyoauth2.version>
|
||||||
<zxcvbn.version>1.9.0</zxcvbn.version>
|
<zxcvbn.version>1.9.0</zxcvbn.version>
|
||||||
|
|
||||||
<!-- test dependencies -->
|
<!-- test dependencies -->
|
||||||
<junit.jupiter.version>5.13.4</junit.jupiter.version>
|
<junit.jupiter.version>6.0.3</junit.jupiter.version>
|
||||||
<mockito.version>5.20.0</mockito.version>
|
<mockito.version>5.22.0</mockito.version>
|
||||||
<hamcrest.version>3.0</hamcrest.version>
|
<hamcrest.version>3.0</hamcrest.version>
|
||||||
|
|
||||||
<!-- build-time dependencies -->
|
<!-- build-time dependencies -->
|
||||||
<jetbrains.annotations.version>26.0.2-1</jetbrains.annotations.version>
|
<jetbrains.annotations.version>26.1.0</jetbrains.annotations.version>
|
||||||
<dependency-check.version>12.1.5</dependency-check.version>
|
<dependency-check.version>12.2.0</dependency-check.version>
|
||||||
<jacoco.version>0.8.14</jacoco.version>
|
<jacoco.version>0.8.14</jacoco.version>
|
||||||
<license-generator.version>2.7.0</license-generator.version>
|
<license-generator.version>2.7.1</license-generator.version>
|
||||||
<junit-tree-reporter.version>1.4.0</junit-tree-reporter.version>
|
<junit-tree-reporter.version>1.5.1</junit-tree-reporter.version>
|
||||||
<mvn-compiler.version>3.14.1</mvn-compiler.version>
|
<mvn-compiler.version>3.15.0</mvn-compiler.version>
|
||||||
<mvn-resources.version>3.3.1</mvn-resources.version>
|
<mvn-resources.version>3.5.0</mvn-resources.version>
|
||||||
<mvn-dependency.version>3.8.1</mvn-dependency.version>
|
<mvn-dependency.version>3.10.0</mvn-dependency.version>
|
||||||
<mvn-surefire.version>3.5.4</mvn-surefire.version>
|
<mvn-surefire.version>3.5.3</mvn-surefire.version>
|
||||||
<mvn-jar.version>3.4.2</mvn-jar.version>
|
<mvn-jar.version>3.5.0</mvn-jar.version>
|
||||||
|
|
||||||
<!-- Property used by surefire to determine jacoco engine -->
|
<!-- Property used by surefire to determine jacoco engine -->
|
||||||
<surefire.jacoco.args></surefire.jacoco.args>
|
<surefire.jacoco.args></surefire.jacoco.args>
|
||||||
@@ -93,6 +94,11 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Cryptomator Libs -->
|
<!-- Cryptomator Libs -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.cryptomator</groupId>
|
||||||
|
<artifactId>webdav-nio-adapter-servlet</artifactId>
|
||||||
|
<version>${cryptomator.webdav-servlet.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>cryptolib</artifactId>
|
<artifactId>cryptolib</artifactId>
|
||||||
@@ -521,11 +527,57 @@
|
|||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
<profile>
|
<profile>
|
||||||
<id>linux</id>
|
<id>linux-aarch64</id>
|
||||||
<activation>
|
<activation>
|
||||||
<os>
|
<os>
|
||||||
<family>unix</family>
|
<family>unix</family>
|
||||||
<name>Linux</name>
|
<name>Linux</name>
|
||||||
|
<arch>aarch64</arch>
|
||||||
|
</os>
|
||||||
|
<property>
|
||||||
|
<name>idea.version</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.cryptomator</groupId>
|
||||||
|
<artifactId>integrations-linux</artifactId>
|
||||||
|
<version>${cryptomator.integrations.linux.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-base</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<classifier>linux-aarch64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-graphics</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<classifier>linux-aarch64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-controls</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<classifier>linux-aarch64</classifier>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-fxml</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
<classifier>linux-aarch64</classifier>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>linux-x86_64</id>
|
||||||
|
<activation>
|
||||||
|
<os>
|
||||||
|
<family>unix</family>
|
||||||
|
<name>Linux</name>
|
||||||
|
<arch>amd64</arch>
|
||||||
</os>
|
</os>
|
||||||
<property>
|
<property>
|
||||||
<name>idea.version</name>
|
<name>idea.version</name>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvid
|
|||||||
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
|
||||||
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
|
||||||
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.cryptomator.integrations.tray.TrayMenuController;
|
import org.cryptomator.integrations.tray.TrayMenuController;
|
||||||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
||||||
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
||||||
@@ -20,6 +21,7 @@ import org.cryptomator.networking.SSLContextProvider;
|
|||||||
import org.cryptomator.networking.SSLContextWithMacKeychain;
|
import org.cryptomator.networking.SSLContextWithMacKeychain;
|
||||||
import org.cryptomator.networking.SSLContextWithPKCS12TrustStore;
|
import org.cryptomator.networking.SSLContextWithPKCS12TrustStore;
|
||||||
import org.cryptomator.networking.SSLContextWithWindowsCertStore;
|
import org.cryptomator.networking.SSLContextWithWindowsCertStore;
|
||||||
|
import org.cryptomator.ui.fxapp.JfxRevealPathService;
|
||||||
import org.cryptomator.ui.fxapp.JfxUiAppearanceProvider;
|
import org.cryptomator.ui.fxapp.JfxUiAppearanceProvider;
|
||||||
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
||||||
|
|
||||||
@@ -64,6 +66,7 @@ open module org.cryptomator.desktop {
|
|||||||
uses org.cryptomator.event.NotificationHandler;
|
uses org.cryptomator.event.NotificationHandler;
|
||||||
|
|
||||||
provides UiAppearanceProvider with JfxUiAppearanceProvider;
|
provides UiAppearanceProvider with JfxUiAppearanceProvider;
|
||||||
|
provides RevealPathService with JfxRevealPathService;
|
||||||
provides TrayMenuController with AwtTrayMenuController;
|
provides TrayMenuController with AwtTrayMenuController;
|
||||||
provides Configurator with LogbackConfiguratorFactory;
|
provides Configurator with LogbackConfiguratorFactory;
|
||||||
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;
|
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import javax.inject.Named;
|
|||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
@@ -76,8 +74,8 @@ public abstract class CommonsModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static Optional<RevealPathService> provideRevealPathService() {
|
static RevealPathService provideRevealPathService() {
|
||||||
return RevealPathService.get().findFirst();
|
return RevealPathService.get().findFirst().orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,13 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.Spliterators;
|
import java.util.Spliterators;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
@@ -20,20 +23,22 @@ public class Environment {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Environment.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Environment.class);
|
||||||
private static final int DEFAULT_MIN_PW_LENGTH = 8;
|
private static final int DEFAULT_MIN_PW_LENGTH = 8;
|
||||||
private static final String SETTINGS_PATH_PROP_NAME = "cryptomator.settingsPath";
|
public static final String SETTINGS_PATH_PROP_NAME = "cryptomator.settingsPath";
|
||||||
private static final String IPC_SOCKET_PATH_PROP_NAME = "cryptomator.ipcSocketPath";
|
public static final String IPC_SOCKET_PATH_PROP_NAME = "cryptomator.ipcSocketPath";
|
||||||
private static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
|
public static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
|
||||||
private static final String WINDOWS_HELLO_KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.windowsHelloKeychainPaths";
|
public static final String WINDOWS_HELLO_KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.windowsHelloKeychainPaths";
|
||||||
private static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
|
public static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
|
||||||
private static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
|
public static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
|
||||||
private static final String LOOPBACK_ALIAS_PROP_NAME = "cryptomator.loopbackAlias";
|
public static final String LOOPBACK_ALIAS_PROP_NAME = "cryptomator.loopbackAlias";
|
||||||
private static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
|
public static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
|
||||||
private static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
|
public static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
|
||||||
private static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
|
public static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
|
||||||
private static final String BUILD_NUMBER_PROP_NAME = "cryptomator.buildNumber";
|
public static final String BUILD_NUMBER_PROP_NAME = "cryptomator.buildNumber";
|
||||||
private static final String PLUGIN_DIR_PROP_NAME = "cryptomator.pluginDir";
|
public static final String PLUGIN_DIR_PROP_NAME = "cryptomator.pluginDir";
|
||||||
private static final String TRAY_ICON_PROP_NAME = "cryptomator.showTrayIcon";
|
public static final String TRAY_ICON_PROP_NAME = "cryptomator.showTrayIcon";
|
||||||
private static final String DISABLE_UPDATE_CHECK_PROP_NAME = "cryptomator.disableUpdateCheck";
|
public static final String DISABLE_UPDATE_CHECK_PROP_NAME = "cryptomator.disableUpdateCheck";
|
||||||
|
public static final String HUB_ALLOWED_HOSTS_PROP_NAME = "cryptomator.hub.allowedHosts";
|
||||||
|
public static final String HUB_TOFU_PROP_NAME = "cryptomator.hub.enableTrustOnFirstUse";
|
||||||
|
|
||||||
private Environment() {}
|
private Environment() {}
|
||||||
|
|
||||||
@@ -57,6 +62,8 @@ public class Environment {
|
|||||||
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
|
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(TRAY_ICON_PROP_NAME);
|
logCryptomatorSystemProperty(TRAY_ICON_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(DISABLE_UPDATE_CHECK_PROP_NAME);
|
logCryptomatorSystemProperty(DISABLE_UPDATE_CHECK_PROP_NAME);
|
||||||
|
logCryptomatorSystemProperty(HUB_ALLOWED_HOSTS_PROP_NAME);
|
||||||
|
logCryptomatorSystemProperty(HUB_TOFU_PROP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Environment getInstance() {
|
public static Environment getInstance() {
|
||||||
@@ -145,6 +152,18 @@ public class Environment {
|
|||||||
return Boolean.getBoolean(DISABLE_UPDATE_CHECK_PROP_NAME);
|
return Boolean.getBoolean(DISABLE_UPDATE_CHECK_PROP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> hubAllowedHosts() {
|
||||||
|
var allowedHubHostsString = System.getProperty(HUB_ALLOWED_HOSTS_PROP_NAME, "");
|
||||||
|
return Arrays.stream(allowedHubHostsString.split(","))
|
||||||
|
.map(String::trim)
|
||||||
|
.filter(Predicate.not(String::isEmpty))
|
||||||
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hubTrustOnFirstUse() {
|
||||||
|
return Boolean.getBoolean(HUB_TOFU_PROP_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
private Optional<Path> getPath(String propertyName) {
|
private Optional<Path> getPath(String propertyName) {
|
||||||
String value = System.getProperty(propertyName);
|
String value = System.getProperty(propertyName);
|
||||||
return Optional.ofNullable(value).map(Paths::get);
|
return Optional.ofNullable(value).map(Paths::get);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.cryptomator.common;
|
package org.cryptomator.common;
|
||||||
|
|
||||||
import org.jetbrains.annotations.VisibleForTesting;
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@@ -13,10 +13,12 @@ public class SubstitutingProperties extends PropertiesDecorator {
|
|||||||
private static final Pattern TEMPLATE = Pattern.compile("@\\{(\\w+)}");
|
private static final Pattern TEMPLATE = Pattern.compile("@\\{(\\w+)}");
|
||||||
|
|
||||||
private final Map<String, String> env;
|
private final Map<String, String> env;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
public SubstitutingProperties(Properties props, Map<String, String> systemEnvironment) {
|
public SubstitutingProperties(Properties props, Map<String, String> systemEnvironment, Logger logger) {
|
||||||
super(props);
|
super(props);
|
||||||
this.env = systemEnvironment;
|
this.env = systemEnvironment;
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -44,7 +46,7 @@ public class SubstitutingProperties extends PropertiesDecorator {
|
|||||||
case "localappdata" -> resolveFrom("LOCALAPPDATA", Source.ENV);
|
case "localappdata" -> resolveFrom("LOCALAPPDATA", Source.ENV);
|
||||||
case "userhome" -> resolveFrom("user.home", Source.PROPS);
|
case "userhome" -> resolveFrom("user.home", Source.PROPS);
|
||||||
default -> {
|
default -> {
|
||||||
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Unknown variable {} in property value {}.", match.group(), value);
|
logger.warn("Unknown variable {} in property value {}.", match.group(), value);
|
||||||
yield match.group();
|
yield match.group();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -56,7 +58,7 @@ public class SubstitutingProperties extends PropertiesDecorator {
|
|||||||
case PROPS -> delegate.getProperty(key);
|
case PROPS -> delegate.getProperty(key);
|
||||||
};
|
};
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Variable {} used for substitution not found in {}. Replaced with empty string.", key, src);
|
logger.warn("Variable {} used for substitution not found in {}. Replaced with empty string.", key, src);
|
||||||
return "";
|
return "";
|
||||||
} else {
|
} else {
|
||||||
return Matcher.quoteReplacement(val);
|
return Matcher.quoteReplacement(val);
|
||||||
|
|||||||
@@ -24,9 +24,12 @@ import javafx.beans.property.SimpleStringProperty;
|
|||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.ObservableSet;
|
||||||
import javafx.geometry.NodeOrientation;
|
import javafx.geometry.NodeOrientation;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class Settings {
|
public class Settings {
|
||||||
|
|
||||||
@@ -78,6 +81,7 @@ public class Settings {
|
|||||||
public final ObjectProperty<Instant> lastSuccessfulUpdateCheck;
|
public final ObjectProperty<Instant> lastSuccessfulUpdateCheck;
|
||||||
public final ObjectProperty<Path> previouslyUsedVaultDirectory;
|
public final ObjectProperty<Path> previouslyUsedVaultDirectory;
|
||||||
public final StringProperty lastUpdateAttemptedByVersion;
|
public final StringProperty lastUpdateAttemptedByVersion;
|
||||||
|
public final ObservableSet<String> trustedHosts;
|
||||||
|
|
||||||
public static Settings create(SettingsProvider provider, Environment env) {
|
public static Settings create(SettingsProvider provider, Environment env) {
|
||||||
var defaults = new SettingsJson();
|
var defaults = new SettingsJson();
|
||||||
@@ -118,6 +122,7 @@ public class Settings {
|
|||||||
this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck);
|
this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck);
|
||||||
this.previouslyUsedVaultDirectory = new SimpleObjectProperty<>(this, "previouslyUsedVaultDirectory", json.previouslyUsedVaultDirectory);
|
this.previouslyUsedVaultDirectory = new SimpleObjectProperty<>(this, "previouslyUsedVaultDirectory", json.previouslyUsedVaultDirectory);
|
||||||
this.lastUpdateAttemptedByVersion = new SimpleStringProperty(this, "lastUpdateAttemptedByVersion", json.lastUpdateAttemptedByVersion);
|
this.lastUpdateAttemptedByVersion = new SimpleStringProperty(this, "lastUpdateAttemptedByVersion", json.lastUpdateAttemptedByVersion);
|
||||||
|
this.trustedHosts = FXCollections.observableSet(json.trustedHosts);
|
||||||
|
|
||||||
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
|
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
|
||||||
|
|
||||||
@@ -149,6 +154,7 @@ public class Settings {
|
|||||||
lastSuccessfulUpdateCheck.addListener(this::somethingChanged);
|
lastSuccessfulUpdateCheck.addListener(this::somethingChanged);
|
||||||
previouslyUsedVaultDirectory.addListener(this::somethingChanged);
|
previouslyUsedVaultDirectory.addListener(this::somethingChanged);
|
||||||
lastUpdateAttemptedByVersion.addListener(this::somethingChanged);
|
lastUpdateAttemptedByVersion.addListener(this::somethingChanged);
|
||||||
|
trustedHosts.addListener(this::somethingChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@@ -207,6 +213,7 @@ public class Settings {
|
|||||||
json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get();
|
json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get();
|
||||||
json.previouslyUsedVaultDirectory = previouslyUsedVaultDirectory.get();
|
json.previouslyUsedVaultDirectory = previouslyUsedVaultDirectory.get();
|
||||||
json.lastUpdateAttemptedByVersion = lastUpdateAttemptedByVersion.get();
|
json.lastUpdateAttemptedByVersion = lastUpdateAttemptedByVersion.get();
|
||||||
|
json.trustedHosts = Set.copyOf(trustedHosts);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,23 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||||
|
import com.fasterxml.jackson.annotation.Nulls;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
class SettingsJson {
|
class SettingsJson {
|
||||||
|
|
||||||
@JsonProperty("directories")
|
@JsonProperty("directories")
|
||||||
List<VaultSettingsJson> directories = List.of();
|
@JsonSetter(nulls = Nulls.AS_EMPTY)
|
||||||
|
List<VaultSettingsJson> directories = new ArrayList<>();
|
||||||
|
|
||||||
@JsonProperty("writtenByVersion")
|
@JsonProperty("writtenByVersion")
|
||||||
String writtenByVersion;
|
String writtenByVersion;
|
||||||
@@ -99,4 +105,8 @@ class SettingsJson {
|
|||||||
|
|
||||||
@JsonProperty("lastUpdateAttemptedByVersion")
|
@JsonProperty("lastUpdateAttemptedByVersion")
|
||||||
String lastUpdateAttemptedByVersion;
|
String lastUpdateAttemptedByVersion;
|
||||||
|
|
||||||
|
@JsonProperty("trustedHosts")
|
||||||
|
@JsonSetter(nulls = Nulls.AS_EMPTY)
|
||||||
|
Set<String> trustedHosts = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import java.util.Set;
|
|||||||
* <li>cryptomator.p12Path</li>
|
* <li>cryptomator.p12Path</li>
|
||||||
* <li>cryptomator.mountPointsDir</li>
|
* <li>cryptomator.mountPointsDir</li>
|
||||||
* <li>cryptomator.disableUpdateCheck</li>
|
* <li>cryptomator.disableUpdateCheck</li>
|
||||||
|
* <li>cryptomator.hub.allowedHosts</li>
|
||||||
|
* <li>cryptomator.hub.enableTrustOnFirstUse</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @see Properties
|
* @see Properties
|
||||||
@@ -42,7 +44,9 @@ class AdminPropertiesFactory {
|
|||||||
"cryptomator.pluginDir", //
|
"cryptomator.pluginDir", //
|
||||||
"cryptomator.p12Path", //
|
"cryptomator.p12Path", //
|
||||||
"cryptomator.mountPointsDir", //
|
"cryptomator.mountPointsDir", //
|
||||||
"cryptomator.disableUpdateCheck");
|
"cryptomator.disableUpdateCheck", //
|
||||||
|
"cryptomator.hub.allowedHosts", //
|
||||||
|
"cryptomator.hub.enableTrustOnFirstUse");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class Cryptomator {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
var adminProps = AdminPropertiesFactory.create();
|
var adminProps = AdminPropertiesFactory.create();
|
||||||
var lazyProcessedProps = new SubstitutingProperties(adminProps, System.getenv());
|
var lazyProcessedProps = new SubstitutingProperties(adminProps, System.getenv(), EventualLogger.INSTANCE);
|
||||||
System.setProperties(lazyProcessedProps);
|
System.setProperties(lazyProcessedProps);
|
||||||
CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.factory().create(STARTUP_TIME);
|
CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.factory().create(STARTUP_TIME);
|
||||||
LOG = LoggerFactory.getLogger(Cryptomator.class);
|
LOG = LoggerFactory.getLogger(Cryptomator.class);
|
||||||
@@ -65,7 +65,6 @@ public class Cryptomator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
EventualLogger.INSTANCE.drainTo(LOG);
|
|
||||||
var printVersion = Optional.ofNullable(args) //
|
var printVersion = Optional.ofNullable(args) //
|
||||||
.stream() //Streams either one element (the args-array) or zero elements
|
.stream() //Streams either one element (the args-array) or zero elements
|
||||||
.flatMap(Arrays::stream) //
|
.flatMap(Arrays::stream) //
|
||||||
@@ -91,10 +90,11 @@ public class Cryptomator {
|
|||||||
* @return Nonzero exit code in case of an error.
|
* @return Nonzero exit code in case of an error.
|
||||||
*/
|
*/
|
||||||
private int run(String[] args) {
|
private int run(String[] args) {
|
||||||
|
debugMode.initialize();
|
||||||
|
EventualLogger.INSTANCE.drainTo(LOG);
|
||||||
env.log();
|
env.log();
|
||||||
LOG.debug("Dagger graph initialized after {}ms", System.currentTimeMillis() - STARTUP_TIME);
|
LOG.debug("Dagger graph initialized after {}ms", System.currentTimeMillis() - STARTUP_TIME);
|
||||||
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
||||||
debugMode.initialize();
|
|
||||||
supportedLanguages.applyPreferred();
|
supportedLanguages.applyPreferred();
|
||||||
changeDefaultSSLContext();
|
changeDefaultSSLContext();
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
|||||||
public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
|
public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
|
||||||
try {
|
try {
|
||||||
KeyStore truststore = getTruststore();
|
KeyStore truststore = getTruststore();
|
||||||
truststore.load(null, null);
|
ensureLoaded(truststore);
|
||||||
|
|
||||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
tmf.init(truststore);
|
tmf.init(truststore);
|
||||||
@@ -30,4 +30,13 @@ abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
|||||||
throw new SSLContextBuildException(e);
|
throw new SSLContextBuildException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ensureLoaded(KeyStore truststore) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
|
||||||
|
try {
|
||||||
|
truststore.aliases();
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
// Not initialized yet (e.g. custom KeyStore SPI); initialize without replacing preloaded stores.
|
||||||
|
truststore.load(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,73 @@
|
|||||||
package org.cryptomator.networking;
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import org.cryptomator.common.Nullable;
|
||||||
import org.cryptomator.integrations.common.OperatingSystem;
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSLContextProvider for Windows using the Windows certificate store as trust store
|
* SSLContextProvider for Windows using the Windows certificate store as trust store and the bundled JDK cacerts as fallback
|
||||||
* <p>
|
* <p>
|
||||||
* In order to work, the jdk.crypto.mscapi jmod is needed
|
* In order to work, the jdk.crypto.mscapi jmod is needed
|
||||||
*/
|
*/
|
||||||
@OperatingSystem(OperatingSystem.Value.WINDOWS)
|
@OperatingSystem(OperatingSystem.Value.WINDOWS)
|
||||||
public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(SSLContextWithWindowsCertStore.class);
|
||||||
|
private static final String DEFAULT_TRUSTSTORE_PASSWORD = "changeit"; //default JDK cacerts password
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
KeyStore getTruststore() throws KeyStoreException {
|
KeyStore getTruststore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
|
||||||
return KeyStore.getInstance("WINDOWS-ROOT");
|
var windowsKeyStore = KeyStore.getInstance("WINDOWS-ROOT");
|
||||||
|
var jdkKeyStore = getShippedCaCertsStore();
|
||||||
|
if (jdkKeyStore == null) {
|
||||||
|
return windowsKeyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureLoaded(windowsKeyStore);
|
||||||
|
ensureLoaded(jdkKeyStore);
|
||||||
|
try {
|
||||||
|
CombinedKeyStoreSpi spi = CombinedKeyStoreSpi.create(windowsKeyStore, jdkKeyStore);
|
||||||
|
Provider dummyProvider = new Provider("CombinedKeyStoreProvider", "1.0", "Provides a combined, read-only KeyStore") {};
|
||||||
|
return new KeyStore(spi, dummyProvider, "CombinedKeyStoreProvider") {};
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new KeyStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
KeyStore getShippedCaCertsStore() {
|
||||||
|
return getCaCertsStoreByProperties(System.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
//for testability
|
||||||
|
@VisibleForTesting
|
||||||
|
@Nullable
|
||||||
|
KeyStore getCaCertsStoreByProperties(Properties props) {
|
||||||
|
var javaHome = Path.of(props.getProperty("java.home"));
|
||||||
|
var trustStorePassword = props.getProperty("javax.net.ssl.trustStorePassword", DEFAULT_TRUSTSTORE_PASSWORD).toCharArray();
|
||||||
|
for (var candidate : List.of(javaHome.resolve("lib/security/cacerts"), javaHome.resolve("conf/security/cacerts"))) {
|
||||||
|
try {
|
||||||
|
if (Files.isRegularFile(candidate)) {
|
||||||
|
return KeyStore.getInstance(candidate.toFile(), trustStorePassword);
|
||||||
|
}
|
||||||
|
} catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException e) {
|
||||||
|
LOG.info("Unable to load fallback cacerts {} file. Skipping fallback.", candidate, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public enum FxmlFile {
|
|||||||
HEALTH_START("/fxml/health_start.fxml"), //
|
HEALTH_START("/fxml/health_start.fxml"), //
|
||||||
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
||||||
HUB_NO_KEYCHAIN("/fxml/hub_no_keychain.fxml"), //
|
HUB_NO_KEYCHAIN("/fxml/hub_no_keychain.fxml"), //
|
||||||
|
HUB_CHECK_HOST_TRUST("/fxml/hub_check_host_trust.fxml"), //
|
||||||
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
|
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
|
||||||
HUB_INVALID_LICENSE("/fxml/hub_invalid_license.fxml"), //
|
HUB_INVALID_LICENSE("/fxml/hub_invalid_license.fxml"), //
|
||||||
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
|
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
|
||||||
@@ -29,6 +30,7 @@ public enum FxmlFile {
|
|||||||
HUB_REGISTER_FAILED("/fxml/hub_register_failed.fxml"), //
|
HUB_REGISTER_FAILED("/fxml/hub_register_failed.fxml"), //
|
||||||
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
|
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
|
||||||
HUB_UNAUTHORIZED_DEVICE("/fxml/hub_unauthorized_device.fxml"), //
|
HUB_UNAUTHORIZED_DEVICE("/fxml/hub_unauthorized_device.fxml"), //
|
||||||
|
HUB_UNTRUSTED_HOST("/fxml/hub_untrusted_host.fxml"), //
|
||||||
HUB_REQUIRE_ACCOUNT_INIT("/fxml/hub_require_account_init.fxml"), //
|
HUB_REQUIRE_ACCOUNT_INIT("/fxml/hub_require_account_init.fxml"), //
|
||||||
LOCK_FORCED("/fxml/lock_forced.fxml"), //
|
LOCK_FORCED("/fxml/lock_forced.fxml"), //
|
||||||
LOCK_FAILED("/fxml/lock_failed.fxml"), //
|
LOCK_FAILED("/fxml/lock_failed.fxml"), //
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package org.cryptomator.ui.common;
|
package org.cryptomator.ui.common;
|
||||||
|
|
||||||
import dagger.Lazy;
|
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
import org.cryptomator.common.vaults.VaultState;
|
import org.cryptomator.common.vaults.VaultState;
|
||||||
import org.cryptomator.integrations.mount.Mountpoint;
|
import org.cryptomator.integrations.mount.Mountpoint;
|
||||||
import org.cryptomator.integrations.mount.UnmountFailedException;
|
import org.cryptomator.integrations.mount.UnmountFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.application.HostServices;
|
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -28,12 +27,12 @@ public class VaultService {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
|
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
|
||||||
|
|
||||||
private final Lazy<Application> application;
|
private final RevealPathService revealPathService;
|
||||||
private final ExecutorService executorService;
|
private final ExecutorService executorService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public VaultService(Lazy<Application> application, ExecutorService executorService) {
|
public VaultService(RevealPathService revealPathService, ExecutorService executorService) {
|
||||||
this.application = application;
|
this.revealPathService = revealPathService;
|
||||||
this.executorService = executorService;
|
this.executorService = executorService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,9 +46,9 @@ public class VaultService {
|
|||||||
* @param vault The vault to reveal
|
* @param vault The vault to reveal
|
||||||
*/
|
*/
|
||||||
public Task<Vault> createRevealTask(Vault vault) {
|
public Task<Vault> createRevealTask(Vault vault) {
|
||||||
Task<Vault> task = new RevealVaultTask(vault, application.get().getHostServices());
|
Task<Vault> task = new RevealVaultTask(vault, revealPathService);
|
||||||
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayName()));
|
task.setOnSucceeded(_ -> LOG.info("Revealed {}", vault.getDisplayName()));
|
||||||
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), evt.getSource().getException()));
|
task.setOnFailed(evt -> LOG.warn("Failed to reveal {}", vault.getDisplayName(), evt.getSource().getException()));
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,19 +109,18 @@ public class VaultService {
|
|||||||
private static class RevealVaultTask extends Task<Vault> {
|
private static class RevealVaultTask extends Task<Vault> {
|
||||||
|
|
||||||
private final Vault vault;
|
private final Vault vault;
|
||||||
private final HostServices hostServices;
|
private final RevealPathService rs;
|
||||||
|
|
||||||
public RevealVaultTask(Vault vault, HostServices hostServices) {
|
public RevealVaultTask(Vault vault, RevealPathService revealPathService) {
|
||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
this.hostServices = hostServices;
|
this.rs = revealPathService;
|
||||||
setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), getException()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Vault call() {
|
protected Vault call() throws RevealFailedException {
|
||||||
switch (vault.getMountPoint()) {
|
switch (vault.getMountPoint()) {
|
||||||
case null -> LOG.warn("Not currently mounted");
|
case null -> LOG.warn("Not currently mounted");
|
||||||
case Mountpoint.WithPath m -> hostServices.showDocument(m.uri().toString());
|
case Mountpoint.WithPath m -> rs.reveal(m.path());
|
||||||
case Mountpoint.WithUri m -> LOG.info("Vault mounted at {}", m.uri()); // TODO show in UI?
|
case Mountpoint.WithUri m -> LOG.info("Vault mounted at {}", m.uri()); // TODO show in UI?
|
||||||
}
|
}
|
||||||
return vault;
|
return vault;
|
||||||
|
|||||||
@@ -2,18 +2,17 @@ package org.cryptomator.ui.eventview;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.common.Constants;
|
import org.cryptomator.common.Constants;
|
||||||
import org.cryptomator.cryptofs.event.FileIsInUseEvent;
|
|
||||||
import org.cryptomator.event.FSEventBucket;
|
|
||||||
import org.cryptomator.event.FSEventBucketContent;
|
|
||||||
import org.cryptomator.event.FileSystemEventAggregator;
|
|
||||||
import org.cryptomator.common.Nullable;
|
import org.cryptomator.common.Nullable;
|
||||||
import org.cryptomator.common.ObservableUtil;
|
import org.cryptomator.common.ObservableUtil;
|
||||||
import org.cryptomator.cryptofs.CryptoPath;
|
|
||||||
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
|
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
|
||||||
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
|
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
|
||||||
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
|
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
|
||||||
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
|
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
|
||||||
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
|
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.FileIsInUseEvent;
|
||||||
|
import org.cryptomator.event.FSEventBucket;
|
||||||
|
import org.cryptomator.event.FSEventBucketContent;
|
||||||
|
import org.cryptomator.event.FileSystemEventAggregator;
|
||||||
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
import org.cryptomator.integrations.revealpath.RevealPathService;
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
@@ -46,7 +45,6 @@ import java.time.ZoneId;
|
|||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.FormatStyle;
|
import java.time.format.FormatStyle;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -57,7 +55,6 @@ public class EventListCellController implements FxController {
|
|||||||
private static final DateTimeFormatter LOCAL_TIME_FORMATTER = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withZone(ZoneId.systemDefault());
|
private static final DateTimeFormatter LOCAL_TIME_FORMATTER = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
private final FileSystemEventAggregator fileSystemEventAggregator;
|
private final FileSystemEventAggregator fileSystemEventAggregator;
|
||||||
@Nullable
|
|
||||||
private final RevealPathService revealService;
|
private final RevealPathService revealService;
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
private final ObjectProperty<Map.Entry<FSEventBucket, FSEventBucketContent>> eventEntry;
|
private final ObjectProperty<Map.Entry<FSEventBucket, FSEventBucketContent>> eventEntry;
|
||||||
@@ -82,15 +79,17 @@ public class EventListCellController implements FxController {
|
|||||||
Button eventActionsButton;
|
Button eventActionsButton;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public EventListCellController(FileSystemEventAggregator fileSystemEventAggregator, Optional<RevealPathService> revealService, ResourceBundle resourceBundle) {
|
public EventListCellController(FileSystemEventAggregator fileSystemEventAggregator,
|
||||||
|
RevealPathService revealService,
|
||||||
|
ResourceBundle resourceBundle) {
|
||||||
this.fileSystemEventAggregator = fileSystemEventAggregator;
|
this.fileSystemEventAggregator = fileSystemEventAggregator;
|
||||||
this.revealService = revealService.orElseGet(() -> null);
|
this.revealService = revealService;
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
this.eventEntry = new SimpleObjectProperty<>(null);
|
this.eventEntry = new SimpleObjectProperty<>(null);
|
||||||
this.eventMessage = new SimpleStringProperty();
|
this.eventMessage = new SimpleStringProperty();
|
||||||
this.eventDescription = new SimpleStringProperty();
|
this.eventDescription = new SimpleStringProperty();
|
||||||
this.eventIcon = new SimpleObjectProperty<>();
|
this.eventIcon = new SimpleObjectProperty<>();
|
||||||
this.eventCount = ObservableUtil.mapWithDefault(eventEntry, e -> e.getValue().count() == 1? "" : "("+ e.getValue().count() +")", "");
|
this.eventCount = ObservableUtil.mapWithDefault(eventEntry, e -> e.getValue().count() == 1 ? "" : "(" + e.getValue().count() + ")", "");
|
||||||
this.vaultUnlocked = ObservableUtil.mapWithDefault(eventEntry.flatMap(e -> e.getKey().vault().unlockedProperty()), Function.identity(), false);
|
this.vaultUnlocked = ObservableUtil.mapWithDefault(eventEntry.flatMap(e -> e.getKey().vault().unlockedProperty()), Function.identity(), false);
|
||||||
this.readableTime = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_TIME_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
|
this.readableTime = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_TIME_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
|
||||||
this.readableDate = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_DATE_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
|
this.readableDate = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_DATE_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
|
||||||
@@ -136,13 +135,8 @@ public class EventListCellController implements FxController {
|
|||||||
eventMessage.setValue(resourceBundle.getString("eventView.entry.inUse.message"));
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.inUse.message"));
|
||||||
var indexFileName = fiiue.cleartextPath().lastIndexOf("/");
|
var indexFileName = fiiue.cleartextPath().lastIndexOf("/");
|
||||||
eventDescription.setValue(fiiue.cleartextPath().substring(indexFileName + 1));
|
eventDescription.setValue(fiiue.cleartextPath().substring(indexFileName + 1));
|
||||||
if (revealService != null) {
|
addLocalizedAction("eventView.entry.inUse.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(fiiue.cleartextPath())));
|
||||||
addLocalizedAction("eventView.entry.inUse.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(fiiue.cleartextPath())));
|
addLocalizedAction("eventView.entry.inUse.showEncrypted", () -> reveal(revealService, fiiue.ciphertextPath()));
|
||||||
addLocalizedAction("eventView.entry.inUse.showEncrypted", () -> reveal(revealService, fiiue.ciphertextPath()));
|
|
||||||
} else {
|
|
||||||
addLocalizedAction("eventView.entry.inUse.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(fiiue.cleartextPath()).toString()));
|
|
||||||
addLocalizedAction("eventView.entry.inUse.copyEncrypted", () -> copyToClipboard(fiiue.ciphertextPath().toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
var userAndDevice = fiiue.owner().split(Constants.HUB_USER_DEVICE_SEPARATOR);
|
var userAndDevice = fiiue.owner().split(Constants.HUB_USER_DEVICE_SEPARATOR);
|
||||||
var user = userAndDevice[0];
|
var user = userAndDevice[0];
|
||||||
@@ -156,11 +150,7 @@ public class EventListCellController implements FxController {
|
|||||||
eventIcon.setValue(FontAwesome5Icon.TIMES);
|
eventIcon.setValue(FontAwesome5Icon.TIMES);
|
||||||
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message"));
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message"));
|
||||||
eventDescription.setValue(bfe.ciphertextPath().getFileName().toString());
|
eventDescription.setValue(bfe.ciphertextPath().getFileName().toString());
|
||||||
if (revealService != null) {
|
addLocalizedAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath()));
|
||||||
addLocalizedAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath()));
|
|
||||||
} else {
|
|
||||||
addLocalizedAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString()));
|
|
||||||
}
|
|
||||||
addLocalizedAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
|
addLocalizedAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,46 +158,29 @@ public class EventListCellController implements FxController {
|
|||||||
eventIcon.setValue(FontAwesome5Icon.CHECK);
|
eventIcon.setValue(FontAwesome5Icon.CHECK);
|
||||||
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflictResolved.message"));
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflictResolved.message"));
|
||||||
eventDescription.setValue(cre.resolvedCiphertextPath().getFileName().toString());
|
eventDescription.setValue(cre.resolvedCiphertextPath().getFileName().toString());
|
||||||
if (revealService != null) {
|
addLocalizedAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
|
||||||
addLocalizedAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
|
|
||||||
} else {
|
|
||||||
addLocalizedAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustToConflictEvent(ConflictResolutionFailedEvent cfe) {
|
private void adjustToConflictEvent(ConflictResolutionFailedEvent cfe) {
|
||||||
eventIcon.setValue(FontAwesome5Icon.COMPRESS_ALT);
|
eventIcon.setValue(FontAwesome5Icon.COMPRESS_ALT);
|
||||||
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflict.message"));
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflict.message"));
|
||||||
eventDescription.setValue(cfe.conflictingCiphertextPath().getFileName().toString());
|
eventDescription.setValue(cfe.conflictingCiphertextPath().getFileName().toString());
|
||||||
if (revealService != null) {
|
addLocalizedAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
|
||||||
addLocalizedAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
|
addLocalizedAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
|
||||||
addLocalizedAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
|
|
||||||
} else {
|
|
||||||
addLocalizedAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString()));
|
|
||||||
addLocalizedAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustToDecryptionFailedEvent(DecryptionFailedEvent dfe) {
|
private void adjustToDecryptionFailedEvent(DecryptionFailedEvent dfe) {
|
||||||
eventIcon.setValue(FontAwesome5Icon.BAN);
|
eventIcon.setValue(FontAwesome5Icon.BAN);
|
||||||
eventMessage.setValue(resourceBundle.getString("eventView.entry.decryptionFailed.message"));
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.decryptionFailed.message"));
|
||||||
eventDescription.setValue(dfe.ciphertextPath().getFileName().toString());
|
eventDescription.setValue(dfe.ciphertextPath().getFileName().toString());
|
||||||
if (revealService != null) {
|
addLocalizedAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
|
||||||
addLocalizedAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
|
|
||||||
} else {
|
|
||||||
addLocalizedAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustToBrokenDirFileEvent(BrokenDirFileEvent bde) {
|
private void adjustToBrokenDirFileEvent(BrokenDirFileEvent bde) {
|
||||||
eventIcon.setValue(FontAwesome5Icon.TIMES);
|
eventIcon.setValue(FontAwesome5Icon.TIMES);
|
||||||
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenDirFile.message"));
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenDirFile.message"));
|
||||||
eventDescription.setValue(bde.ciphertextPath().getParent().getFileName().toString());
|
eventDescription.setValue(bde.ciphertextPath().getParent().getFileName().toString());
|
||||||
if (revealService != null) {
|
addLocalizedAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
|
||||||
addLocalizedAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
|
|
||||||
} else {
|
|
||||||
addLocalizedAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLocalizedAction(String localizationKey, Runnable action) {
|
private void addLocalizedAction(String localizationKey, Runnable action) {
|
||||||
@@ -270,7 +243,7 @@ public class EventListCellController implements FxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mountPoint = v.getMountPoint().uri().getPath();
|
var mountPoint = v.getMountPoint().uri().getPath();
|
||||||
if(SystemUtils.IS_OS_WINDOWS) {
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
mountPoint = mountPoint.substring(1); //strip away any leading "/", otherwise there are errors
|
mountPoint = mountPoint.substring(1); //strip away any leading "/", otherwise there are errors
|
||||||
}
|
}
|
||||||
return Path.of(mountPoint, vaultInternalPath.substring(1)); //vaultPaths are always absolute
|
return Path.of(mountPoint, vaultInternalPath.substring(1)); //vaultPaths are always absolute
|
||||||
|
|||||||
@@ -10,16 +10,20 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@FxApplicationScoped
|
@FxApplicationScoped
|
||||||
public class FxApplication {
|
public class FxApplication {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(FxApplication.class);
|
private static final Logger LOG = LoggerFactory.getLogger(FxApplication.class);
|
||||||
|
|
||||||
|
static final AtomicReference<Application> INSTANCE = new AtomicReference<>();
|
||||||
|
|
||||||
private final long startupTime;
|
private final long startupTime;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
@@ -33,7 +37,8 @@ public class FxApplication {
|
|||||||
private final FxNotificationManager notificationManager;
|
private final FxNotificationManager notificationManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
FxApplication(@Named("startupTime") long startupTime, //
|
FxApplication(Application fxApp,
|
||||||
|
@Named("startupTime") long startupTime, //
|
||||||
Environment environment, //
|
Environment environment, //
|
||||||
Settings settings, //
|
Settings settings, //
|
||||||
AppLaunchEventHandler launchEventHandler, //
|
AppLaunchEventHandler launchEventHandler, //
|
||||||
@@ -55,6 +60,8 @@ public class FxApplication {
|
|||||||
this.autoUnlocker = autoUnlocker;
|
this.autoUnlocker = autoUnlocker;
|
||||||
this.fxFSEventList = fxFSEventList;
|
this.fxFSEventList = fxFSEventList;
|
||||||
this.notificationManager = notificationManager;
|
this.notificationManager = notificationManager;
|
||||||
|
|
||||||
|
INSTANCE.set(fxApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
|
|||||||
@@ -64,17 +64,6 @@ abstract class FxApplicationModule {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@FxApplicationScoped
|
|
||||||
static MainWindowComponent provideMainWindowComponent(MainWindowComponent.Builder builder) {
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@FxApplicationScoped
|
|
||||||
static PreferencesComponent providePreferencesComponent(PreferencesComponent.Builder builder) {
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@FxApplicationScoped
|
@FxApplicationScoped
|
||||||
@@ -88,10 +77,4 @@ abstract class FxApplicationModule {
|
|||||||
return factory.create();
|
return factory.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@FxApplicationScoped
|
|
||||||
static NotificationComponent provideNotificationComponent(NotificationComponent.Factory factory) {
|
|
||||||
return factory.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,7 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionStage;
|
import java.util.concurrent.CompletionStage;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@FxApplicationScoped
|
@FxApplicationScoped
|
||||||
public class FxApplicationWindows {
|
public class FxApplicationWindows {
|
||||||
@@ -47,15 +48,15 @@ public class FxApplicationWindows {
|
|||||||
|
|
||||||
private final Stage primaryStage;
|
private final Stage primaryStage;
|
||||||
private final Optional<TrayIntegrationProvider> trayIntegration;
|
private final Optional<TrayIntegrationProvider> trayIntegration;
|
||||||
private final Lazy<MainWindowComponent> mainWindow;
|
private final CachedLazy<MainWindowComponent> mainWindow;
|
||||||
private final Lazy<PreferencesComponent> preferencesWindow;
|
private final CachedLazy<PreferencesComponent> preferencesWindow;
|
||||||
private final QuitComponent.Builder quitWindowBuilder;
|
private final QuitComponent.Builder quitWindowBuilder;
|
||||||
private final UnlockComponent.Factory unlockWorkflowFactory;
|
private final UnlockComponent.Factory unlockWorkflowFactory;
|
||||||
private final UpdateReminderComponent.Factory updateReminderWindowFactory;
|
private final UpdateReminderComponent.Factory updateReminderWindowFactory;
|
||||||
private final LockComponent.Factory lockWorkflowFactory;
|
private final LockComponent.Factory lockWorkflowFactory;
|
||||||
private final ErrorComponent.Factory errorWindowFactory;
|
private final ErrorComponent.Factory errorWindowFactory;
|
||||||
private final Lazy<EventViewComponent> eventViewWindow;
|
private final CachedLazy<EventViewComponent> eventViewWindow;
|
||||||
private final Lazy<NotificationComponent> notificationWindow;
|
private final CachedLazy<NotificationComponent> notificationWindow;
|
||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
private final VaultOptionsComponent.Factory vaultOptionsWindow;
|
private final VaultOptionsComponent.Factory vaultOptionsWindow;
|
||||||
private final ShareVaultComponent.Factory shareVaultWindow;
|
private final ShareVaultComponent.Factory shareVaultWindow;
|
||||||
@@ -65,8 +66,8 @@ public class FxApplicationWindows {
|
|||||||
@Inject
|
@Inject
|
||||||
public FxApplicationWindows(@PrimaryStage Stage primaryStage, //
|
public FxApplicationWindows(@PrimaryStage Stage primaryStage, //
|
||||||
Optional<TrayIntegrationProvider> trayIntegration, //
|
Optional<TrayIntegrationProvider> trayIntegration, //
|
||||||
Lazy<MainWindowComponent> mainWindow, //
|
MainWindowComponent.Builder mainWindowBuilder, //
|
||||||
Lazy<PreferencesComponent> preferencesWindow, //
|
PreferencesComponent.Builder preferencesWindowBuilder, //
|
||||||
QuitComponent.Builder quitWindowBuilder, //
|
QuitComponent.Builder quitWindowBuilder, //
|
||||||
UnlockComponent.Factory unlockWorkflowFactory, //
|
UnlockComponent.Factory unlockWorkflowFactory, //
|
||||||
UpdateReminderComponent.Factory updateReminderWindowFactory, //
|
UpdateReminderComponent.Factory updateReminderWindowFactory, //
|
||||||
@@ -74,21 +75,21 @@ public class FxApplicationWindows {
|
|||||||
ErrorComponent.Factory errorWindowFactory, //
|
ErrorComponent.Factory errorWindowFactory, //
|
||||||
VaultOptionsComponent.Factory vaultOptionsWindow, //
|
VaultOptionsComponent.Factory vaultOptionsWindow, //
|
||||||
ShareVaultComponent.Factory shareVaultWindow, //
|
ShareVaultComponent.Factory shareVaultWindow, //
|
||||||
Lazy<EventViewComponent> eventViewWindow, //
|
EventViewComponent.Factory eventViewWindowFactory, //
|
||||||
Lazy<NotificationComponent> notificationWindow,
|
NotificationComponent.Factory notificationWindowFactory, //
|
||||||
ExecutorService executor, //
|
ExecutorService executor, //
|
||||||
Dialogs dialogs) {
|
Dialogs dialogs) {
|
||||||
this.primaryStage = primaryStage;
|
this.primaryStage = primaryStage;
|
||||||
this.trayIntegration = trayIntegration;
|
this.trayIntegration = trayIntegration;
|
||||||
this.mainWindow = mainWindow;
|
this.mainWindow = new CachedLazy<>(mainWindowBuilder::build);
|
||||||
this.preferencesWindow = preferencesWindow;
|
this.preferencesWindow = new CachedLazy<>(preferencesWindowBuilder::build);
|
||||||
this.quitWindowBuilder = quitWindowBuilder;
|
this.quitWindowBuilder = quitWindowBuilder;
|
||||||
this.unlockWorkflowFactory = unlockWorkflowFactory;
|
this.unlockWorkflowFactory = unlockWorkflowFactory;
|
||||||
this.updateReminderWindowFactory = updateReminderWindowFactory;
|
this.updateReminderWindowFactory = updateReminderWindowFactory;
|
||||||
this.lockWorkflowFactory = lockWorkflowFactory;
|
this.lockWorkflowFactory = lockWorkflowFactory;
|
||||||
this.errorWindowFactory = errorWindowFactory;
|
this.errorWindowFactory = errorWindowFactory;
|
||||||
this.eventViewWindow = eventViewWindow;
|
this.eventViewWindow = new CachedLazy<>(eventViewWindowFactory::create);
|
||||||
this.notificationWindow = notificationWindow;
|
this.notificationWindow = new CachedLazy<>(notificationWindowFactory::create);
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.vaultOptionsWindow = vaultOptionsWindow;
|
this.vaultOptionsWindow = vaultOptionsWindow;
|
||||||
this.shareVaultWindow = shareVaultWindow;
|
this.shareVaultWindow = shareVaultWindow;
|
||||||
@@ -218,4 +219,29 @@ public class FxApplicationWindows {
|
|||||||
LOG.error("Failed to display stage", error);
|
LOG.error("Failed to display stage", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class CachedLazy<T> implements Lazy<T> {
|
||||||
|
|
||||||
|
private final Supplier<T> supplier;
|
||||||
|
private volatile T instance = null;
|
||||||
|
|
||||||
|
public CachedLazy(Supplier<T> supplier) {
|
||||||
|
this.supplier = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T get() {
|
||||||
|
T value = instance;
|
||||||
|
if (value == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
value = instance;
|
||||||
|
if (value == null) {
|
||||||
|
value = supplier.get();
|
||||||
|
instance = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.cryptomator.ui.fxapp;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.DisplayName;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
import org.cryptomator.integrations.common.Priority;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RevealPathService} service implementation using the JavaFX {@link javafx.application.HostServices#showDocument(String)} to reveal documents.
|
||||||
|
* <p>
|
||||||
|
* Internally the HostServices class uses GTK on Linux.
|
||||||
|
*
|
||||||
|
* @implNote {@link #reveal(Path)} only succeeds when the class {@link FxApplication} is initialized.
|
||||||
|
*/
|
||||||
|
@DisplayName("JavaFX HostServices (GTK)")
|
||||||
|
@OperatingSystem(OperatingSystem.Value.LINUX)
|
||||||
|
@Priority(10)
|
||||||
|
public class JfxRevealPathService implements RevealPathService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reveal(Path p) throws RevealFailedException {
|
||||||
|
var fxApp = FxApplication.INSTANCE.get();
|
||||||
|
if (fxApp != null) {
|
||||||
|
fxApp.getHostServices().showDocument(p.toUri().toString());
|
||||||
|
} else {
|
||||||
|
throw new RevealFailedException("JavaFX Application not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,12 @@ import com.google.common.base.Throwables;
|
|||||||
import org.cryptomator.common.Environment;
|
import org.cryptomator.common.Environment;
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
import org.cryptomator.cryptofs.VaultConfig;
|
import org.cryptomator.cryptofs.VaultConfig;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.application.Application;
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
@@ -25,6 +28,7 @@ import java.util.stream.Collectors;
|
|||||||
@HealthCheckScoped
|
@HealthCheckScoped
|
||||||
public class ReportWriter {
|
public class ReportWriter {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ReportWriter.class);
|
||||||
private static final String REPORT_HEADER = """
|
private static final String REPORT_HEADER = """
|
||||||
*******************************************
|
*******************************************
|
||||||
* Cryptomator Vault Health Report *
|
* Cryptomator Vault Health Report *
|
||||||
@@ -43,14 +47,14 @@ public class ReportWriter {
|
|||||||
|
|
||||||
private final Vault vault;
|
private final Vault vault;
|
||||||
private final VaultConfig vaultConfig;
|
private final VaultConfig vaultConfig;
|
||||||
private final Application application;
|
private final RevealPathService revealPathService;
|
||||||
private final Path exportDestination;
|
private final Path exportDestination;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ReportWriter(@HealthCheckWindow Vault vault, AtomicReference<VaultConfig> vaultConfigRef, Application application, Environment env) {
|
public ReportWriter(@HealthCheckWindow Vault vault, AtomicReference<VaultConfig> vaultConfigRef, RevealPathService revealPathService, Environment env) {
|
||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
this.vaultConfig = Objects.requireNonNull(vaultConfigRef.get());
|
this.vaultConfig = Objects.requireNonNull(vaultConfigRef.get());
|
||||||
this.application = application;
|
this.revealPathService = revealPathService;
|
||||||
this.exportDestination = env.getLogDir().orElse(Path.of(System.getProperty("user.home"))).resolve("healthReport_" + vault.getDisplayName() + "_" + TIME_STAMP.format(Instant.now()) + ".log");
|
this.exportDestination = env.getLogDir().orElse(Path.of(System.getProperty("user.home"))).resolve("healthReport_" + vault.getDisplayName() + "_" + TIME_STAMP.format(Instant.now()) + ".log");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +96,11 @@ public class ReportWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reveal() {
|
private void reveal() {
|
||||||
application.getHostServices().showDocument(exportDestination.getParent().toUri().toString());
|
try {
|
||||||
|
revealPathService.reveal(exportDestination.getParent());
|
||||||
|
} catch (RevealFailedException e) {
|
||||||
|
LOG.warn("Failed to reveal export destination location of report", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.cryptomator.ui.keyloading.hub;
|
package org.cryptomator.ui.keyloading.hub;
|
||||||
|
|
||||||
import com.nimbusds.jose.JWEObject;
|
|
||||||
import dagger.Lazy;
|
import dagger.Lazy;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
@@ -12,8 +11,6 @@ import javax.inject.Inject;
|
|||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Bindings;
|
|
||||||
import javafx.beans.binding.StringBinding;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.concurrent.WorkerStateEvent;
|
import javafx.concurrent.WorkerStateEvent;
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
package org.cryptomator.ui.keyloading.hub;
|
||||||
|
|
||||||
|
import dagger.Lazy;
|
||||||
|
import org.cryptomator.common.Environment;
|
||||||
|
import org.cryptomator.common.settings.Settings;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||||
|
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||||
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.scene.text.TextFlow;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@KeyLoadingScoped
|
||||||
|
public class CheckHostTrustController implements FxController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CheckHostTrustController.class);
|
||||||
|
private static final String CHECK_KEY = "hub.checkHostTrust.message.check";
|
||||||
|
private static final String ASK_SINGULAR_KEY = "hub.checkHostTrust.message.ask";
|
||||||
|
private static final String ASK_PLURAL_KEY = "hub.checkHostTrust.message.ask.plural";
|
||||||
|
private static final String TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN = ".cryptomator.cloud";
|
||||||
|
|
||||||
|
private final Stage window;
|
||||||
|
private final HubConfig hubConfig;
|
||||||
|
private final URI canonicalHubUri;
|
||||||
|
private final URI canonicalAuthUri;
|
||||||
|
private final Lazy<Scene> authFlowScene;
|
||||||
|
private final Lazy<Scene> untrustedHostScene;
|
||||||
|
private final CompletableFuture<ReceivedKey> result;
|
||||||
|
private final Settings settings;
|
||||||
|
private final Environment env;
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
private final SortedSet<String> hostnames;
|
||||||
|
private final StringProperty messageLabel;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TextFlow hostnamesFlow;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CheckHostTrustController(@KeyLoading Stage window, //
|
||||||
|
HubConfig hubConfig, //
|
||||||
|
@FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, //
|
||||||
|
@FxmlScene(FxmlFile.HUB_UNTRUSTED_HOST) Lazy<Scene> untrustedHostScene, //
|
||||||
|
CompletableFuture<ReceivedKey> result, //
|
||||||
|
Settings settings, //
|
||||||
|
Environment env, //
|
||||||
|
ResourceBundle resourceBundle) {
|
||||||
|
this.window = window;
|
||||||
|
this.hubConfig = hubConfig;
|
||||||
|
this.canonicalHubUri = hubConfig.getApiBaseUrl();
|
||||||
|
this.canonicalAuthUri = URI.create(hubConfig.authEndpoint);
|
||||||
|
this.authFlowScene = authFlowScene;
|
||||||
|
this.untrustedHostScene = untrustedHostScene;
|
||||||
|
this.result = result;
|
||||||
|
this.settings = settings;
|
||||||
|
this.env = env;
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
this.hostnames = new TreeSet<>();
|
||||||
|
this.messageLabel = new SimpleStringProperty(resourceBundle.getString(CHECK_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
if (!isConsistentHubConfig()) {
|
||||||
|
LOG.warn("Inconsistent hub config detected. Denying access to protect the user.");
|
||||||
|
deny();
|
||||||
|
} else if (isAllCryptomatorCloud() && !isAnyHttpHost()) {
|
||||||
|
trust(); // trust *.cryptomator.cloud by default, domain is owned by Cryptomator maintainers
|
||||||
|
} else if (containsAllowedHosts(env.hubAllowedHosts())) {
|
||||||
|
trust(); // trust hosts explicitly allowlisted via system property
|
||||||
|
} else if (isAnyHttpHost() && !isAllLocalhost()) {
|
||||||
|
LOG.warn("Denying attempt to connect to hub instance via unencrypted HTTP.");
|
||||||
|
deny(); // never trust http hosts except for local testing
|
||||||
|
} else if (env.hubTrustOnFirstUse() && containsAllowedHosts(settings.trustedHosts)) {
|
||||||
|
trust(); // trust hosts previously allowlisted by the user
|
||||||
|
} else if (env.hubTrustOnFirstUse()) {
|
||||||
|
hostnames.add(getAuthority(canonicalHubUri));
|
||||||
|
hostnames.add(getAuthority(canonicalAuthUri));
|
||||||
|
renderHostnames(); // ask user whether to trust these hosts
|
||||||
|
} else {
|
||||||
|
LOG.warn("Cryptomator is not allowed to connect to {}. Check your {} config.", getAuthority(canonicalHubUri), Environment.HUB_ALLOWED_HOSTS_PROP_NAME);
|
||||||
|
deny();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void trust() {
|
||||||
|
settings.trustedHosts.addAll(hostnames);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
window.setScene(authFlowScene.get());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void deny() {
|
||||||
|
result.cancel(true);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
window.setScene(untrustedHostScene.get());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderHostnames() {
|
||||||
|
hostnamesFlow.getChildren().clear();
|
||||||
|
for (var hostname : hostnames) {
|
||||||
|
hostnamesFlow.getChildren().add(new Text(hostname + System.lineSeparator()));
|
||||||
|
}
|
||||||
|
var messageKey = hostnames.size() > 1 ? ASK_PLURAL_KEY : ASK_SINGULAR_KEY;
|
||||||
|
messageLabel.set(resourceBundle.getString(messageKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isConsistentHubConfig() {
|
||||||
|
var canonicalHubAuthority = getAuthority(canonicalHubUri);
|
||||||
|
var canonicalAuthAuthority = getAuthority(canonicalAuthUri);
|
||||||
|
|
||||||
|
// apiBaseURL.host == deviceUrl.host == authSuccessUrl.host == authErrorUrl.host
|
||||||
|
return (hubConfig.apiBaseUrl == null || getAuthority(hubConfig.apiBaseUrl).equals(canonicalHubAuthority)) //
|
||||||
|
&& (hubConfig.devicesResourceUrl == null || getAuthority(hubConfig.devicesResourceUrl).equals(canonicalHubAuthority)) //
|
||||||
|
&& getAuthority(hubConfig.authSuccessUrl).equals(canonicalHubAuthority) //
|
||||||
|
&& getAuthority(hubConfig.authErrorUrl).equals(canonicalHubAuthority) //
|
||||||
|
// authUrl.host == tokenUrl.host:
|
||||||
|
&& getAuthority(hubConfig.tokenEndpoint).equals(canonicalAuthAuthority);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAllCryptomatorCloud() {
|
||||||
|
return canonicalHubUri.getHost().endsWith(TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN) && canonicalAuthUri.getHost().endsWith(TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAnyHttpHost() {
|
||||||
|
return "http".equalsIgnoreCase(canonicalHubUri.getScheme()) || "http".equalsIgnoreCase(canonicalAuthUri.getScheme());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAllLocalhost() {
|
||||||
|
return "localhost".equalsIgnoreCase(canonicalHubUri.getHost()) && "localhost".equalsIgnoreCase(canonicalAuthUri.getHost());
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean containsAllowedHosts(Set<String> allowedHubHosts) {
|
||||||
|
return allowedHubHosts.contains(getAuthority(canonicalHubUri)) && allowedHubHosts.contains(getAuthority(canonicalAuthUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAuthority(String string) {
|
||||||
|
return getAuthority(URI.create(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAuthority(URI uri) {
|
||||||
|
if (uri.getPort() == -1) {
|
||||||
|
return "%s://%s".formatted(uri.getScheme(), uri.getHost());
|
||||||
|
} else {
|
||||||
|
return "%s://%s:%s".formatted(uri.getScheme(), uri.getHost(), uri.getPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- JavaFX property getter & setter
|
||||||
|
public StringProperty messageLabelProperty() {
|
||||||
|
return messageLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageLabel() {
|
||||||
|
return messageLabel.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -98,6 +98,13 @@ public abstract class HubKeyLoadingModule {
|
|||||||
return fxmlLoaders.createScene(FxmlFile.HUB_NO_KEYCHAIN);
|
return fxmlLoaders.createScene(FxmlFile.HUB_NO_KEYCHAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@FxmlScene(FxmlFile.HUB_CHECK_HOST_TRUST)
|
||||||
|
@KeyLoadingScoped
|
||||||
|
static Scene provideHubCheckHostTrustScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||||
|
return fxmlLoaders.createScene(FxmlFile.HUB_CHECK_HOST_TRUST);
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
|
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
|
||||||
@KeyLoadingScoped
|
@KeyLoadingScoped
|
||||||
@@ -168,6 +175,13 @@ public abstract class HubKeyLoadingModule {
|
|||||||
return fxmlLoaders.createScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE);
|
return fxmlLoaders.createScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@FxmlScene(FxmlFile.HUB_UNTRUSTED_HOST)
|
||||||
|
@KeyLoadingScoped
|
||||||
|
static Scene provideHubUntrustedHostScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||||
|
return fxmlLoaders.createScene(FxmlFile.HUB_UNTRUSTED_HOST);
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT)
|
@FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT)
|
||||||
@KeyLoadingScoped
|
@KeyLoadingScoped
|
||||||
@@ -180,6 +194,11 @@ public abstract class HubKeyLoadingModule {
|
|||||||
@FxControllerKey(NoKeychainController.class)
|
@FxControllerKey(NoKeychainController.class)
|
||||||
abstract FxController bindNoKeychainController(NoKeychainController controller);
|
abstract FxController bindNoKeychainController(NoKeychainController controller);
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FxControllerKey(CheckHostTrustController.class)
|
||||||
|
abstract FxController bindCheckHostAuthenticityController(CheckHostTrustController controller);
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FxControllerKey(AuthFlowController.class)
|
@FxControllerKey(AuthFlowController.class)
|
||||||
@@ -225,6 +244,11 @@ public abstract class HubKeyLoadingModule {
|
|||||||
@FxControllerKey(UnauthorizedDeviceController.class)
|
@FxControllerKey(UnauthorizedDeviceController.class)
|
||||||
abstract FxController bindUnauthorizedDeviceController(UnauthorizedDeviceController controller);
|
abstract FxController bindUnauthorizedDeviceController(UnauthorizedDeviceController controller);
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FxControllerKey(UntrustedHostController.class)
|
||||||
|
abstract FxController bindUnauthorizedHostController(UntrustedHostController controller);
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FxControllerKey(RequireAccountInitController.class)
|
@FxControllerKey(RequireAccountInitController.class)
|
||||||
|
|||||||
@@ -36,19 +36,19 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy, FilesystemOwne
|
|||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final KeychainManager keychainManager;
|
private final KeychainManager keychainManager;
|
||||||
private final AtomicReference<String> fsOwnerId;
|
private final AtomicReference<String> fsOwnerId;
|
||||||
private final Lazy<Scene> authFlowScene;
|
private final Lazy<Scene> checkHostTrustScene;
|
||||||
private final Lazy<Scene> noKeychainScene;
|
private final Lazy<Scene> noKeychainScene;
|
||||||
private final CompletableFuture<ReceivedKey> result;
|
private final CompletableFuture<ReceivedKey> result;
|
||||||
private final DeviceKey deviceKey;
|
private final DeviceKey deviceKey;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy<Scene> noKeychainScene, CompletableFuture<ReceivedKey> result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle, @Named("filesystemOwnerId") AtomicReference<String> fsOwnerId) {
|
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_CHECK_HOST_TRUST) Lazy<Scene> checkHostTrustScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy<Scene> noKeychainScene, CompletableFuture<ReceivedKey> result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle, @Named("filesystemOwnerId") AtomicReference<String> fsOwnerId) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.keychainManager = keychainManager;
|
this.keychainManager = keychainManager;
|
||||||
this.fsOwnerId = fsOwnerId;
|
this.fsOwnerId = fsOwnerId;
|
||||||
window.setTitle(windowTitle);
|
window.setTitle(windowTitle);
|
||||||
window.setOnCloseRequest(_ -> result.cancel(true));
|
window.setOnCloseRequest(_ -> result.cancel(true));
|
||||||
this.authFlowScene = authFlowScene;
|
this.checkHostTrustScene = checkHostTrustScene;
|
||||||
this.noKeychainScene = noKeychainScene;
|
this.noKeychainScene = noKeychainScene;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.deviceKey = deviceKey;
|
this.deviceKey = deviceKey;
|
||||||
@@ -62,7 +62,7 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy, FilesystemOwne
|
|||||||
throw new NoKeychainAccessProviderException();
|
throw new NoKeychainAccessProviderException();
|
||||||
}
|
}
|
||||||
var keypair = deviceKey.get();
|
var keypair = deviceKey.get();
|
||||||
showWindow(authFlowScene);
|
showWindow(checkHostTrustScene);
|
||||||
var jwe = result.get();
|
var jwe = result.get();
|
||||||
return jwe.decryptMasterkey(keypair.getPrivate());
|
return jwe.decryptMasterkey(keypair.getPrivate());
|
||||||
} catch (NoKeychainAccessProviderException e) {
|
} catch (NoKeychainAccessProviderException e) {
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.cryptomator.ui.keyloading.hub;
|
||||||
|
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||||
|
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.WindowEvent;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@KeyLoadingScoped
|
||||||
|
public class UntrustedHostController implements FxController {
|
||||||
|
|
||||||
|
private final Stage window;
|
||||||
|
private final CompletableFuture<ReceivedKey> result;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public UntrustedHostController(@KeyLoading Stage window, CompletableFuture<ReceivedKey> result) {
|
||||||
|
this.window = window;
|
||||||
|
this.result = result;
|
||||||
|
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void close() {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void windowClosed(WindowEvent windowEvent) {
|
||||||
|
result.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-2
@@ -1,6 +1,7 @@
|
|||||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.cryptomator.common.Constants;
|
||||||
import org.cryptomator.common.Passphrase;
|
import org.cryptomator.common.Passphrase;
|
||||||
import org.cryptomator.common.keychain.KeychainManager;
|
import org.cryptomator.common.keychain.KeychainManager;
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
@@ -63,16 +64,21 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
|||||||
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
|
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
|
||||||
window.setTitle(resourceBundle.getString("unlock.title").formatted(vault.getDisplayName()));
|
window.setTitle(resourceBundle.getString("unlock.title").formatted(vault.getDisplayName()));
|
||||||
Preconditions.checkArgument(SCHEME.equalsIgnoreCase(keyId.getScheme()), "Only supports keys with scheme " + SCHEME);
|
Preconditions.checkArgument(SCHEME.equalsIgnoreCase(keyId.getScheme()), "Only supports keys with scheme " + SCHEME);
|
||||||
|
if (!Constants.MASTERKEY_FILENAME.equals(keyId.getSchemeSpecificPart())) {
|
||||||
|
LOG.warn("unsupported masterkey path found in vault.cryptomator: {}", keyId.getSchemeSpecificPart());
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Path filePath = vault.getPath().resolve(keyId.getSchemeSpecificPart());
|
// determine masterkey file path:
|
||||||
|
Path filePath = vault.getPath().resolve(Constants.MASTERKEY_FILENAME);
|
||||||
if (!Files.exists(filePath)) {
|
if (!Files.exists(filePath)) {
|
||||||
filePath = askUserForMasterkeyFilePath();
|
filePath = askUserForMasterkeyFilePath();
|
||||||
}
|
}
|
||||||
|
// unlock:
|
||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
askForPassphrase();
|
askForPassphrase();
|
||||||
}
|
}
|
||||||
var masterkey = masterkeyFileAccess.load(filePath, passphrase);
|
var masterkey = masterkeyFileAccess.load(filePath, passphrase);
|
||||||
//backup
|
// backup on successful unlock:
|
||||||
if (filePath.startsWith(vault.getPath())) {
|
if (filePath.startsWith(vault.getPath())) {
|
||||||
try {
|
try {
|
||||||
BackupHelper.attemptBackup(filePath);
|
BackupHelper.attemptBackup(filePath);
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ package org.cryptomator.ui.mainwindow;
|
|||||||
|
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
import org.cryptomator.common.vaults.VaultState;
|
import org.cryptomator.common.vaults.VaultState;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.cryptomator.ui.common.Animations;
|
import org.cryptomator.ui.common.Animations;
|
||||||
import org.cryptomator.ui.common.AutoAnimator;
|
import org.cryptomator.ui.common.AutoAnimator;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
@@ -19,10 +22,12 @@ import javafx.fxml.FXML;
|
|||||||
@MainWindowScoped
|
@MainWindowScoped
|
||||||
public class VaultDetailController implements FxController {
|
public class VaultDetailController implements FxController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(VaultDetailController.class);
|
||||||
|
|
||||||
private final ReadOnlyObjectProperty<Vault> vault;
|
private final ReadOnlyObjectProperty<Vault> vault;
|
||||||
private final Application application;
|
|
||||||
private final ObservableValue<FontAwesome5Icon> glyph;
|
private final ObservableValue<FontAwesome5Icon> glyph;
|
||||||
private final BooleanBinding anyVaultSelected;
|
private final BooleanBinding anyVaultSelected;
|
||||||
|
private final RevealPathService revealPathService;
|
||||||
|
|
||||||
private AutoAnimator spinAnimation;
|
private AutoAnimator spinAnimation;
|
||||||
|
|
||||||
@@ -31,11 +36,11 @@ public class VaultDetailController implements FxController {
|
|||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
VaultDetailController(ObjectProperty<Vault> vault, Application application) {
|
VaultDetailController(ObjectProperty<Vault> vault, RevealPathService revealPathService) {
|
||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
this.application = application;
|
|
||||||
this.glyph = vault.flatMap(Vault::stateProperty).map(this::getGlyphForVaultState);
|
this.glyph = vault.flatMap(Vault::stateProperty).map(this::getGlyphForVaultState);
|
||||||
this.anyVaultSelected = vault.isNotNull();
|
this.anyVaultSelected = vault.isNotNull();
|
||||||
|
this.revealPathService = revealPathService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
@@ -61,7 +66,11 @@ public class VaultDetailController implements FxController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void revealStorageLocation() {
|
public void revealStorageLocation() {
|
||||||
application.getHostServices().showDocument(vault.get().getPath().toUri().toString());
|
try {
|
||||||
|
revealPathService.reveal(vault.get().getPath());
|
||||||
|
} catch (RevealFailedException e) {
|
||||||
|
LOG.warn("Failed to reveal vault storage location", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Observable Properties */
|
/* Observable Properties */
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
@@ -31,7 +30,6 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.input.Clipboard;
|
import javafx.scene.input.Clipboard;
|
||||||
import javafx.scene.input.ClipboardContent;
|
import javafx.scene.input.ClipboardContent;
|
||||||
import javafx.scene.input.DataFormat;
|
|
||||||
import javafx.scene.input.DragEvent;
|
import javafx.scene.input.DragEvent;
|
||||||
import javafx.scene.input.TransferMode;
|
import javafx.scene.input.TransferMode;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
@@ -40,12 +38,8 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -60,7 +54,7 @@ public class VaultDetailUnlockedController implements FxController {
|
|||||||
private final VaultService vaultService;
|
private final VaultService vaultService;
|
||||||
private final WrongFileAlertComponent.Builder wrongFileAlert;
|
private final WrongFileAlertComponent.Builder wrongFileAlert;
|
||||||
private final Stage mainWindow;
|
private final Stage mainWindow;
|
||||||
private final Optional<RevealPathService> revealPathService;
|
private final RevealPathService revealPathService;
|
||||||
private final DecryptNameComponent.Factory decryptNameWindowFactory;
|
private final DecryptNameComponent.Factory decryptNameWindowFactory;
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
private final LoadingCache<Vault, VaultStatisticsComponent> vaultStats;
|
private final LoadingCache<Vault, VaultStatisticsComponent> vaultStats;
|
||||||
@@ -84,7 +78,7 @@ public class VaultDetailUnlockedController implements FxController {
|
|||||||
VaultStatisticsComponent.Builder vaultStatsBuilder, //
|
VaultStatisticsComponent.Builder vaultStatsBuilder, //
|
||||||
WrongFileAlertComponent.Builder wrongFileAlert, //
|
WrongFileAlertComponent.Builder wrongFileAlert, //
|
||||||
@MainWindow Stage mainWindow, //
|
@MainWindow Stage mainWindow, //
|
||||||
Optional<RevealPathService> revealPathService, //
|
RevealPathService revealPathService, //
|
||||||
DecryptNameComponent.Factory decryptNameWindowFactory, //
|
DecryptNameComponent.Factory decryptNameWindowFactory, //
|
||||||
ResourceBundle resourceBundle) {
|
ResourceBundle resourceBundle) {
|
||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
@@ -111,7 +105,7 @@ public class VaultDetailUnlockedController implements FxController {
|
|||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
revealEncryptedDropZone.setOnDragOver(e -> handleDragOver(e, draggingOverLocateEncrypted));
|
revealEncryptedDropZone.setOnDragOver(e -> handleDragOver(e, draggingOverLocateEncrypted));
|
||||||
revealEncryptedDropZone.setOnDragDropped(e -> handleDragDropped(e, this::getCiphertextPath, this::revealOrCopyPaths));
|
revealEncryptedDropZone.setOnDragDropped(e -> handleDragDropped(e, this::getCiphertextPath, this::revealPaths));
|
||||||
revealEncryptedDropZone.setOnDragExited(_ -> draggingOverLocateEncrypted.setValue(false));
|
revealEncryptedDropZone.setOnDragExited(_ -> draggingOverLocateEncrypted.setValue(false));
|
||||||
|
|
||||||
decryptNameDropZone.setOnDragOver(e -> handleDragOver(e, draggingOverDecryptName));
|
decryptNameDropZone.setOnDragOver(e -> handleDragOver(e, draggingOverDecryptName));
|
||||||
@@ -156,7 +150,7 @@ public class VaultDetailUnlockedController implements FxController {
|
|||||||
if (cleartextFile != null) {
|
if (cleartextFile != null) {
|
||||||
var ciphertextPath = getCiphertextPath(cleartextFile.toPath());
|
var ciphertextPath = getCiphertextPath(cleartextFile.toPath());
|
||||||
if (ciphertextPath != null) {
|
if (ciphertextPath != null) {
|
||||||
revealOrCopyPaths(List.of(ciphertextPath));
|
revealPaths(List.of(ciphertextPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,34 +182,18 @@ public class VaultDetailUnlockedController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void revealOrCopyPaths(List<Path> paths) {
|
private void revealPaths(List<Path> paths) {
|
||||||
revealPathService.ifPresentOrElse(svc -> revealPaths(svc, paths), () -> {
|
|
||||||
LOG.warn("No service provider to reveal files found.");
|
|
||||||
copyPathsToClipboard(paths);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void revealPaths(RevealPathService service, List<Path> paths) {
|
|
||||||
paths.forEach(path -> {
|
paths.forEach(path -> {
|
||||||
try {
|
try {
|
||||||
LOG.debug("Revealing {}", path);
|
LOG.debug("Revealing {}", path);
|
||||||
service.reveal(path);
|
revealPathService.reveal(path);
|
||||||
} catch (RevealFailedException e) {
|
} catch (RevealFailedException e) {
|
||||||
|
//TODO: show popup in ui
|
||||||
LOG.error("Revealing ciphertext file failed.", e);
|
LOG.error("Revealing ciphertext file failed.", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyPathsToClipboard(List<Path> paths) {
|
|
||||||
StringBuilder clipboardString = new StringBuilder();
|
|
||||||
paths.forEach(p -> clipboardString.append(p.toString()).append("\n"));
|
|
||||||
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, clipboardString.toString()));
|
|
||||||
ciphertextPathsCopied.setValue(true);
|
|
||||||
CompletableFuture.delayedExecutor(2, TimeUnit.SECONDS, Platform::runLater).execute(() -> {
|
|
||||||
ciphertextPathsCopied.set(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private VaultStatisticsComponent buildVaultStats(Vault vault) {
|
private VaultStatisticsComponent buildVaultStats(Vault vault) {
|
||||||
return vaultStatsBuilder.vault(vault).build();
|
return vaultStatsBuilder.vault(vault).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,16 +10,18 @@ import org.cryptomator.integrations.common.NamedServiceProvider;
|
|||||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||||
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
||||||
import org.cryptomator.integrations.quickaccess.QuickAccessService;
|
import org.cryptomator.integrations.quickaccess.QuickAccessService;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ChoiceBox;
|
import javafx.scene.control.ChoiceBox;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
@@ -41,7 +43,7 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
private final Optional<AutoStartProvider> autoStartProvider;
|
private final Optional<AutoStartProvider> autoStartProvider;
|
||||||
private final List<QuickAccessService> quickAccessServices;
|
private final List<QuickAccessService> quickAccessServices;
|
||||||
private final Application application;
|
private final RevealPathService revealPathService;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
private final List<KeychainAccessProvider> keychainAccessProviders;
|
private final List<KeychainAccessProvider> keychainAccessProviders;
|
||||||
private final KeychainManager keychain;
|
private final KeychainManager keychain;
|
||||||
@@ -55,14 +57,21 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
public CheckBox autoCloseVaultsCheckbox;
|
public CheckBox autoCloseVaultsCheckbox;
|
||||||
public CheckBox debugModeCheckbox;
|
public CheckBox debugModeCheckbox;
|
||||||
public CheckBox autoStartCheckbox;
|
public CheckBox autoStartCheckbox;
|
||||||
|
public Button resetTrustedHostsButton;
|
||||||
public ToggleGroup nodeOrientation;
|
public ToggleGroup nodeOrientation;
|
||||||
|
|
||||||
private CompletionStage<Void> keychainMigrations = CompletableFuture.completedFuture(null);
|
private CompletionStage<Void> keychainMigrations = CompletableFuture.completedFuture(null);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, Optional<AutoStartProvider> autoStartProvider, //
|
GeneralPreferencesController(@PreferencesWindow Stage window, //
|
||||||
List<KeychainAccessProvider> keychainAccessProviders, KeychainManager keychain, Application application, //
|
Settings settings, //
|
||||||
Environment environment, FxApplicationWindows appWindows, ExecutorService backgroundExecutor) {
|
Optional<AutoStartProvider> autoStartProvider, //
|
||||||
|
List<KeychainAccessProvider> keychainAccessProviders, //
|
||||||
|
KeychainManager keychain, //
|
||||||
|
RevealPathService revealPathService, //
|
||||||
|
Environment environment, //
|
||||||
|
FxApplicationWindows appWindows, //
|
||||||
|
ExecutorService backgroundExecutor) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.autoStartProvider = autoStartProvider;
|
this.autoStartProvider = autoStartProvider;
|
||||||
@@ -70,7 +79,7 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
this.keychain = keychain;
|
this.keychain = keychain;
|
||||||
this.backgroundExecutor = backgroundExecutor;
|
this.backgroundExecutor = backgroundExecutor;
|
||||||
this.quickAccessServices = QuickAccessService.get().toList();
|
this.quickAccessServices = QuickAccessService.get().toList();
|
||||||
this.application = application;
|
this.revealPathService = revealPathService;
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.appWindows = appWindows;
|
this.appWindows = appWindows;
|
||||||
}
|
}
|
||||||
@@ -98,6 +107,9 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
quickAccessServiceChoiceBox.setConverter(new NamedServiceConverter<>());
|
quickAccessServiceChoiceBox.setConverter(new NamedServiceConverter<>());
|
||||||
Bindings.bindBidirectional(settings.quickAccessService, quickAccessServiceChoiceBox.valueProperty(), quickAccessSettingsConverter);
|
Bindings.bindBidirectional(settings.quickAccessService, quickAccessServiceChoiceBox.valueProperty(), quickAccessSettingsConverter);
|
||||||
quickAccessServiceChoiceBox.disableProperty().bind(useQuickAccessCheckbox.selectedProperty().not());
|
quickAccessServiceChoiceBox.disableProperty().bind(useQuickAccessCheckbox.selectedProperty().not());
|
||||||
|
if (resetTrustedHostsButton != null) {
|
||||||
|
resetTrustedHostsButton.disableProperty().bind(Bindings.isEmpty(settings.trustedHosts));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void migrateKeychainEntries(Observable observable, KeychainAccessProvider oldProvider, KeychainAccessProvider newProvider) {
|
private void migrateKeychainEntries(Observable observable, KeychainAccessProvider oldProvider, KeychainAccessProvider newProvider) {
|
||||||
@@ -124,6 +136,10 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
return autoStartProvider.isPresent();
|
return autoStartProvider.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isHubTrustOnFirstUseEnabled() {
|
||||||
|
return environment.hubTrustOnFirstUse();
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void toggleAutoStart() {
|
public void toggleAutoStart() {
|
||||||
autoStartProvider.ifPresent(autoStart -> {
|
autoStartProvider.ifPresent(autoStart -> {
|
||||||
@@ -146,9 +162,18 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
return !quickAccessServices.isEmpty();
|
return !quickAccessServices.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void resetTrustedHosts() {
|
||||||
|
settings.trustedHosts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void showLogfileDirectory() {
|
public void showLogfileDirectory() {
|
||||||
environment.getLogDir().ifPresent(logDirPath -> application.getHostServices().showDocument(logDirPath.toUri().toString()));
|
try {
|
||||||
|
revealPathService.reveal(environment.getLogDir().orElseThrow());
|
||||||
|
} catch (RevealFailedException e) {
|
||||||
|
LOG.warn("Failed to reveal log files directory.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper classes */
|
/* Helper classes */
|
||||||
@@ -196,4 +221,5 @@ public class GeneralPreferencesController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,19 @@ package org.cryptomator.ui.preferences;
|
|||||||
import org.cryptomator.common.Environment;
|
import org.cryptomator.common.Environment;
|
||||||
import org.cryptomator.common.settings.Settings;
|
import org.cryptomator.common.settings.Settings;
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.cryptomator.integrations.update.UpdateStep;
|
import org.cryptomator.integrations.update.UpdateStep;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.common.VaultService;
|
import org.cryptomator.ui.common.VaultService;
|
||||||
import org.cryptomator.updater.UpdateChecker;
|
|
||||||
import org.cryptomator.updater.FallbackUpdateInfo;
|
import org.cryptomator.updater.FallbackUpdateInfo;
|
||||||
|
import org.cryptomator.updater.UpdateChecker;
|
||||||
import org.cryptomator.updater.UpdateService;
|
import org.cryptomator.updater.UpdateService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.animation.PauseTransition;
|
import javafx.animation.PauseTransition;
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
@@ -49,7 +50,7 @@ public class UpdatesPreferencesController implements FxController {
|
|||||||
private static final Logger LOG = LoggerFactory.getLogger(UpdatesPreferencesController.class);
|
private static final Logger LOG = LoggerFactory.getLogger(UpdatesPreferencesController.class);
|
||||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
|
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
|
||||||
|
|
||||||
private final Application application;
|
private final RevealPathService revealPathService;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
@@ -72,8 +73,8 @@ public class UpdatesPreferencesController implements FxController {
|
|||||||
public CheckBox checkForUpdatesCheckbox;
|
public CheckBox checkForUpdatesCheckbox;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UpdatesPreferencesController(Application application, Environment environment, ResourceBundle resourceBundle, Settings settings, UpdateChecker updateChecker, ObservableList<Vault> vaults, VaultService vaultService) {
|
UpdatesPreferencesController(RevealPathService revealPathService, Environment environment, ResourceBundle resourceBundle, Settings settings, UpdateChecker updateChecker, ObservableList<Vault> vaults, VaultService vaultService) {
|
||||||
this.application = application;
|
this.revealPathService = revealPathService;
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
@@ -106,9 +107,14 @@ public class UpdatesPreferencesController implements FxController {
|
|||||||
updateService.setOnFailed(this::updateFailed);
|
updateService.setOnFailed(this::updateFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void showLogfileDirectory() {
|
public void showLogfileDirectory() {
|
||||||
environment.getLogDir().ifPresent(logDirPath -> application.getHostServices().showDocument(logDirPath.toUri().toString()));
|
try {
|
||||||
|
revealPathService.reveal(environment.getLogDir().orElseThrow());
|
||||||
|
} catch (RevealFailedException e) {
|
||||||
|
LOG.warn("Failed to reveal log files directory.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -254,7 +260,7 @@ public class UpdatesPreferencesController implements FxController {
|
|||||||
|
|
||||||
public boolean isProhibitUpdateWhileUnlocked() {
|
public boolean isProhibitUpdateWhileUnlocked() {
|
||||||
// If the result of the last update check was from the fallback mechanism, we don't need to show the warning
|
// If the result of the last update check was from the fallback mechanism, we don't need to show the warning
|
||||||
return !unlockedVaults.isEmpty() && !FallbackUpdateInfo.class.isInstance(updateChecker.getUpdate());
|
return !unlockedVaults.isEmpty() && updateChecker.isUpdateAvailable() && !FallbackUpdateInfo.class.isInstance(updateChecker.getUpdate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BooleanBinding prohibitUpdateWhileUnlockedProperty() {
|
public BooleanBinding prohibitUpdateWhileUnlockedProperty() {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ public class TrayMenuBuilder {
|
|||||||
vaults.addListener(this::vaultListChanged);
|
vaults.addListener(this::vaultListChanged);
|
||||||
vaults.forEach(v -> {
|
vaults.forEach(v -> {
|
||||||
v.displayNameProperty().addListener(this::vaultListChanged);
|
v.displayNameProperty().addListener(this::vaultListChanged);
|
||||||
|
v.stateProperty().addListener(this::vaultListChanged);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -76,7 +77,9 @@ public class TrayMenuBuilder {
|
|||||||
for (Vault vault : vaults) {
|
for (Vault vault : vaults) {
|
||||||
VaultListManager.redetermineVaultState(vault);
|
VaultListManager.redetermineVaultState(vault);
|
||||||
}
|
}
|
||||||
|
rebuildMenu();
|
||||||
});
|
});
|
||||||
|
vaults.forEach(VaultListManager::redetermineVaultState);
|
||||||
rebuildMenu();
|
rebuildMenu();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
} catch (TrayMenuException e) {
|
} catch (TrayMenuException e) {
|
||||||
@@ -122,18 +125,27 @@ public class TrayMenuBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<TrayMenuItem> buildSubmenu(Vault vault) {
|
private List<TrayMenuItem> buildSubmenu(Vault vault) {
|
||||||
if (vault.isLocked()) {
|
return switch (vault.getState()) {
|
||||||
return List.of( //
|
case LOCKED -> List.of( //
|
||||||
new ActionItem(resourceBundle.getString("traymenu.vault.unlock"), () -> this.unlockVault(vault)) //
|
new ActionItem(resourceBundle.getString("traymenu.vault.unlock"), () -> this.unlockVault(vault)) //
|
||||||
);
|
);
|
||||||
} else if (vault.isUnlocked()) {
|
case UNLOCKED -> List.of( //
|
||||||
return List.of( //
|
|
||||||
new ActionItem(resourceBundle.getString("traymenu.vault.lock"), () -> this.lockVault(vault)), //
|
new ActionItem(resourceBundle.getString("traymenu.vault.lock"), () -> this.lockVault(vault)), //
|
||||||
new ActionItem(resourceBundle.getString("traymenu.vault.reveal"), () -> this.revealVault(vault)) //
|
new ActionItem(resourceBundle.getString("traymenu.vault.reveal"), () -> this.revealVault(vault)) //
|
||||||
);
|
);
|
||||||
} else {
|
case PROCESSING -> List.of( //
|
||||||
return List.of();
|
new ActionItem(resourceBundle.getString("vault.state.processing"), () -> {}, false) //
|
||||||
}
|
);
|
||||||
|
case MISSING, VAULT_CONFIG_MISSING, ALL_MISSING -> List.of( //
|
||||||
|
new ActionItem(resourceBundle.getString("vault.state.missing"), () -> {}, false) //
|
||||||
|
);
|
||||||
|
case NEEDS_MIGRATION -> List.of( //
|
||||||
|
new ActionItem(resourceBundle.getString("vault.state.migrationNeeded"), () -> {}, false) //
|
||||||
|
);
|
||||||
|
case ERROR -> List.of( //
|
||||||
|
new ActionItem(resourceBundle.getString("vault.state.error"), () -> {}, false) //
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* action listeners: */
|
/* action listeners: */
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ButtonBar?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.Group?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.layout.Region?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import javafx.scene.shape.Circle?>
|
||||||
|
<?import javafx.scene.text.TextFlow?>
|
||||||
|
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||||
|
xmlns="http://javafx.com/javafx"
|
||||||
|
fx:controller="org.cryptomator.ui.keyloading.hub.CheckHostTrustController"
|
||||||
|
minWidth="400"
|
||||||
|
maxWidth="400"
|
||||||
|
minHeight="145"
|
||||||
|
spacing="12"
|
||||||
|
alignment="TOP_LEFT"
|
||||||
|
accessibleRole="DIALOG">
|
||||||
|
<padding>
|
||||||
|
<Insets topRightBottomLeft="12"/>
|
||||||
|
</padding>
|
||||||
|
<children>
|
||||||
|
<Group>
|
||||||
|
<StackPane>
|
||||||
|
<padding>
|
||||||
|
<Insets topRightBottomLeft="6"/>
|
||||||
|
</padding>
|
||||||
|
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||||
|
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
|
||||||
|
</StackPane>
|
||||||
|
</Group>
|
||||||
|
<VBox HBox.hgrow="ALWAYS">
|
||||||
|
<Label styleClass="label-large" text="${controller.messageLabel}" wrapText="true" textAlignment="LEFT">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="6" top="6"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<TextFlow fx:id="hostnamesFlow" styleClass="text-flow" minHeight="60"/>
|
||||||
|
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||||
|
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||||
|
<buttons>
|
||||||
|
<Button text="%hub.checkHostTrust.denyBtn" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#deny"/>
|
||||||
|
<Button text="%hub.checkHostTrust.trustBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#trust"/>
|
||||||
|
</buttons>
|
||||||
|
</ButtonBar>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.Group?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ButtonBar?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.layout.Region?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import javafx.scene.shape.Circle?>
|
||||||
|
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||||
|
xmlns="http://javafx.com/javafx"
|
||||||
|
fx:controller="org.cryptomator.ui.keyloading.hub.UntrustedHostController"
|
||||||
|
minWidth="400"
|
||||||
|
maxWidth="400"
|
||||||
|
minHeight="145"
|
||||||
|
spacing="12"
|
||||||
|
alignment="TOP_LEFT"
|
||||||
|
accessibleRole="DIALOG">
|
||||||
|
<padding>
|
||||||
|
<Insets topRightBottomLeft="12"/>
|
||||||
|
</padding>
|
||||||
|
<children>
|
||||||
|
<Group>
|
||||||
|
<StackPane>
|
||||||
|
<padding>
|
||||||
|
<Insets topRightBottomLeft="6"/>
|
||||||
|
</padding>
|
||||||
|
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||||
|
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||||
|
</StackPane>
|
||||||
|
</Group>
|
||||||
|
<VBox HBox.hgrow="ALWAYS">
|
||||||
|
<Label styleClass="label-large" text="%hub.untrustedHost.message" wrapText="true" textAlignment="LEFT">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="6" top="6"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="%hub.untrustedHost.description" wrapText="true"/>
|
||||||
|
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||||
|
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||||
|
<buttons>
|
||||||
|
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" onAction="#close"/>
|
||||||
|
</buttons>
|
||||||
|
</ButtonBar>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<BorderPane xmlns="http://javafx.com/javafx"
|
<BorderPane xmlns="http://javafx.com/javafx"
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
fx:controller="org.cryptomator.ui.notification.NotificationController"
|
fx:controller="org.cryptomator.ui.notification.NotificationController"
|
||||||
prefHeight="200.0" prefWidth="400.0" maxHeight="200.0" maxWidth="400.0"
|
prefHeight="224.0" prefWidth="400.0" maxHeight="224.0" maxWidth="400.0"
|
||||||
styleClass="notification-window"
|
styleClass="notification-window"
|
||||||
accessibleRole="DIALOG">
|
accessibleRole="DIALOG">
|
||||||
<padding>
|
<padding>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
<Label text="${controller.message}" styleClass="label-large" wrapText="true"/>
|
<Label text="${controller.message}" styleClass="label-large" wrapText="true"/>
|
||||||
<Label text="${controller.fileName}" styleClass="label" textOverrun="CENTER_ELLIPSIS" visible="${!controller.fileName.empty}" managed="${!controller.fileName.empty}"/>
|
<Label text="${controller.fileName}" styleClass="label" textOverrun="CENTER_ELLIPSIS" visible="${!controller.fileName.empty}" managed="${!controller.fileName.empty}"/>
|
||||||
<Region minHeight="6"/>
|
<Region minHeight="6"/>
|
||||||
<ScrollPane minViewportWidth="370" minViewportHeight="50">
|
<ScrollPane minViewportWidth="370" minViewportHeight="70">
|
||||||
<Label text="${controller.description}" styleClass="label" wrapText="true" maxWidth="370"/>
|
<Label text="${controller.description}" styleClass="label" wrapText="true" maxWidth="370"/>
|
||||||
</ScrollPane>
|
</ScrollPane>
|
||||||
<Region VBox.vgrow="ALWAYS"/>
|
<Region VBox.vgrow="ALWAYS"/>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.CheckBox?>
|
<?import javafx.scene.control.CheckBox?>
|
||||||
<?import javafx.scene.control.ChoiceBox?>
|
<?import javafx.scene.control.ChoiceBox?>
|
||||||
<?import javafx.scene.control.Hyperlink?>
|
<?import javafx.scene.control.Hyperlink?>
|
||||||
@@ -34,6 +35,8 @@
|
|||||||
<CheckBox fx:id="useQuickAccessCheckbox" text="%preferences.general.quickAccessService"/>
|
<CheckBox fx:id="useQuickAccessCheckbox" text="%preferences.general.quickAccessService"/>
|
||||||
<ChoiceBox fx:id="quickAccessServiceChoiceBox" accessibleText="%preferences.general.quickAccessService"/>
|
<ChoiceBox fx:id="quickAccessServiceChoiceBox" accessibleText="%preferences.general.quickAccessService"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
|
<Button fx:id="resetTrustedHostsButton" text="%preferences.general.resetTrustedHosts" visible="${controller.hubTrustOnFirstUseEnabled}" managed="${controller.hubTrustOnFirstUseEnabled}" onAction="#resetTrustedHosts"/>
|
||||||
<Region VBox.vgrow="ALWAYS"/>
|
<Region VBox.vgrow="ALWAYS"/>
|
||||||
|
|
||||||
<HBox spacing="12" alignment="CENTER_LEFT">
|
<HBox spacing="12" alignment="CENTER_LEFT">
|
||||||
|
|||||||
@@ -162,6 +162,12 @@ unlock.error.title=Unlock "%s" failed
|
|||||||
hub.noKeychain.message=Unable to access device key
|
hub.noKeychain.message=Unable to access device key
|
||||||
hub.noKeychain.description=In order to unlock Hub vaults, a device key is required, which is secured using a keychain. To proceed, enable “%s” and select a keychain in the preferences.
|
hub.noKeychain.description=In order to unlock Hub vaults, a device key is required, which is secured using a keychain. To proceed, enable “%s” and select a keychain in the preferences.
|
||||||
hub.noKeychain.openBtn=Open Preferences
|
hub.noKeychain.openBtn=Open Preferences
|
||||||
|
### Check Host Authenticity
|
||||||
|
hub.checkHostTrust.message.check=Checking Configuration…
|
||||||
|
hub.checkHostTrust.message.ask=Trust this host?
|
||||||
|
hub.checkHostTrust.message.ask.plural=Trust these hosts?
|
||||||
|
hub.checkHostTrust.trustBtn=Trust
|
||||||
|
hub.checkHostTrust.denyBtn=Deny
|
||||||
### Waiting
|
### Waiting
|
||||||
hub.auth.message=Waiting for authentication…
|
hub.auth.message=Waiting for authentication…
|
||||||
hub.auth.description=You should automatically be redirected to the login page.
|
hub.auth.description=You should automatically be redirected to the login page.
|
||||||
@@ -193,6 +199,9 @@ hub.archived.description=This vault has been archived and is no longer accessibl
|
|||||||
### Unauthorized
|
### Unauthorized
|
||||||
hub.unauthorized.message=Access denied
|
hub.unauthorized.message=Access denied
|
||||||
hub.unauthorized.description=You are not authorized to open this vault. Contact the vault's owner to request access.
|
hub.unauthorized.description=You are not authorized to open this vault. Contact the vault's owner to request access.
|
||||||
|
### Untrusted Host
|
||||||
|
hub.untrustedHost.message=Host not trusted
|
||||||
|
hub.untrustedHost.description=Connection to Hub was blocked for your security. If you believe the Hub host is safe, contact your Hub administrator or try again.
|
||||||
### Requires Account Initialization
|
### Requires Account Initialization
|
||||||
hub.requireAccountInit.message=Action required
|
hub.requireAccountInit.message=Action required
|
||||||
hub.requireAccountInit.description.0=To proceed, please complete the steps required in your
|
hub.requireAccountInit.description.0=To proceed, please complete the steps required in your
|
||||||
@@ -306,6 +315,7 @@ preferences.general.debugDirectory=Reveal log files
|
|||||||
preferences.general.autoStart=Launch Cryptomator on system start
|
preferences.general.autoStart=Launch Cryptomator on system start
|
||||||
preferences.general.keychainBackend=Store passwords with
|
preferences.general.keychainBackend=Store passwords with
|
||||||
preferences.general.quickAccessService=Add unlocked vaults to the quick access area
|
preferences.general.quickAccessService=Add unlocked vaults to the quick access area
|
||||||
|
preferences.general.resetTrustedHosts=Reset trusted hosts
|
||||||
## Interface
|
## Interface
|
||||||
preferences.interface=Interface
|
preferences.interface=Interface
|
||||||
preferences.interface.theme=Look & Feel
|
preferences.interface.theme=Look & Feel
|
||||||
@@ -696,33 +706,25 @@ eventView.cell.actionsButton.tooltip=Event actions
|
|||||||
eventView.entry.vaultLocked.description=Unlock "%s" for details
|
eventView.entry.vaultLocked.description=Unlock "%s" for details
|
||||||
eventView.entry.conflictResolved.message=Resolved conflict
|
eventView.entry.conflictResolved.message=Resolved conflict
|
||||||
eventView.entry.conflictResolved.showDecrypted=Show decrypted file
|
eventView.entry.conflictResolved.showDecrypted=Show decrypted file
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Copy decrypted path
|
|
||||||
eventView.entry.conflict.message=Conflict resolution failed
|
eventView.entry.conflict.message=Conflict resolution failed
|
||||||
eventView.entry.conflict.showDecrypted=Show decrypted, original file
|
eventView.entry.conflict.showDecrypted=Show decrypted, original file
|
||||||
eventView.entry.conflict.copyDecrypted=Copy decrypted, original path
|
|
||||||
eventView.entry.conflict.showEncrypted=Show conflicting, encrypted file
|
eventView.entry.conflict.showEncrypted=Show conflicting, encrypted file
|
||||||
eventView.entry.conflict.copyEncrypted=Copy conflicting, encrypted path
|
|
||||||
eventView.entry.decryptionFailed.message=Decryption failed
|
eventView.entry.decryptionFailed.message=Decryption failed
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Show encrypted file
|
eventView.entry.decryptionFailed.showEncrypted=Show encrypted file
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Copy encrypted path
|
|
||||||
eventView.entry.brokenDirFile.message=Broken directory link
|
eventView.entry.brokenDirFile.message=Broken directory link
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Show broken, encrypted link
|
eventView.entry.brokenDirFile.showEncrypted=Show broken, encrypted link
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Copy path of broken link
|
|
||||||
eventView.entry.brokenFileNode.message=Broken filesystem node
|
eventView.entry.brokenFileNode.message=Broken filesystem node
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Show broken, encrypted node
|
eventView.entry.brokenFileNode.showEncrypted=Show broken, encrypted node
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Copy path of broken, encrypted node
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Copy decrypted path
|
eventView.entry.brokenFileNode.copyDecrypted=Copy decrypted path
|
||||||
eventView.entry.inUse.message=Locked File
|
eventView.entry.inUse.message=File in use
|
||||||
eventView.entry.inUse.showDecrypted=Show decrypted file
|
eventView.entry.inUse.showDecrypted=Show decrypted file
|
||||||
eventView.entry.inUse.copyDecrypted=Copy decrypted path
|
|
||||||
eventView.entry.inUse.showEncrypted=Show encrypted file
|
eventView.entry.inUse.showEncrypted=Show encrypted file
|
||||||
eventView.entry.inUse.copyEncrypted=Copy encrypted path
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Copy locking user and device name
|
eventView.entry.inUse.copyUserAndDevice=Copy locking user and device name
|
||||||
eventView.entry.inUse.ignoreLock=Ignore Lock
|
eventView.entry.inUse.ignoreLock=Ignore use status
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=File is locked by another device
|
notification.inUse.message=File is in use on another device
|
||||||
notification.inUse.description=The file is opened by %s on device %s. Ask the user to close the file and sync again. Otherwise, you can ignore the lock and open it anyway.
|
notification.inUse.description=The file is open by %s on %s. Ask them to close the file and let synchronization finish. You can ignore the status to open it now, but this may cause conflicts or overwrite newer changes.
|
||||||
notification.inUse.action=Ignore Lock
|
notification.inUse.action=Ignore Use Status
|
||||||
|
|||||||
@@ -630,26 +630,18 @@ eventView.clearListButton.tooltip=تفريغ القائمة
|
|||||||
eventView.entry.vaultLocked.description=فتح "%s" للحصول على التفاصيل
|
eventView.entry.vaultLocked.description=فتح "%s" للحصول على التفاصيل
|
||||||
eventView.entry.conflictResolved.message=تم حل التضارب
|
eventView.entry.conflictResolved.message=تم حل التضارب
|
||||||
eventView.entry.conflictResolved.showDecrypted=إظهار الملف غير المشفر
|
eventView.entry.conflictResolved.showDecrypted=إظهار الملف غير المشفر
|
||||||
eventView.entry.conflictResolved.copyDecrypted=نسخ المسار غير المشفر
|
|
||||||
eventView.entry.conflict.message=فشل حل التضارب
|
eventView.entry.conflict.message=فشل حل التضارب
|
||||||
eventView.entry.conflict.showDecrypted=إظهار الملَف غير المشفر الأصلي
|
eventView.entry.conflict.showDecrypted=إظهار الملَف غير المشفر الأصلي
|
||||||
eventView.entry.conflict.copyDecrypted=نسخ المسار غير المشفر والأصلي
|
|
||||||
eventView.entry.conflict.showEncrypted=إظهار ملف متضارب ومشفر
|
eventView.entry.conflict.showEncrypted=إظهار ملف متضارب ومشفر
|
||||||
eventView.entry.conflict.copyEncrypted=نسخ مسار التشفير المتعارض
|
|
||||||
eventView.entry.decryptionFailed.message=فشل فك التشفير
|
eventView.entry.decryptionFailed.message=فشل فك التشفير
|
||||||
eventView.entry.decryptionFailed.showEncrypted=عرض ملَف المشفر
|
eventView.entry.decryptionFailed.showEncrypted=عرض ملَف المشفر
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=نسخ مسار المشفر
|
|
||||||
eventView.entry.brokenDirFile.message=رابط الدليل المكسور
|
eventView.entry.brokenDirFile.message=رابط الدليل المكسور
|
||||||
eventView.entry.brokenDirFile.showEncrypted=إظهار الرابط المكسور، المشفر
|
eventView.entry.brokenDirFile.showEncrypted=إظهار الرابط المكسور، المشفر
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=نسخ مسار الرابط المكسور
|
|
||||||
eventView.entry.brokenFileNode.message=عقدة ملفات النظام التافلة
|
eventView.entry.brokenFileNode.message=عقدة ملفات النظام التافلة
|
||||||
eventView.entry.brokenFileNode.showEncrypted=عرض العقدة المشفّرة التافلة
|
eventView.entry.brokenFileNode.showEncrypted=عرض العقدة المشفّرة التافلة
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=نسخ مسار العقدة المشفّرة التافلة
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=نسخ المسار غير المشفر
|
eventView.entry.brokenFileNode.copyDecrypted=نسخ المسار غير المشفر
|
||||||
eventView.entry.inUse.showDecrypted=إظهار الملف غير المشفر
|
eventView.entry.inUse.showDecrypted=إظهار الملف غير المشفر
|
||||||
eventView.entry.inUse.copyDecrypted=نسخ المسار غير المشفر
|
|
||||||
eventView.entry.inUse.showEncrypted=عرض ملَف المشفر
|
eventView.entry.inUse.showEncrypted=عرض ملَف المشفر
|
||||||
eventView.entry.inUse.copyEncrypted=نسخ مسار المشفر
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ generic.button.print=Отпечатване
|
|||||||
generic.button.remove=Премахване
|
generic.button.remove=Премахване
|
||||||
|
|
||||||
## Vault state
|
## Vault state
|
||||||
|
vault.state.locked=Заключено
|
||||||
|
vault.state.unlocked=Отключено
|
||||||
|
vault.state.missing=Липсващ
|
||||||
|
vault.state.migrationNeeded=Необходима е миграция
|
||||||
|
vault.state.processing=Обработване
|
||||||
|
vault.state.error=Грешка
|
||||||
|
|
||||||
# Error
|
# Error
|
||||||
error.message=Възникна грешка
|
error.message=Възникна грешка
|
||||||
@@ -98,6 +104,7 @@ addvault.new.readme.accessLocation.4=При желание можете да п
|
|||||||
## Existing
|
## Existing
|
||||||
addvaultwizard.existing.title=Добавяне на съществуващо хранилище
|
addvaultwizard.existing.title=Добавяне на съществуващо хранилище
|
||||||
addvaultwizard.existing.instruction=Изберете файла „vault.cryptomator“ от съществуващото хранилище, но ако има само файл „masterkey.cryptomator“, изберете него.
|
addvaultwizard.existing.instruction=Изберете файла „vault.cryptomator“ от съществуващото хранилище, но ако има само файл „masterkey.cryptomator“, изберете него.
|
||||||
|
addvaultwizard.existing.restore=Възстановяване…
|
||||||
addvaultwizard.existing.chooseBtn=Избиране…
|
addvaultwizard.existing.chooseBtn=Избиране…
|
||||||
addvaultwizard.existing.filePickerTitle=Избор на файл на хранилището
|
addvaultwizard.existing.filePickerTitle=Избор на файл на хранилището
|
||||||
addvaultwizard.existing.filePickerMimeDesc=Хранилище на Криптоматор
|
addvaultwizard.existing.filePickerMimeDesc=Хранилище на Криптоматор
|
||||||
@@ -145,6 +152,7 @@ unlock.error.customPath.description.hideawayNotDir=Временният, скр
|
|||||||
unlock.error.customPath.description.couldNotBeCleaned=Хранилището не може да бъде монтирано на „%s“. Опитайте отново или изберете друг път.
|
unlock.error.customPath.description.couldNotBeCleaned=Хранилището не може да бъде монтирано на „%s“. Опитайте отново или изберете друг път.
|
||||||
unlock.error.customPath.description.notEmptyDir=Потребителският път на монтиране „%s“ не е празна папка. Изберете празна папка и опитайте отново.
|
unlock.error.customPath.description.notEmptyDir=Потребителският път на монтиране „%s“ не е празна папка. Изберете празна папка и опитайте отново.
|
||||||
unlock.error.customPath.description.generic=Избрали сте потребителски път за монтиране на това хранилище, но при използването му възникна следната грешка: %2$s
|
unlock.error.customPath.description.generic=Избрали сте потребителски път за монтиране на това хранилище, но при използването му възникна следната грешка: %2$s
|
||||||
|
unlock.error.restartRequired.message=Хранилището не може да бъде отключено
|
||||||
unlock.error.title=Неуспешно отключване на „%s“
|
unlock.error.title=Неуспешно отключване на „%s“
|
||||||
## Hub
|
## Hub
|
||||||
hub.noKeychain.message=Няма достъп до ключа на устройството
|
hub.noKeychain.message=Няма достъп до ключа на устройството
|
||||||
@@ -369,6 +377,7 @@ main.vaultlist.contextMenu.unlock=Отключване…
|
|||||||
main.vaultlist.contextMenu.unlockNow=Отключване сега
|
main.vaultlist.contextMenu.unlockNow=Отключване сега
|
||||||
main.vaultlist.contextMenu.vaultoptions=Настройки на хранилището
|
main.vaultlist.contextMenu.vaultoptions=Настройки на хранилището
|
||||||
main.vaultlist.contextMenu.reveal=Разкриване на диска
|
main.vaultlist.contextMenu.reveal=Разкриване на диска
|
||||||
|
main.vaultlist.contextMenu.share=Споделяне…
|
||||||
main.vaultlist.addVaultButton.tooltip=Добавяне на хранилище
|
main.vaultlist.addVaultButton.tooltip=Добавяне на хранилище
|
||||||
##Notification
|
##Notification
|
||||||
## Vault Detail
|
## Vault Detail
|
||||||
|
|||||||
@@ -269,6 +269,8 @@ health.check.detail.checkFinishedAndFound=Kontrolproceduren er kørt færdig. Ge
|
|||||||
health.check.detail.checkFailed=Kontrolproceduren blev afbrudt af en fejl.
|
health.check.detail.checkFailed=Kontrolproceduren blev afbrudt af en fejl.
|
||||||
health.check.detail.checkCancelled=Kontrolproceduren blev annulleret.
|
health.check.detail.checkCancelled=Kontrolproceduren blev annulleret.
|
||||||
health.check.detail.listFilters.label=Filter
|
health.check.detail.listFilters.label=Filter
|
||||||
|
health.check.detail.filterSeverity=Filtrér efter sværhedsgrad
|
||||||
|
health.check.detail.filterFixState=Filtrér efter fix status
|
||||||
health.check.detail.fixAllSpecificBtn=Løs alle af type
|
health.check.detail.fixAllSpecificBtn=Løs alle af type
|
||||||
health.check.exportBtn=Eksportér rapport
|
health.check.exportBtn=Eksportér rapport
|
||||||
## Result view
|
## Result view
|
||||||
@@ -358,6 +360,7 @@ preferences.contribute.promptText=Indsæt koden for supporter-certifikatet her
|
|||||||
preferences.contribute.thankYou=Tak fordi du støtter Cryptomators open source-udvikling!
|
preferences.contribute.thankYou=Tak fordi du støtter Cryptomators open source-udvikling!
|
||||||
preferences.contribute.donate=Donér
|
preferences.contribute.donate=Donér
|
||||||
preferences.contribute.sponsor=Sponsor
|
preferences.contribute.sponsor=Sponsor
|
||||||
|
preferences.contribute.removeCert.tooltip=Fjern certifikat
|
||||||
|
|
||||||
### Remove License Key Dialog
|
### Remove License Key Dialog
|
||||||
removeCert.title=Fjern certifikat
|
removeCert.title=Fjern certifikat
|
||||||
@@ -367,6 +370,7 @@ removeCert.description=Cryptomators kernefunktioner påvirkes ikke af dette. Hve
|
|||||||
|
|
||||||
## About
|
## About
|
||||||
preferences.about=Om
|
preferences.about=Om
|
||||||
|
preferences.about.thirdPartyLicenses=Tredjepartslicenser
|
||||||
|
|
||||||
# Vault Statistics
|
# Vault Statistics
|
||||||
stats.title=Statistik for %s
|
stats.title=Statistik for %s
|
||||||
@@ -406,6 +410,7 @@ stats.access.total=Samlede adgang: %d
|
|||||||
# Main Window
|
# Main Window
|
||||||
## Vault List
|
## Vault List
|
||||||
main.vaultlist=Bokse
|
main.vaultlist=Bokse
|
||||||
|
main.vaultlist.listEntry=Boks %s (%s)
|
||||||
main.vaultlist.emptyList.onboardingInstruction=Klik her for at tilføje en boks
|
main.vaultlist.emptyList.onboardingInstruction=Klik her for at tilføje en boks
|
||||||
main.vaultlist.contextMenu.remove=Fjern…
|
main.vaultlist.contextMenu.remove=Fjern…
|
||||||
main.vaultlist.contextMenu.lock=Lås
|
main.vaultlist.contextMenu.lock=Lås
|
||||||
@@ -419,12 +424,15 @@ main.vaultlist.addVaultBtn.menuItemExisting=Åbn eksisterende boks…
|
|||||||
main.vaultlist.addVaultBtn.menuItemRecover=Genopret eksisterende boks…
|
main.vaultlist.addVaultBtn.menuItemRecover=Genopret eksisterende boks…
|
||||||
main.vaultlist.addVaultButton.tooltip=Tilføj boks
|
main.vaultlist.addVaultButton.tooltip=Tilføj boks
|
||||||
main.vaultlist.showEventsButton.tooltip=Åbn begivenhedsvisning
|
main.vaultlist.showEventsButton.tooltip=Åbn begivenhedsvisning
|
||||||
|
main.vaultlist.showPreferencesButton.tooltip=Vis Indstillinger
|
||||||
##Notification
|
##Notification
|
||||||
main.notification.updateAvailable=Opdatering er tilgængelig.
|
main.notification.updateAvailable=Opdatering er tilgængelig.
|
||||||
main.notification.support=Støt Cryptomator.
|
main.notification.support=Støt Cryptomator.
|
||||||
|
main.notification.closeButton.tooltip=Luk infobjælke
|
||||||
## Vault Detail
|
## Vault Detail
|
||||||
### Welcome
|
### Welcome
|
||||||
main.vaultDetail.welcomeOnboarding=Tak fordi du valgte Cryptomator til at beskytte dine filer. Hvis du har brug for hjælp, så tjek vores guider for at komme i gang:
|
main.vaultDetail.welcomeOnboarding=Tak fordi du valgte Cryptomator til at beskytte dine filer. Hvis du har brug for hjælp, så tjek vores guider for at komme i gang:
|
||||||
|
main.vaultDetail.storageLocation=Placering af boks
|
||||||
### Locked
|
### Locked
|
||||||
main.vaultDetail.lockedStatus=LÅST
|
main.vaultDetail.lockedStatus=LÅST
|
||||||
main.vaultDetail.unlockBtn=Lås op…
|
main.vaultDetail.unlockBtn=Lås op…
|
||||||
@@ -482,6 +490,7 @@ vaultOptions.general=Generelt
|
|||||||
vaultOptions.general.vaultName=Boks-navn
|
vaultOptions.general.vaultName=Boks-navn
|
||||||
vaultOptions.general.autoLock.lockAfterTimePart1=Lås efter inaktivitet i
|
vaultOptions.general.autoLock.lockAfterTimePart1=Lås efter inaktivitet i
|
||||||
vaultOptions.general.autoLock.lockAfterTimePart2=minutter
|
vaultOptions.general.autoLock.lockAfterTimePart2=minutter
|
||||||
|
vaultOptions.general.autoLock.accessibleText=Lås timeout i minutter
|
||||||
vaultOptions.general.unlockAfterStartup=Lås boksen op når Cryptomator starter
|
vaultOptions.general.unlockAfterStartup=Lås boksen op når Cryptomator starter
|
||||||
vaultOptions.general.actionAfterUnlock=Efter oplåsning af boks
|
vaultOptions.general.actionAfterUnlock=Efter oplåsning af boks
|
||||||
vaultOptions.general.actionAfterUnlock.ignore=Gør intet
|
vaultOptions.general.actionAfterUnlock.ignore=Gør intet
|
||||||
@@ -512,6 +521,7 @@ vaultOptions.masterkey.forgetSavedPasswordBtn=Glem gemt adgangskode
|
|||||||
vaultOptions.masterkey.recoveryKeyExplanation=En gendannelsesnøgle er den eneste måde du kan få adgang til din boks på, hvis du har glemt dit password.
|
vaultOptions.masterkey.recoveryKeyExplanation=En gendannelsesnøgle er den eneste måde du kan få adgang til din boks på, hvis du har glemt dit password.
|
||||||
vaultOptions.masterkey.showRecoveryKeyBtn=Vis gendannelsesnøgle
|
vaultOptions.masterkey.showRecoveryKeyBtn=Vis gendannelsesnøgle
|
||||||
vaultOptions.masterkey.recoverPasswordBtn=Nulstil adgangskode
|
vaultOptions.masterkey.recoverPasswordBtn=Nulstil adgangskode
|
||||||
|
vaultOptions.masterkey.missingMasterkeyFile=Disse tilvalg er kun tilgængelige hvis masterkeyfilen er til stede i boksmappen.
|
||||||
## Hub
|
## Hub
|
||||||
vaultOptions.hub=Gendannelse
|
vaultOptions.hub=Gendannelse
|
||||||
vaultOptions.hub.convertInfo=Du kan bruge gendannelsesnøglen til at konvertere denne Hub-boks til en adgangskode-baseret boks i en nødsituation.
|
vaultOptions.hub.convertInfo=Du kan bruge gendannelsesnøglen til at konvertere denne Hub-boks til en adgangskode-baseret boks i en nødsituation.
|
||||||
@@ -665,6 +675,8 @@ decryptNames.filePicker.title=Vælg krypteret fil
|
|||||||
decryptNames.filePicker.extensionDescription=Cryptomator krypteret fil
|
decryptNames.filePicker.extensionDescription=Cryptomator krypteret fil
|
||||||
decryptNames.copyTable.tooltip=Kopiér tabel
|
decryptNames.copyTable.tooltip=Kopiér tabel
|
||||||
decryptNames.clearTable.tooltip=Ryd tabel
|
decryptNames.clearTable.tooltip=Ryd tabel
|
||||||
|
decryptNames.column.encrypted=Krypteret
|
||||||
|
decryptNames.column.decrypted=Dekrypteret
|
||||||
decryptNames.copyHint=Kopiér celleindhold med %s
|
decryptNames.copyHint=Kopiér celleindhold med %s
|
||||||
decryptNames.dropZone.message=Slip filer eller klik for at vælge
|
decryptNames.dropZone.message=Slip filer eller klik for at vælge
|
||||||
decryptNames.dropZone.error.vaultInternalFiles=Boks interne filer med intet dekryptérbart navn valgt
|
decryptNames.dropZone.error.vaultInternalFiles=Boks interne filer med intet dekryptérbart navn valgt
|
||||||
@@ -677,34 +689,31 @@ decryptNames.dropZone.error.generic=Kunne ikke dekryptere filnavne
|
|||||||
eventView.title=Begivenheder
|
eventView.title=Begivenheder
|
||||||
eventView.filter.allVaults=Alle
|
eventView.filter.allVaults=Alle
|
||||||
eventView.clearListButton.tooltip=Ryd liste
|
eventView.clearListButton.tooltip=Ryd liste
|
||||||
|
eventView.filterVaults=Filtrér efter boks
|
||||||
|
eventView.cell.actionsButton.tooltip=Begivenhedshandlinger
|
||||||
## event list entries
|
## event list entries
|
||||||
eventView.entry.vaultLocked.description=Lås "%s" op for detaljer
|
eventView.entry.vaultLocked.description=Lås "%s" op for detaljer
|
||||||
eventView.entry.conflictResolved.message=Løst konflikt
|
eventView.entry.conflictResolved.message=Løst konflikt
|
||||||
eventView.entry.conflictResolved.showDecrypted=Vis dekrypteret fil
|
eventView.entry.conflictResolved.showDecrypted=Vis dekrypteret fil
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Kopiér dekrypteret sti
|
|
||||||
eventView.entry.conflict.message=Konfliktløsning mislykkedes
|
eventView.entry.conflict.message=Konfliktløsning mislykkedes
|
||||||
eventView.entry.conflict.showDecrypted=Vis dekrypteret, original fil
|
eventView.entry.conflict.showDecrypted=Vis dekrypteret, original fil
|
||||||
eventView.entry.conflict.copyDecrypted=Kopier dekrypteret, original sti
|
|
||||||
eventView.entry.conflict.showEncrypted=Vis modstridende, krypteret fil
|
eventView.entry.conflict.showEncrypted=Vis modstridende, krypteret fil
|
||||||
eventView.entry.conflict.copyEncrypted=Kopier modstridende, krypteret sti
|
|
||||||
eventView.entry.decryptionFailed.message=Dekryptering mislykkedes
|
eventView.entry.decryptionFailed.message=Dekryptering mislykkedes
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Vis krypteret fil
|
eventView.entry.decryptionFailed.showEncrypted=Vis krypteret fil
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Kopiér krypteret sti
|
|
||||||
eventView.entry.brokenDirFile.message=Brudt mappelink
|
eventView.entry.brokenDirFile.message=Brudt mappelink
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Vis brudt, krypteret link
|
eventView.entry.brokenDirFile.showEncrypted=Vis brudt, krypteret link
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Kopiér sti til brudt link
|
|
||||||
eventView.entry.brokenFileNode.message=Brudt filsystem-node
|
eventView.entry.brokenFileNode.message=Brudt filsystem-node
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Vis brudt, krypteret node
|
eventView.entry.brokenFileNode.showEncrypted=Vis brudt, krypteret node
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Kopiér sti af brudt, krypteret node
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Kopiér dekrypteret sti
|
eventView.entry.brokenFileNode.copyDecrypted=Kopiér dekrypteret sti
|
||||||
|
eventView.entry.inUse.message=Fil i brug
|
||||||
eventView.entry.inUse.showDecrypted=Vis dekrypteret fil
|
eventView.entry.inUse.showDecrypted=Vis dekrypteret fil
|
||||||
eventView.entry.inUse.copyDecrypted=Kopiér dekrypteret sti
|
|
||||||
eventView.entry.inUse.showEncrypted=Vis krypteret fil
|
eventView.entry.inUse.showEncrypted=Vis krypteret fil
|
||||||
eventView.entry.inUse.copyEncrypted=Kopiér krypteret sti
|
eventView.entry.inUse.copyUserAndDevice=Kopiér låsebruger og enhedsnavn
|
||||||
|
eventView.entry.inUse.ignoreLock=Ignorér anvendelsesstatus
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Filen er låst af en anden enhed
|
notification.inUse.message=Filen er i brug på en anden enhed
|
||||||
notification.inUse.description=Filen åbnes af %s på enheden %s. Bed brugeren om at lukke filen og synkronisere igen. Ellers kan du ignorere låsen og åbne den alligevel.
|
notification.inUse.description=Filen er åbnet af %s på %s. Bed dem om at lukke filen og lade synkroniseringen afslutte. Du kan ignorere status for at åbne den nu, men det kan forårsage konflikter eller overskrive nyere ændringer.
|
||||||
notification.inUse.action=Ignorér Lås
|
notification.inUse.action=Ignorér anvendelsesstatus
|
||||||
@@ -684,32 +684,21 @@ eventView.cell.actionsButton.tooltip=Ereignisaktionen
|
|||||||
eventView.entry.vaultLocked.description=Entsperre "%s" für Details
|
eventView.entry.vaultLocked.description=Entsperre "%s" für Details
|
||||||
eventView.entry.conflictResolved.message=Konflikt gelöst
|
eventView.entry.conflictResolved.message=Konflikt gelöst
|
||||||
eventView.entry.conflictResolved.showDecrypted=Entschlüsselte Datei anzeigen
|
eventView.entry.conflictResolved.showDecrypted=Entschlüsselte Datei anzeigen
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Pfad der entschlüsselten Datei kopieren
|
|
||||||
eventView.entry.conflict.message=Konfliktlösung fehlgeschlagen
|
eventView.entry.conflict.message=Konfliktlösung fehlgeschlagen
|
||||||
eventView.entry.conflict.showDecrypted=Entschlüsselte, ursprüngliche Datei anzeigen
|
eventView.entry.conflict.showDecrypted=Entschlüsselte, ursprüngliche Datei anzeigen
|
||||||
eventView.entry.conflict.copyDecrypted=Entschlüsselten, ursprünglicher Pfad kopieren
|
|
||||||
eventView.entry.conflict.showEncrypted=Zeige verschlüsselte Konfliktdatei
|
eventView.entry.conflict.showEncrypted=Zeige verschlüsselte Konfliktdatei
|
||||||
eventView.entry.conflict.copyEncrypted=Verschlüsselten Konfliktpfad kopieren
|
|
||||||
eventView.entry.decryptionFailed.message=Entschlüsselung fehlgeschlagen
|
eventView.entry.decryptionFailed.message=Entschlüsselung fehlgeschlagen
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Verschlüsselte Datei anzeigen
|
eventView.entry.decryptionFailed.showEncrypted=Verschlüsselte Datei anzeigen
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Pfad der verschlüsselten Datei kopieren
|
|
||||||
eventView.entry.brokenDirFile.message=Ungültiger Verzeichnislink
|
eventView.entry.brokenDirFile.message=Ungültiger Verzeichnislink
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Defekten, verschlüsselten Link anzeigen
|
eventView.entry.brokenDirFile.showEncrypted=Defekten, verschlüsselten Link anzeigen
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Pfad des ungültigen Links kopieren
|
|
||||||
eventView.entry.brokenFileNode.message=Beschädigter Dateisystemknoten
|
eventView.entry.brokenFileNode.message=Beschädigter Dateisystemknoten
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Beschädigten, verschlüsselten Knoten anzeigen
|
eventView.entry.brokenFileNode.showEncrypted=Beschädigten, verschlüsselten Knoten anzeigen
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Pfad des beschädigten, verschlüsselten Knotens kopieren
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Pfad der entschlüsselten Datei kopieren
|
eventView.entry.brokenFileNode.copyDecrypted=Pfad der entschlüsselten Datei kopieren
|
||||||
eventView.entry.inUse.message=Gesperrte Datei
|
|
||||||
eventView.entry.inUse.showDecrypted=Entschlüsselte Datei anzeigen
|
eventView.entry.inUse.showDecrypted=Entschlüsselte Datei anzeigen
|
||||||
eventView.entry.inUse.copyDecrypted=Pfad der entschlüsselten Datei kopieren
|
|
||||||
eventView.entry.inUse.showEncrypted=Verschlüsselte Datei anzeigen
|
eventView.entry.inUse.showEncrypted=Verschlüsselte Datei anzeigen
|
||||||
eventView.entry.inUse.copyEncrypted=Pfad der verschlüsselten Datei kopieren
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Benutzer- und Gerätenamen der Sperre kopieren
|
eventView.entry.inUse.copyUserAndDevice=Benutzer- und Gerätenamen der Sperre kopieren
|
||||||
eventView.entry.inUse.ignoreLock=Sperre ignorieren
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Die Datei ist über ein anderes Gerät gesperrt
|
notification.inUse.action=Verwendungsstatus ignorieren
|
||||||
notification.inUse.action=Sperre ignorieren
|
|
||||||
@@ -630,26 +630,18 @@ eventView.clearListButton.tooltip=Εκκαθάριση λίστας
|
|||||||
eventView.entry.vaultLocked.description=Ξεκλείδωμα "%s" για λεπτομέρειες
|
eventView.entry.vaultLocked.description=Ξεκλείδωμα "%s" για λεπτομέρειες
|
||||||
eventView.entry.conflictResolved.message=Επίλυση σύγκρουσης
|
eventView.entry.conflictResolved.message=Επίλυση σύγκρουσης
|
||||||
eventView.entry.conflictResolved.showDecrypted=Εμφάνιση αποκρυπτογραφημένου αρχείου
|
eventView.entry.conflictResolved.showDecrypted=Εμφάνιση αποκρυπτογραφημένου αρχείου
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Αντιγραφή αποκρυπτογραφημένης διαδρομής
|
|
||||||
eventView.entry.conflict.message=Η επίλυση συγκρούσεων απέτυχε
|
eventView.entry.conflict.message=Η επίλυση συγκρούσεων απέτυχε
|
||||||
eventView.entry.conflict.showDecrypted=Εμφάνιση αποκρυπτογραφημένων, αρχικό αρχείο
|
eventView.entry.conflict.showDecrypted=Εμφάνιση αποκρυπτογραφημένων, αρχικό αρχείο
|
||||||
eventView.entry.conflict.copyDecrypted=Αντιγραφή αποκρυπτογραφημένων, αρχική διαδρομή
|
|
||||||
eventView.entry.conflict.showEncrypted=Εμφάνιση αντικρουόμενου, κρυπτογραφημένο αρχείο
|
eventView.entry.conflict.showEncrypted=Εμφάνιση αντικρουόμενου, κρυπτογραφημένο αρχείο
|
||||||
eventView.entry.conflict.copyEncrypted=Αντιγραφή σύγκρουσης, κρυπτογραφημένη διαδρομή
|
|
||||||
eventView.entry.decryptionFailed.message=Η αποκρυπτογράφηση απέτυχε
|
eventView.entry.decryptionFailed.message=Η αποκρυπτογράφηση απέτυχε
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Εμφάνιση κρυπτογραφημένου αρχείου
|
eventView.entry.decryptionFailed.showEncrypted=Εμφάνιση κρυπτογραφημένου αρχείου
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Αντιγραφή κρυπτογραφημένης διαδρομής
|
|
||||||
eventView.entry.brokenDirFile.message=Μη λειτουργικός σύνδεσμος καταλόγου
|
eventView.entry.brokenDirFile.message=Μη λειτουργικός σύνδεσμος καταλόγου
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Εμφάνιση μη λειτουργικού, κρυπτογραφημένου συνδέσμου
|
eventView.entry.brokenDirFile.showEncrypted=Εμφάνιση μη λειτουργικού, κρυπτογραφημένου συνδέσμου
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Αντιγραφή διαδρομής του μη λειτουργικού συνδέσμου
|
|
||||||
eventView.entry.brokenFileNode.message=Μη λειτουργικός κόμβος συστήματος αρχείων
|
eventView.entry.brokenFileNode.message=Μη λειτουργικός κόμβος συστήματος αρχείων
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Εμφάνιση μη λειτουργικού, κρυπτογραφημένου κόμβου
|
eventView.entry.brokenFileNode.showEncrypted=Εμφάνιση μη λειτουργικού, κρυπτογραφημένου κόμβου
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Αντιγραφή διαδρομής του μη λειτουργικού, κρυπτογραφημένου κόμβου
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Αντιγραφή αποκρυπτογραφημένης διαδρομής
|
eventView.entry.brokenFileNode.copyDecrypted=Αντιγραφή αποκρυπτογραφημένης διαδρομής
|
||||||
eventView.entry.inUse.showDecrypted=Εμφάνιση αποκρυπτογραφημένου αρχείου
|
eventView.entry.inUse.showDecrypted=Εμφάνιση αποκρυπτογραφημένου αρχείου
|
||||||
eventView.entry.inUse.copyDecrypted=Αντιγραφή αποκρυπτογραφημένης διαδρομής
|
|
||||||
eventView.entry.inUse.showEncrypted=Εμφάνιση κρυπτογραφημένου αρχείου
|
eventView.entry.inUse.showEncrypted=Εμφάνιση κρυπτογραφημένου αρχείου
|
||||||
eventView.entry.inUse.copyEncrypted=Αντιγραφή κρυπτογραφημένης διαδρομής
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|||||||
@@ -684,27 +684,24 @@ eventView.cell.actionsButton.tooltip=Acciones del evento
|
|||||||
eventView.entry.vaultLocked.description=Desbloquear "%s" para más detalles
|
eventView.entry.vaultLocked.description=Desbloquear "%s" para más detalles
|
||||||
eventView.entry.conflictResolved.message=Conflicto resuelto
|
eventView.entry.conflictResolved.message=Conflicto resuelto
|
||||||
eventView.entry.conflictResolved.showDecrypted=Mostrar archivo descifrado
|
eventView.entry.conflictResolved.showDecrypted=Mostrar archivo descifrado
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Copiar ruta descifrada
|
|
||||||
eventView.entry.conflict.message=Resolución de conflictos fallida
|
eventView.entry.conflict.message=Resolución de conflictos fallida
|
||||||
eventView.entry.conflict.showDecrypted=Mostrar archivo descifrado, original
|
eventView.entry.conflict.showDecrypted=Mostrar archivo descifrado, original
|
||||||
eventView.entry.conflict.copyDecrypted=Copiar ruta descifrada, original
|
|
||||||
eventView.entry.conflict.showEncrypted=Mostrar archivo en conflicto, cifrado
|
eventView.entry.conflict.showEncrypted=Mostrar archivo en conflicto, cifrado
|
||||||
eventView.entry.conflict.copyEncrypted=Copiar ruta en conflicto, cifrada
|
|
||||||
eventView.entry.decryptionFailed.message=Desencriptación fallida
|
eventView.entry.decryptionFailed.message=Desencriptación fallida
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Mostrar archivo cifrado
|
eventView.entry.decryptionFailed.showEncrypted=Mostrar archivo cifrado
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Copiar ruta cifrada
|
|
||||||
eventView.entry.brokenDirFile.message=Enlace de directorio roto
|
eventView.entry.brokenDirFile.message=Enlace de directorio roto
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Mostrar enlace roto, cifrado
|
eventView.entry.brokenDirFile.showEncrypted=Mostrar enlace roto, cifrado
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Copiar ruta del enlace roto
|
|
||||||
eventView.entry.brokenFileNode.message=Nodo de sistema de archivos roto
|
eventView.entry.brokenFileNode.message=Nodo de sistema de archivos roto
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Mostrar nodo roto, cifrado
|
eventView.entry.brokenFileNode.showEncrypted=Mostrar nodo roto, cifrado
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Copiar ruta del enlace roto, encriptado
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Copiar ruta descifrada
|
eventView.entry.brokenFileNode.copyDecrypted=Copiar ruta descifrada
|
||||||
|
eventView.entry.inUse.message=Fichero en uso
|
||||||
eventView.entry.inUse.showDecrypted=Mostrar archivo descifrado
|
eventView.entry.inUse.showDecrypted=Mostrar archivo descifrado
|
||||||
eventView.entry.inUse.copyDecrypted=Copiar ruta descifrada
|
|
||||||
eventView.entry.inUse.showEncrypted=Mostrar archivo cifrado
|
eventView.entry.inUse.showEncrypted=Mostrar archivo cifrado
|
||||||
eventView.entry.inUse.copyEncrypted=Copiar ruta cifrada
|
eventView.entry.inUse.ignoreLock=Ignorar el estado de uso
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
|
notification.inUse.message=El archivo está en uso en otro dispositivo
|
||||||
|
notification.inUse.description=El archivo está abierto por %s en %s. Solicítale que cierre el archivo y deje que finalice la sincronización. Puede ignorar el estado para abrirlo ahora, pero esto puede causar conflictos o sobrescribir cambios más recientes.
|
||||||
|
notification.inUse.action=Ignorar el Estado de Uso
|
||||||
@@ -683,26 +683,18 @@ eventView.cell.actionsButton.tooltip=Toiminnot
|
|||||||
eventView.entry.vaultLocked.description=Avaa "%s" lisätietoja varten
|
eventView.entry.vaultLocked.description=Avaa "%s" lisätietoja varten
|
||||||
eventView.entry.conflictResolved.message=Ratkaistu ristiriita
|
eventView.entry.conflictResolved.message=Ratkaistu ristiriita
|
||||||
eventView.entry.conflictResolved.showDecrypted=Näytä purettu tiedosto
|
eventView.entry.conflictResolved.showDecrypted=Näytä purettu tiedosto
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Kopioi purettu polku
|
|
||||||
eventView.entry.conflict.message=Ristiriidan ratkaisu epäonnistui
|
eventView.entry.conflict.message=Ristiriidan ratkaisu epäonnistui
|
||||||
eventView.entry.conflict.showDecrypted=Näytä purettu, alkuperäinen tiedosto
|
eventView.entry.conflict.showDecrypted=Näytä purettu, alkuperäinen tiedosto
|
||||||
eventView.entry.conflict.copyDecrypted=Näytä purettu, alkuperäinen polku
|
|
||||||
eventView.entry.conflict.showEncrypted=Näytä ristiriitainen, salattu tiedosto
|
eventView.entry.conflict.showEncrypted=Näytä ristiriitainen, salattu tiedosto
|
||||||
eventView.entry.conflict.copyEncrypted=Kopioi ristiriitainen, salattu polku
|
|
||||||
eventView.entry.decryptionFailed.message=Salauksen purku epäonnistui
|
eventView.entry.decryptionFailed.message=Salauksen purku epäonnistui
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Näytä salattu tiedosto
|
eventView.entry.decryptionFailed.showEncrypted=Näytä salattu tiedosto
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Kopioi salattu polku
|
|
||||||
eventView.entry.brokenDirFile.message=Virheellinen hakemiston linkki
|
eventView.entry.brokenDirFile.message=Virheellinen hakemiston linkki
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Näytä virheellinen, salattu linkki
|
eventView.entry.brokenDirFile.showEncrypted=Näytä virheellinen, salattu linkki
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Kopioi virheellisen polun linkki
|
|
||||||
eventView.entry.brokenFileNode.message=Virheellinen tiedostojärjestelmän solmu
|
eventView.entry.brokenFileNode.message=Virheellinen tiedostojärjestelmän solmu
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Näytä virheellinen, salattu solmu
|
eventView.entry.brokenFileNode.showEncrypted=Näytä virheellinen, salattu solmu
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Kopioi virheellisen, salatun solmun polku
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Kopioi purettu polku
|
eventView.entry.brokenFileNode.copyDecrypted=Kopioi purettu polku
|
||||||
eventView.entry.inUse.showDecrypted=Näytä purettu tiedosto
|
eventView.entry.inUse.showDecrypted=Näytä purettu tiedosto
|
||||||
eventView.entry.inUse.copyDecrypted=Kopioi purettu polku
|
|
||||||
eventView.entry.inUse.showEncrypted=Näytä salattu tiedosto
|
eventView.entry.inUse.showEncrypted=Näytä salattu tiedosto
|
||||||
eventView.entry.inUse.copyEncrypted=Kopioi salattu polku
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|||||||
@@ -695,33 +695,25 @@ eventView.cell.actionsButton.tooltip=Actions d'évènement
|
|||||||
eventView.entry.vaultLocked.description=Déverrouillez "%s" pour plus de détails
|
eventView.entry.vaultLocked.description=Déverrouillez "%s" pour plus de détails
|
||||||
eventView.entry.conflictResolved.message=Conflit résolu
|
eventView.entry.conflictResolved.message=Conflit résolu
|
||||||
eventView.entry.conflictResolved.showDecrypted=Afficher le fichier déchiffré
|
eventView.entry.conflictResolved.showDecrypted=Afficher le fichier déchiffré
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Copier le chemin déchiffré
|
|
||||||
eventView.entry.conflict.message=La résolution des conflits a échoué
|
eventView.entry.conflict.message=La résolution des conflits a échoué
|
||||||
eventView.entry.conflict.showDecrypted=Afficher le fichier original déchiffré
|
eventView.entry.conflict.showDecrypted=Afficher le fichier original déchiffré
|
||||||
eventView.entry.conflict.copyDecrypted=Copier le chemin original déchiffré
|
|
||||||
eventView.entry.conflict.showEncrypted=Afficher le fichier chiffré en conflit
|
eventView.entry.conflict.showEncrypted=Afficher le fichier chiffré en conflit
|
||||||
eventView.entry.conflict.copyEncrypted=Copier le chemin chiffré en conflit
|
|
||||||
eventView.entry.decryptionFailed.message=Le déchiffrement a échoué
|
eventView.entry.decryptionFailed.message=Le déchiffrement a échoué
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Afficher le fichier chiffré
|
eventView.entry.decryptionFailed.showEncrypted=Afficher le fichier chiffré
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Copier le chemin chiffré
|
|
||||||
eventView.entry.brokenDirFile.message=Lien de répertoire cassé
|
eventView.entry.brokenDirFile.message=Lien de répertoire cassé
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Afficher le lien chiffré cassé
|
eventView.entry.brokenDirFile.showEncrypted=Afficher le lien chiffré cassé
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Copier le chemin du lien cassé
|
|
||||||
eventView.entry.brokenFileNode.message=Nœud de système de fichiers cassé
|
eventView.entry.brokenFileNode.message=Nœud de système de fichiers cassé
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Afficher le nœud chiffré cassé
|
eventView.entry.brokenFileNode.showEncrypted=Afficher le nœud chiffré cassé
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Copier le chemin du nœud chiffré cassé
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Copier le chemin déchiffré
|
eventView.entry.brokenFileNode.copyDecrypted=Copier le chemin déchiffré
|
||||||
eventView.entry.inUse.message=Fichier verrouillé
|
eventView.entry.inUse.message=Fichier en cours d’utilisation
|
||||||
eventView.entry.inUse.showDecrypted=Afficher le fichier déchiffré
|
eventView.entry.inUse.showDecrypted=Afficher le fichier déchiffré
|
||||||
eventView.entry.inUse.copyDecrypted=Copier le chemin déchiffré
|
|
||||||
eventView.entry.inUse.showEncrypted=Afficher le fichier chiffré
|
eventView.entry.inUse.showEncrypted=Afficher le fichier chiffré
|
||||||
eventView.entry.inUse.copyEncrypted=Copier le chemin chiffré
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Copier le verrouillage de l'utilisateur et le nom de l'appareil
|
eventView.entry.inUse.copyUserAndDevice=Copier le verrouillage de l'utilisateur et le nom de l'appareil
|
||||||
eventView.entry.inUse.ignoreLock=Ignorer le verrou
|
eventView.entry.inUse.ignoreLock=Ignorer le statut d’utilisation
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Le fichier est verrouillé par un autre appareil
|
notification.inUse.message=Le fichier est utilisé sur un autre appareil
|
||||||
notification.inUse.description=Le fichier est ouvert par %s sur l’appareil %s. Demandez à l’utilisateur de fermer le fichier et synchronisez à nouveau. Autrement vous pouvez ignorer le verrouillage et ouvrir quand même le fichier.
|
notification.inUse.description=Le fichier est ouvert par %s sur %s. Demandez-lui à fermer le fichier et laissez la synchronisation se terminer. Vous pouvez ignorer le statut pour l’ouvrir maintenant, mais cela pourrait entraîner des conflits ou écraser des modifications récentes.
|
||||||
notification.inUse.action=Ignorer le verrou
|
notification.inUse.action=Ignorer le statut d’utilisation
|
||||||
@@ -695,33 +695,25 @@ eventView.cell.actionsButton.tooltip=Azioni dell'evento
|
|||||||
eventView.entry.vaultLocked.description=Sblocca "%s" per i dettagli
|
eventView.entry.vaultLocked.description=Sblocca "%s" per i dettagli
|
||||||
eventView.entry.conflictResolved.message=Conflitto risolto
|
eventView.entry.conflictResolved.message=Conflitto risolto
|
||||||
eventView.entry.conflictResolved.showDecrypted=Mostra file decifrato
|
eventView.entry.conflictResolved.showDecrypted=Mostra file decifrato
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Copia percorso decriptato
|
|
||||||
eventView.entry.conflict.message=Risoluzione dei conflitti fallita
|
eventView.entry.conflict.message=Risoluzione dei conflitti fallita
|
||||||
eventView.entry.conflict.showDecrypted=Mostra il file originale decifrato
|
eventView.entry.conflict.showDecrypted=Mostra il file originale decifrato
|
||||||
eventView.entry.conflict.copyDecrypted=Copia il percorso originale decifrato
|
|
||||||
eventView.entry.conflict.showEncrypted=Mostra file cifrato in conflitto
|
eventView.entry.conflict.showEncrypted=Mostra file cifrato in conflitto
|
||||||
eventView.entry.conflict.copyEncrypted=Copia il percorso cifrato in conflitto
|
|
||||||
eventView.entry.decryptionFailed.message=Decifratura fallita
|
eventView.entry.decryptionFailed.message=Decifratura fallita
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Mostra file cifrato
|
eventView.entry.decryptionFailed.showEncrypted=Mostra file cifrato
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Copia percorso cifrato
|
|
||||||
eventView.entry.brokenDirFile.message=Collegamento directory errato
|
eventView.entry.brokenDirFile.message=Collegamento directory errato
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Visualizza il link cifrato errato
|
eventView.entry.brokenDirFile.showEncrypted=Visualizza il link cifrato errato
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Copia il percorso errato del file cifrato
|
|
||||||
eventView.entry.brokenFileNode.message=Nodo file errato
|
eventView.entry.brokenFileNode.message=Nodo file errato
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Visualizza il nodo file cifrato errato
|
eventView.entry.brokenFileNode.showEncrypted=Visualizza il nodo file cifrato errato
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Copia il percorso errato del nodo file cifrato
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Copia il percorso decifrato
|
eventView.entry.brokenFileNode.copyDecrypted=Copia il percorso decifrato
|
||||||
eventView.entry.inUse.message=File bloccato
|
eventView.entry.inUse.message=File in uso
|
||||||
eventView.entry.inUse.showDecrypted=Mostra file decifrato
|
eventView.entry.inUse.showDecrypted=Mostra file decifrato
|
||||||
eventView.entry.inUse.copyDecrypted=Copia percorso decriptato
|
|
||||||
eventView.entry.inUse.showEncrypted=Mostra file cifrato
|
eventView.entry.inUse.showEncrypted=Mostra file cifrato
|
||||||
eventView.entry.inUse.copyEncrypted=Copia percorso cifrato
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Copia il nome del dispositivo e dell'utente che sta bloccando
|
eventView.entry.inUse.copyUserAndDevice=Copia il nome del dispositivo e dell'utente che sta bloccando
|
||||||
eventView.entry.inUse.ignoreLock=Ignora blocco
|
eventView.entry.inUse.ignoreLock=Ignora lo stato di utilizzo
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Il file è bloccato da un altro dispositivo
|
notification.inUse.message=Il file è in uso su un altro dispositivo
|
||||||
notification.inUse.description=Il file è aperto da %s sul dispositivo %s. Chiedi all'utente di chiudere il file e sincronizzalo di nuovo. In caso contrario, puoi ignorare il blocco e aprirlo comunque.
|
notification.inUse.description=Il file è aperto da %s su %s. Chiedigli di chiudere il file e permettere che la sincronizzazione termini. È possibile ignorare lo stato ed aprirlo ora, ma questo può causare conflitti o la sovrascrittura delle modifiche più recenti.
|
||||||
notification.inUse.action=Ignora blocco
|
notification.inUse.action=Ignora lo Stato di Utilizzo
|
||||||
@@ -626,16 +626,10 @@ decryptNames.dropZone.error.generic=ファイル名の復号化に失敗しま
|
|||||||
|
|
||||||
# Event View
|
# Event View
|
||||||
## event list entries
|
## event list entries
|
||||||
eventView.entry.inUse.message=ロックされたファイル
|
|
||||||
eventView.entry.inUse.showDecrypted=復号化されたファイルを表示
|
eventView.entry.inUse.showDecrypted=復号化されたファイルを表示
|
||||||
eventView.entry.inUse.copyDecrypted=復号化されたパスをコピー
|
|
||||||
eventView.entry.inUse.showEncrypted=暗号化されたファイルを表示
|
eventView.entry.inUse.showEncrypted=暗号化されたファイルを表示
|
||||||
eventView.entry.inUse.copyEncrypted=暗号化されたパスをコピー
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=ロックしているユーザーとデバイス名をコピー
|
eventView.entry.inUse.copyUserAndDevice=ロックしているユーザーとデバイス名をコピー
|
||||||
eventView.entry.inUse.ignoreLock=ロックを無視する
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=ファイルは別のデバイスによってロックされています
|
|
||||||
notification.inUse.action=ロックを無視する
|
|
||||||
@@ -42,7 +42,7 @@ defaults.vault.vaultName=Vault
|
|||||||
|
|
||||||
# Tray Menu
|
# Tray Menu
|
||||||
traymenu.showMainWindow=보기
|
traymenu.showMainWindow=보기
|
||||||
traymenu.showPreferencesWindow=환경설정
|
traymenu.showPreferencesWindow=환경 설정
|
||||||
traymenu.lockAllVaults=모두 잠그기
|
traymenu.lockAllVaults=모두 잠그기
|
||||||
traymenu.quitApplication=종료
|
traymenu.quitApplication=종료
|
||||||
traymenu.vault.unlock=잠금 해제
|
traymenu.vault.unlock=잠금 해제
|
||||||
@@ -114,7 +114,7 @@ addvaultwizard.success.nextStepsInstructions="%s" Vault가 추가되었습니다
|
|||||||
addvaultwizard.success.unlockNow=지금 잠금 해제
|
addvaultwizard.success.unlockNow=지금 잠금 해제
|
||||||
|
|
||||||
# Remove Vault
|
# Remove Vault
|
||||||
removeVault.title=Vault 제거
|
removeVault.title=Vault "%s" 제거
|
||||||
removeVault.message=Vault를 삭제하시겠습니까?
|
removeVault.message=Vault를 삭제하시겠습니까?
|
||||||
removeVault.description=이 행위는 Cryptomator에서만 이 Vault를 지웁니다. 나중에 다시 추가할 수 있습니다. 암호화된 파일은 하드디스크에서 삭제되지 않습니다.
|
removeVault.description=이 행위는 Cryptomator에서만 이 Vault를 지웁니다. 나중에 다시 추가할 수 있습니다. 암호화된 파일은 하드디스크에서 삭제되지 않습니다.
|
||||||
|
|
||||||
@@ -132,18 +132,18 @@ forgetPassword.confirmBtn=비밀번호 삭제
|
|||||||
# Unlock
|
# Unlock
|
||||||
unlock.title="%s" 잠금 해제
|
unlock.title="%s" 잠금 해제
|
||||||
unlock.passwordPrompt="%s"의 비밀번호를 입력하십시오.
|
unlock.passwordPrompt="%s"의 비밀번호를 입력하십시오.
|
||||||
unlock.savePassword=비밀번호 기억
|
unlock.savePassword=비밀번호 기억하기
|
||||||
unlock.unlockBtn=잠금 해제
|
unlock.unlockBtn=잠금 해제
|
||||||
## Select
|
## Select
|
||||||
unlock.chooseMasterkey.message=마스터키 파일을 찾을 수 없습니다
|
unlock.chooseMasterkey.message=마스터키 파일을 찾을 수 없습니다
|
||||||
unlock.chooseMasterkey.description=이 Vault의 Masterkey를 찾지 못했습니다. 마스터 키 위치를 수동으로 선택하여 주십시오.
|
unlock.chooseMasterkey.description=이 "%s" Vault의 마스터키를 찾지 못했습니다. 마스터키 위치를 수동으로 선택하여 주십시오.
|
||||||
unlock.chooseMasterkey.restoreInstead=대신 마스터키 파일 복구
|
unlock.chooseMasterkey.restoreInstead=대신 마스터키 파일 복구
|
||||||
unlock.chooseMasterkey.filePickerTitle=Masterkey 파일 선택
|
unlock.chooseMasterkey.filePickerTitle=Masterkey 파일 선택
|
||||||
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
|
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
|
||||||
## Success
|
## Success
|
||||||
unlock.success.message=잠금 해제 성공
|
unlock.success.message=잠금 해제 성공
|
||||||
unlock.success.description="%s"이(가) 성공적으로 잠금 해제되었습니다. 이제 이 Vault를 마운트 지점으로 접근할 수 있습니다.
|
unlock.success.description="%s"이(가) 성공적으로 잠금 해제되었습니다. 이제 이 Vault를 마운트 지점으로 접근할 수 있습니다.
|
||||||
unlock.success.rememberChoice=선택 기억하기, 다시 묻지 않음
|
unlock.success.rememberChoice=선택을 기억하고 다시 묻지 않음
|
||||||
unlock.success.revealBtn=드라이브 표시
|
unlock.success.revealBtn=드라이브 표시
|
||||||
## Failure
|
## Failure
|
||||||
unlock.error.customPath.message=Vault를 사용자 정의 경로에 마운트할 수 없습니다.
|
unlock.error.customPath.message=Vault를 사용자 정의 경로에 마운트할 수 없습니다.
|
||||||
@@ -166,7 +166,7 @@ hub.auth.message=인증 대기 중…
|
|||||||
hub.auth.description=자동으로 로그인 페이지로 리다이렉트 될 것입니다.
|
hub.auth.description=자동으로 로그인 페이지로 리다이렉트 될 것입니다.
|
||||||
hub.auth.loginLink=수동으로 열려면 클릭하십시오.
|
hub.auth.loginLink=수동으로 열려면 클릭하십시오.
|
||||||
### Receive Key
|
### Receive Key
|
||||||
hub.receive.message=응답 처리중…
|
hub.receive.message=응답 처리 중…
|
||||||
hub.receive.description=Hub로부터 응답을 처리하고 있습니다. 잠시만 기다려 주십시오.
|
hub.receive.description=Hub로부터 응답을 처리하고 있습니다. 잠시만 기다려 주십시오.
|
||||||
### Register Device
|
### Register Device
|
||||||
hub.register.message=새 기기
|
hub.register.message=새 기기
|
||||||
@@ -181,7 +181,7 @@ hub.register.legacy.description=이 기기로부터 첫번째 Hub 접근입니
|
|||||||
hub.registerSuccess.message=기기 등록됨
|
hub.registerSuccess.message=기기 등록됨
|
||||||
hub.registerSuccess.description=등록에 성공하였습니다. Vault를 잠금 해제할 수 있습니다.
|
hub.registerSuccess.description=등록에 성공하였습니다. Vault를 잠금 해제할 수 있습니다.
|
||||||
hub.registerSuccess.unlockBtn=잠금 해제
|
hub.registerSuccess.unlockBtn=잠금 해제
|
||||||
hub.registerSuccess.legacy.description=Vault에 접근하기 위해서는 이 기기를 Vault 소유주가 추가적으로 허가해야 합니다.
|
hub.registerSuccess.legacy.description=Vault에 접근하기 위해서는 이 기기를 Vault 소유자가 추가적으로 허가해야 합니다.
|
||||||
### Registration Failed
|
### Registration Failed
|
||||||
hub.registerFailed.message=기기 등록 실패
|
hub.registerFailed.message=기기 등록 실패
|
||||||
hub.registerFailed.description.generic=등록 중에 오류가 발생했습니다. 앱 로그에서 자세한 정보를 확인할 수 있습니다.
|
hub.registerFailed.description.generic=등록 중에 오류가 발생했습니다. 앱 로그에서 자세한 정보를 확인할 수 있습니다.
|
||||||
@@ -209,18 +209,18 @@ lock.forced.retryBtn=재시도
|
|||||||
lock.forced.forceBtn=강제 잠금
|
lock.forced.forceBtn=강제 잠금
|
||||||
## Failure
|
## Failure
|
||||||
lock.fail.message=Vault 잠금에 실패하였습니다.
|
lock.fail.message=Vault 잠금에 실패하였습니다.
|
||||||
lock.fail.description="%s" Vault를 잠글 수 없습니다. 저장되지 않은 작업이 다른 곳에 저장된 것과 중요한 읽기/쓰기 동작이 완료되었는지 확인 하십시요. Vault를 닫기 위해, Cryptomator 프로세스를 강제로 종료 하십시오.
|
lock.fail.description="%s" Vault를 잠글 수 없습니다. 저장되지 않은 작업이 다른 곳에 저장된 것과 중요한 읽기/쓰기 동작이 완료되었는지 확인 하십시요. Vault를 닫기 위해, Cryptomator 프로세스를 강제로 종료하십시오.
|
||||||
|
|
||||||
# Migration
|
# Migration
|
||||||
migration.title=Vault 업그레이드
|
migration.title=Vault 업그레이드
|
||||||
## Start
|
## Start
|
||||||
migration.start.header=Vault 업그레이드
|
migration.start.header=Vault 업그레이드
|
||||||
migration.start.text=Vault "%s"를 현재 버전의 Cryptomator에서 열기 위해서는 해당 vault를 새 버전으로 업그레이드해야 합니다. 업그레이드를 하기 전에 다음 사항들을 알고 있어야 합니다:
|
migration.start.text=Vault "%s"를 현재 버전의 Cryptomator에서 열기 위해서는 해당 Vault를 새 버전으로 업그레이드해야 합니다. 업그레이드를 하기 전에 다음 사항들을 알고 있어야 합니다:
|
||||||
migration.start.remarkUndone=이 업그레이드는 되돌릴 수 없습니다.
|
migration.start.remarkUndone=이 업그레이드는 되돌릴 수 없습니다.
|
||||||
migration.start.remarkVersions=과거 버전의 Cryptomator는 업그레이드된 Vault를 열 수 없습니다.
|
migration.start.remarkVersions=과거 버전의 Cryptomator는 업그레이드된 Vault를 열 수 없습니다.
|
||||||
migration.start.remarkCanRun=이 Vault를 열 때 사용하는 모든 기기가 현재 버전의 Cryptomator를 실행할 수 있는지 확인해야 합니다.
|
migration.start.remarkCanRun=이 Vault를 열 때 사용하는 모든 기기가 현재 버전의 Cryptomator를 실행할 수 있는지 확인해야 합니다.
|
||||||
migration.start.remarkSynced=업그레이드하기 전에 해당 Vault가 모든 기기에 정상적으로 동기화되어야 합니다.
|
migration.start.remarkSynced=업그레이드하기 전에 해당 Vault가 모든 기기에 정상적으로 동기화되어야 합니다.
|
||||||
migration.start.confirm=나는 위 정보를 읽고 정말 이해했습니다.
|
migration.start.confirm=위 내용을 충분히 숙지하였음을 확인합니다.
|
||||||
## Run
|
## Run
|
||||||
migration.run.enterPassword="%s"의 비밀번호를 입력하십시오.
|
migration.run.enterPassword="%s"의 비밀번호를 입력하십시오.
|
||||||
migration.run.startMigrationBtn=Vault 마이그레이션
|
migration.run.startMigrationBtn=Vault 마이그레이션
|
||||||
@@ -231,8 +231,8 @@ migration.success.unlockNow=지금 잠금 해제
|
|||||||
## Missing file system capabilities
|
## Missing file system capabilities
|
||||||
migration.error.missingFileSystemCapabilities.title=지원하지 않는 파일 시스템
|
migration.error.missingFileSystemCapabilities.title=지원하지 않는 파일 시스템
|
||||||
migration.error.missingFileSystemCapabilities.description=Vault가 부적절한 파일 시스템에 있기 때문에 마이그레이션이 시작되지 않았습니다.
|
migration.error.missingFileSystemCapabilities.description=Vault가 부적절한 파일 시스템에 있기 때문에 마이그레이션이 시작되지 않았습니다.
|
||||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=너무 긴 파일 이름을 파일 시스템에서 지원하지 않습니다.
|
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=파일 시스템이 긴 파일 이름을 지원하지 않습니다.
|
||||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=너무 긴 경로를 파일 시스템에서 지원하지 않습니다.
|
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=파일 시스템이 긴 경로를 지원하지 않습니다.
|
||||||
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=파일 시스템이 읽기를 허용하지 않습니다.
|
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=파일 시스템이 읽기를 허용하지 않습니다.
|
||||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=파일 시스템이 쓰기를 허용하지 않습니다.
|
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=파일 시스템이 쓰기를 허용하지 않습니다.
|
||||||
## Impossible
|
## Impossible
|
||||||
@@ -267,7 +267,7 @@ health.check.detail.checkSkipped=선택된 검사항목이 없습니다.
|
|||||||
health.check.detail.checkFinished=검사가 성공적으로 완료되었습니다.
|
health.check.detail.checkFinished=검사가 성공적으로 완료되었습니다.
|
||||||
health.check.detail.checkFinishedAndFound=검사가 완료되었습니다. 검사 결과를 확인해주세요.
|
health.check.detail.checkFinishedAndFound=검사가 완료되었습니다. 검사 결과를 확인해주세요.
|
||||||
health.check.detail.checkFailed=오류로 인해 검사가 종료되었습니다.
|
health.check.detail.checkFailed=오류로 인해 검사가 종료되었습니다.
|
||||||
health.check.detail.checkCancelled=검사가 취소되었습니다
|
health.check.detail.checkCancelled=검사가 취소되었습니다.
|
||||||
health.check.detail.listFilters.label=필터
|
health.check.detail.listFilters.label=필터
|
||||||
health.check.detail.filterSeverity=중요도로 정렬
|
health.check.detail.filterSeverity=중요도로 정렬
|
||||||
health.check.detail.filterFixState=해결 상태로 정렬
|
health.check.detail.filterFixState=해결 상태로 정렬
|
||||||
@@ -286,7 +286,7 @@ health.result.severityTip.crit=상태: 심각\nVault 구조가 손상되었습
|
|||||||
health.result.fixStateFilter.all=모든 문제 해결 상태
|
health.result.fixStateFilter.all=모든 문제 해결 상태
|
||||||
health.result.fixStateFilter.fixable=문제 해결 가능
|
health.result.fixStateFilter.fixable=문제 해결 가능
|
||||||
health.result.fixStateFilter.notFixable=문제 해결 불가
|
health.result.fixStateFilter.notFixable=문제 해결 불가
|
||||||
health.result.fixStateFilter.fixing=문제 해결중…
|
health.result.fixStateFilter.fixing=문제 해결 중…
|
||||||
health.result.fixStateFilter.fixed=문제 해결됨
|
health.result.fixStateFilter.fixed=문제 해결됨
|
||||||
health.result.fixStateFilter.fixFailed=문제 해결 실패
|
health.result.fixStateFilter.fixFailed=문제 해결 실패
|
||||||
## Fix Application
|
## Fix Application
|
||||||
@@ -295,7 +295,7 @@ health.fix.successTip=문제 해결이 성공적으로 완료되었습니다
|
|||||||
health.fix.failTip=문제 해결 실패, 상세 정보는 로그를 참조하십시오.
|
health.fix.failTip=문제 해결 실패, 상세 정보는 로그를 참조하십시오.
|
||||||
|
|
||||||
# Preferences
|
# Preferences
|
||||||
preferences.title=환경설정
|
preferences.title=환경 설정
|
||||||
## General
|
## General
|
||||||
preferences.general=일반
|
preferences.general=일반
|
||||||
preferences.general.startHidden=Cryptomator를 시작할 때 창 숨김
|
preferences.general.startHidden=Cryptomator를 시작할 때 창 숨김
|
||||||
@@ -309,9 +309,9 @@ preferences.general.quickAccessService=열린 Vault를 빠른 접근 위치에
|
|||||||
preferences.interface=인터페이스
|
preferences.interface=인터페이스
|
||||||
preferences.interface.theme=테마
|
preferences.interface.theme=테마
|
||||||
preferences.interface.theme.automatic=자동
|
preferences.interface.theme.automatic=자동
|
||||||
preferences.interface.theme.dark=어둡게
|
preferences.interface.theme.dark=다크 모드
|
||||||
preferences.interface.theme.light=밝게
|
preferences.interface.theme.light=라이트 모드
|
||||||
preferences.interface.unlockThemes=다크모드 해제
|
preferences.interface.unlockThemes=다크 모드 사용 권한을 얻어보세요!
|
||||||
preferences.interface.language=언어 (재시작 필요)
|
preferences.interface.language=언어 (재시작 필요)
|
||||||
preferences.interface.language.auto=시스템 기본 설정
|
preferences.interface.language.auto=시스템 기본 설정
|
||||||
preferences.interface.interfaceOrientation=인터페이스 방향
|
preferences.interface.interfaceOrientation=인터페이스 방향
|
||||||
@@ -356,7 +356,7 @@ preferences.contribute=후원하기
|
|||||||
preferences.contribute.registeredFor=%s(으)로 후원자 인증 등록됨
|
preferences.contribute.registeredFor=%s(으)로 후원자 인증 등록됨
|
||||||
preferences.contribute.noCertificate=Cryptomator를 후원하시고 후원자 인증을 받으십시오. 라이선스 키와 비슷하지만 무료 소프트웨어를 사용하는 멋진 사람들을 위한 것입니다. ;-)
|
preferences.contribute.noCertificate=Cryptomator를 후원하시고 후원자 인증을 받으십시오. 라이선스 키와 비슷하지만 무료 소프트웨어를 사용하는 멋진 사람들을 위한 것입니다. ;-)
|
||||||
preferences.contribute.getCertificate=아직 후원자 인증이 없으신가요? 어떻게 얻는지 배울 수 있습니다.
|
preferences.contribute.getCertificate=아직 후원자 인증이 없으신가요? 어떻게 얻는지 배울 수 있습니다.
|
||||||
preferences.contribute.promptText=후원자 인증코드를 여기에 붙여넣기
|
preferences.contribute.promptText=후원자 인증 코드를 여기에 붙여넣기
|
||||||
preferences.contribute.thankYou=Cryptomator의 오픈 소스 개발을 지원해 주셔서 감사합니다!
|
preferences.contribute.thankYou=Cryptomator의 오픈 소스 개발을 지원해 주셔서 감사합니다!
|
||||||
preferences.contribute.donate=후원하기
|
preferences.contribute.donate=후원하기
|
||||||
preferences.contribute.sponsor=스폰서
|
preferences.contribute.sponsor=스폰서
|
||||||
@@ -364,7 +364,7 @@ preferences.contribute.removeCert.tooltip=인증서 제거
|
|||||||
|
|
||||||
### Remove License Key Dialog
|
### Remove License Key Dialog
|
||||||
removeCert.title=인증서 제거
|
removeCert.title=인증서 제거
|
||||||
removeCert.message=서포터 인증서를 제거하시겠습니까?
|
removeCert.message=후원자 인증서를 제거하시겠습니까?
|
||||||
removeCert.description=Cryptomator의 핵심 기능은 영향을 받지 않습니다. Vault에 대한 접근이 제한되거나 보안이 약화되지 않습니다.
|
removeCert.description=Cryptomator의 핵심 기능은 영향을 받지 않습니다. Vault에 대한 접근이 제한되거나 보안이 약화되지 않습니다.
|
||||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||||
|
|
||||||
@@ -392,7 +392,7 @@ stats.read.accessCount=총 읽기 횟수: %d
|
|||||||
stats.write.throughput.idle=쓰기: 대기 중
|
stats.write.throughput.idle=쓰기: 대기 중
|
||||||
stats.write.throughput.kibs=쓰기: %.2f KiB/s
|
stats.write.throughput.kibs=쓰기: %.2f KiB/s
|
||||||
stats.write.throughput.mibs=쓰기: %.2f MiB/s
|
stats.write.throughput.mibs=쓰기: %.2f MiB/s
|
||||||
stats.write.total.data.none=데이터 기록됨: -
|
stats.write.total.data.none=데이터 쓰기: -
|
||||||
stats.write.total.data.kib=데이터 쓰기: %.1f KiB
|
stats.write.total.data.kib=데이터 쓰기: %.1f KiB
|
||||||
stats.write.total.data.mib=데이터 쓰기: %.1f MiB
|
stats.write.total.data.mib=데이터 쓰기: %.1f MiB
|
||||||
stats.write.total.data.gib=데이터 쓰기: %.1f GiB
|
stats.write.total.data.gib=데이터 쓰기: %.1f GiB
|
||||||
@@ -427,11 +427,11 @@ main.vaultlist.showEventsButton.tooltip=이벤트 뷰어 열기
|
|||||||
main.vaultlist.showPreferencesButton.tooltip=환경 설정 표시
|
main.vaultlist.showPreferencesButton.tooltip=환경 설정 표시
|
||||||
##Notification
|
##Notification
|
||||||
main.notification.updateAvailable=업데이트가 있습니다.
|
main.notification.updateAvailable=업데이트가 있습니다.
|
||||||
main.notification.support=Cryptomator 지원하기.
|
main.notification.support=Cryptomator 지원해 주세요
|
||||||
main.notification.closeButton.tooltip=정보 표시줄 닫기
|
main.notification.closeButton.tooltip=정보 표시줄 닫기
|
||||||
## Vault Detail
|
## Vault Detail
|
||||||
### Welcome
|
### Welcome
|
||||||
main.vaultDetail.welcomeOnboarding=파일을 보호하기 위해 Cryptomator를 선택해주셔서 감사합니다. 만약 다른 도움이 필요하시면, 시작 안내서를 참조하시기 바랍니다.
|
main.vaultDetail.welcomeOnboarding=파일 보호를 위해 Cryptomator를 선택해 주셔서 감사합니다. 도움이 필요하시면 시작 가이드를 확인해 주십시오:
|
||||||
main.vaultDetail.storageLocation=Vault 저장 위치
|
main.vaultDetail.storageLocation=Vault 저장 위치
|
||||||
### Locked
|
### Locked
|
||||||
main.vaultDetail.lockedStatus=잠김
|
main.vaultDetail.lockedStatus=잠김
|
||||||
@@ -695,32 +695,25 @@ eventView.cell.actionsButton.tooltip=이벤트별 동작
|
|||||||
eventView.entry.vaultLocked.description="%s"를 잠금 해제하여 세부정보 보기
|
eventView.entry.vaultLocked.description="%s"를 잠금 해제하여 세부정보 보기
|
||||||
eventView.entry.conflictResolved.message=해결된 충돌
|
eventView.entry.conflictResolved.message=해결된 충돌
|
||||||
eventView.entry.conflictResolved.showDecrypted=복호화된 파일 보기
|
eventView.entry.conflictResolved.showDecrypted=복호화된 파일 보기
|
||||||
eventView.entry.conflictResolved.copyDecrypted=복호화된 경로 복사하기
|
|
||||||
eventView.entry.conflict.message=충돌 해결 실패
|
eventView.entry.conflict.message=충돌 해결 실패
|
||||||
eventView.entry.conflict.showDecrypted=복호화된 원본 파일 보기
|
eventView.entry.conflict.showDecrypted=복호화된 원본 파일 보기
|
||||||
eventView.entry.conflict.copyDecrypted=복호화된 원본 경로 복사하기
|
|
||||||
eventView.entry.conflict.showEncrypted=충돌하는 암호화된 파일 보기
|
eventView.entry.conflict.showEncrypted=충돌하는 암호화된 파일 보기
|
||||||
eventView.entry.conflict.copyEncrypted=충돌하는 암호화된 경로 복사하기
|
|
||||||
eventView.entry.decryptionFailed.message=복호화 실패
|
eventView.entry.decryptionFailed.message=복호화 실패
|
||||||
eventView.entry.decryptionFailed.showEncrypted=암호화된 파일 보기
|
eventView.entry.decryptionFailed.showEncrypted=암호화된 파일 보기
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=암호화된 경로 복사하기
|
|
||||||
eventView.entry.brokenDirFile.message=망가진 디렉터리 링크
|
eventView.entry.brokenDirFile.message=망가진 디렉터리 링크
|
||||||
eventView.entry.brokenDirFile.showEncrypted=망가진 암호화된 링크 보기
|
eventView.entry.brokenDirFile.showEncrypted=망가진 암호화된 링크 보기
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=망가진 링크의 경로 복사하리
|
eventView.entry.brokenFileNode.message=망가진 파일 시스템 노드
|
||||||
eventView.entry.brokenFileNode.message=망가진 파일시스템 노드
|
|
||||||
eventView.entry.brokenFileNode.showEncrypted=망가진 암호화된 노드 보기
|
eventView.entry.brokenFileNode.showEncrypted=망가진 암호화된 노드 보기
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=망가진 암호화된 노드의 경로 복사하기
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=복호화된 경로 복사하기
|
eventView.entry.brokenFileNode.copyDecrypted=복호화된 경로 복사하기
|
||||||
eventView.entry.inUse.message=잠긴 파일
|
eventView.entry.inUse.message=파일 사용 중
|
||||||
eventView.entry.inUse.showDecrypted=복호화된 파일 보기
|
eventView.entry.inUse.showDecrypted=복호화된 파일 보기
|
||||||
eventView.entry.inUse.copyDecrypted=복호화된 경로 복사하기
|
|
||||||
eventView.entry.inUse.showEncrypted=암호화된 파일 보기
|
eventView.entry.inUse.showEncrypted=암호화된 파일 보기
|
||||||
eventView.entry.inUse.copyEncrypted=암호화된 경로 복사하기
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=파일 잠금 사용자 및 기기 이름 복사
|
eventView.entry.inUse.copyUserAndDevice=파일 잠금 사용자 및 기기 이름 복사
|
||||||
eventView.entry.inUse.ignoreLock=잠금 무시
|
eventView.entry.inUse.ignoreLock=사용 여부 상태 무시
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=다른 기기에서 파일이 잠겼습니다.
|
notification.inUse.message=다른 기기에서 파일 사용 중
|
||||||
notification.inUse.action=잠금 무시
|
notification.inUse.description=해당 파일은 %s이(가) %s의 컴퓨터에서 열어 놓은 상태입니다. 파일을 닫고 동기화가 완료될 때까지 기다리도록 요청하세요. 상태를 무시하고 지금 파일을 열 수도 있지만, 이렇게 하면 충돌이 발생하거나 최신 변경 사항이 덮어쓰여질 수 있습니다.
|
||||||
|
notification.inUse.action=사용 여부 상태 무시
|
||||||
@@ -694,31 +694,25 @@ eventView.cell.actionsButton.tooltip=Notikumu darbības
|
|||||||
eventView.entry.vaultLocked.description=Atslēgt "%s", lai redzētu informāciju
|
eventView.entry.vaultLocked.description=Atslēgt "%s", lai redzētu informāciju
|
||||||
eventView.entry.conflictResolved.message=Atrisināta nesaderība
|
eventView.entry.conflictResolved.message=Atrisināta nesaderība
|
||||||
eventView.entry.conflictResolved.showDecrypted=Parādīt atšifrēto datni
|
eventView.entry.conflictResolved.showDecrypted=Parādīt atšifrēto datni
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Ievietot starpliktuvē atšifrēto ceļu
|
|
||||||
eventView.entry.conflict.message=Nesaderības atrisināšana neizdevās
|
eventView.entry.conflict.message=Nesaderības atrisināšana neizdevās
|
||||||
eventView.entry.conflict.showDecrypted=Parādīt atšifrēto, sākotnējo datni
|
eventView.entry.conflict.showDecrypted=Parādīt atšifrēto, sākotnējo datni
|
||||||
eventView.entry.conflict.copyDecrypted=Ievietot starpliktuvē atšifrēto, sākotnējo datni
|
|
||||||
eventView.entry.conflict.showEncrypted=Parādīt nesaderīgo, šifrēto datni
|
eventView.entry.conflict.showEncrypted=Parādīt nesaderīgo, šifrēto datni
|
||||||
eventView.entry.conflict.copyEncrypted=Ievietot starpliktuvē nesaderīgo, šifrēto ceļu
|
|
||||||
eventView.entry.decryptionFailed.message=Atšifrēšana neizdevās
|
eventView.entry.decryptionFailed.message=Atšifrēšana neizdevās
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Parādīt šifrēto datni
|
eventView.entry.decryptionFailed.showEncrypted=Parādīt šifrēto datni
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Ievietot starpliktuvē šifrēto ceļu
|
|
||||||
eventView.entry.brokenDirFile.message=Bojāta mapes saite
|
eventView.entry.brokenDirFile.message=Bojāta mapes saite
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Parādīt bojāto, šifrēto saiti
|
eventView.entry.brokenDirFile.showEncrypted=Parādīt bojāto, šifrēto saiti
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Ievietot starpliktuvē bojātās saites ceļu
|
|
||||||
eventView.entry.brokenFileNode.message=Bojāts datņu sistēmas mezgls
|
eventView.entry.brokenFileNode.message=Bojāts datņu sistēmas mezgls
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Parādīt bojāto, šifrēto mezglu
|
eventView.entry.brokenFileNode.showEncrypted=Parādīt bojāto, šifrēto mezglu
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Ievietot starpliktuvē botjātā, šifrētā mezgla ceļu
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Ievietot starpliktuvē atšifrēto ceļu
|
eventView.entry.brokenFileNode.copyDecrypted=Ievietot starpliktuvē atšifrēto ceļu
|
||||||
eventView.entry.inUse.message=Aizslēgta datne
|
eventView.entry.inUse.message=Datne tiek izmantota
|
||||||
eventView.entry.inUse.showDecrypted=Parādīt atšifrēto datni
|
eventView.entry.inUse.showDecrypted=Parādīt atšifrēto datni
|
||||||
eventView.entry.inUse.copyDecrypted=Ievietot starpliktuvē atšifrēto ceļu
|
|
||||||
eventView.entry.inUse.showEncrypted=Parādīt šifrēto datni
|
eventView.entry.inUse.showEncrypted=Parādīt šifrēto datni
|
||||||
eventView.entry.inUse.copyEncrypted=Ievietot starpliktuvē šifrēto ceļu
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Ievietot starpliktuvē lietotāju un ierīces, kurā aizslēgta, nosaukumu
|
eventView.entry.inUse.copyUserAndDevice=Ievietot starpliktuvē lietotāju un ierīces, kurā aizslēgta, nosaukumu
|
||||||
eventView.entry.inUse.ignoreLock=Neņemt vērā slēgu
|
eventView.entry.inUse.ignoreLock=Neņemt vēra izmantošanas stāvokli
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.action=Neņemt vērā slēgu
|
notification.inUse.message=Datne tiek izmantota citā ierīcē
|
||||||
|
notification.inUse.description=Datni atvēra %s ierīcē %s. Jāvaicā aizvērt datni un ļaut pabeigties sinhronizēšanai. Stāvokli tagad var neņemt vērā, lai atvērtu datni, bet tas var radīt nesaderības vai pārrakstīt jaunākas izmaiņas.
|
||||||
|
notification.inUse.action=Neņemt vēra izmantošanas stāvokli
|
||||||
@@ -695,33 +695,25 @@ eventView.cell.actionsButton.tooltip=Acties op Gebeurtenissen
|
|||||||
eventView.entry.vaultLocked.description=Ontgrendel "%s" voor details
|
eventView.entry.vaultLocked.description=Ontgrendel "%s" voor details
|
||||||
eventView.entry.conflictResolved.message=Opgelost conflict
|
eventView.entry.conflictResolved.message=Opgelost conflict
|
||||||
eventView.entry.conflictResolved.showDecrypted=Toon gedecodeerd bestand
|
eventView.entry.conflictResolved.showDecrypted=Toon gedecodeerd bestand
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Kopieer gedecodeerd pad
|
|
||||||
eventView.entry.conflict.message=Conflictoplossing is mislukt
|
eventView.entry.conflict.message=Conflictoplossing is mislukt
|
||||||
eventView.entry.conflict.showDecrypted=Toon gedecodeerd, origineel bestand
|
eventView.entry.conflict.showDecrypted=Toon gedecodeerd, origineel bestand
|
||||||
eventView.entry.conflict.copyDecrypted=Kopieer gedecodeerd, origineel pad
|
|
||||||
eventView.entry.conflict.showEncrypted=Conflicterend, versleuteld bestand weergeven
|
eventView.entry.conflict.showEncrypted=Conflicterend, versleuteld bestand weergeven
|
||||||
eventView.entry.conflict.copyEncrypted=Conflicterend, versleuteld pad kopiëren
|
|
||||||
eventView.entry.decryptionFailed.message=Decodering mislukt
|
eventView.entry.decryptionFailed.message=Decodering mislukt
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Toon gedecodeerd bestand
|
eventView.entry.decryptionFailed.showEncrypted=Toon gedecodeerd bestand
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Kopieer gedecodeerd pad
|
|
||||||
eventView.entry.brokenDirFile.message=Verbroken directory link
|
eventView.entry.brokenDirFile.message=Verbroken directory link
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Toon verbroken gecodeerde link
|
eventView.entry.brokenDirFile.showEncrypted=Toon verbroken gecodeerde link
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Kopieer pad van verbroken link
|
|
||||||
eventView.entry.brokenFileNode.message=Kapot bestandssysteemknooppunt
|
eventView.entry.brokenFileNode.message=Kapot bestandssysteemknooppunt
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Toon verbroken gecodeerde link
|
eventView.entry.brokenFileNode.showEncrypted=Toon verbroken gecodeerde link
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Kopieer pad van verbroken, versleuteld knooppunt
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Kopieer gedecodeerd pad
|
eventView.entry.brokenFileNode.copyDecrypted=Kopieer gedecodeerd pad
|
||||||
eventView.entry.inUse.message=Vergrendeld Bestand
|
eventView.entry.inUse.message=Bestand in gebruik
|
||||||
eventView.entry.inUse.showDecrypted=Toon gedecodeerd bestand
|
eventView.entry.inUse.showDecrypted=Toon gedecodeerd bestand
|
||||||
eventView.entry.inUse.copyDecrypted=Kopieer gedecodeerd pad
|
|
||||||
eventView.entry.inUse.showEncrypted=Toon gedecodeerd bestand
|
eventView.entry.inUse.showEncrypted=Toon gedecodeerd bestand
|
||||||
eventView.entry.inUse.copyEncrypted=Kopieer gedecodeerd pad
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Kopieer vergrendeling gebruikersnaam en apparaatnaam
|
eventView.entry.inUse.copyUserAndDevice=Kopieer vergrendeling gebruikersnaam en apparaatnaam
|
||||||
eventView.entry.inUse.ignoreLock=Vergrendeling negeren
|
eventView.entry.inUse.ignoreLock=Gebruiksstatus negeren
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Bestand is vergrendeld door een ander apparaat
|
notification.inUse.message=Bestand is op een ander apparaat in gebruik
|
||||||
notification.inUse.description=Het bestand wordt geopend door %s op apparaat %s. Vraag de gebruiker om het bestand te sluiten en opnieuw te synchroniseren. Anders kunt u de vergrendeling negeren en het toch openen.
|
notification.inUse.description=Het bestand is geopend door %s op %s. Vraag ze om het bestand te sluiten en laat de synchronisatie eindigen. Je kunt de status negeren om het nu te openen, maar dit kan conflicten veroorzaken of nieuwere wijzigingen overschrijven.
|
||||||
notification.inUse.action=Vergrendeling negeren
|
notification.inUse.action=Gebruiksstatus negeren
|
||||||
@@ -573,17 +573,13 @@ eventView.clearListButton.tooltip=ਸੂਚੀ ਨੂੰ ਮਿਟਾਓ
|
|||||||
## event list entries
|
## event list entries
|
||||||
eventView.entry.vaultLocked.description=ਵੇਰਵਿਆਂ ਲਈ "%s" ਨੂੰ ਅਣ-ਲਾਕ ਕਰੋ
|
eventView.entry.vaultLocked.description=ਵੇਰਵਿਆਂ ਲਈ "%s" ਨੂੰ ਅਣ-ਲਾਕ ਕਰੋ
|
||||||
eventView.entry.conflictResolved.showDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
eventView.entry.conflictResolved.showDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
||||||
eventView.entry.conflictResolved.copyDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੇ ਪਾਥ ਨੂੰ ਕਾਪੀ ਕਰੋ
|
|
||||||
eventView.entry.decryptionFailed.message=ਡਿਕ੍ਰਿਪਟ ਕਰਨਾ ਅਸਫ਼ਲ ਹੈ
|
eventView.entry.decryptionFailed.message=ਡਿਕ੍ਰਿਪਟ ਕਰਨਾ ਅਸਫ਼ਲ ਹੈ
|
||||||
eventView.entry.decryptionFailed.showEncrypted=ਇੰਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
eventView.entry.decryptionFailed.showEncrypted=ਇੰਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=ਇੰਕ੍ਰਿਪਟ ਕੀਤੇ ਪਾਥ ਨੂੰ ਕਾਪੀ ਕਰੋ
|
|
||||||
eventView.entry.brokenDirFile.message=ਡਾਇਰੈਕਟਰੀ ਲਿੰਕ ਖ਼ਰਾਬ ਹੈ
|
eventView.entry.brokenDirFile.message=ਡਾਇਰੈਕਟਰੀ ਲਿੰਕ ਖ਼ਰਾਬ ਹੈ
|
||||||
eventView.entry.brokenDirFile.showEncrypted=ਖ਼ਰਾਬ, ਇੰੰਕ੍ਰਿਪਟ ਕੀਤੇ ਲਿੰਕ ਨੂੰ ਵੇਖਾਓ
|
eventView.entry.brokenDirFile.showEncrypted=ਖ਼ਰਾਬ, ਇੰੰਕ੍ਰਿਪਟ ਕੀਤੇ ਲਿੰਕ ਨੂੰ ਵੇਖਾਓ
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੇ ਪਾਥ ਨੂੰ ਕਾਪੀ ਕਰੋ
|
eventView.entry.brokenFileNode.copyDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੇ ਪਾਥ ਨੂੰ ਕਾਪੀ ਕਰੋ
|
||||||
eventView.entry.inUse.showDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
eventView.entry.inUse.showDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
||||||
eventView.entry.inUse.copyDecrypted=ਡਿਕ੍ਰਿਪਟ ਕੀਤੇ ਪਾਥ ਨੂੰ ਕਾਪੀ ਕਰੋ
|
|
||||||
eventView.entry.inUse.showEncrypted=ਇੰਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
eventView.entry.inUse.showEncrypted=ਇੰਕ੍ਰਿਪਟ ਕੀਤੀ ਫ਼ਾਇਲ ਨੂੰ ਵੇਖੋ
|
||||||
eventView.entry.inUse.copyEncrypted=ਇੰਕ੍ਰਿਪਟ ਕੀਤੇ ਪਾਥ ਨੂੰ ਕਾਪੀ ਕਰੋ
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|||||||
@@ -695,31 +695,20 @@ eventView.cell.actionsButton.tooltip=Akcje zdarzeń
|
|||||||
eventView.entry.vaultLocked.description=Odblokuj "%s" po szczegóły
|
eventView.entry.vaultLocked.description=Odblokuj "%s" po szczegóły
|
||||||
eventView.entry.conflictResolved.message=Konflikt rozwiązany
|
eventView.entry.conflictResolved.message=Konflikt rozwiązany
|
||||||
eventView.entry.conflictResolved.showDecrypted=Pokaż odszyfrowany plik
|
eventView.entry.conflictResolved.showDecrypted=Pokaż odszyfrowany plik
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Kopiuj odszyfrowaną ścieżkę
|
|
||||||
eventView.entry.conflict.message=Rozwiązywanie konfliktu nie powiodło się
|
eventView.entry.conflict.message=Rozwiązywanie konfliktu nie powiodło się
|
||||||
eventView.entry.conflict.showDecrypted=Pokaż odszyfrowany, oryginalny plik
|
eventView.entry.conflict.showDecrypted=Pokaż odszyfrowany, oryginalny plik
|
||||||
eventView.entry.conflict.copyDecrypted=Kopiuj odszyfrowaną, oryginalną ścieżkę
|
|
||||||
eventView.entry.conflict.showEncrypted=Pokaż sprzeczny, zaszyfrowany plik
|
eventView.entry.conflict.showEncrypted=Pokaż sprzeczny, zaszyfrowany plik
|
||||||
eventView.entry.conflict.copyEncrypted=Kopiuj sprzeczną, zaszyfrowaną ścieżkę
|
|
||||||
eventView.entry.decryptionFailed.message=Odszyfrowywanie nie powiodło się
|
eventView.entry.decryptionFailed.message=Odszyfrowywanie nie powiodło się
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Pokaż zaszyfrowany plik
|
eventView.entry.decryptionFailed.showEncrypted=Pokaż zaszyfrowany plik
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Kopiuj zaszyfrowaną ścieżkę
|
|
||||||
eventView.entry.brokenDirFile.message=Uszkodzony link do katalogu
|
eventView.entry.brokenDirFile.message=Uszkodzony link do katalogu
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Pokaż uszkodzony, zaszyfrowany link
|
eventView.entry.brokenDirFile.showEncrypted=Pokaż uszkodzony, zaszyfrowany link
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Kopiuj ścieżkę uszkodzonego linku
|
|
||||||
eventView.entry.brokenFileNode.message=Uszkodzony węzeł systemu plików
|
eventView.entry.brokenFileNode.message=Uszkodzony węzeł systemu plików
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Pokaż uszkodzony, zaszyfrowany węzeł
|
eventView.entry.brokenFileNode.showEncrypted=Pokaż uszkodzony, zaszyfrowany węzeł
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Kopiuj ścieżkę uszkodzonego, zaszyfrowanego węzła
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Kopiuj odszyfrowaną ścieżkę
|
eventView.entry.brokenFileNode.copyDecrypted=Kopiuj odszyfrowaną ścieżkę
|
||||||
eventView.entry.inUse.message=Zablokowany plik
|
|
||||||
eventView.entry.inUse.showDecrypted=Pokaż odszyfrowany plik
|
eventView.entry.inUse.showDecrypted=Pokaż odszyfrowany plik
|
||||||
eventView.entry.inUse.copyDecrypted=Kopiuj odszyfrowaną ścieżkę
|
|
||||||
eventView.entry.inUse.showEncrypted=Pokaż zaszyfrowany plik
|
eventView.entry.inUse.showEncrypted=Pokaż zaszyfrowany plik
|
||||||
eventView.entry.inUse.copyEncrypted=Kopiuj zaszyfrowaną ścieżkę
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Kopiowanie blokady użytkownika i nazwy urządzenia
|
eventView.entry.inUse.copyUserAndDevice=Kopiowanie blokady użytkownika i nazwy urządzenia
|
||||||
eventView.entry.inUse.ignoreLock=Ignoruj blokadę
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.action=Ignoruj blokadę
|
|
||||||
@@ -695,33 +695,25 @@ eventView.cell.actionsButton.tooltip=Ações dos eventos
|
|||||||
eventView.entry.vaultLocked.description=Desbloquear "%s" para detalhes
|
eventView.entry.vaultLocked.description=Desbloquear "%s" para detalhes
|
||||||
eventView.entry.conflictResolved.message=Conflito resolvido
|
eventView.entry.conflictResolved.message=Conflito resolvido
|
||||||
eventView.entry.conflictResolved.showDecrypted=Mostrar o ficheiro desencriptado
|
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.message=A resolução do conflito falhou
|
||||||
eventView.entry.conflict.showDecrypted=Mostrar o ficheiro original desencriptado
|
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.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.message=A desencriptação falhou
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Mostrar ficheiro encriptado
|
eventView.entry.decryptionFailed.showEncrypted=Mostrar ficheiro encriptado
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Copiar o caminho encriptado
|
|
||||||
eventView.entry.brokenDirFile.message=Link de diretório quebrado
|
eventView.entry.brokenDirFile.message=Link de diretório quebrado
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Mostrar o 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.message=Nó do sistema de ficheiros avariado
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Mostrar nó encriptado e danificado
|
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 o caminho desencriptado
|
eventView.entry.brokenFileNode.copyDecrypted=Copiar o caminho desencriptado
|
||||||
eventView.entry.inUse.message=Ficheiro bloqueado
|
eventView.entry.inUse.message=Ficheiro em utilização
|
||||||
eventView.entry.inUse.showDecrypted=Mostrar o ficheiro desencriptado
|
eventView.entry.inUse.showDecrypted=Mostrar o ficheiro desencriptado
|
||||||
eventView.entry.inUse.copyDecrypted=Copiar o caminho desencriptado
|
|
||||||
eventView.entry.inUse.showEncrypted=Mostrar ficheiro encriptado
|
eventView.entry.inUse.showEncrypted=Mostrar ficheiro encriptado
|
||||||
eventView.entry.inUse.copyEncrypted=Copiar o caminho encriptado
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Copiar nome do utilizador e dispositivo bloqueado
|
eventView.entry.inUse.copyUserAndDevice=Copiar nome do utilizador e dispositivo bloqueado
|
||||||
eventView.entry.inUse.ignoreLock=Ignorar bloqueio
|
eventView.entry.inUse.ignoreLock=Ignorar estado de utilização
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=O ficheiro está bloqueado por outro dispositivo
|
notification.inUse.message=O ficheiro está em utilização noutro dispositivo
|
||||||
notification.inUse.description=O ficheiro foi aberto por %s no dispositivo %s. Peça ao utilizador para fechar o ficheiro e sincronizar novamente. Caso contrário, pode ignorar o bloqueio e abri-lo na mesma.
|
notification.inUse.description=O ficheiro está aberto por %s em %s. Peça-lhes que fechem o ficheiro e deixem a sincronização terminar. Pode ignorar o estado para o abrir agora, mas isso pode causar conflitos ou sobrescrever alterações mais recentes.
|
||||||
notification.inUse.action=Ignorar bloqueio
|
notification.inUse.action=Ignorar estado de utilização
|
||||||
@@ -27,15 +27,15 @@ vault.state.error=Erro
|
|||||||
|
|
||||||
# Error
|
# Error
|
||||||
error.message=Ocorreu um erro
|
error.message=Ocorreu um erro
|
||||||
error.description=O Cryptomator não esperava que isso acontecesse. Você pode procurar soluções existentes para este erro. Ou, se ainda não foi relatado, sinta-se à vontade para fazê-lo.
|
error.description=O Cryptomator não esperava que isso acontecesse. Você pode buscar soluções existentes para esse erro. Se ainda não o relatou, sinta-se à vontade para fazê-lo.
|
||||||
error.hyperlink.lookup=Procurar este erro
|
error.hyperlink.lookup=Buscar este erro
|
||||||
error.hyperlink.report=Relatar este erro
|
error.hyperlink.report=Relatar este erro
|
||||||
error.technicalDetails=Detalhes:
|
error.technicalDetails=Detalhes:
|
||||||
error.existingSolutionDescription=O Cryptomator encontrou um erro inesperado, mas há uma solução pré-existente disponível no seguinte link.
|
error.existingSolutionDescription=O Cryptomator não esperava que isso acontecesse. Encontramos uma solução existente para esse erro. Acesse o link a seguir.
|
||||||
error.hyperlink.solution=Procure a solução
|
error.hyperlink.solution=Busque a solução
|
||||||
error.lookupPermissionMessage=O Cryptomator pode procurar uma solução para este problema online. Isso enviará uma solicitação para nosso banco de dados de problemas a partir do seu endereço IP.
|
error.lookupPermissionMessage=O Cryptomator pode buscar uma solução para esse problema on-line. Isso enviará uma solicitação para nosso banco de dados de problemas a partir do seu endereço IP.
|
||||||
error.dismiss=Ignorar
|
error.dismiss=Ignorar
|
||||||
error.lookUpSolution=Procurar solução
|
error.lookUpSolution=Buscar solução
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
defaults.vault.vaultName=Cofre
|
defaults.vault.vaultName=Cofre
|
||||||
@@ -66,7 +66,7 @@ addvaultwizard.new.directoryPickerButton=Escolher…
|
|||||||
addvaultwizard.new.directoryPickerTitle=Selecionar diretório
|
addvaultwizard.new.directoryPickerTitle=Selecionar diretório
|
||||||
addvaultwizard.new.fileAlreadyExists=Já existe um arquivo ou diretório com esse nome
|
addvaultwizard.new.fileAlreadyExists=Já existe um arquivo ou diretório com esse nome
|
||||||
addvaultwizard.new.locationDoesNotExist=Um diretório no caminho especificado não existe ou não pode ser acessado
|
addvaultwizard.new.locationDoesNotExist=Um diretório no caminho especificado não existe ou não pode ser acessado
|
||||||
addvaultwizard.new.locationIsNotWritable=Sem acesso de gravação no caminho especificado
|
addvaultwizard.new.locationIsNotWritable=Nenhum acesso de gravação no caminho especificado
|
||||||
addvaultwizard.new.locationIsOk=Local adequado para o seu cofre
|
addvaultwizard.new.locationIsOk=Local adequado para o seu cofre
|
||||||
addvaultwizard.new.invalidName=Nome do cofre inválido
|
addvaultwizard.new.invalidName=Nome do cofre inválido
|
||||||
addvaultwizard.new.validName=Nome do cofre válido
|
addvaultwizard.new.validName=Nome do cofre válido
|
||||||
@@ -82,7 +82,7 @@ addvaultwizard.new.expertSettings.shorteningThreshold.title=Comprimento máximo
|
|||||||
addvaultwizard.new.expertSettings.shorteningThreshold.valid=Válido
|
addvaultwizard.new.expertSettings.shorteningThreshold.valid=Válido
|
||||||
### Password
|
### Password
|
||||||
addvaultwizard.new.createVaultBtn=Criar cofre
|
addvaultwizard.new.createVaultBtn=Criar cofre
|
||||||
addvaultwizard.new.generateRecoveryKeyChoice=Você não será capaz de acessar seus dados sem sua senha. Você quer uma chave de recuperação para o caso de perder sua senha?
|
addvaultwizard.new.generateRecoveryKeyChoice=Você será incapaz de acessar os seus dados sem a sua senha. Deseja uma chave de recuperação para caso perca a sua senha?
|
||||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Sim, por favor. Melhor prevenir do que remediar
|
addvaultwizard.new.generateRecoveryKeyChoice.yes=Sim, por favor. Melhor prevenir do que remediar
|
||||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Não, obrigado. Eu não perderei minha senha
|
addvaultwizard.new.generateRecoveryKeyChoice.no=Não, obrigado. Eu não perderei minha senha
|
||||||
### Information
|
### Information
|
||||||
@@ -100,33 +100,33 @@ addvault.new.readme.storageLocation.10=Se precisar de ajuda, visite a documenta
|
|||||||
addvault.new.readme.accessLocation.fileName=BEM-VINDO(A).rtf
|
addvault.new.readme.accessLocation.fileName=BEM-VINDO(A).rtf
|
||||||
addvault.new.readme.accessLocation.1=🔐️ VOLUME ENCRIPTADO 🔐️
|
addvault.new.readme.accessLocation.1=🔐️ VOLUME ENCRIPTADO 🔐️
|
||||||
addvault.new.readme.accessLocation.2=Este é o local de acesso ao seu cofre.
|
addvault.new.readme.accessLocation.2=Este é o local de acesso ao seu cofre.
|
||||||
addvault.new.readme.accessLocation.3=Todos os arquivos adicionados a este volume serão criptografados de forma transparente pelo Cryptomator. Você pode trabalhar nele como se fosse qualquer unidade/pasta. Esta é apenas uma visão não criptografada do seu conteúdo, mas seus arquivos permanecem criptografados na sua unidade o tempo todo.
|
addvault.new.readme.accessLocation.3=Qualquer arquivo adicionado a este volume será criptografado pelo Cryptomator. Você pode trabalhar nele como em qualquer outro disco ou pasta. Esta é apenas uma visualização descriptografada do conteúdo, seus arquivos permanecem criptografados no seu disco rígido o tempo todo.
|
||||||
addvault.new.readme.accessLocation.4=Fique à vontade para apagar este arquivo.
|
addvault.new.readme.accessLocation.4=Fique à vontade para apagar este arquivo.
|
||||||
## Existing
|
## Existing
|
||||||
addvaultwizard.existing.title=Adicionar cofre existente
|
addvaultwizard.existing.title=Adicionar cofre existente
|
||||||
addvaultwizard.existing.instruction=Escolha o arquivo "vault.cryptomator" do seu cofre existente. Caso exista apenas um arquivo chamado "masterkey.cryptomator", selecione outro.
|
addvaultwizard.existing.instruction=Escolha o arquivo "vault.cryptomator" do seu cofre existente. Caso exista apenas um arquivo chamado "masterkey.cryptomator", selecione outro.
|
||||||
addvaultwizard.existing.restore=Restaurar…
|
addvaultwizard.existing.restore=Restaurar…
|
||||||
addvaultwizard.existing.chooseBtn=Selecionar…
|
addvaultwizard.existing.chooseBtn=Escolher…
|
||||||
addvaultwizard.existing.filePickerTitle=Selecionar arquivo do Cofre
|
addvaultwizard.existing.filePickerTitle=Selecionar arquivo do cofre
|
||||||
addvaultwizard.existing.filePickerMimeDesc=Cofre Cryptomator
|
addvaultwizard.existing.filePickerMimeDesc=Cofre Cryptomator
|
||||||
## Success
|
## Success
|
||||||
addvaultwizard.success.nextStepsInstructions=Cofre "%s" adicionado.\nVocê precisa desbloquear este cofre para acessar ou adicionar conteúdo. Você também pode desbloqueá-lo a qualquer momento.
|
addvaultwizard.success.nextStepsInstructions=Cofre "%s" adicionado.\nVocê precisa desbloqueá-lo para acessar ou adicionar conteúdo. O desbloqueio dele pode ser feito a qualquer momento.
|
||||||
addvaultwizard.success.unlockNow=Desbloquear agora
|
addvaultwizard.success.unlockNow=Desbloquear agora
|
||||||
|
|
||||||
# Remove Vault
|
# Remove Vault
|
||||||
removeVault.title=Remover o cofre "%s"
|
removeVault.title=Remover o cofre "%s"
|
||||||
removeVault.message=Remover o cofre?
|
removeVault.message=Remover o cofre?
|
||||||
removeVault.description=Isso só fará com que o Cryptomator esqueça esse cofre. Você pode adicioná-lo novamente. Nenhum arquivo criptografado será excluído do seu disco rígido.
|
removeVault.description=Isto só fará com que o Cryptomator esqueça este cofre. Você pode adicioná-lo novamente. Nenhum arquivo criptografado será apagado do seu disco rígido.
|
||||||
|
|
||||||
# Change Password
|
# Change Password
|
||||||
changepassword.title=Alterar senha
|
changepassword.title=Alterar senha
|
||||||
changepassword.enterOldPassword=Digite a senha atual para o cofre "%s"
|
changepassword.enterOldPassword=Digite a senha atual para o cofre "%s"
|
||||||
changepassword.finalConfirmation=Eu entendo que não poderei acessar os meus dados caso esqueça a minha senha
|
changepassword.finalConfirmation=Estou ciente que não conseguirei acessar os meus dados caso esqueça a minha senha
|
||||||
|
|
||||||
# Forget Password
|
# Forget Password
|
||||||
forgetPassword.title=Esqueci a senha
|
forgetPassword.title=Esqueci a senha
|
||||||
forgetPassword.message=Esqueceu sua senha?
|
forgetPassword.message=Esqueceu sua senha?
|
||||||
forgetPassword.description=Isso excluirá a senha que você salvou deste cofre, do chaveiro de senhas do sistema.
|
forgetPassword.description=Isto apagará a senha salva deste cofre do chaveiro do seu sistema.
|
||||||
forgetPassword.confirmBtn=Esqueci a senha
|
forgetPassword.confirmBtn=Esqueci a senha
|
||||||
|
|
||||||
# Unlock
|
# Unlock
|
||||||
@@ -137,28 +137,29 @@ unlock.unlockBtn=Desbloquear
|
|||||||
## Select
|
## Select
|
||||||
unlock.chooseMasterkey.message=O arquivo Masterkey foi não encontrado
|
unlock.chooseMasterkey.message=O arquivo Masterkey foi não encontrado
|
||||||
unlock.chooseMasterkey.description=Não foi possível encontrar o arquivo masterkey para o cofre "%s". Selecione manualmente o arquivo contendo a chave.
|
unlock.chooseMasterkey.description=Não foi possível encontrar o arquivo masterkey para o cofre "%s". Selecione manualmente o arquivo contendo a chave.
|
||||||
|
unlock.chooseMasterkey.restoreInstead=Em vez disso, restaure o arquivo masterkey
|
||||||
unlock.chooseMasterkey.filePickerTitle=Selecione o arquivo Masterkey
|
unlock.chooseMasterkey.filePickerTitle=Selecione o arquivo Masterkey
|
||||||
unlock.chooseMasterkey.filePickerMimeDesc=Masterkey do Cryptomator
|
unlock.chooseMasterkey.filePickerMimeDesc=Masterkey do Cryptomator
|
||||||
## Success
|
## Success
|
||||||
unlock.success.message=Desbloqueado com sucesso
|
unlock.success.message=Desbloqueado com sucesso
|
||||||
unlock.success.description="%s" desbloqueado com êxito! Seu cofre agora está acessível na unidade virtual.
|
unlock.success.description=O conteúdo no cofre "%s" agora está acessível no seu ponto de montagem.
|
||||||
unlock.success.rememberChoice=Lembrar opção escolhida, não mostrar isto novamente
|
unlock.success.rememberChoice=Lembrar opção escolhida. Não perguntar novamente
|
||||||
unlock.success.revealBtn=Revelar volume
|
unlock.success.revealBtn=Revelar volume
|
||||||
## Failure
|
## Failure
|
||||||
unlock.error.customPath.message=Não foi possível iniciar o cofre no caminho personalizado
|
unlock.error.customPath.message=Não foi possível iniciar o cofre no caminho personalizado
|
||||||
unlock.error.customPath.description.notSupported=Se você deseja continuar usando o caminho personalizado, por favor vá para as preferências e selecione um tipo de volume que o suporte. Caso contrário, vá para as opções de cofre e escolha um ponto de montagem suportado.
|
unlock.error.customPath.description.notSupported=Se você deseja continuar usando o caminho personalizado, acesse as preferências e selecione um tipo de volume que seja compatível. Caso contrário, vá para as opções do cofre e escolha um ponto de montagem suportado.
|
||||||
unlock.error.customPath.description.notExists=O caminho de montagem personalizado não existe. Crie o caminho em seu sistema de arquivos local, ou o altere nas opções de cofre.
|
unlock.error.customPath.description.notExists=O caminho de montagem personalizado não existe. Crie o caminho em seu sistema de arquivos local ou o altere nas opções do cofre.
|
||||||
unlock.error.customPath.description.inUse=A letra da unidade ou o caminho de montagem "%s" já está em uso.
|
unlock.error.customPath.description.inUse=A letra de unidade ou o caminho de montagem "%s" já está em uso.
|
||||||
unlock.error.customPath.description.hideawayNotDir=O arquivo oculto e temporário "%3$s" usado para desbloquear não pôde ser removido. Exclua-o manualmente.
|
unlock.error.customPath.description.hideawayNotDir=Não foi possível remover o arquivo oculto e temporário "%3$s". Verifique-o e depois apague ele manualmente.
|
||||||
unlock.error.customPath.description.couldNotBeCleaned=Seu cofre não pôde ser montado no caminho "%s". Tente novamente ou escolha um caminho diferente.
|
unlock.error.customPath.description.couldNotBeCleaned=Não foi possível montar seu cofre no caminho "%s". Tente novamente ou escolha um caminho diferente.
|
||||||
unlock.error.customPath.description.notEmptyDir=O caminho de montagem escolhido "%s" não é uma pasta vazia. Escolha uma pasta vazia e tente novamente.
|
unlock.error.customPath.description.notEmptyDir=O caminho de montagem personalizado escolhido "%s" não é uma pasta vazia. Escolha uma pasta vazia e tente novamente.
|
||||||
unlock.error.customPath.description.generic=Você selecionou um caminho de montagem personalizado para este cofre, mas falhou com a mensagem: %2$s
|
unlock.error.customPath.description.generic=Você selecionou um caminho de montagem personalizado para este cofre, mas falhou com a mensagem: %2$s
|
||||||
unlock.error.restartRequired.message=Não foi possível desbloquear o cofre
|
unlock.error.restartRequired.message=Não foi possível desbloquear o cofre
|
||||||
unlock.error.restartRequired.description=Altere o tipo de volume nas opções do cofre ou reinicie o Cryptomator.
|
unlock.error.restartRequired.description=Altere o tipo de volume nas opções do cofre ou reinicie o Cryptomator.
|
||||||
unlock.error.title=Falha ao desbloquear "%s"
|
unlock.error.title=Falha ao desbloquear "%s"
|
||||||
## Hub
|
## Hub
|
||||||
hub.noKeychain.message=Não foi possível acessar a chave do dispositivo
|
hub.noKeychain.message=Não foi possível acessar a chave do dispositivo
|
||||||
hub.noKeychain.description=Para desbloquear os cofres centrais, é necessário a chave do dispositivo, protegida por um chaveiro. Para proceder, ative "%s" e selecione um chaveiro nas preferências.
|
hub.noKeychain.description=Para desbloquear os cofres do Hub, você precisa de uma chave do dispositivo que fica protegida usando um chaveiro. Para continuar, ative "%s" e escolha um chaveiro nas preferências.
|
||||||
hub.noKeychain.openBtn=Abrir preferências
|
hub.noKeychain.openBtn=Abrir preferências
|
||||||
### Waiting
|
### Waiting
|
||||||
hub.auth.message=Aguardando autenticação…
|
hub.auth.message=Aguardando autenticação…
|
||||||
@@ -166,34 +167,34 @@ hub.auth.description=Você será redirecionado automaticamente para a página de
|
|||||||
hub.auth.loginLink=Não foi redirecionado? Clique aqui para abrir.
|
hub.auth.loginLink=Não foi redirecionado? Clique aqui para abrir.
|
||||||
### Receive Key
|
### Receive Key
|
||||||
hub.receive.message=Processando resposta…
|
hub.receive.message=Processando resposta…
|
||||||
hub.receive.description=Cryptomator está recebendo e processando a resposta do Hub. Por favor, aguarde.
|
hub.receive.description=O Cryptomator está recebendo e processando a resposta do Hub. Aguarde.
|
||||||
### Register Device
|
### Register Device
|
||||||
hub.register.message=Novo dispositivo
|
hub.register.message=Novo dispositivo
|
||||||
hub.register.description=Este é o primeiro acesso do Hub neste dispositivo. Por favor, registre-o usando sua Chave de Conta.
|
hub.register.description=Este é o primeiro acesso do Hub neste dispositivo. Registre-o usando sua Chave de Conta.
|
||||||
hub.register.nameLabel=Nome do dispositivo
|
hub.register.nameLabel=Nome do dispositivo
|
||||||
hub.register.invalidAccountKeyLabel=Chave da conta inválida
|
hub.register.invalidAccountKeyLabel=Chave da conta inválida
|
||||||
hub.register.registerBtn=Registrar
|
hub.register.registerBtn=Registrar
|
||||||
### Register Device Legacy
|
### Register Device Legacy
|
||||||
hub.register.legacy.occupiedMsg=Esse nome já está em uso
|
hub.register.legacy.occupiedMsg=Esse nome já está em uso
|
||||||
hub.register.legacy.description=Este é o primeiro acesso do Hub neste dispositivo. Por favor, registre-o.
|
hub.register.legacy.description=Este é o primeiro acesso do Hub neste dispositivo. Registre-o.
|
||||||
### Registration Success
|
### Registration Success
|
||||||
hub.registerSuccess.message=Dispositivo registrado
|
hub.registerSuccess.message=Dispositivo registrado
|
||||||
hub.registerSuccess.description=Seu dispositivo foi registrado com sucesso. Agora você pode continuar a desbloquear o cofre.
|
hub.registerSuccess.description=Seu dispositivo foi registrado com sucesso. Prossiga com o desbloqueio do cofre.
|
||||||
hub.registerSuccess.unlockBtn=Desbloquear
|
hub.registerSuccess.unlockBtn=Desbloquear
|
||||||
hub.registerSuccess.legacy.description=Para acessar o cofre, seu dispositivo precisa ser autorizado pelo proprietário do cofre.
|
hub.registerSuccess.legacy.description=Para acessar o cofre, seu dispositivo precisa ser autorizado pelo proprietário do cofre.
|
||||||
### Registration Failed
|
### Registration Failed
|
||||||
hub.registerFailed.message=Falha ao registrar o dispositivo
|
hub.registerFailed.message=Falha ao registrar o dispositivo
|
||||||
hub.registerFailed.description.generic=Um erro ocorreu no processo de registro. Para mais detalhes, verifique o log da aplicação.
|
hub.registerFailed.description.generic=Ocorreu um erro no processo de registro. Para mais detalhes, verifique o registro da aplicação.
|
||||||
hub.registerFailed.description.deviceAlreadyExists=Este dispositivo já está registrado para um usuário diferente. Tente alterar a conta de usuário ou use um dispositivo diferente.
|
hub.registerFailed.description.deviceAlreadyExists=Este dispositivo já está registrado para um usuário diferente. Tente alterar a conta de usuário ou use outro dispositivo.
|
||||||
### Archived
|
### Archived
|
||||||
hub.archived.message=Cofre arquivado
|
hub.archived.message=Cofre arquivado
|
||||||
hub.archived.description=Este cofre foi arquivo e está inacessível. Contate o proprietário dele.
|
hub.archived.description=Este cofre foi arquivo e está inacessível. Contate o proprietário dele.
|
||||||
### Unauthorized
|
### Unauthorized
|
||||||
hub.unauthorized.message=Acesso negado
|
hub.unauthorized.message=Acesso negado
|
||||||
hub.unauthorized.description=Você não está autorizado a abrir este cofre. Entre em contato com o proprietário do cofre para solicitar acesso.
|
hub.unauthorized.description=Você não tem autorização para abrir este cofre. Entre em contato com o proprietário dele para solicitar acesso.
|
||||||
### Requires Account Initialization
|
### Requires Account Initialization
|
||||||
hub.requireAccountInit.message=Ação necessária
|
hub.requireAccountInit.message=Ação necessária
|
||||||
hub.requireAccountInit.description.0=Para prosseguir, por favor, complete os passos necessários
|
hub.requireAccountInit.description.0=Para prosseguir, complete as etapas obrigatórias no seu
|
||||||
hub.requireAccountInit.description.1=Perfil de usuário do Hub
|
hub.requireAccountInit.description.1=Perfil de usuário do Hub
|
||||||
hub.requireAccountInit.description.2=.
|
hub.requireAccountInit.description.2=.
|
||||||
### License Exceeded
|
### License Exceeded
|
||||||
@@ -203,65 +204,65 @@ hub.invalidLicense.description=Sua instância do Cryptomator Hub tem uma licenç
|
|||||||
# Lock
|
# Lock
|
||||||
## Force
|
## Force
|
||||||
lock.forced.message=Bloqueio falhou
|
lock.forced.message=Bloqueio falhou
|
||||||
lock.forced.description=Trancar "%s" foi bloqueado por operações pendentes ou arquivos abertos. Você pode forçar o bloqueio deste cofre, no entanto, a interrupção pode resultar em perda de dados não salvos.
|
lock.forced.description=O fechamento do cofre "%s" foi impedido por arquivos abertos ou tarefas em andamento. Você pode forçar o fechamento, mas interromper a gravação de dados pode causar a perda de arquivos não salvos.
|
||||||
lock.forced.retryBtn=Tentar novamente
|
lock.forced.retryBtn=Tentar novamente
|
||||||
lock.forced.forceBtn=Forçar bloqueio
|
lock.forced.forceBtn=Forçar bloqueio
|
||||||
## Failure
|
## Failure
|
||||||
lock.fail.message=O bloqueio do cofre falhou.
|
lock.fail.message=O bloqueio do cofre falhou.
|
||||||
lock.fail.description=Cofre "%s" não pôde ser bloqueado. Certifique-se de que o trabalho não salvo está salvo em outro lugar e que operações de Leitura/Escrita importantes sejam concluídas. Para fechar o cofre, encerre o processo do Cryptomator.
|
lock.fail.description=Não foi possível bloquear o cofre "%s". Certifique-se de que o trabalho não salvo foi armazenado em outro local e que as operações importantes de leitura/gravação foram concluídas. Para fechar o cofre, encerre o processo do Cryptomator.
|
||||||
|
|
||||||
# Migration
|
# Migration
|
||||||
migration.title=Atualizar cofre
|
migration.title=Atualizar cofre
|
||||||
## Start
|
## Start
|
||||||
migration.start.header=Atualizar cofre
|
migration.start.header=Atualizar cofre
|
||||||
migration.start.text=Para abrir o seu cofre "%s" nesta nova versão do Cryptomator, o cofre precisa ser atualizado para um formato mais recente. Antes de fazer isso, você deve saber o seguinte:
|
migration.start.text=Para abrir seu cofre "%s" nesta nova versão do Cryptomator, o cofre precisa ser atualizado para um formato mais recente. Antes de realizar esse procedimento, esteja ciente do seguinte:
|
||||||
migration.start.remarkUndone=Esta melhoria não pode ser desfeita.
|
migration.start.remarkUndone=Esta melhoria não pode ser desfeita.
|
||||||
migration.start.remarkVersions=Versões mais antigas do Cryptomator não conseguirão abrir o cofre na versão atualizada.
|
migration.start.remarkVersions=Versões mais antigas do Cryptomator não conseguirão abrir o cofre na versão atualizada.
|
||||||
migration.start.remarkCanRun=Você deve ter certeza de que todos os dispositivos a partir dos quais você acessar o cofre podem executar esta versão do Cryptomator.
|
migration.start.remarkCanRun=Garanta que todos os dispositivos que você usa para acessar o cofre consigam executar esta versão do Cryptomator.
|
||||||
migration.start.remarkSynced=Você deve ter certeza de que o seu cofre está totalmente sincronizado neste dispositivo e em outros dispositivos, antes de atualizá-lo.
|
migration.start.remarkSynced=Antes de atualizá-lo, tenha certeza de que seu cofre está totalmente sincronizado neste e em outros dispositivos.
|
||||||
migration.start.confirm=Eu li e entendi a informação acima
|
migration.start.confirm=Li e estou ciente das informações acima
|
||||||
## Run
|
## Run
|
||||||
migration.run.enterPassword=Digite a senha para "%s"
|
migration.run.enterPassword=Digite a senha para "%s"
|
||||||
migration.run.startMigrationBtn=Migrar cofre
|
migration.run.startMigrationBtn=Migrar cofre
|
||||||
migration.run.progressHint=Isso pode levar algum tempo…
|
migration.run.progressHint=Isso pode levar algum tempo…
|
||||||
## Success
|
## Success
|
||||||
migration.success.nextStepsInstructions="%s" migrado com sucesso.\nVocê agora pode desbloquear este cofre.
|
migration.success.nextStepsInstructions="%s" migrado com sucesso.\nAgora você pode desbloquear este cofre.
|
||||||
migration.success.unlockNow=Desbloquear agora
|
migration.success.unlockNow=Desbloquear agora
|
||||||
## Missing file system capabilities
|
## Missing file system capabilities
|
||||||
migration.error.missingFileSystemCapabilities.title=Sistema de arquivos incompatível
|
migration.error.missingFileSystemCapabilities.title=Sistema de arquivos incompatível
|
||||||
migration.error.missingFileSystemCapabilities.description=A migração não foi iniciada porque o seu cofre está localizado em um sistema de arquivos inadequado.
|
migration.error.missingFileSystemCapabilities.description=A migração não foi iniciada porque o seu cofre está localizado em um sistema de arquivos inadequado.
|
||||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=O sistema de arquivos não suporta arquivos com nome longo.
|
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=O sistema de arquivos não suporta arquivos com nomes longos.
|
||||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=O sistema de arquivos não suporta caminhos longos.
|
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=O sistema de arquivos não suporta caminhos longos.
|
||||||
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=O sistema de arquivos não permite leitura.
|
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=O sistema de arquivos não permite leitura.
|
||||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=O sistema de arquivos não permite ser gravado.
|
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=O sistema de arquivos não permite ser gravado.
|
||||||
## Impossible
|
## Impossible
|
||||||
migration.impossible.heading=Não é possível migrar o cofre
|
migration.impossible.heading=Não é possível migrar o cofre
|
||||||
migration.impossible.reason=O cofre não pode ser migrado automaticamente porque sua localização de armazenamento ou o ponto de acesso não é compatível.
|
migration.impossible.reason=O cofre não pode ser migrado automaticamente porque sua localização de armazenamento ou o ponto de acesso é incompatível.
|
||||||
migration.impossible.moreInfo=O cofre ainda pode ser aberto com uma versão mais antiga. Para instruções sobre como migrar um cofre manualmente, visite
|
migration.impossible.moreInfo=O cofre ainda pode ser aberto com uma versão mais antiga. Para instruções sobre como migrar um cofre manualmente, visite
|
||||||
|
|
||||||
# Health Check
|
# Health Check
|
||||||
## Start
|
## Start
|
||||||
health.title=Verificação de saúde de "%s"
|
health.title=Verificação de saúde de "%s"
|
||||||
health.intro.header=Verificação de Saúde
|
health.intro.header=Verificação de Saúde
|
||||||
health.intro.text=A Verificação de Saúde é um grupo de verificações que detectam e tentam corrigir problemas na estrutura interna do cofre. Lembre-se de:
|
health.intro.text=A verificação de saúde é um grupo de verificações que detectam e tentam corrigir problemas na estrutura interna do cofre. Lembre-se de:
|
||||||
health.intro.remarkSync=Certifique-se de que todos os dispositivos estejam completamente sincronizados, isso resolve a maioria dos problemas.
|
health.intro.remarkSync=Certifique-se de que todos os dispositivos estejam completamente sincronizados. Isso resolve a maioria dos problemas.
|
||||||
health.intro.remarkFix=Nem todos os problemas podem ser corrigidos.
|
health.intro.remarkFix=A maioria dos problema podem ser corrigidos.
|
||||||
health.intro.remarkBackup=Se os dados estiverem corrompidos, apenas um backup poderá ajudar.
|
health.intro.remarkBackup=Caso os dados corrompam, apenas um backup poderá ajudar.
|
||||||
health.intro.affirmation=Eu li e entendi a informação acima
|
health.intro.affirmation=Li e estou ciente das informações acima
|
||||||
## Start Failure
|
## Start Failure
|
||||||
health.fail.header=Erro ao carregar configuração do Cofre
|
health.fail.header=Erro ao carregar a configuração do cofre
|
||||||
health.fail.ioError=Ocorreu um erro ao acessar e ler o arquivo de configuração.
|
health.fail.ioError=Ocorreu um erro ao acessar e ler o arquivo de configuração.
|
||||||
health.fail.parseError=Ocorreu um erro ao analisar a configuração do cofre.
|
health.fail.parseError=Ocorreu um erro ao analisar a configuração do cofre.
|
||||||
health.fail.moreInfo=Mais informações
|
health.fail.moreInfo=Mais informações
|
||||||
## Check Selection
|
## Check Selection
|
||||||
health.checkList.description=Selecione as verificações na lista esquerda ou use os botões abaixo.
|
health.checkList.description=Selecione as verificações na lista à esquerda ou use os botões abaixo.
|
||||||
health.checkList.selectAllButton=Selecionar todas as verificações
|
health.checkList.selectAllButton=Selecionar todas as verificações
|
||||||
health.checkList.deselectAllButton=Desmarcar todas as verificações
|
health.checkList.deselectAllButton=Desmarcar todas as verificações
|
||||||
health.check.runBatchBtn=Executar Verificações
|
health.check.runBatchBtn=Executar verificações selecionadas
|
||||||
## Detail view
|
## Detail view
|
||||||
health.check.detail.noSelectedCheck=Para ver os resultados, selecione uma verificação na lista à esquerda.
|
health.check.detail.noSelectedCheck=Para ver os resultados, selecione uma verificação de saúde na lista à esquerda.
|
||||||
health.check.detail.checkScheduled=A verificação está programada.
|
health.check.detail.checkScheduled=A verificação está programada.
|
||||||
health.check.detail.checkRunning=A verificação está rodando…
|
health.check.detail.checkRunning=A verificação está em execução…
|
||||||
health.check.detail.checkSkipped=A verificação não foi selecionada para execução.
|
health.check.detail.checkSkipped=A verificação não foi selecionada para execução.
|
||||||
health.check.detail.checkFinished=A verificação terminou com sucesso.
|
health.check.detail.checkFinished=A verificação terminou com sucesso.
|
||||||
health.check.detail.checkFinishedAndFound=A verificação terminou. Verifique os resultados.
|
health.check.detail.checkFinishedAndFound=A verificação terminou. Verifique os resultados.
|
||||||
@@ -270,21 +271,21 @@ health.check.detail.checkCancelled=A verificação foi cancelada.
|
|||||||
health.check.detail.listFilters.label=Filtro
|
health.check.detail.listFilters.label=Filtro
|
||||||
health.check.detail.filterSeverity=Filtrar por severidade
|
health.check.detail.filterSeverity=Filtrar por severidade
|
||||||
health.check.detail.filterFixState=Filtrar por estado de correção
|
health.check.detail.filterFixState=Filtrar por estado de correção
|
||||||
health.check.detail.fixAllSpecificBtn=Reparar todos deste tipo
|
health.check.detail.fixAllSpecificBtn=Corrigir todos deste tipo
|
||||||
health.check.exportBtn=Exportar Relatório
|
health.check.exportBtn=Exportar relatório
|
||||||
## Result view
|
## Result view
|
||||||
health.result.severityFilter.all=Gravidade - Todas
|
health.result.severityFilter.all=Gravidade — Todas
|
||||||
health.result.severityFilter.good=Bom
|
health.result.severityFilter.good=Boa
|
||||||
health.result.severityFilter.info=Informação
|
health.result.severityFilter.info=Informação
|
||||||
health.result.severityFilter.warn=Aviso
|
health.result.severityFilter.warn=Alerta
|
||||||
health.result.severityFilter.crit=Crítico
|
health.result.severityFilter.crit=Crítica
|
||||||
health.result.severityTip.good=Severidade: Boa\nEstrutura do cofre normal.
|
health.result.severityTip.good=Severidade: Boa\nEstrutura do cofre normal.
|
||||||
health.result.severityTip.info=Gravidade: Info\nEstrutura de cofre intacta, correção sugerida.
|
health.result.severityTip.info=Gravidade: Informação\nEstrutura de cofre intacta. Recomenda-se correção.
|
||||||
health.result.severityTip.warn=Gravidade: Aviso\nEstrutura de cofre corrompida, correção altamente aconselhada.
|
health.result.severityTip.warn=Gravidade: Alerta\nEstrutura de cofre corrompida. É altamente recomendado realizar a correção.
|
||||||
health.result.severityTip.crit=Gravidade: Crítica\nEstrutura do cofre corrompida, haverá perda de dados.
|
health.result.severityTip.crit=Gravidade: Crítica\nEstrutura do cofre corrompida. Os dados poderão ser perdidos.
|
||||||
health.result.fixStateFilter.all=Estado de reparo - Todos
|
health.result.fixStateFilter.all=Estado de reparo — Todos
|
||||||
health.result.fixStateFilter.fixable=Reparável
|
health.result.fixStateFilter.fixable=Corrigível
|
||||||
health.result.fixStateFilter.notFixable=Não reparável
|
health.result.fixStateFilter.notFixable=Incorrigível
|
||||||
health.result.fixStateFilter.fixing=Corrigindo…
|
health.result.fixStateFilter.fixing=Corrigindo…
|
||||||
health.result.fixStateFilter.fixed=Corrigido
|
health.result.fixStateFilter.fixed=Corrigido
|
||||||
health.result.fixStateFilter.fixFailed=Correção falhou
|
health.result.fixStateFilter.fixFailed=Correção falhou
|
||||||
@@ -301,13 +302,13 @@ preferences.general.startHidden=Ocultar janela ao iniciar o Cryptomator
|
|||||||
preferences.general.autoCloseVaults=Bloquear cofres sem perguntar ao sair do aplicativo
|
preferences.general.autoCloseVaults=Bloquear cofres sem perguntar ao sair do aplicativo
|
||||||
preferences.general.debugLogging=Ativar registro de depuração
|
preferences.general.debugLogging=Ativar registro de depuração
|
||||||
preferences.general.debugDirectory=Mostrar arquivos de registro
|
preferences.general.debugDirectory=Mostrar arquivos de registro
|
||||||
preferences.general.autoStart=Iniciar o Cryptomator ao inicializar o sistema
|
preferences.general.autoStart=Iniciar o Cryptomator com o sistema
|
||||||
preferences.general.keychainBackend=Armazenar senhas com
|
preferences.general.keychainBackend=Armazenar senhas com
|
||||||
preferences.general.quickAccessService=Adicione cofres desbloqueados à área de acesso rápido
|
preferences.general.quickAccessService=Adicione cofres desbloqueados à área de acesso rápido
|
||||||
## Interface
|
## Interface
|
||||||
preferences.interface=Interface
|
preferences.interface=Interface
|
||||||
preferences.interface.theme=Aparência
|
preferences.interface.theme=Aparência
|
||||||
preferences.interface.theme.automatic=Automático
|
preferences.interface.theme.automatic=Automática
|
||||||
preferences.interface.theme.dark=Escura
|
preferences.interface.theme.dark=Escura
|
||||||
preferences.interface.theme.light=Clara
|
preferences.interface.theme.light=Clara
|
||||||
preferences.interface.unlockThemes=Desbloquear o modo escuro
|
preferences.interface.unlockThemes=Desbloquear o modo escuro
|
||||||
@@ -317,35 +318,35 @@ preferences.interface.interfaceOrientation=Orientação da interface
|
|||||||
preferences.interface.interfaceOrientation.ltr=Da esquerda para a direita
|
preferences.interface.interfaceOrientation.ltr=Da esquerda para a direita
|
||||||
preferences.interface.interfaceOrientation.rtl=Da direita para a esquerda
|
preferences.interface.interfaceOrientation.rtl=Da direita para a esquerda
|
||||||
preferences.interface.showTrayIcon=Mostrar ícone na barra do sistema (requer reinicialização)
|
preferences.interface.showTrayIcon=Mostrar ícone na barra do sistema (requer reinicialização)
|
||||||
preferences.interface.compactMode=Habilitar lista de cofres compactos
|
preferences.interface.compactMode=Ativar lista de cofres compacta
|
||||||
## Volume
|
## Volume
|
||||||
preferences.volume=Volume Virtual
|
preferences.volume=Volume virtual
|
||||||
preferences.volume.type=Tipo de volume padrão
|
preferences.volume.type=Tipo de volume padrão
|
||||||
preferences.volume.type.automatic=Automático
|
preferences.volume.type.automatic=Automático
|
||||||
preferences.volume.docsTooltip=Abra a documentação para saber mais sobre os diferentes tipos de volumes.
|
preferences.volume.docsTooltip=Acesse a documentação para saber mais sobre os diferentes tipos de volumes.
|
||||||
preferences.volume.fuseRestartRequired=Para aplicar as mudanças, o Cryptomator precisa ser reiniciado.
|
preferences.volume.fuseRestartRequired=Para aplicar as alterações, o Cryptomator precisa ser reiniciado.
|
||||||
preferences.volume.tcp.port=Porta TCP Padrão
|
preferences.volume.tcp.port=Porta TCP padrão
|
||||||
preferences.volume.supportedFeatures=O tipo de volume escolhido suporta os seguintes recursos:
|
preferences.volume.supportedFeatures=O tipo de volume escolhido suporta os seguintes recursos:
|
||||||
preferences.volume.feature.mountAuto=Seleção automática de ponto de montagem
|
preferences.volume.feature.mountAuto=Seleção automática de ponto de montagem
|
||||||
preferences.volume.feature.mountToDir=Diretório personalizado como ponto de montagem
|
preferences.volume.feature.mountToDir=Diretório personalizado como ponto de montagem
|
||||||
preferences.volume.feature.mountToDriveLetter=Cartaz como ponto de montagem
|
preferences.volume.feature.mountToDriveLetter=Letra de unidade como ponto de montagem
|
||||||
preferences.volume.feature.mountFlags=Opções customizadas
|
preferences.volume.feature.mountFlags=Opções personalizadas de montagem
|
||||||
preferences.volume.feature.readOnly=Montaria somente leitura
|
preferences.volume.feature.readOnly=Montagem de somente leitura
|
||||||
## Updates
|
## Updates
|
||||||
preferences.updates=Atualizações
|
preferences.updates=Atualizações
|
||||||
preferences.updates.currentVersion=Versão atual: %s
|
preferences.updates.currentVersion=Versão atual: %s
|
||||||
preferences.updates.autoUpdateCheck=Buscar atualizações automaticamente
|
preferences.updates.autoUpdateCheck=Buscar atualizações automaticamente
|
||||||
preferences.updates.checkNowBtn=Buscar Agora
|
preferences.updates.checkNowBtn=Verificar agora
|
||||||
preferences.updates.updateAvailable=Atualizar para versão %s disponível.
|
preferences.updates.updateAvailable=Atualizar para versão %s disponível.
|
||||||
preferences.updates.lastUpdateCheck=Última verificação: %s
|
preferences.updates.lastUpdateCheck=Última verificação: %s
|
||||||
preferences.updates.lastUpdateCheck.never=nunca
|
preferences.updates.lastUpdateCheck.never=nunca
|
||||||
preferences.updates.lastUpdateCheck.recently=recentemente
|
preferences.updates.lastUpdateCheck.recently=recentemente
|
||||||
preferences.updates.lastUpdateCheck.daysAgo=%s dia atrás
|
preferences.updates.lastUpdateCheck.daysAgo=Há %s dias
|
||||||
preferences.updates.lastUpdateCheck.hoursAgo=%s horas atrás
|
preferences.updates.lastUpdateCheck.hoursAgo=Há %s horas
|
||||||
preferences.updates.prohibitedDueToUnlockedVaults.1=Por favor
|
preferences.updates.prohibitedDueToUnlockedVaults.1=Por favor
|
||||||
preferences.updates.prohibitedDueToUnlockedVaults.2=bloqueie seus cofres
|
preferences.updates.prohibitedDueToUnlockedVaults.2=bloqueie seus cofres
|
||||||
preferences.updates.prohibitedDueToUnlockedVaults.3=para instalar a atualização.
|
preferences.updates.prohibitedDueToUnlockedVaults.3=para instalar a atualização.
|
||||||
preferences.updates.checkFailed=Procura por atualizações falhou. Por favor, verifique sua conexão com a internet ou tente novamente mais tarde.
|
preferences.updates.checkFailed=A busca por atualizações falhou. Verifique sua conexão à rede ou tente novamente mais tarde.
|
||||||
preferences.updates.updateFailed=Falha na atualização. Instale-a manualmente.
|
preferences.updates.updateFailed=Falha na atualização. Instale-a manualmente.
|
||||||
preferences.updates.upToDate=O Cryptomator está atualizado.
|
preferences.updates.upToDate=O Cryptomator está atualizado.
|
||||||
preferences.updates.visitDownloadPage=Visite a página de download
|
preferences.updates.visitDownloadPage=Visite a página de download
|
||||||
@@ -354,16 +355,16 @@ preferences.updates.visitDownloadPage=Visite a página de download
|
|||||||
preferences.contribute=Apoie-nos
|
preferences.contribute=Apoie-nos
|
||||||
preferences.contribute.registeredFor=Certificado de apoiador registrado para %s
|
preferences.contribute.registeredFor=Certificado de apoiador registrado para %s
|
||||||
preferences.contribute.noCertificate=Apoie o Cryptomator e receba um certificado de apoiador. Ele é como uma chave de licença para pessoas maravilhosas que usam software livre. ;-)
|
preferences.contribute.noCertificate=Apoie o Cryptomator e receba um certificado de apoiador. Ele é como uma chave de licença para pessoas maravilhosas que usam software livre. ;-)
|
||||||
preferences.contribute.getCertificate=Não tem um ainda? Saiba como obtê-lo.
|
preferences.contribute.getCertificate=Ainda não tem um? Saiba como obtê-lo.
|
||||||
preferences.contribute.promptText=Cole o código do certificado de apoiador aqui
|
preferences.contribute.promptText=Cole o código do certificado de apoiador aqui
|
||||||
preferences.contribute.thankYou=Obrigado por apoiar o desenvolvimento open-source do Cryptomator!
|
preferences.contribute.thankYou=Obrigado por apoiar o desenvolvimento de código aberto do Cryptomator!
|
||||||
preferences.contribute.donate=Doar
|
preferences.contribute.donate=Doar
|
||||||
preferences.contribute.sponsor=Patrocinador
|
preferences.contribute.sponsor=Apoiador
|
||||||
preferences.contribute.removeCert.tooltip=Remover certificado
|
preferences.contribute.removeCert.tooltip=Remover certificado
|
||||||
|
|
||||||
### Remove License Key Dialog
|
### Remove License Key Dialog
|
||||||
removeCert.title=Excluir Certificado
|
removeCert.title=Remover certificado
|
||||||
removeCert.message=Excluir certificado de apoiador?
|
removeCert.message=Remover o certificado de apoiador?
|
||||||
removeCert.description=Os principais recursos do Cryptomador não são afetados por isso. Nem o acesso aos seus cofres é restrito, nem o nível de segurança é reduzido.
|
removeCert.description=Os principais recursos do Cryptomador não são afetados por isso. Nem o acesso aos seus cofres é restrito, nem o nível de segurança é reduzido.
|
||||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||||
|
|
||||||
@@ -373,13 +374,13 @@ preferences.about.thirdPartyLicenses=Licenças de terceiros
|
|||||||
|
|
||||||
# Vault Statistics
|
# Vault Statistics
|
||||||
stats.title=Estatísticas para %s
|
stats.title=Estatísticas para %s
|
||||||
stats.cacheHitRate=Taxa de Utilização do Cache
|
stats.cacheHitRate=Taxa de uso do cache
|
||||||
## Read
|
## Read
|
||||||
stats.read.throughput.idle=Leitura: ociosa
|
stats.read.throughput.idle=Leitura: ociosa
|
||||||
stats.read.throughput.kibs=Leitura: %.2f MiB/s
|
stats.read.throughput.kibs=Leitura: %.2f KiB/s
|
||||||
stats.read.throughput.mibs=Leitura: %.2f MiB/s
|
stats.read.throughput.mibs=Leitura: %.2f MiB/s
|
||||||
stats.read.total.data.none=Dados lidos: -
|
stats.read.total.data.none=Dados lidos: -
|
||||||
stats.read.total.data.kib=Dados lidos: %.1f GiB
|
stats.read.total.data.kib=Dados lidos: %.1f KiB
|
||||||
stats.read.total.data.mib=Dados lidos: %.1f MiB
|
stats.read.total.data.mib=Dados lidos: %.1f MiB
|
||||||
stats.read.total.data.gib=Dados lidos: %.1f GiB
|
stats.read.total.data.gib=Dados lidos: %.1f GiB
|
||||||
stats.decr.total.data.none=Dados descriptografados: -
|
stats.decr.total.data.none=Dados descriptografados: -
|
||||||
@@ -414,7 +415,7 @@ main.vaultlist.emptyList.onboardingInstruction=Clique aqui para adicionar um cof
|
|||||||
main.vaultlist.contextMenu.remove=Remover…
|
main.vaultlist.contextMenu.remove=Remover…
|
||||||
main.vaultlist.contextMenu.lock=Bloquear
|
main.vaultlist.contextMenu.lock=Bloquear
|
||||||
main.vaultlist.contextMenu.unlock=Desbloquear…
|
main.vaultlist.contextMenu.unlock=Desbloquear…
|
||||||
main.vaultlist.contextMenu.unlockNow=Desbloquear Agora
|
main.vaultlist.contextMenu.unlockNow=Desbloquear agora
|
||||||
main.vaultlist.contextMenu.vaultoptions=Mostrar opções do cofre
|
main.vaultlist.contextMenu.vaultoptions=Mostrar opções do cofre
|
||||||
main.vaultlist.contextMenu.reveal=Revelar volume
|
main.vaultlist.contextMenu.reveal=Revelar volume
|
||||||
main.vaultlist.contextMenu.share=Compartilhar…
|
main.vaultlist.contextMenu.share=Compartilhar…
|
||||||
@@ -435,7 +436,7 @@ main.vaultDetail.storageLocation=Local de armazenamento do cofre
|
|||||||
### Locked
|
### Locked
|
||||||
main.vaultDetail.lockedStatus=BLOQUEADO
|
main.vaultDetail.lockedStatus=BLOQUEADO
|
||||||
main.vaultDetail.unlockBtn=Desbloquear…
|
main.vaultDetail.unlockBtn=Desbloquear…
|
||||||
main.vaultDetail.unlockNowBtn=Desbloquear Agora
|
main.vaultDetail.unlockNowBtn=Desbloquear agora
|
||||||
main.vaultDetail.optionsBtn=Opções do cofre
|
main.vaultDetail.optionsBtn=Opções do cofre
|
||||||
main.vaultDetail.passwordSavedInKeychain=Senha salva
|
main.vaultDetail.passwordSavedInKeychain=Senha salva
|
||||||
main.vaultDetail.share=Compartilhar…
|
main.vaultDetail.share=Compartilhar…
|
||||||
@@ -450,94 +451,98 @@ main.vaultDetail.bytesPerSecondWritten=Gravação:
|
|||||||
main.vaultDetail.throughput.idle=ocioso
|
main.vaultDetail.throughput.idle=ocioso
|
||||||
main.vaultDetail.throughput.kbps=%.1f KiB/s
|
main.vaultDetail.throughput.kbps=%.1f KiB/s
|
||||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||||
main.vaultDetail.stats=Estatísticas do Cofre
|
main.vaultDetail.stats=Estatísticas do cofre
|
||||||
main.vaultDetail.locateEncryptedFileBtn=Localizar Arquivo Criptografado
|
main.vaultDetail.locateEncryptedFileBtn=Localizar arquivo criptografado
|
||||||
main.vaultDetail.locateEncryptedFileBtn.tooltip=Escolha um arquivo do seu cofre para localizar sua versão criptografada
|
main.vaultDetail.locateEncryptedFileBtn.tooltip=Escolha um arquivo do seu cofre para localizar sua versão criptografada
|
||||||
main.vaultDetail.encryptedPathsCopied=Caminhos copiados para a Área de Transferência!
|
main.vaultDetail.encryptedPathsCopied=Caminhos copiados para a área de transferência!
|
||||||
main.vaultDetail.locateEncrypted.filePickerTitle=Selecionar Arquivo no Cofre
|
main.vaultDetail.locateEncrypted.filePickerTitle=Selecionar arquivo no cofre
|
||||||
main.vaultDetail.decryptName.buttonLabel=Descriptografar Nome do Arquivo
|
main.vaultDetail.decryptName.buttonLabel=Descriptografar nome do arquivo
|
||||||
main.vaultDetail.decryptName.tooltip=Escolha um arquivo criptografado do cofre para descriptografar seu nome
|
main.vaultDetail.decryptName.tooltip=Escolha um arquivo criptografado do cofre para descriptografar seu nome
|
||||||
### Missing
|
### Missing
|
||||||
main.vaultDetail.missing.info=O Cryptomator não encontrou um cofre neste caminho.
|
main.vaultDetail.missing.info=O Cryptomator não encontrou um cofre nesse caminho.
|
||||||
main.vaultDetail.missing.recheck=Verificar novamente
|
main.vaultDetail.missing.recheck=Verificar novamente
|
||||||
main.vaultDetail.missing.remove=Remover da lista de cofres…
|
main.vaultDetail.missing.remove=Remover da lista de cofres…
|
||||||
main.vaultDetail.missing.changeLocation=Alterar Localização do Cofre…
|
main.vaultDetail.missing.changeLocation=Alterar localização do cofre…
|
||||||
### Missing Vault Config
|
### Missing Vault Config
|
||||||
main.vaultDetail.missingVaultConfig.info=A configuração do cofre está faltando.
|
main.vaultDetail.missingVaultConfig.info=A configuração do cofre está faltando.
|
||||||
|
main.vaultDetail.missingVaultConfig.restore=Restaurar configuração do cofre
|
||||||
### Needs Migration
|
### Needs Migration
|
||||||
main.vaultDetail.migrateButton=Atualizar Cofre
|
main.vaultDetail.migrateButton=Atualizar cofre
|
||||||
main.vaultDetail.migratePrompt=Seu cofre precisa ser atualizado para um novo formato antes de poder acessá-lo
|
main.vaultDetail.migratePrompt=Seu cofre precisa ser atualizado para um novo formato antes de conseguir acessá-lo
|
||||||
### Error
|
### Error
|
||||||
main.vaultDetail.error.info=Ocorreu um erro ao carregar o cofre do disco.
|
main.vaultDetail.error.info=Ocorreu um erro ao carregar o cofre do disco.
|
||||||
main.vaultDetail.error.reload=Recarregar
|
main.vaultDetail.error.reload=Recarregar
|
||||||
main.vaultDetail.error.windowTitle=Erro ao carregar cofre
|
main.vaultDetail.error.windowTitle=Erro ao carregar o cofre
|
||||||
|
|
||||||
# Wrong File Alert
|
# Wrong File Alert
|
||||||
wrongFileAlert.title=Como Encriptar Arquivos
|
wrongFileAlert.title=Como criptografar os arquivos
|
||||||
wrongFileAlert.message=Você tentou encriptar esses arquivos?
|
wrongFileAlert.message=Você tentou criptografar estes arquivos?
|
||||||
wrongFileAlert.description=Para este propósito, o Cryptomator fornece um volume no seu gerenciador de arquivos do sistema.
|
wrongFileAlert.description=Para esta finalidade, o Cryptomator fornece um volume no seu gerenciador de arquivos do sistema.
|
||||||
wrongFileAlert.instruction.0=Para encriptar arquivos, siga estes passos:
|
wrongFileAlert.instruction.0=Para criptografar os arquivos, siga as etapas abaixo:
|
||||||
wrongFileAlert.instruction.1=1. Desbloqueie o seu cofre.
|
wrongFileAlert.instruction.1=1. Desbloqueie o seu cofre;
|
||||||
wrongFileAlert.instruction.2=2. Clique em "Revelar" para abrir o volume no seu gerenciador de arquivos.
|
wrongFileAlert.instruction.2=2. Clique em "Revelar" para abrir o volume no seu gerenciador de arquivos.
|
||||||
wrongFileAlert.instruction.3=3. Adicione seus arquivos a este volume.
|
wrongFileAlert.instruction.3=3. Adicione seus arquivos a esse volume;
|
||||||
wrongFileAlert.link=Para obter assistência, visite
|
wrongFileAlert.link=Para obter assistência, visite
|
||||||
|
|
||||||
# Vault Options
|
# Vault Options
|
||||||
## General
|
## General
|
||||||
vaultOptions.general=Geral
|
vaultOptions.general=Geral
|
||||||
vaultOptions.general.vaultName=Nome do cofre
|
vaultOptions.general.vaultName=Nome do cofre
|
||||||
vaultOptions.general.autoLock.lockAfterTimePart1=Bloquear quando inativo por
|
vaultOptions.general.autoLock.lockAfterTimePart1=Bloquear quando inativo após
|
||||||
vaultOptions.general.autoLock.lockAfterTimePart2=minuto(s)
|
vaultOptions.general.autoLock.lockAfterTimePart2=minuto(s)
|
||||||
vaultOptions.general.unlockAfterStartup=Desbloqueie o cofre ao iniciar o Cryptomator
|
vaultOptions.general.autoLock.accessibleText=Bloquear tempo limite em minutos
|
||||||
|
vaultOptions.general.unlockAfterStartup=Desbloquear o cofre ao iniciar o Cryptomator
|
||||||
vaultOptions.general.actionAfterUnlock=Após desbloquear
|
vaultOptions.general.actionAfterUnlock=Após desbloquear
|
||||||
vaultOptions.general.actionAfterUnlock.ignore=Não fazer nada
|
vaultOptions.general.actionAfterUnlock.ignore=Não fazer nada
|
||||||
vaultOptions.general.actionAfterUnlock.reveal=Revelar volume
|
vaultOptions.general.actionAfterUnlock.reveal=Revelar volume
|
||||||
vaultOptions.general.actionAfterUnlock.ask=Perguntar
|
vaultOptions.general.actionAfterUnlock.ask=Perguntar
|
||||||
vaultOptions.general.startHealthCheckBtn=Iniciar Exame de Saúde
|
vaultOptions.general.startHealthCheckBtn=Iniciar verificação de saúde
|
||||||
|
|
||||||
## Mount
|
## Mount
|
||||||
vaultOptions.mount=Montagem
|
vaultOptions.mount=Montagem
|
||||||
vaultOptions.mount.info=Abra preferências de drive virtual para alterar as configurações padrão.
|
vaultOptions.mount.info=Abra preferências do volume virtual para alterar as configurações padrões.
|
||||||
vaultOptions.mount.readonly=Somente Leitura
|
vaultOptions.mount.readonly=Somente leitura
|
||||||
vaultOptions.mount.customMountFlags=Flags Personalizadas de Montagem
|
vaultOptions.mount.customMountFlags=Flags personalizadas de montagem
|
||||||
vaultOptions.mount.winDriveLetterOccupied=ocupado
|
vaultOptions.mount.winDriveLetterOccupied=ocupado
|
||||||
vaultOptions.mount.mountPoint=Ponto de Montagem
|
vaultOptions.mount.mountPoint=Ponto de montagem
|
||||||
vaultOptions.mount.mountPoint.auto=Escolher automaticamente um local adequado
|
vaultOptions.mount.mountPoint.auto=Escolher automaticamente um local adequado
|
||||||
vaultOptions.mount.mountPoint.driveLetter=Usar letra de unidade atribuída
|
vaultOptions.mount.mountPoint.driveLetter=Usar letra de unidade atribuída
|
||||||
vaultOptions.mount.mountPoint.custom=Usar diretório escolhido
|
vaultOptions.mount.mountPoint.custom=Usar diretório escolhido
|
||||||
vaultOptions.mount.mountPoint.directoryPickerButton=Escolher…
|
vaultOptions.mount.mountPoint.directoryPickerButton=Escolher…
|
||||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Escolha um diretório
|
vaultOptions.mount.mountPoint.directoryPickerTitle=Escolha um diretório
|
||||||
vaultOptions.mount.volumeType.default=Padrão (%s)
|
vaultOptions.mount.volumeType.default=Padrão (%s)
|
||||||
vaultOptions.mount.volumeType.restartRequired=Para usar esse tipo de volume, o Cryptomator precisa ser reiniciado.
|
vaultOptions.mount.volumeType.restartRequired=Para usar este tipo de volume, o Cryptomator precisa ser reiniciado.
|
||||||
vaultOptions.mount.volume.tcp.port=Porta TCP
|
vaultOptions.mount.volume.tcp.port=Porta TCP
|
||||||
vaultOptions.mount.volume.type=Tipo de Volume
|
vaultOptions.mount.volume.type=Tipo de volume
|
||||||
## Master Key
|
## Master Key
|
||||||
vaultOptions.masterkey=Senha
|
vaultOptions.masterkey=Senha
|
||||||
vaultOptions.masterkey.changePasswordBtn=Alterar senha
|
vaultOptions.masterkey.changePasswordBtn=Alterar senha
|
||||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Esquecer a senha salva
|
vaultOptions.masterkey.forgetSavedPasswordBtn=Esquecer a senha salva
|
||||||
vaultOptions.masterkey.recoveryKeyExplanation=Se você perder a sua senha, a única forma de restaurar acesso a um cofre é através de uma chave de recuperação.
|
vaultOptions.masterkey.recoveryKeyExplanation=Caso perca a sua senha, a única forma de restaurar acesso a um cofre é através de uma chave de recuperação.
|
||||||
vaultOptions.masterkey.showRecoveryKeyBtn=Mostrar chave de recuperação
|
vaultOptions.masterkey.showRecoveryKeyBtn=Mostrar chave de recuperação
|
||||||
vaultOptions.masterkey.recoverPasswordBtn=Redefinir senha
|
vaultOptions.masterkey.recoverPasswordBtn=Redefinir senha
|
||||||
|
vaultOptions.masterkey.missingMasterkeyFile=Essas opções ficarão disponíveis se o arquivo masterkey estiver na pasta do cofre.
|
||||||
## Hub
|
## Hub
|
||||||
vaultOptions.hub=Recuperação
|
vaultOptions.hub=Recuperação
|
||||||
vaultOptions.hub.convertInfo=Você pode usar a chave de recuperação para converter este cofre do Hub em um cofre protegido por senha de emergência.
|
vaultOptions.hub.convertInfo=Você pode usar a chave de recuperação para converter este cofre do Hub em um cofre protegido por senha de emergência.
|
||||||
vaultOptions.hub.convertBtn=Converter para Cofre protegido por senha
|
vaultOptions.hub.convertBtn=Converter para cofre protegido por senha
|
||||||
|
|
||||||
# Recovery Key
|
# Recovery Key
|
||||||
## Display Recovery Key
|
## Display Recovery Key
|
||||||
recoveryKey.display.title=Mostrar Chave de Recuperação
|
recoveryKey.display.title=Mostrar Chave de Recuperação
|
||||||
recoveryKey.create.message=Senha obrigatória
|
recoveryKey.create.message=Requer senha
|
||||||
recoveryKey.create.description=Digite sua senha para mostrar a chave de recuperação de "%s":
|
recoveryKey.create.description=Digite a senha para mostrar a chave de recuperação de "%s":
|
||||||
|
recoveryKey.recover.description=Digite a senha para "%s" para recuperar a configuração do cofre.
|
||||||
recoveryKey.display.description=A seguinte chave de recuperação pode ser usada para restaurar o acesso a "%s":
|
recoveryKey.display.description=A seguinte chave de recuperação pode ser usada para restaurar o acesso a "%s":
|
||||||
recoveryKey.display.StorageHints=Mantenha-a em um lugar bem seguro, por exemplo:\n • Guarde num gerenciador de senhas\n • Grave num flash drive USB\n • Imprima, ou escreva, num papel
|
recoveryKey.display.StorageHints=Mantenha-a em um lugar bem seguro. Por exemplo:\n • Guarde em um gerenciador de senhas;\n • Grave em um pen drive;\n • Imprima ou escreva em um papel.
|
||||||
## Reset Password
|
## Reset Password
|
||||||
### Enter Recovery Key
|
### Enter Recovery Key
|
||||||
recoveryKey.recover.title=Redefinir Senha
|
recoveryKey.recover.title=Redefinir senha
|
||||||
recoveryKey.recover.prompt=Digite a chave de recuperação para "%s":
|
recoveryKey.recover.prompt=Digite a chave de recuperação para "%s":
|
||||||
recoveryKey.recover.correctKey=Esta é uma chave de recuperação válida
|
recoveryKey.recover.correctKey=Essa é uma chave de recuperação válida
|
||||||
recoveryKey.recover.wrongKey=Esta chave de recuperação pertence a um outro cofre
|
recoveryKey.recover.wrongKey=Essa chave de recuperação pertence a um outro cofre
|
||||||
recoveryKey.recover.invalidKey=Esta chave de recuperação não é válida
|
recoveryKey.recover.invalidKey=Essa chave de recuperação é inválida
|
||||||
recoveryKey.printout.heading=Chave de Recuperação do Cryptomator\n"%s"\n
|
recoveryKey.printout.heading=Chave de Recuperação do Cryptomator\n"%s"
|
||||||
### Reset Password
|
### Reset Password
|
||||||
recoveryKey.recover.resetBtn=Redefinir
|
recoveryKey.recover.resetBtn=Redefinir
|
||||||
recoveryKey.recover.recoverBtn=Recuperar
|
recoveryKey.recover.recoverBtn=Recuperar
|
||||||
@@ -545,41 +550,61 @@ recoveryKey.recover.recoverBtn=Recuperar
|
|||||||
recoveryKey.recover.resetSuccess.message=Senha redefinida com sucesso
|
recoveryKey.recover.resetSuccess.message=Senha redefinida com sucesso
|
||||||
recoveryKey.recover.resetSuccess.description=Você pode desbloquear o seu cofre com a nova senha.
|
recoveryKey.recover.resetSuccess.description=Você pode desbloquear o seu cofre com a nova senha.
|
||||||
### Recovery Key Vault Config Reset Success
|
### Recovery Key Vault Config Reset Success
|
||||||
|
recoveryKey.recover.resetVaultConfigSuccess.message=Configuração do cofre recuperada
|
||||||
|
recoveryKey.recover.resetMasterkeyFileSuccess.message=Arquivo Masterkey recuperado
|
||||||
recoveryKey.recover.resetMasterkeyFileSuccess.description=Agora você pode desbloquear o seu cofre com a sua nova senha.
|
recoveryKey.recover.resetMasterkeyFileSuccess.description=Agora você pode desbloquear o seu cofre com a sua nova senha.
|
||||||
|
|
||||||
# Recover Vault Config File and/or Masterkey
|
# Recover Vault Config File and/or Masterkey
|
||||||
##Add Existing Vault without recovery - Dialog
|
##Add Existing Vault without recovery - Dialog
|
||||||
recover.existing.title=Cofre adicionado
|
recover.existing.title=Cofre adicionado
|
||||||
recover.existing.message=O cofre foi adicionado com sucesso
|
recover.existing.message=O cofre foi adicionado com sucesso
|
||||||
|
recover.existing.description=O seu cofre "%s" foi adicionado à lista de cofre. Nenhum processo de recuperação foi necessário.
|
||||||
|
|
||||||
##Vault Already Exists - Dialog
|
##Vault Already Exists - Dialog
|
||||||
recover.alreadyExists.title=O cofre já existe
|
recover.alreadyExists.title=O cofre já existe
|
||||||
recover.alreadyExists.message=Este cofre já foi adicionado
|
recover.alreadyExists.message=Este cofre já foi adicionado
|
||||||
|
recover.alreadyExists.description=Seu cofre "%s" não foi adicionado novamente porque já está na sua lista de cofres.
|
||||||
|
|
||||||
##Invalid Selection - Dialog
|
##Invalid Selection - Dialog
|
||||||
recover.invalidSelection.title=Seleção inválida
|
recover.invalidSelection.title=Seleção inválida
|
||||||
|
recover.invalidSelection.message=Sua seleção não é um cofre
|
||||||
|
recover.invalidSelection.description=A pasta selecionada precisa ser um cofre válido do Cryptomator.
|
||||||
|
|
||||||
## Contact Hub Vault Owner - Dialog
|
## Contact Hub Vault Owner - Dialog
|
||||||
contactHubVaultOwner.title=Cofre do Hub
|
contactHubVaultOwner.title=Cofre do Hub
|
||||||
|
contactHubVaultOwner.message=Este cofre foi criado com o Cryptomator Hub
|
||||||
|
contactHubVaultOwner.description=Entre em contato com o proprietário do cofre para restaurar o arquivo restante. Eles podem baixar o modelo de cofre no Cryptomator Hub.
|
||||||
|
|
||||||
##Dialog Title
|
##Dialog Title
|
||||||
|
recover.recoverVaultConfig.title=Recuperar a configuração do cofre
|
||||||
recover.recoverMasterkey.title=Recuperar Masterkey
|
recover.recoverMasterkey.title=Recuperar Masterkey
|
||||||
|
|
||||||
## OnBoarding
|
## OnBoarding
|
||||||
|
recover.onBoarding.chooseMethod=Escolha o método de recuperação:
|
||||||
recover.onBoarding.useRecoveryKey=Usar chave de recuperação
|
recover.onBoarding.useRecoveryKey=Usar chave de recuperação
|
||||||
recover.onBoarding.usePassword=Usar senha
|
recover.onBoarding.usePassword=Usar senha
|
||||||
|
recover.onBoarding.intro=Certifique-se de verificar o seguinte:
|
||||||
|
recover.onBoarding.pleaseConfirm=Antes de prosseguir, confirme que:
|
||||||
|
recover.onBoarding.otherwisePleaseConfirm=Caso contrário, confirme que:
|
||||||
|
recover.onBoarding.allMissing.intro=Se este cofre for gerenciado pelo Cryptomator Hub, o proprietário do cofre deve restaurá-lo para você.
|
||||||
|
recover.onBoarding.intro.ensure=Todos os arquivos estão sincronizados.
|
||||||
|
recover.onBoarding.affirmation=Li e estou ciente dos requisitos
|
||||||
|
|
||||||
###Vault Config Missing
|
###Vault Config Missing
|
||||||
|
recover.onBoarding.intro.recoveryKey=Você tem a chave de recuperação e sabe se as configurações avançadas foram usadas.
|
||||||
|
recover.onBoarding.intro.password=Você tem a senha do cofre e sabe se as configurações avançadas foram usadas.
|
||||||
###Masterkey Missing
|
###Masterkey Missing
|
||||||
|
recover.onBoarding.intro.masterkey.recoveryKey=Você tem a chave de recuperação do cofre.
|
||||||
|
|
||||||
## Expert Settings
|
## Expert Settings
|
||||||
|
recover.expertSettings.shorteningThreshold.title=Este valor deve corresponder ao usado antes da recuperação para garantir a compatibilidade com os dados criptografados anteriormente.
|
||||||
|
|
||||||
# Convert Vault
|
# Convert Vault
|
||||||
convertVault.title=Converter Cofre
|
convertVault.title=Converter cofre
|
||||||
convertVault.convert.convertBtn.before=Converter
|
convertVault.convert.convertBtn.before=Converter
|
||||||
convertVault.convert.convertBtn.processing=Convertendo...
|
convertVault.convert.convertBtn.processing=Convertendo...
|
||||||
convertVault.success.message=Conversão bem sucedida
|
convertVault.success.message=Conversão concluída
|
||||||
convertVault.hubToPassword.success.description=Agora você pode desbloquear o cofre com a senha escolhida sem exigir acesso ao Hub.
|
convertVault.hubToPassword.success.description=Agora você pode desbloquear o cofre com a senha escolhida sem solicitar acesso ao Hub.
|
||||||
|
|
||||||
# New Password
|
# New Password
|
||||||
newPassword.promptText=Digite a nova senha
|
newPassword.promptText=Digite a nova senha
|
||||||
@@ -595,57 +620,57 @@ passwordStrength.messageLabel.4=Muito forte
|
|||||||
|
|
||||||
# Quit
|
# Quit
|
||||||
quit.title=Sair da aplicação
|
quit.title=Sair da aplicação
|
||||||
quit.message=Existem cofres desbloqueados
|
quit.message=Há cofres desbloqueados
|
||||||
quit.description=Por favor, confirme que você deseja sair. O Cryptomador irá bloquear cuidadosamente todos os cofres abertos para evitar a perda de dados.
|
quit.description=Confirme que deseja sair. O Cryptomador bloqueará cuidadosamente todos os cofres abertos para evitar a perda de dados.
|
||||||
quit.lockAndQuitBtn=Bloquear e Sair
|
quit.lockAndQuitBtn=Bloquear e sair
|
||||||
|
|
||||||
# Forced Quit
|
# Forced Quit
|
||||||
quit.forced.message=Alguns cofres não puderam ser trancados
|
quit.forced.message=Alguns cofres não foram trancados
|
||||||
quit.forced.description=O bloqueio dos cofres foi impedido por operações pendentes ou arquivos abertos. Você pode forçar o bloqueio dos cofres restantes, no entanto, essa interrupção de E/S pode resultar na perda de dados não salvos nos cofres — “seus dados”.
|
quit.forced.description=O bloqueio dos cofres foi impedido por operações pendentes ou arquivos abertos. Você pode forçar o bloqueio dos cofres restantes, mas essa interrupção de gravação de dados pode resultar na perda de arquivos não salvos nos cofres.
|
||||||
quit.forced.forceAndQuitBtn=Forçar e Sair
|
quit.forced.forceAndQuitBtn=Forçar e sair
|
||||||
|
|
||||||
# Update Reminder
|
# Update Reminder
|
||||||
updateReminder.title=Verificação de Atualizações
|
updateReminder.title=Verificação de atualizações
|
||||||
updateReminder.message=Verificar Atualizações?
|
updateReminder.message=Verificar atualizações?
|
||||||
updateReminder.description=Mantenha-se atualizado com novos recursos, correções de bugs e melhoramentos de segurança. Recomendamos verificar atualizações automaticamente.
|
updateReminder.description=Mantenha-se atualizado com novos recursos, correções de bugs e melhorias de segurança. Recomendamos verificar as atualizações automaticamente.
|
||||||
updateReminder.notNow=Agora Não
|
updateReminder.notNow=Agora não
|
||||||
updateReminder.yesOnce=Sim, uma vez
|
updateReminder.yesOnce=Sim, uma vez
|
||||||
updateReminder.yesAutomatically=Sim, Automaticamente
|
updateReminder.yesAutomatically=Sim, automaticamente
|
||||||
|
|
||||||
#Dokany Support End
|
#Dokany Support End
|
||||||
dokanySupportEnd.title=Aviso de descontinuação
|
dokanySupportEnd.title=Aviso de descontinuação
|
||||||
dokanySupportEnd.message=Fim do suporte para o Dokany
|
dokanySupportEnd.message=Fim do suporte para o Dokany
|
||||||
dokanySupportEnd.description=O volume do tipo Dokany não é mais suportado pelo Cryptomator. Suas configurações serão ajustadas para usar o tipo de volume padrão agora. Você pode ver o tipo padrão nas preferências.
|
dokanySupportEnd.description=O volume do tipo Dokany não é mais compatível com o Cryptomator. Suas configurações serão ajustadas para usar o tipo de volume padrão. Veja o tipo padrão nas preferências.
|
||||||
dokanySupportEnd.preferencesBtn=Abrir preferências
|
dokanySupportEnd.preferencesBtn=Abrir preferências
|
||||||
|
|
||||||
#Retry If Readonly
|
#Retry If Readonly
|
||||||
retryIfReadonly.title=Acesso Restrito ao Cofre
|
retryIfReadonly.title=Acesso restrito ao cofre
|
||||||
retryIfReadonly.message=Sem acesso de gravação ao diretório do cofre
|
retryIfReadonly.message=Sem acesso de gravação ao diretório do cofre
|
||||||
retryIfReadonly.description=O Cryptomator não pode escrever no diretório do cofre. Você pode alterar o cofre para somente leitura e tentar novamente. Esta opção pode ser desativada nas opções de cofre.
|
retryIfReadonly.description=O Cryptomator não pode gravar no diretório do cofre. Você pode alterar o cofre para somente leitura e tentar novamente. Esta opção pode ser desativada nas opções do cofre.
|
||||||
retryIfReadonly.retry=Alterar e Repetir
|
retryIfReadonly.retry=Alterar e repetir
|
||||||
|
|
||||||
# Share Vault
|
# Share Vault
|
||||||
shareVault.title=Compartilhar Cofre
|
shareVault.title=Compartilhar cofre
|
||||||
shareVault.message=Gostaria de compartilhar o seu cofre com outras pessoas?
|
shareVault.message=Gostaria de compartilhar o seu cofre com outras pessoas?
|
||||||
shareVault.description=Sempre tenha cuidado ao compartilhar seu cofre com outras pessoas. Em resumo, siga esses passos:
|
shareVault.description=Sempre tenha cuidado ao compartilhar seu cofre com terceiros. Em resumo, siga esses passos:
|
||||||
shareVault.instruction.1=1. Compartilhe o acesso da pasta do cofre criptografado via armazenamento na nuvem.
|
shareVault.instruction.1=1. Compartilhe o acesso da pasta do cofre criptografado via armazenamento em nuvem.
|
||||||
shareVault.instruction.2=2. Compartilhe a senha do cofre de forma segura.
|
shareVault.instruction.2=2. Compartilhe a senha do cofre de forma segura.
|
||||||
shareVault.remarkBestPractices=Para mais informações, confira as sugestões de melhores práticas em nossos documentos.
|
shareVault.remarkBestPractices=Para mais informações, confira as sugestões de boas práticas em nossas documentações.
|
||||||
shareVault.docsTooltip=Abra a documentação para aprender mais sobre compartilhamento de cofres.
|
shareVault.docsTooltip=Abra a documentação para aprender mais sobre o compartilhamento de cofres.
|
||||||
shareVault.hubAd.description=A maneira segura de trabalhar em equipes
|
shareVault.hubAd.description=A maneira segura de trabalhar em equipes
|
||||||
shareVault.hubAd.keyManagement=• Gerenciamento de chaves de Zero-Conhecimento
|
shareVault.hubAd.keyManagement=• Gerenciamento de chaves de conhecimento zero
|
||||||
shareVault.hubAd.authentication=• Autenticação forte
|
shareVault.hubAd.authentication=• Autenticação forte
|
||||||
shareVault.hubAd.encryption=• Criptografia de ponta-a-ponta
|
shareVault.hubAd.encryption=• Criptografia de ponta-a-ponta
|
||||||
shareVault.visitHub=Visite o Cryptomator Hub
|
shareVault.visitHub=Visite o Cryptomator Hub
|
||||||
|
|
||||||
shareVault.hub.message=Como compartilhar um cofre do Hub
|
shareVault.hub.message=Como compartilhar um cofre do Hub
|
||||||
shareVault.hub.description=Para compartilhar o conteúdo do cofre com outro membro da equipe, você deve realizar duas etapas:
|
shareVault.hub.description=Para compartilhar o conteúdo do cofre com outro membro da equipe, você deve realizar duas etapas:
|
||||||
shareVault.hub.instruction.1=1. Compartilhe o acesso da pasta do cofre criptografado via armazenamento na nuvem.
|
shareVault.hub.instruction.1=1. Compartilhe o acesso da pasta do cofre criptografado via armazenamento em nuvem.
|
||||||
shareVault.hub.instruction.2=2. Conceda acesso ao membro da equipe no Cryptomator Hub.
|
shareVault.hub.instruction.2=2. Conceda acesso ao membro da equipe no Cryptomator Hub.
|
||||||
shareVault.hub.openHub=Abrir o Cryptomator Hub
|
shareVault.hub.openHub=Abrir o Cryptomator Hub
|
||||||
|
|
||||||
# Decrypt File Names
|
# Decrypt File Names
|
||||||
decryptNames.title=Descriptografar Nomes de Arquivos
|
decryptNames.title=Descriptografar nomes de arquivos
|
||||||
decryptNames.filePicker.title=Selecione o arquivo criptografado
|
decryptNames.filePicker.title=Selecione o arquivo criptografado
|
||||||
decryptNames.filePicker.extensionDescription=Arquivo criptografado do Cryptomator
|
decryptNames.filePicker.extensionDescription=Arquivo criptografado do Cryptomator
|
||||||
decryptNames.copyTable.tooltip=Copiar tabela
|
decryptNames.copyTable.tooltip=Copiar tabela
|
||||||
@@ -653,10 +678,10 @@ decryptNames.clearTable.tooltip=Limpar tabela
|
|||||||
decryptNames.column.encrypted=Criptografado
|
decryptNames.column.encrypted=Criptografado
|
||||||
decryptNames.column.decrypted=Descriptografado
|
decryptNames.column.decrypted=Descriptografado
|
||||||
decryptNames.copyHint=Copiar conteúdo da célula com %s
|
decryptNames.copyHint=Copiar conteúdo da célula com %s
|
||||||
decryptNames.dropZone.message=Arraste e solte arquivos ou clique para selecionar
|
decryptNames.dropZone.message=Arraste e solte os arquivos ou clique para selecionar
|
||||||
decryptNames.dropZone.error.vaultInternalFiles=Selecionados arquivos internos do cofre sem nome descriptografável
|
decryptNames.dropZone.error.vaultInternalFiles=Arquivos internos do cofre sem nome descriptografável selecionados
|
||||||
decryptNames.dropZone.error.foreignFiles=Arquivos não pertencem ao cofre "%s"
|
decryptNames.dropZone.error.foreignFiles=Os arquivos não pertencem ao cofre "%s"
|
||||||
decryptNames.dropZone.error.noDirIdBackup=Diretório dos arquivos selecionados não contém o arquivo dirId.c9r
|
decryptNames.dropZone.error.noDirIdBackup=O diretório dos arquivos selecionados não contém o arquivo dirId.c9r
|
||||||
decryptNames.dropZone.error.generic=Falha ao descriptografar os nomes de arquivos
|
decryptNames.dropZone.error.generic=Falha ao descriptografar os nomes de arquivos
|
||||||
|
|
||||||
|
|
||||||
@@ -667,35 +692,28 @@ eventView.clearListButton.tooltip=Limpar lista
|
|||||||
eventView.filterVaults=Filtrar por cofre
|
eventView.filterVaults=Filtrar por cofre
|
||||||
eventView.cell.actionsButton.tooltip=Ações de evento
|
eventView.cell.actionsButton.tooltip=Ações de evento
|
||||||
## event list entries
|
## event list entries
|
||||||
eventView.entry.vaultLocked.description=Desbloquear "%s" para detalhes
|
eventView.entry.vaultLocked.description=Desbloquear "%s" para mais detalhes
|
||||||
eventView.entry.conflictResolved.message=Conflito resolvido
|
eventView.entry.conflictResolved.message=Conflito resolvido
|
||||||
eventView.entry.conflictResolved.showDecrypted=Mostrar arquivo descriptografado
|
eventView.entry.conflictResolved.showDecrypted=Mostrar arquivo descriptografado
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Copiar caminho descriptografado
|
eventView.entry.conflict.message=Falha na resolução de conflitos
|
||||||
eventView.entry.conflict.message=Resolução de conflitos falhou
|
|
||||||
eventView.entry.conflict.showDecrypted=Mostrar arquivo original descriptografado
|
eventView.entry.conflict.showDecrypted=Mostrar arquivo original descriptografado
|
||||||
eventView.entry.conflict.copyDecrypted=Copiar caminho original descriptografado
|
|
||||||
eventView.entry.conflict.showEncrypted=Mostrar arquivo criptografado conflitante
|
eventView.entry.conflict.showEncrypted=Mostrar arquivo criptografado conflitante
|
||||||
eventView.entry.conflict.copyEncrypted=Copiar caminho criptografado conflitante
|
eventView.entry.decryptionFailed.message=Falha ao descriptografar
|
||||||
eventView.entry.decryptionFailed.message=Decriptação falhou
|
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Mostrar arquivo criptografado
|
eventView.entry.decryptionFailed.showEncrypted=Mostrar arquivo criptografado
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Copiar caminho encriptado
|
|
||||||
eventView.entry.brokenDirFile.message=Link do diretório quebrado
|
eventView.entry.brokenDirFile.message=Link do diretório quebrado
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Mostrar link quebrado e criptografado
|
eventView.entry.brokenDirFile.showEncrypted=Mostrar link quebrado e criptografado
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Copiar caminho do link quebrado
|
|
||||||
eventView.entry.brokenFileNode.message=Nó de sistema de arquivos danificado
|
eventView.entry.brokenFileNode.message=Nó de sistema de arquivos danificado
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Mostrar nó criptografado com falha
|
eventView.entry.brokenFileNode.showEncrypted=Mostrar nó criptografado com falha
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Copiar caminho do nó quebrado criptografado
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Copiar caminho descriptografado
|
eventView.entry.brokenFileNode.copyDecrypted=Copiar caminho descriptografado
|
||||||
eventView.entry.inUse.message=Arquivo bloqueado
|
eventView.entry.inUse.message=Arquivo em uso
|
||||||
eventView.entry.inUse.showDecrypted=Mostrar arquivo descriptografado
|
eventView.entry.inUse.showDecrypted=Mostrar arquivo descriptografado
|
||||||
eventView.entry.inUse.copyDecrypted=Copiar caminho descriptografado
|
|
||||||
eventView.entry.inUse.showEncrypted=Mostrar arquivo criptografado
|
eventView.entry.inUse.showEncrypted=Mostrar arquivo criptografado
|
||||||
eventView.entry.inUse.copyEncrypted=Copiar caminho encriptado
|
eventView.entry.inUse.copyUserAndDevice=Copiar usuário de bloqueio e nome do dispositivo
|
||||||
eventView.entry.inUse.ignoreLock=Ignorar bloqueio
|
eventView.entry.inUse.ignoreLock=Ignorar status de uso
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=O arquivo está bloqueado por outro dispositivo
|
notification.inUse.message=O arquivo está sendo usado em outro dispositivo
|
||||||
notification.inUse.description=O arquivo é aberto por %s no dispositivo %s. Solicite ao usuário para fechá-lo e o sincronizar novamente. Caso contrário, você pode ignorar o bloqueio e abri-lo mesmo assim.
|
notification.inUse.description=O arquivo é aberto por %s em %s. Solicite a eles para fechá-lo e deixar a sincronização finalizar. Você pode ignorar o status para abri-lo agora, mas isso pode causar conflitos ou substituir novas alterações.
|
||||||
notification.inUse.action=Ignorar bloqueio
|
notification.inUse.action=Ignorar status de uso
|
||||||
@@ -695,33 +695,25 @@ eventView.cell.actionsButton.tooltip=Действия события
|
|||||||
eventView.entry.vaultLocked.description=Разблокируйте "%s" для деталей
|
eventView.entry.vaultLocked.description=Разблокируйте "%s" для деталей
|
||||||
eventView.entry.conflictResolved.message=Решённый конфликт
|
eventView.entry.conflictResolved.message=Решённый конфликт
|
||||||
eventView.entry.conflictResolved.showDecrypted=Показать расшифрованный файл
|
eventView.entry.conflictResolved.showDecrypted=Показать расшифрованный файл
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Скопировать расшифрованный путь
|
|
||||||
eventView.entry.conflict.message=Не удалось решить конфликты
|
eventView.entry.conflict.message=Не удалось решить конфликты
|
||||||
eventView.entry.conflict.showDecrypted=Показать расшифрованный исходный файл
|
eventView.entry.conflict.showDecrypted=Показать расшифрованный исходный файл
|
||||||
eventView.entry.conflict.copyDecrypted=Скопировать расшифрованный исходный путь
|
|
||||||
eventView.entry.conflict.showEncrypted=Показать конфликтующий зашифрованный файл
|
eventView.entry.conflict.showEncrypted=Показать конфликтующий зашифрованный файл
|
||||||
eventView.entry.conflict.copyEncrypted=Скопировать конфликтующий зашифрованный путь
|
|
||||||
eventView.entry.decryptionFailed.message=Ошибка дешифрования
|
eventView.entry.decryptionFailed.message=Ошибка дешифрования
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Показать зашифрованный файл
|
eventView.entry.decryptionFailed.showEncrypted=Показать зашифрованный файл
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Скопировать зашифрованный путь
|
|
||||||
eventView.entry.brokenDirFile.message=Повреждённая ссылка на папку
|
eventView.entry.brokenDirFile.message=Повреждённая ссылка на папку
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Показать повреждённую зашифрованную ссылку
|
eventView.entry.brokenDirFile.showEncrypted=Показать повреждённую зашифрованную ссылку
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Скопировать путь повреждённой ссылки
|
|
||||||
eventView.entry.brokenFileNode.message=Повреждённый узел файловой системы
|
eventView.entry.brokenFileNode.message=Повреждённый узел файловой системы
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Показать повреждённый зашифрованный узел
|
eventView.entry.brokenFileNode.showEncrypted=Показать повреждённый зашифрованный узел
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Скопировать путь повреждённого зашифрованного узла
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Скопировать расшифрованный путь
|
eventView.entry.brokenFileNode.copyDecrypted=Скопировать расшифрованный путь
|
||||||
eventView.entry.inUse.message=Заблокированный файл
|
eventView.entry.inUse.message=Файл используется
|
||||||
eventView.entry.inUse.showDecrypted=Показать расшифрованный файл
|
eventView.entry.inUse.showDecrypted=Показать расшифрованный файл
|
||||||
eventView.entry.inUse.copyDecrypted=Скопировать расшифрованный путь
|
|
||||||
eventView.entry.inUse.showEncrypted=Показать зашифрованный файл
|
eventView.entry.inUse.showEncrypted=Показать зашифрованный файл
|
||||||
eventView.entry.inUse.copyEncrypted=Скопировать зашифрованный путь
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Скопировать блокирующее имя пользователя и устройства
|
eventView.entry.inUse.copyUserAndDevice=Скопировать блокирующее имя пользователя и устройства
|
||||||
eventView.entry.inUse.ignoreLock=Игнорировать блокировку
|
eventView.entry.inUse.ignoreLock=Игнорировать статус использования
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Файл заблокирован другим устройством
|
notification.inUse.message=Файл используется на другом устройстве
|
||||||
notification.inUse.description=Файл открыт %s на устройстве %s. Попросите пользователя закрыть файл и синхронизировать снова. В противном случае вы можете проигнорировать блокировку и всё равно открыть его.
|
notification.inUse.description=Файл открыт %s на %s. Попросите закрыть файл и завершить синхронизацию. Вы можете проигнорировать статус и открыть его, но есть риск конфликтов или перезаписи новых изменений.
|
||||||
notification.inUse.action=Игнорировать блокировку
|
notification.inUse.action=Игнорировать статус использования
|
||||||
@@ -647,33 +647,22 @@ eventView.cell.actionsButton.tooltip=Akcie udalostí
|
|||||||
eventView.entry.vaultLocked.description=Podrobnosti získate odomknutím „%s“
|
eventView.entry.vaultLocked.description=Podrobnosti získate odomknutím „%s“
|
||||||
eventView.entry.conflictResolved.message=Vyriešený konflikt
|
eventView.entry.conflictResolved.message=Vyriešený konflikt
|
||||||
eventView.entry.conflictResolved.showDecrypted=Zobraziť dešifrovaný súbor
|
eventView.entry.conflictResolved.showDecrypted=Zobraziť dešifrovaný súbor
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Skopírujte dešifrovanú cestu
|
|
||||||
eventView.entry.conflict.message=Riešenie konfliktu zlyhalo
|
eventView.entry.conflict.message=Riešenie konfliktu zlyhalo
|
||||||
eventView.entry.conflict.showDecrypted=Zobraziť dešifrovaný pôvodný súbor
|
eventView.entry.conflict.showDecrypted=Zobraziť dešifrovaný pôvodný súbor
|
||||||
eventView.entry.conflict.copyDecrypted=Kopírovať dešifrovanú, pôvodnú cestu
|
|
||||||
eventView.entry.conflict.showEncrypted=Zobraziť konfliktný zašifrovaný súbor
|
eventView.entry.conflict.showEncrypted=Zobraziť konfliktný zašifrovaný súbor
|
||||||
eventView.entry.conflict.copyEncrypted=Kopírovať konfliktnú zašifrovanú cestu
|
|
||||||
eventView.entry.decryptionFailed.message=Dešifrovanie zlyhalo
|
eventView.entry.decryptionFailed.message=Dešifrovanie zlyhalo
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Zobraziť zašifrovaný súbor
|
eventView.entry.decryptionFailed.showEncrypted=Zobraziť zašifrovaný súbor
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Skopírujte zašifrovanú cestu
|
|
||||||
eventView.entry.brokenDirFile.message=Nefunkčný odkaz na adresár
|
eventView.entry.brokenDirFile.message=Nefunkčný odkaz na adresár
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Zobraziť nefunkčný, šifrovaný odkaz
|
eventView.entry.brokenDirFile.showEncrypted=Zobraziť nefunkčný, šifrovaný odkaz
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Kopírovať cestu nefunkčného odkazu
|
|
||||||
eventView.entry.brokenFileNode.message=Poškodený uzol súborového systému
|
eventView.entry.brokenFileNode.message=Poškodený uzol súborového systému
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Zobraziť nefunkčný, zašifrovaný uzol
|
eventView.entry.brokenFileNode.showEncrypted=Zobraziť nefunkčný, zašifrovaný uzol
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Kopírovať cestu nefunkčného, šifrovaného uzla
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Skopírujte dešifrovanú cestu
|
eventView.entry.brokenFileNode.copyDecrypted=Skopírujte dešifrovanú cestu
|
||||||
eventView.entry.inUse.message=Zamknutý súbor
|
eventView.entry.inUse.message=Súbor sa používa
|
||||||
eventView.entry.inUse.showDecrypted=Zobraziť dešifrovaný súbor
|
eventView.entry.inUse.showDecrypted=Zobraziť dešifrovaný súbor
|
||||||
eventView.entry.inUse.copyDecrypted=Skopírujte dešifrovanú cestu
|
|
||||||
eventView.entry.inUse.showEncrypted=Zobraziť zašifrovaný súbor
|
eventView.entry.inUse.showEncrypted=Zobraziť zašifrovaný súbor
|
||||||
eventView.entry.inUse.copyEncrypted=Skopírujte zašifrovanú cestu
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Kopírovať zamykaného užívateľa a meno zariadenia
|
eventView.entry.inUse.copyUserAndDevice=Kopírovať zamykaného užívateľa a meno zariadenia
|
||||||
eventView.entry.inUse.ignoreLock=Ignorovať zamknutie
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Súbor je blokovaný iným zariadením
|
notification.inUse.message=Súbor je používaný iným zariadením
|
||||||
notification.inUse.description=Súbor je otvorený %s na zariadení %s. Požiadajte užívateľa o zatvorenie súboru a synchronizujte znovu. Alebo môžte ignorovať uzamknutie a napriek tomu ho otvoriť.
|
|
||||||
notification.inUse.action=Ignorovať zamknutie
|
|
||||||
@@ -678,31 +678,20 @@ eventView.filterVaults=Filtrera efter valv
|
|||||||
eventView.entry.vaultLocked.description=Lås upp "%s" för detaljer
|
eventView.entry.vaultLocked.description=Lås upp "%s" för detaljer
|
||||||
eventView.entry.conflictResolved.message=Löst konflikt
|
eventView.entry.conflictResolved.message=Löst konflikt
|
||||||
eventView.entry.conflictResolved.showDecrypted=Visa dekrypterad fil
|
eventView.entry.conflictResolved.showDecrypted=Visa dekrypterad fil
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Kopiera dekrypterad sökväg
|
|
||||||
eventView.entry.conflict.message=Konfliktlösning misslyckades
|
eventView.entry.conflict.message=Konfliktlösning misslyckades
|
||||||
eventView.entry.conflict.showDecrypted=Visa dekrypterad, originalfil
|
eventView.entry.conflict.showDecrypted=Visa dekrypterad, originalfil
|
||||||
eventView.entry.conflict.copyDecrypted=Kopiera dekrypterad, ursprunglig sökväg
|
|
||||||
eventView.entry.conflict.showEncrypted=Visa krypterad fil som inte kunde synkroniseras
|
eventView.entry.conflict.showEncrypted=Visa krypterad fil som inte kunde synkroniseras
|
||||||
eventView.entry.conflict.copyEncrypted=Kopiera krypterad sökväg som inte kunde synkroniseras
|
|
||||||
eventView.entry.decryptionFailed.message=Dekryptering misslyckades
|
eventView.entry.decryptionFailed.message=Dekryptering misslyckades
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Visa krypterad fil
|
eventView.entry.decryptionFailed.showEncrypted=Visa krypterad fil
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Kopiera krypterad sökväg
|
|
||||||
eventView.entry.brokenDirFile.message=Trasig kataloglänk
|
eventView.entry.brokenDirFile.message=Trasig kataloglänk
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Visa trasig, krypterad länk
|
eventView.entry.brokenDirFile.showEncrypted=Visa trasig, krypterad länk
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Kopiera sökväg för trasig länk
|
|
||||||
eventView.entry.brokenFileNode.message=Trasig filsystemsnod
|
eventView.entry.brokenFileNode.message=Trasig filsystemsnod
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Visa trasig krypterad nod
|
eventView.entry.brokenFileNode.showEncrypted=Visa trasig krypterad nod
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Kopiera sökväg för trasig, krypterad nod
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Kopiera dekrypterad sökväg
|
eventView.entry.brokenFileNode.copyDecrypted=Kopiera dekrypterad sökväg
|
||||||
eventView.entry.inUse.message=Låst fil
|
|
||||||
eventView.entry.inUse.showDecrypted=Visa dekrypterad fil
|
eventView.entry.inUse.showDecrypted=Visa dekrypterad fil
|
||||||
eventView.entry.inUse.copyDecrypted=Kopiera dekrypterad sökväg
|
|
||||||
eventView.entry.inUse.showEncrypted=Visa krypterad fil
|
eventView.entry.inUse.showEncrypted=Visa krypterad fil
|
||||||
eventView.entry.inUse.copyEncrypted=Kopiera krypterad sökväg
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Kopiera blockerande användare och enhet
|
eventView.entry.inUse.copyUserAndDevice=Kopiera blockerande användare och enhet
|
||||||
eventView.entry.inUse.ignoreLock=Ignorera lås
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.action=Ignorera lås
|
|
||||||
@@ -18,6 +18,10 @@ generic.button.print=Yazdır
|
|||||||
generic.button.remove=Kaldır
|
generic.button.remove=Kaldır
|
||||||
|
|
||||||
## Vault state
|
## Vault state
|
||||||
|
vault.state.locked=Kilitli
|
||||||
|
vault.state.unlocked=Kilidi açık
|
||||||
|
vault.state.missing=Kayıt
|
||||||
|
vault.state.processing=İşleniyor
|
||||||
vault.state.error=Hata
|
vault.state.error=Hata
|
||||||
|
|
||||||
# Error
|
# Error
|
||||||
@@ -180,6 +184,7 @@ hub.registerFailed.message=Cihaz kaydı başarısız oldu
|
|||||||
hub.registerFailed.description.generic=Kayıt işleminde bir hata oluştu. Daha fazla bilgi için uygulama günlüğüne bakın.
|
hub.registerFailed.description.generic=Kayıt işleminde bir hata oluştu. Daha fazla bilgi için uygulama günlüğüne bakın.
|
||||||
hub.registerFailed.description.deviceAlreadyExists=Bu cihaz zaten farklı bir kullanıcı için kayıtlı. Kullanıcı hesabını değiştirmeyi veya farklı bir cihaz kullanmayı deneyin.
|
hub.registerFailed.description.deviceAlreadyExists=Bu cihaz zaten farklı bir kullanıcı için kayıtlı. Kullanıcı hesabını değiştirmeyi veya farklı bir cihaz kullanmayı deneyin.
|
||||||
### Archived
|
### Archived
|
||||||
|
hub.archived.message=Kasa arşivlendi
|
||||||
### Unauthorized
|
### Unauthorized
|
||||||
hub.unauthorized.message=Erişim engellendi
|
hub.unauthorized.message=Erişim engellendi
|
||||||
hub.unauthorized.description=Bu kasayı açma yetkiniz yok. Erişim talebinde bulunmak için kasanın sahibiyle iletişime geçin.
|
hub.unauthorized.description=Bu kasayı açma yetkiniz yok. Erişim talebinde bulunmak için kasanın sahibiyle iletişime geçin.
|
||||||
@@ -332,6 +337,7 @@ preferences.updates.lastUpdateCheck.never=asla
|
|||||||
preferences.updates.lastUpdateCheck.recently=az önce
|
preferences.updates.lastUpdateCheck.recently=az önce
|
||||||
preferences.updates.lastUpdateCheck.daysAgo=%s gün önce
|
preferences.updates.lastUpdateCheck.daysAgo=%s gün önce
|
||||||
preferences.updates.lastUpdateCheck.hoursAgo=%s saat önce
|
preferences.updates.lastUpdateCheck.hoursAgo=%s saat önce
|
||||||
|
preferences.updates.prohibitedDueToUnlockedVaults.1=Lütfen
|
||||||
preferences.updates.checkFailed=Güncelleme kontrolü başarısız oldu. Lütfen internet bağlantınızı kontrol edin veya daha sonra tekrar deneyin.
|
preferences.updates.checkFailed=Güncelleme kontrolü başarısız oldu. Lütfen internet bağlantınızı kontrol edin veya daha sonra tekrar deneyin.
|
||||||
preferences.updates.upToDate=Cryptomator güncel.
|
preferences.updates.upToDate=Cryptomator güncel.
|
||||||
|
|
||||||
@@ -608,12 +614,24 @@ shareVault.hub.instruction.2=2. Cryptomator Hub'da ekip üyesine erişim izni ve
|
|||||||
shareVault.hub.openHub=Cryptomator Hub'ı aç
|
shareVault.hub.openHub=Cryptomator Hub'ı aç
|
||||||
|
|
||||||
# Decrypt File Names
|
# Decrypt File Names
|
||||||
|
decryptNames.copyTable.tooltip=Tabloyu kopyala
|
||||||
|
decryptNames.clearTable.tooltip=Tabloyu temizle
|
||||||
|
decryptNames.column.encrypted=Şifrelendi
|
||||||
|
decryptNames.column.decrypted=Şifresi çözüldü
|
||||||
|
|
||||||
|
|
||||||
# Event View
|
# Event View
|
||||||
|
eventView.title=Etkinlikler
|
||||||
eventView.filter.allVaults=Tümü
|
eventView.filter.allVaults=Tümü
|
||||||
|
eventView.clearListButton.tooltip=Listeyi temizle
|
||||||
|
eventView.filterVaults=Kasayı süz
|
||||||
## event list entries
|
## event list entries
|
||||||
|
eventView.entry.inUse.message=Kullanılan dosya
|
||||||
|
eventView.entry.inUse.ignoreLock=Kullanım durumunu yok say
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
|
notification.inUse.message=Dosya başka bir cihazda kullanılıyor
|
||||||
|
notification.inUse.description=Dosya %s tarafından %s tarihinde açıldı. Onlardan dosyayı kapatmalarını ve senkronizasyonun tamamlanmasını beklemelerini isteyin. Dosyayı şimdi açmak için durumu görmezden gelebilirsiniz, ancak bu çakışmalara veya yeni değişikliklerin üzerine yazılmasına neden olabilir.
|
||||||
|
notification.inUse.action=Kullanım Durumunu Yok Say
|
||||||
@@ -696,33 +696,25 @@ eventView.cell.actionsButton.tooltip=Дії події
|
|||||||
eventView.entry.vaultLocked.description=Розблокуйте «%s» для отримання деталей
|
eventView.entry.vaultLocked.description=Розблокуйте «%s» для отримання деталей
|
||||||
eventView.entry.conflictResolved.message=Конфлікт вирішено
|
eventView.entry.conflictResolved.message=Конфлікт вирішено
|
||||||
eventView.entry.conflictResolved.showDecrypted=Показати розшифрований файл
|
eventView.entry.conflictResolved.showDecrypted=Показати розшифрований файл
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Копіювати розшифрований шлях
|
|
||||||
eventView.entry.conflict.message=Не вдалося вирішити конфлікт
|
eventView.entry.conflict.message=Не вдалося вирішити конфлікт
|
||||||
eventView.entry.conflict.showDecrypted=Показати розшифрований оригінальний файл
|
eventView.entry.conflict.showDecrypted=Показати розшифрований оригінальний файл
|
||||||
eventView.entry.conflict.copyDecrypted=Скопіювати розшифрований оригінальний шлях
|
|
||||||
eventView.entry.conflict.showEncrypted=Показати конфліктуючий зашифрований файл
|
eventView.entry.conflict.showEncrypted=Показати конфліктуючий зашифрований файл
|
||||||
eventView.entry.conflict.copyEncrypted=Скопіювати конфліктуючий зашифрований шлях
|
|
||||||
eventView.entry.decryptionFailed.message=Не вдалося розшифрувати
|
eventView.entry.decryptionFailed.message=Не вдалося розшифрувати
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Показати зашифрований файл
|
eventView.entry.decryptionFailed.showEncrypted=Показати зашифрований файл
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Копіювати зашифрований шлях
|
|
||||||
eventView.entry.brokenDirFile.message=Пошкоджене посилання на каталог
|
eventView.entry.brokenDirFile.message=Пошкоджене посилання на каталог
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Показати пошкоджене зашифроване посилання
|
eventView.entry.brokenDirFile.showEncrypted=Показати пошкоджене зашифроване посилання
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Копіювати шлях пошкодженого посилання
|
|
||||||
eventView.entry.brokenFileNode.message=Пошкоджений вузол файлової системи
|
eventView.entry.brokenFileNode.message=Пошкоджений вузол файлової системи
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Показати пошкоджений зашифрований вузол
|
eventView.entry.brokenFileNode.showEncrypted=Показати пошкоджений зашифрований вузол
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Скопіювати шлях до пошкодженого зашифрованого вузла
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Копіювати розшифрований шлях
|
eventView.entry.brokenFileNode.copyDecrypted=Копіювати розшифрований шлях
|
||||||
eventView.entry.inUse.message=Заблокований файл
|
eventView.entry.inUse.message=Файл використовується
|
||||||
eventView.entry.inUse.showDecrypted=Показати розшифрований файл
|
eventView.entry.inUse.showDecrypted=Показати розшифрований файл
|
||||||
eventView.entry.inUse.copyDecrypted=Копіювати розшифрований шлях
|
|
||||||
eventView.entry.inUse.showEncrypted=Показати зашифрований файл
|
eventView.entry.inUse.showEncrypted=Показати зашифрований файл
|
||||||
eventView.entry.inUse.copyEncrypted=Копіювати зашифрований шлях
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=Копіювати ім'я користувача та пристрою, що блокують
|
eventView.entry.inUse.copyUserAndDevice=Копіювати ім'я користувача та пристрою, що блокують
|
||||||
eventView.entry.inUse.ignoreLock=Ігнорування блокування
|
eventView.entry.inUse.ignoreLock=Ігнорувати статус використання
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.message=Файл заблоковано іншим пристроєм
|
notification.inUse.message=Файл використовується на іншому пристрої
|
||||||
notification.inUse.description=Файл відкрито в «%s» на пристрої «%s». Попросіть користувача закрити файл і повторити синхронізацію. В іншому випадку можна проігнорувати блокування і відкрити файл.
|
notification.inUse.description=Файл відкритий користувачем %s на пристрої %s. Попросіть його закрити файл, щоб завершити синхронізацію. Ви можете ігнорувати цей статус і відкрити файл зараз, але це може призвести до конфліктів або перезапису новіших змін.
|
||||||
notification.inUse.action=Ігнорування блокування
|
notification.inUse.action=Ігнорувати статус використання
|
||||||
@@ -629,26 +629,18 @@ eventView.clearListButton.tooltip=Xóa danh sách
|
|||||||
eventView.entry.vaultLocked.description=Mở khóa "%s" để xem chi tiết
|
eventView.entry.vaultLocked.description=Mở khóa "%s" để xem chi tiết
|
||||||
eventView.entry.conflictResolved.message=Đã xử lý xung đột
|
eventView.entry.conflictResolved.message=Đã xử lý xung đột
|
||||||
eventView.entry.conflictResolved.showDecrypted=Xem tệp đã giải mã
|
eventView.entry.conflictResolved.showDecrypted=Xem tệp đã giải mã
|
||||||
eventView.entry.conflictResolved.copyDecrypted=Sao chép đường dẫn giải mã
|
|
||||||
eventView.entry.conflict.message=Giải quyết xung đột thất bại
|
eventView.entry.conflict.message=Giải quyết xung đột thất bại
|
||||||
eventView.entry.conflict.showDecrypted=Xem tệp gốc đã giải mã
|
eventView.entry.conflict.showDecrypted=Xem tệp gốc đã giải mã
|
||||||
eventView.entry.conflict.copyDecrypted=Sao chép đường dẫn gốc đã giải mã
|
|
||||||
eventView.entry.conflict.showEncrypted=Hiển thị tệp bị xung đột, đã mã hóa
|
eventView.entry.conflict.showEncrypted=Hiển thị tệp bị xung đột, đã mã hóa
|
||||||
eventView.entry.conflict.copyEncrypted=Sao chép đường dẫn mã hóa bị xung đột
|
|
||||||
eventView.entry.decryptionFailed.message=Giải mã thất bại
|
eventView.entry.decryptionFailed.message=Giải mã thất bại
|
||||||
eventView.entry.decryptionFailed.showEncrypted=Hiển thị tệp đã mã hóa
|
eventView.entry.decryptionFailed.showEncrypted=Hiển thị tệp đã mã hóa
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=Sao chép đường dẫn tệp đã mã hóa
|
|
||||||
eventView.entry.brokenDirFile.message=Liên kết thư mục hỏng
|
eventView.entry.brokenDirFile.message=Liên kết thư mục hỏng
|
||||||
eventView.entry.brokenDirFile.showEncrypted=Hiển thị liên kết mã hóa bị hỏng
|
eventView.entry.brokenDirFile.showEncrypted=Hiển thị liên kết mã hóa bị hỏng
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=Sao chép đường dẫn liên kết bị hỏng
|
|
||||||
eventView.entry.brokenFileNode.message=Nút tập tin bị hỏng
|
eventView.entry.brokenFileNode.message=Nút tập tin bị hỏng
|
||||||
eventView.entry.brokenFileNode.showEncrypted=Hiển thị nút mã hóa bị hỏng
|
eventView.entry.brokenFileNode.showEncrypted=Hiển thị nút mã hóa bị hỏng
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=Sao chép đường dẫn nút mã hóa bị hỏng
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=Sao chép đường dẫn giải mã
|
eventView.entry.brokenFileNode.copyDecrypted=Sao chép đường dẫn giải mã
|
||||||
eventView.entry.inUse.showDecrypted=Xem tệp đã giải mã
|
eventView.entry.inUse.showDecrypted=Xem tệp đã giải mã
|
||||||
eventView.entry.inUse.copyDecrypted=Sao chép đường dẫn giải mã
|
|
||||||
eventView.entry.inUse.showEncrypted=Hiển thị tệp đã mã hóa
|
eventView.entry.inUse.showEncrypted=Hiển thị tệp đã mã hóa
|
||||||
eventView.entry.inUse.copyEncrypted=Sao chép đường dẫn tệp đã mã hóa
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|||||||
@@ -678,31 +678,20 @@ eventView.cell.actionsButton.tooltip=事件操作
|
|||||||
eventView.entry.vaultLocked.description=解锁“%s”查看详情
|
eventView.entry.vaultLocked.description=解锁“%s”查看详情
|
||||||
eventView.entry.conflictResolved.message=已解决冲突
|
eventView.entry.conflictResolved.message=已解决冲突
|
||||||
eventView.entry.conflictResolved.showDecrypted=显示解密文件
|
eventView.entry.conflictResolved.showDecrypted=显示解密文件
|
||||||
eventView.entry.conflictResolved.copyDecrypted=复制解密路径
|
|
||||||
eventView.entry.conflict.message=冲突解决失败
|
eventView.entry.conflict.message=冲突解决失败
|
||||||
eventView.entry.conflict.showDecrypted=显示解密后的原始文件
|
eventView.entry.conflict.showDecrypted=显示解密后的原始文件
|
||||||
eventView.entry.conflict.copyDecrypted=复制解密后的原始路径
|
|
||||||
eventView.entry.conflict.showEncrypted=显示冲突的加密文件
|
eventView.entry.conflict.showEncrypted=显示冲突的加密文件
|
||||||
eventView.entry.conflict.copyEncrypted=复制冲突的加密路径
|
|
||||||
eventView.entry.decryptionFailed.message=解密失败
|
eventView.entry.decryptionFailed.message=解密失败
|
||||||
eventView.entry.decryptionFailed.showEncrypted=显示加密文件
|
eventView.entry.decryptionFailed.showEncrypted=显示加密文件
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=复制加密路径
|
|
||||||
eventView.entry.brokenDirFile.message=目录链接已损坏
|
eventView.entry.brokenDirFile.message=目录链接已损坏
|
||||||
eventView.entry.brokenDirFile.showEncrypted=显示损坏的加密链接
|
eventView.entry.brokenDirFile.showEncrypted=显示损坏的加密链接
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=复制损坏链接的路径
|
|
||||||
eventView.entry.brokenFileNode.message=损坏的文件系统节点
|
eventView.entry.brokenFileNode.message=损坏的文件系统节点
|
||||||
eventView.entry.brokenFileNode.showEncrypted=显示损坏的加密节点
|
eventView.entry.brokenFileNode.showEncrypted=显示损坏的加密节点
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=复制损坏的加密节点的路径
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=复制解密路径
|
eventView.entry.brokenFileNode.copyDecrypted=复制解密路径
|
||||||
eventView.entry.inUse.message=已锁定的文件
|
|
||||||
eventView.entry.inUse.showDecrypted=显示解密文件
|
eventView.entry.inUse.showDecrypted=显示解密文件
|
||||||
eventView.entry.inUse.copyDecrypted=复制解密路径
|
|
||||||
eventView.entry.inUse.showEncrypted=显示加密文件
|
eventView.entry.inUse.showEncrypted=显示加密文件
|
||||||
eventView.entry.inUse.copyEncrypted=复制加密路径
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=复制锁定用户和设备名称
|
eventView.entry.inUse.copyUserAndDevice=复制锁定用户和设备名称
|
||||||
eventView.entry.inUse.ignoreLock=忽略锁定
|
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.action=忽略锁定
|
|
||||||
@@ -695,31 +695,25 @@ eventView.cell.actionsButton.tooltip=事件動作
|
|||||||
eventView.entry.vaultLocked.description=解鎖「%s」以顯示詳細資訊
|
eventView.entry.vaultLocked.description=解鎖「%s」以顯示詳細資訊
|
||||||
eventView.entry.conflictResolved.message=以解決的衝突
|
eventView.entry.conflictResolved.message=以解決的衝突
|
||||||
eventView.entry.conflictResolved.showDecrypted=顯示解密的檔案
|
eventView.entry.conflictResolved.showDecrypted=顯示解密的檔案
|
||||||
eventView.entry.conflictResolved.copyDecrypted=複製解密路徑
|
|
||||||
eventView.entry.conflict.message=解決衝突失敗
|
eventView.entry.conflict.message=解決衝突失敗
|
||||||
eventView.entry.conflict.showDecrypted=顯示解密、原始的檔案
|
eventView.entry.conflict.showDecrypted=顯示解密、原始的檔案
|
||||||
eventView.entry.conflict.copyDecrypted=複製解密、原始的路徑
|
|
||||||
eventView.entry.conflict.showEncrypted=顯示衝突的加密檔案
|
eventView.entry.conflict.showEncrypted=顯示衝突的加密檔案
|
||||||
eventView.entry.conflict.copyEncrypted=複製衝突的加密檔案
|
|
||||||
eventView.entry.decryptionFailed.message=解密失敗
|
eventView.entry.decryptionFailed.message=解密失敗
|
||||||
eventView.entry.decryptionFailed.showEncrypted=顯示加密的檔案
|
eventView.entry.decryptionFailed.showEncrypted=顯示加密的檔案
|
||||||
eventView.entry.decryptionFailed.copyEncrypted=複製加密路徑
|
|
||||||
eventView.entry.brokenDirFile.message=損壞的目錄連結
|
eventView.entry.brokenDirFile.message=損壞的目錄連結
|
||||||
eventView.entry.brokenDirFile.showEncrypted=顯示損壞的加密路徑
|
eventView.entry.brokenDirFile.showEncrypted=顯示損壞的加密路徑
|
||||||
eventView.entry.brokenDirFile.copyEncrypted=複製損壞的路徑連結
|
|
||||||
eventView.entry.brokenFileNode.message=損壞的檔案系統節點
|
eventView.entry.brokenFileNode.message=損壞的檔案系統節點
|
||||||
eventView.entry.brokenFileNode.showEncrypted=顯示損壞的加密節點
|
eventView.entry.brokenFileNode.showEncrypted=顯示損壞的加密節點
|
||||||
eventView.entry.brokenFileNode.copyEncrypted=複製損壞的加密節點路徑
|
|
||||||
eventView.entry.brokenFileNode.copyDecrypted=複製解密路徑
|
eventView.entry.brokenFileNode.copyDecrypted=複製解密路徑
|
||||||
eventView.entry.inUse.message=鎖定的檔案
|
eventView.entry.inUse.message=檔案正在使用中
|
||||||
eventView.entry.inUse.showDecrypted=顯示解密的檔案
|
eventView.entry.inUse.showDecrypted=顯示解密的檔案
|
||||||
eventView.entry.inUse.copyDecrypted=複製解密路徑
|
|
||||||
eventView.entry.inUse.showEncrypted=顯示加密的檔案
|
eventView.entry.inUse.showEncrypted=顯示加密的檔案
|
||||||
eventView.entry.inUse.copyEncrypted=複製加密路徑
|
|
||||||
eventView.entry.inUse.copyUserAndDevice=複製鎖定的使用者和裝置名稱
|
eventView.entry.inUse.copyUserAndDevice=複製鎖定的使用者和裝置名稱
|
||||||
eventView.entry.inUse.ignoreLock=忽略鎖定
|
eventView.entry.inUse.ignoreLock=忽略使用狀態
|
||||||
|
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
## FileIsInUse Notification
|
## FileIsInUse Notification
|
||||||
notification.inUse.action=忽略鎖定
|
notification.inUse.message=檔案正在被另一部裝置使用中
|
||||||
|
notification.inUse.description=這個檔案正在由 %s 在 %s 開啟中。告訴他們關閉檔案讓同步完成。您可以忽略這個狀態並且馬上開啟,但是可能會造成衝突或把新的變更覆蓋掉。
|
||||||
|
notification.inUse.action=忽略使用狀態
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user