mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-15 09:11:29 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b29f0b4f3 | ||
|
|
f8bcbda8d7 | ||
|
|
e368087c3e | ||
|
|
ddb5da1d79 | ||
|
|
d2374fb8cd | ||
|
|
c73aa49b59 | ||
|
|
de86760a75 | ||
|
|
bfd8a62015 | ||
|
|
9292a3c89c | ||
|
|
732fc2f3dd | ||
|
|
9fb00fcc38 | ||
|
|
12b58a8a32 | ||
|
|
338eb45e24 | ||
|
|
e8c63dd3f3 | ||
|
|
2de23f8fff | ||
|
|
1a0624cc81 | ||
|
|
ef6f87bb19 | ||
|
|
6da8fc1f70 | ||
|
|
49e90515a1 | ||
|
|
983c35eb37 | ||
|
|
1f0c12ef7a | ||
|
|
ba514c8896 | ||
|
|
76c310f1fc | ||
|
|
874f0ee611 | ||
|
|
957f067e9b | ||
|
|
b1931f2c13 | ||
|
|
156e7bbb91 | ||
|
|
aebe848bef | ||
|
|
c40ef2f0f2 | ||
|
|
8fa562aa60 | ||
|
|
303f84166f | ||
|
|
9e594ea127 | ||
|
|
88977ecf20 | ||
|
|
538cac3749 | ||
|
|
30196f6a68 | ||
|
|
8bc79e684d | ||
|
|
7183efa073 | ||
|
|
92f621cd25 | ||
|
|
19d26de4ec | ||
|
|
d39c3969df | ||
|
|
c781755c6e | ||
|
|
4a3d579b76 | ||
|
|
6bad74720f | ||
|
|
77e2be22de | ||
|
|
7b4a3e1313 | ||
|
|
1c76c50a4b | ||
|
|
79e6a4cd48 | ||
|
|
64845f0ffa | ||
|
|
ee68f9d47b | ||
|
|
65bb6773cb | ||
|
|
4bd4cd671b | ||
|
|
e1a72c41a5 | ||
|
|
4d4098e0e0 | ||
|
|
d52e59d7a4 | ||
|
|
9440fb186f | ||
|
|
9856792921 | ||
|
|
806ffe704c | ||
|
|
6ca87d13f5 | ||
|
|
983a4d0b0f | ||
|
|
e95853deac | ||
|
|
d72d9f533c | ||
|
|
85a5146d4b | ||
|
|
0bece0f591 |
13
.github/workflows/appimage.yml
vendored
13
.github/workflows/appimage.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 17
|
||||
@@ -28,6 +32,9 @@ jobs:
|
||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR=${GITHUB_REF##*/}
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
else
|
||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
||||
fi
|
||||
@@ -146,6 +153,6 @@ jobs:
|
||||
fail_on_unmatched_files: true
|
||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
files: |
|
||||
*.AppImage
|
||||
*.zsync
|
||||
*.asc
|
||||
cryptomator-*.AppImage
|
||||
cryptomator-*.zsync
|
||||
cryptomator-*.asc
|
||||
18
.github/workflows/build.yml
vendored
18
.github/workflows/build.yml
vendored
@@ -32,6 +32,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-sonar
|
||||
- name: Build and Test
|
||||
run: >
|
||||
xvfb-run
|
||||
mvn -B verify
|
||||
jacoco:report
|
||||
org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
||||
@@ -42,13 +43,15 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
- name: Upload code coverage report
|
||||
id: codacyCoverageReporter
|
||||
if: "github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'pr:safe')"
|
||||
run: bash <(curl -Ls https://coverage.codacy.com/get.sh)
|
||||
- name: Sign source tarball with key 615D449FE6E6A235
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
git archive --prefix="cryptomator-${{ github.ref_name }}/" -o "cryptomator-${{ github.ref_name }}.tar.gz" ${{ github.ref }}
|
||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz
|
||||
env:
|
||||
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
continue-on-error: true
|
||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||
- name: Draft a release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -57,6 +60,9 @@ jobs:
|
||||
discussion_category_name: releases
|
||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
cryptomator-*.tar.gz.asc
|
||||
fail_on_unmatched_files: true
|
||||
body: |-
|
||||
:construction: Work in Progress
|
||||
|
||||
|
||||
6
.github/workflows/debian.yml
vendored
6
.github/workflows/debian.yml
vendored
@@ -10,6 +10,9 @@ on:
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 17
|
||||
@@ -38,6 +41,9 @@ jobs:
|
||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR=${GITHUB_REF##*/}
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
else
|
||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
||||
fi
|
||||
|
||||
11
.github/workflows/mac-dmg.yml
vendored
11
.github/workflows/mac-dmg.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 17
|
||||
@@ -28,6 +32,9 @@ jobs:
|
||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR=${GITHUB_REF##*/}
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
else
|
||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
||||
fi
|
||||
@@ -226,7 +233,7 @@ jobs:
|
||||
fail_on_unmatched_files: true
|
||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
files: |
|
||||
*.dmg
|
||||
*.asc
|
||||
Cryptomator-*.dmg
|
||||
Cryptomator-*.asc
|
||||
|
||||
|
||||
|
||||
2
.github/workflows/pullrequest.yml
vendored
2
.github/workflows/pullrequest.yml
vendored
@@ -23,4 +23,4 @@ jobs:
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
cache: 'maven'
|
||||
- name: Build and Test
|
||||
run: mvn -B clean install jacoco:report -Pcoverage,dependency-check
|
||||
run: xvfb-run mvn -B clean install jacoco:report -Pcoverage,dependency-check
|
||||
33
.github/workflows/win-exe.yml
vendored
33
.github/workflows/win-exe.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 17
|
||||
@@ -33,6 +37,9 @@ jobs:
|
||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR=${GITHUB_REF##*/}
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
||||
else
|
||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
||||
fi
|
||||
@@ -80,6 +87,7 @@ jobs:
|
||||
--app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}"
|
||||
--java-options "-Xss5m"
|
||||
--java-options "-Xmx256m"
|
||||
--java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\""
|
||||
--java-options "-Dfile.encoding=\"utf-8\""
|
||||
--java-options "-Dcryptomator.logDir=\"~/AppData/Roaming/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/AppData/Roaming/Cryptomator/Plugins\""
|
||||
@@ -217,7 +225,26 @@ jobs:
|
||||
run: >
|
||||
"${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
|
||||
-ext WixBalExtension
|
||||
-out installer/Cryptomator.exe
|
||||
-out installer/unsigned/Cryptomator.exe
|
||||
- name: Detach burn engine in preparation to sign
|
||||
run: >
|
||||
"${WIX}/bin/insignia.exe"
|
||||
-ib installer/unsigned/Cryptomator.exe
|
||||
-o tmp/engine.exe
|
||||
- name: Codesign burn engine
|
||||
uses: skymatic/code-sign-action@v1
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B
|
||||
description: Cryptomator Installer
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: tmp
|
||||
- name: Reattach signed burn engine to installer
|
||||
run : >
|
||||
"${WIX}/bin/insignia.exe"
|
||||
-ab tmp/engine.exe installer/unsigned/Cryptomator.exe
|
||||
-o installer/Cryptomator.exe
|
||||
- name: Codesign EXE
|
||||
uses: skymatic/code-sign-action@v1
|
||||
with:
|
||||
@@ -251,5 +278,5 @@ jobs:
|
||||
fail_on_unmatched_files: true
|
||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
files: |
|
||||
*.exe
|
||||
*.asc
|
||||
Cryptomator-*.exe
|
||||
Cryptomator-*.asc
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,7 +21,6 @@ pom.xml.versionsBackup
|
||||
.idea/dictionaries/**
|
||||
!.idea/dictionaries/dict_*
|
||||
.idea/compiler.xml
|
||||
.idea/encodings.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/uiDesigner.xml
|
||||
.idea/**/libraries/
|
||||
|
||||
8
.idea/encodings.xml
generated
Normal file
8
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator-Dev/Plugins" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dfuse.experimental="true" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator-Dev/Plugins" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
|
||||
[](https://snyk.io/test/github/cryptomator/cryptomator)
|
||||
[](https://www.codacy.com/gh/cryptomator/cryptomator/dashboard)
|
||||
[](https://sonarcloud.io/dashboard?id=cryptomator_cryptomator)
|
||||
[](http://twitter.com/Cryptomator)
|
||||
[](https://translate.cryptomator.org/)
|
||||
[](https://github.com/cryptomator/cryptomator/releases/latest)
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
</content_rating>
|
||||
|
||||
<releases>
|
||||
<release date="2022-03-30" version="1.6.8"/>
|
||||
<release date="2021-12-16" version="1.6.5"/>
|
||||
</releases>
|
||||
</component>
|
||||
|
||||
3
dist/mac/dmg/.gitignore
vendored
3
dist/mac/dmg/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
# created during build
|
||||
Cryptomator.app/
|
||||
runtime/
|
||||
dmg/
|
||||
*.dmg
|
||||
*.dmg
|
||||
27
dist/win/resources/customWizard.wxi
vendored
27
dist/win/resources/customWizard.wxi
vendored
@@ -13,7 +13,6 @@
|
||||
<DialogRef Id="BrowseDlg" />
|
||||
<DialogRef Id="DiskCostDlg" />
|
||||
<DialogRef Id="ErrorDlg" />
|
||||
<DialogRef Id="FatalError" />
|
||||
<DialogRef Id="FilesInUse" />
|
||||
<DialogRef Id="MsiRMFilesInUse" />
|
||||
<DialogRef Id="PrepareDlg" />
|
||||
@@ -24,8 +23,9 @@
|
||||
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
|
||||
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
|
||||
|
||||
<!-- custom end dialog -->
|
||||
<!-- custom end dialogs -->
|
||||
<Publish Dialog="MyExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
|
||||
<Publish Dialog="MyFatalErrorDlg" Control="Finish" Event="EndDialog" Value="Return" Order="998">1</Publish>
|
||||
|
||||
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
|
||||
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
|
||||
@@ -75,11 +75,34 @@
|
||||
</Control>
|
||||
</Dialog>
|
||||
|
||||
<!-- copy pasta from https://github.com/wixtoolset/wix3/blob/develop/src/ext/UIExtension/wixlib/FatalError.wxs with adjustments-->
|
||||
<Dialog Id="MyFatalErrorDlg" Width="370" Height="270" Title="!(loc.FatalError_Title)">
|
||||
<Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUIFinish)">
|
||||
<Publish Event="EndDialog" Value="Exit">1</Publish>
|
||||
</Control>
|
||||
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUICancel)" />
|
||||
<Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.FatalErrorBitmap)" />
|
||||
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)" />
|
||||
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
|
||||
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.FatalErrorTitle)" />
|
||||
<Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="80" Transparent="yes" NoPrefix="yes" Text="!(loc.FatalErrorDescription1) !(loc.FatalErrorDescription2)" />
|
||||
<Control Id="DescriptionReason1" Type="Text" X="135" Y="160" Width="220" Height="20" Transparent="yes" NoPrefix="yes" Hidden="yes" >
|
||||
<Text>Reason:</Text>
|
||||
<Condition Action="show">FOUNDRUNNINGAPP</Condition>
|
||||
</Control>
|
||||
<Control Id="DescriptionReason2" Type="Text" X="135" Y="170" Width="220" Height="40" Transparent="yes" NoPrefix="yes" Hidden="yes" >
|
||||
<Text>Cryptomator was still running during installation.</Text>
|
||||
<Condition Action="show">FOUNDRUNNINGAPP</Condition>
|
||||
</Control>
|
||||
</Dialog>
|
||||
|
||||
<InstallUISequence>
|
||||
<Show Dialog="MyExitDialog" Overridable="yes" OnExit="success"/>
|
||||
<Show Dialog="MyFatalErrorDlg" Overridable="yes" OnExit="error"/>
|
||||
</InstallUISequence>
|
||||
<AdminUISequence>
|
||||
<Show Dialog="MyExitDialog" Overridable="yes" OnExit="success"/>
|
||||
<Show Dialog="MyFatalErrorDlg" Overridable="yes" OnExit="error"/>
|
||||
</AdminUISequence>
|
||||
|
||||
</UI>
|
||||
|
||||
21
dist/win/resources/main.wxs
vendored
21
dist/win/resources/main.wxs
vendored
@@ -127,6 +127,20 @@
|
||||
<!-- WebDAV patches -->
|
||||
<CustomAction Id="PatchWebDAV" Impersonate="no" ExeCommand="[INSTALLDIR]patchWebDAV.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
|
||||
|
||||
<!-- Running App detection and exit -->
|
||||
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
||||
<util:CloseApplication
|
||||
Id="CloseCryptomator"
|
||||
Target="cryptomator.exe"
|
||||
CloseMessage="no"
|
||||
RebootPrompt="no"
|
||||
PromptToContinue="yes"
|
||||
Description="A running instance of Cryptomator is found. Please close it to continue."
|
||||
Property="FOUNDRUNNINGAPP"
|
||||
>
|
||||
</util:CloseApplication>
|
||||
<CustomAction Id="FailOnRunningApp" Impersonate="no" ExeCommand="[SystemFolder]\cmd.exe /c "exit 1"" Directory="INSTALLDIR" Execute="immediate" Return="check" />
|
||||
|
||||
<?ifdef JpIcon ?>
|
||||
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
||||
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
|
||||
@@ -155,7 +169,12 @@
|
||||
<?ifndef JpAllowDowngrades ?>
|
||||
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
||||
<?endif?>
|
||||
<RemoveExistingProducts Before="CostInitialize"/>
|
||||
|
||||
<!-- Check and fail if Cryptomator is running -->
|
||||
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
|
||||
<Custom Action="FailOnRunningApp" After="WixCloseApplications" >FOUNDRUNNINGAPP</Custom>
|
||||
|
||||
<RemoveExistingProducts After="InstallValidate"/>
|
||||
|
||||
<Custom Action="PatchWebDAV" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
24
pom.xml
24
pom.xml
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptomator</artifactId>
|
||||
<version>1.7.0-SNAPSHOT</version>
|
||||
<version>1.6.8</version>
|
||||
<name>Cryptomator Desktop App</name>
|
||||
|
||||
<organization>
|
||||
@@ -27,34 +27,34 @@
|
||||
<nonModularGroupIds>com.github.serceman,com.github.jnr,org.ow2.asm,net.java.dev.jna,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>2.3.1</cryptomator.cryptofs.version>
|
||||
<cryptomator.cryptofs.version>2.4.0</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.1.0-beta1</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.0.0</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.0.0</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.0.1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.3.3</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.3.3</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.2.6</cryptomator.webdav.version>
|
||||
<cryptomator.webdav.version>1.2.7</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>17.0.2</javafx.version>
|
||||
<javafx.version>18</javafx.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<jwt.version>3.18.3</jwt.version>
|
||||
<jwt.version>3.19.1</jwt.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>31.0-jre</guava.version>
|
||||
<dagger.version>2.40.3</dagger.version>
|
||||
<gson.version>2.8.9</gson.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
<dagger.version>2.41</dagger.version>
|
||||
<gson.version>2.9.0</gson.version>
|
||||
<zxcvbn.version>1.5.2</zxcvbn.version>
|
||||
<slf4j.version>1.7.32</slf4j.version>
|
||||
<logback.version>1.2.9</logback.version>
|
||||
<slf4j.version>1.7.36</slf4j.version>
|
||||
<logback.version>1.2.11</logback.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.8.1</junit.jupiter.version>
|
||||
<mockito.version>3.12.4</mockito.version>
|
||||
<mockito.version>4.4.0</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
|
||||
<!-- build plugin dependencies -->
|
||||
<dependency-check.version>7.0.0</dependency-check.version>
|
||||
<dependency-check.version>7.0.2</dependency-check.version>
|
||||
<jacoco.version>0.8.7</jacoco.version>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -89,11 +89,6 @@ public class Environment {
|
||||
return Boolean.getBoolean("cryptomator.showTrayIcon");
|
||||
}
|
||||
|
||||
@Deprecated // TODO: remove as soon as custom mount path works properly on Win+Fuse
|
||||
public boolean useExperimentalFuse() {
|
||||
return Boolean.getBoolean("fuse.experimental");
|
||||
}
|
||||
|
||||
private int getInt(String propertyName, int defaultValue) {
|
||||
String value = System.getProperty(propertyName);
|
||||
try {
|
||||
|
||||
108
src/main/java/org/cryptomator/common/Passphrase.java
Normal file
108
src/main/java/org/cryptomator/common/Passphrase.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import javax.security.auth.Destroyable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A destroyable CharSequence.
|
||||
*/
|
||||
public class Passphrase implements Destroyable, CharSequence {
|
||||
|
||||
private final char[] data;
|
||||
private final int offset;
|
||||
private final int length;
|
||||
private boolean destroyed;
|
||||
|
||||
/**
|
||||
* Wraps (doesn't copy) the given data.
|
||||
*
|
||||
* @param data The wrapped data. Any changes to this will be reflected in this passphrase
|
||||
*/
|
||||
public Passphrase(char[] data) {
|
||||
this(data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps (doesn't copy) a subarray of the given data.
|
||||
*
|
||||
* @param data The wrapped data. Any changes to this will be reflected in this passphrase
|
||||
* @param offset The subarray offset, i.e. the first character of this passphrase
|
||||
* @param length The subarray length, i.e. the length of this passphrase
|
||||
*/
|
||||
public Passphrase(char[] data, int offset, int length) {
|
||||
if (offset < 0 || length < 0 || offset + length > data.length) {
|
||||
throw new IndexOutOfBoundsException("[%1$d %1$d + %2$d[ not within [0, %3$d[".formatted(offset, length, data.length));
|
||||
}
|
||||
this.data = data;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public static Passphrase copyOf(CharSequence cs) {
|
||||
char[] result = new char[cs.length()];
|
||||
for (int i = 0; i < cs.length(); i++) {
|
||||
result[i] = cs.charAt(i);
|
||||
}
|
||||
return new Passphrase(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Passphrase that = (Passphrase) o;
|
||||
// time-constant comparison
|
||||
int diff = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
diff |= charAt(i) ^ that.charAt(i);
|
||||
}
|
||||
return diff == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// basically Arrays.hashCode, but only for a certain subarray
|
||||
int result = 1;
|
||||
for (int i = 0; i < length; i++) {
|
||||
result = 31 * result + charAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String(data, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
if (index < 0 || index >= length) {
|
||||
throw new IndexOutOfBoundsException("%d not within [0, %d[".formatted(index, length));
|
||||
}
|
||||
return data[offset + index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Passphrase subSequence(int start, int end) {
|
||||
if (start < 0 || end < 0 || end > length || start > end) {
|
||||
throw new IndexOutOfBoundsException("[%d, %d[ not within [0, %d[".formatted(start, end, length));
|
||||
}
|
||||
return new Passphrase(Arrays.copyOfRange(data, offset + start, offset + end));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestroyed() {
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Arrays.fill(data, offset, offset + length, '\0');
|
||||
destroyed = true;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Optional;
|
||||
|
||||
class CustomMountPointChooser implements MountPointChooser {
|
||||
@@ -29,17 +30,15 @@ class CustomMountPointChooser implements MountPointChooser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CustomMountPointChooser.class);
|
||||
|
||||
private final VaultSettings vaultSettings;
|
||||
private final Environment environment;
|
||||
|
||||
@Inject
|
||||
public CustomMountPointChooser(VaultSettings vaultSettings, Environment environment) {
|
||||
public CustomMountPointChooser(VaultSettings vaultSettings) {
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Volume caller) {
|
||||
return caller.getImplementationType() != VolumeImpl.FUSE || !SystemUtils.IS_OS_WINDOWS || environment.useExperimentalFuse();
|
||||
return caller.getImplementationType() != VolumeImpl.WEBDAV;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -79,7 +79,7 @@ public class Cryptomator {
|
||||
communicator.sendHandleLaunchargs(List.of(args));
|
||||
communicator.sendRevealRunningApp();
|
||||
LOG.info("Found running application instance. Shutting down...");
|
||||
return 2;
|
||||
return 0;
|
||||
} else {
|
||||
shutdownHook.runOnShutdown(communicator::closeUnchecked);
|
||||
var executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IPC-%d").build());
|
||||
|
||||
@@ -42,7 +42,7 @@ public enum FxmlFile {
|
||||
this.ressourcePathString = ressourcePathString;
|
||||
}
|
||||
|
||||
String getRessourcePathString() {
|
||||
public String getRessourcePathString() {
|
||||
return ressourcePathString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ public class FxmlLoaderFactory {
|
||||
this.resourceBundle = resourceBundle;
|
||||
}
|
||||
|
||||
public static <T extends FxController> FxmlLoaderFactory forController(T controller, Function<Parent, Scene> sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(Map.of(controller.getClass(), () -> controller), sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A new FXMLLoader instance
|
||||
*/
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package org.cryptomator.ui.common;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class UserInteractionLock<E extends Enum<E>> {
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Condition condition = lock.newCondition();
|
||||
private final BooleanProperty awaitingInteraction = new SimpleBooleanProperty();
|
||||
private final AtomicBoolean interacted = new AtomicBoolean();
|
||||
private final AtomicReference<E> state;
|
||||
|
||||
public UserInteractionLock(E initialValue) {
|
||||
this.state = new AtomicReference<>(initialValue);
|
||||
}
|
||||
|
||||
public synchronized void reset(E value) {
|
||||
state.set(value);
|
||||
interacted.set(false);
|
||||
}
|
||||
|
||||
public void interacted(E result) {
|
||||
assert Platform.isFxApplicationThread();
|
||||
lock.lock();
|
||||
try {
|
||||
state.set(result);
|
||||
interacted.set(true);
|
||||
awaitingInteraction.set(false);
|
||||
condition.signal();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public E awaitInteraction() throws InterruptedException {
|
||||
assert !Platform.isFxApplicationThread();
|
||||
lock.lock();
|
||||
try {
|
||||
Platform.runLater(() -> awaitingInteraction.set(true));
|
||||
while (!interacted.get()) {
|
||||
condition.await();
|
||||
}
|
||||
return state.get();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty awaitingInteraction() {
|
||||
return awaitingInteraction;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.cryptomator.ui.controls;
|
||||
|
||||
import org.cryptomator.common.Passphrase;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.StringProperty;
|
||||
@@ -82,7 +84,7 @@ public class NiceSecurePasswordField extends StackPane {
|
||||
return passwordField.textProperty();
|
||||
}
|
||||
|
||||
public CharSequence getCharacters() {
|
||||
public Passphrase getCharacters() {
|
||||
return passwordField.getCharacters();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.cryptomator.ui.controls;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.NamedArg;
|
||||
@@ -28,7 +29,6 @@ import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import java.nio.CharBuffer;
|
||||
import java.text.Normalizer;
|
||||
import java.text.Normalizer.Form;
|
||||
import java.util.Arrays;
|
||||
@@ -203,8 +203,8 @@ public class SecurePasswordField extends TextField {
|
||||
* @see #wipe()
|
||||
*/
|
||||
@Override
|
||||
public CharSequence getCharacters() {
|
||||
return CharBuffer.wrap(content, 0, length);
|
||||
public Passphrase getCharacters() {
|
||||
return new Passphrase(content, 0, length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,7 +26,7 @@ abstract class KeyLoadingModule {
|
||||
@Provides
|
||||
@KeyLoading
|
||||
@KeyLoadingScoped
|
||||
static KeyLoadingStrategy provideKeyLoaderProvider(@KeyLoading Vault vault, Map<String, Provider<KeyLoadingStrategy>> strategies) {
|
||||
static KeyLoadingStrategy provideKeyLoadingStrategy(@KeyLoading Vault vault, Map<String, Provider<KeyLoadingStrategy>> strategies) {
|
||||
try {
|
||||
String scheme = vault.getVaultConfigCache().get().getKeyId().getScheme();
|
||||
var fallback = KeyLoadingStrategy.failed(new IllegalArgumentException("Unsupported key id " + scheme));
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import dagger.Subcomponent;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@ChooseMasterkeyFileScoped
|
||||
@Subcomponent(modules = {ChooseMasterkeyFileModule.class})
|
||||
public interface ChooseMasterkeyFileComponent {
|
||||
|
||||
@ChooseMasterkeyFileScoped
|
||||
Scene chooseMasterkeyScene();
|
||||
|
||||
@ChooseMasterkeyFileScoped
|
||||
CompletableFuture<Path> result();
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
ChooseMasterkeyFileComponent build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@ChooseMasterkeyFileScoped
|
||||
public class ChooseMasterkeyFileController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChooseMasterkeyFileController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final CompletableFuture<Path> result;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
@Inject
|
||||
public ChooseMasterkeyFileController(@KeyLoading Stage window, CompletableFuture<Path> result, ResourceBundle resourceBundle) {
|
||||
this.window = window;
|
||||
this.result = result;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.window.setOnHiding(this::windowClosed);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
result.cancel(true);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void proceed() {
|
||||
LOG.trace("proceed()");
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle(resourceBundle.getString("unlock.chooseMasterkey.filePickerTitle"));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Cryptomator Masterkey", "*.cryptomator"));
|
||||
File masterkeyFile = fileChooser.showOpenDialog(window);
|
||||
if (masterkeyFile != null) {
|
||||
LOG.debug("Chose masterkey file: {}", masterkeyFile);
|
||||
result.complete(masterkeyFile.toPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Module
|
||||
interface ChooseMasterkeyFileModule {
|
||||
|
||||
@Provides
|
||||
@ChooseMasterkeyFileScoped
|
||||
static CompletableFuture<Path> provideResult() {
|
||||
return new CompletableFuture<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ChooseMasterkeyFileScoped
|
||||
static Scene provideChooseMasterkeyScene(ChooseMasterkeyFileController controller, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return FxmlLoaderFactory.forController(controller, sceneFactory, resourceBundle).createScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import javax.inject.Scope;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ChooseMasterkeyFileScoped {
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@KeyLoadingScoped
|
||||
class MasterkeyFileLoadingFinisher {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MasterkeyFileLoadingFinisher.class);
|
||||
|
||||
private final Vault vault;
|
||||
private final Optional<char[]> storedPassword;
|
||||
private final AtomicReference<char[]> enteredPassword;
|
||||
private final AtomicBoolean shouldSavePassword;
|
||||
private final KeychainManager keychain;
|
||||
|
||||
@Inject
|
||||
MasterkeyFileLoadingFinisher(@KeyLoading Vault vault, @Named("savedPassword") Optional<char[]> storedPassword, AtomicReference<char[]> enteredPassword, @Named("savePassword") AtomicBoolean shouldSavePassword, KeychainManager keychain) {
|
||||
this.vault = vault;
|
||||
this.storedPassword = storedPassword;
|
||||
this.enteredPassword = enteredPassword;
|
||||
this.shouldSavePassword = shouldSavePassword;
|
||||
this.keychain = keychain;
|
||||
}
|
||||
|
||||
public void cleanup(boolean successfullyUnlocked) {
|
||||
if (successfullyUnlocked && shouldSavePassword.get()) {
|
||||
savePasswordToSystemkeychain();
|
||||
}
|
||||
wipePassword(storedPassword.orElse(null));
|
||||
wipePassword(enteredPassword.getAndSet(null));
|
||||
}
|
||||
|
||||
private void savePasswordToSystemkeychain() {
|
||||
if (keychain.isSupported()) {
|
||||
try {
|
||||
keychain.storePassphrase(vault.getId(), vault.getDisplayName(), CharBuffer.wrap(enteredPassword.get()));
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to store passphrase in system keychain.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void wipePassword(char[] pw) {
|
||||
if (pw != null) {
|
||||
Arrays.fill(pw, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,54 +8,17 @@ import dagger.multibindings.StringKey;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Module(subcomponents = {ForgetPasswordComponent.class})
|
||||
public abstract class MasterkeyFileLoadingModule {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MasterkeyFileLoadingModule.class);
|
||||
|
||||
public enum PasswordEntry {
|
||||
PASSWORD_ENTERED,
|
||||
CANCELED
|
||||
}
|
||||
|
||||
public enum MasterkeyFileProvision {
|
||||
MASTERKEYFILE_PROVIDED,
|
||||
CANCELED
|
||||
}
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
static UserInteractionLock<PasswordEntry> providePasswordEntryLock() {
|
||||
return new UserInteractionLock<>(null);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
static UserInteractionLock<MasterkeyFileProvision> provideMasterkeyFileProvisionLock() {
|
||||
return new UserInteractionLock<>(null);
|
||||
}
|
||||
@Module(subcomponents = {ForgetPasswordComponent.class, PassphraseEntryComponent.class, ChooseMasterkeyFileComponent.class})
|
||||
public interface MasterkeyFileLoadingModule {
|
||||
|
||||
@Provides
|
||||
@Named("savedPassword")
|
||||
@@ -67,67 +30,12 @@ public abstract class MasterkeyFileLoadingModule {
|
||||
try {
|
||||
return Optional.ofNullable(keychain.loadPassphrase(vault.getId()));
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to load entry from system keychain.", e);
|
||||
LoggerFactory.getLogger(MasterkeyFileLoadingModule.class).error("Failed to load entry from system keychain.", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
static AtomicReference<Path> provideUserProvidedMasterkeyPath() {
|
||||
return new AtomicReference<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
static AtomicReference<char[]> providePassword(@Named("savedPassword") Optional<char[]> storedPassword) {
|
||||
return new AtomicReference<>(storedPassword.orElse(null));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("savePassword")
|
||||
@KeyLoadingScoped
|
||||
static AtomicBoolean provideSavePasswordFlag(@Named("savedPassword") Optional<char[]> storedPassword) {
|
||||
return new AtomicBoolean(storedPassword.isPresent());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideUnlockScene(@KeyLoading FxmlLoaderFactory fxmlLoaders, @KeyLoading Stage window, @KeyLoading Vault v, ResourceBundle resourceBundle) {
|
||||
var scene = fxmlLoaders.createScene(FxmlFile.UNLOCK_ENTER_PASSWORD);
|
||||
scene.windowProperty().addListener((prop, oldVal, newVal) -> {
|
||||
if (window.equals(newVal)) {
|
||||
window.setTitle(String.format(resourceBundle.getString("unlock.title"), v.getDisplayName()));
|
||||
}
|
||||
});
|
||||
return scene;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideUnlockSelectMasterkeyFileScene(@KeyLoading FxmlLoaderFactory fxmlLoaders, @KeyLoading Stage window, @KeyLoading Vault v, ResourceBundle resourceBundle) {
|
||||
var scene = fxmlLoaders.createScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE);
|
||||
scene.windowProperty().addListener((prop, oldVal, newVal) -> {
|
||||
if (window.equals(newVal)) {
|
||||
window.setTitle(String.format(resourceBundle.getString("unlock.chooseMasterkey.title"), v.getDisplayName()));
|
||||
}
|
||||
});
|
||||
return scene;
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(PassphraseEntryController.class)
|
||||
abstract FxController bindUnlockController(PassphraseEntryController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(SelectMasterkeyFileController.class)
|
||||
abstract FxController bindUnlockSelectMasterkeyFileController(SelectMasterkeyFileController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@KeyLoadingScoped
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptofs.common.BackupHelper;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.cryptolib.api.Masterkey;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.common.Animations;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
|
||||
import org.cryptomator.ui.unlock.UnlockCancelledException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@KeyLoading
|
||||
public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
@@ -36,28 +37,26 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
private final Vault vault;
|
||||
private final MasterkeyFileAccess masterkeyFileAccess;
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> passphraseEntryScene;
|
||||
private final Lazy<Scene> selectMasterkeyFileScene;
|
||||
private final UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock;
|
||||
private final UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock;
|
||||
private final AtomicReference<char[]> password;
|
||||
private final AtomicReference<Path> filePath;
|
||||
private final MasterkeyFileLoadingFinisher finisher;
|
||||
private final PassphraseEntryComponent.Builder passphraseEntry;
|
||||
private final ChooseMasterkeyFileComponent.Builder masterkeyFileChoice;
|
||||
private final KeychainManager keychain;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
private boolean wrongPassword;
|
||||
private Passphrase passphrase;
|
||||
private boolean savePassphrase;
|
||||
private boolean wrongPassphrase;
|
||||
|
||||
@Inject
|
||||
public MasterkeyFileLoadingStrategy(@KeyLoading Vault vault, MasterkeyFileAccess masterkeyFileAccess, @KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath, MasterkeyFileLoadingFinisher finisher) {
|
||||
public MasterkeyFileLoadingStrategy(@KeyLoading Vault vault, MasterkeyFileAccess masterkeyFileAccess, @KeyLoading Stage window, @Named("savedPassword") Optional<char[]> savedPassphrase, PassphraseEntryComponent.Builder passphraseEntry, ChooseMasterkeyFileComponent.Builder masterkeyFileChoice, KeychainManager keychain, ResourceBundle resourceBundle) {
|
||||
this.vault = vault;
|
||||
this.masterkeyFileAccess = masterkeyFileAccess;
|
||||
this.window = window;
|
||||
this.passphraseEntryScene = passphraseEntryScene;
|
||||
this.selectMasterkeyFileScene = selectMasterkeyFileScene;
|
||||
this.passwordEntryLock = passwordEntryLock;
|
||||
this.masterkeyFileProvisionLock = masterkeyFileProvisionLock;
|
||||
this.password = password;
|
||||
this.filePath = filePath;
|
||||
this.finisher = finisher;
|
||||
this.passphraseEntry = passphraseEntry;
|
||||
this.masterkeyFileChoice = masterkeyFileChoice;
|
||||
this.keychain = keychain;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.passphrase = savedPassphrase.map(Passphrase::new).orElse(null);
|
||||
this.savePassphrase = savedPassphrase.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,9 +65,11 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
try {
|
||||
Path filePath = vault.getPath().resolve(keyId.getSchemeSpecificPart());
|
||||
if (!Files.exists(filePath)) {
|
||||
filePath = getAlternateMasterkeyFilePath();
|
||||
filePath = askUserForMasterkeyFilePath();
|
||||
}
|
||||
if (passphrase == null) {
|
||||
askForPassphrase();
|
||||
}
|
||||
CharSequence passphrase = getPassphrase();
|
||||
var masterkey = masterkeyFileAccess.load(filePath, passphrase);
|
||||
//backup
|
||||
if (filePath.startsWith(vault.getPath())) {
|
||||
@@ -90,8 +91,9 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
@Override
|
||||
public boolean recoverFromException(MasterkeyLoadingFailedException exception) {
|
||||
if (exception instanceof InvalidPassphraseException) {
|
||||
this.wrongPassword = true;
|
||||
password.set(null);
|
||||
this.wrongPassphrase = true;
|
||||
passphrase.destroy();
|
||||
this.passphrase = null;
|
||||
return true; // reattempting key load
|
||||
} else {
|
||||
return false; // nothing we can do
|
||||
@@ -100,23 +102,29 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
|
||||
@Override
|
||||
public void cleanup(boolean unlockedSuccessfully) {
|
||||
finisher.cleanup(unlockedSuccessfully);
|
||||
}
|
||||
|
||||
private Path getAlternateMasterkeyFilePath() throws UnlockCancelledException, InterruptedException {
|
||||
if (filePath.get() == null) {
|
||||
return switch (askUserForMasterkeyFilePath()) {
|
||||
case MASTERKEYFILE_PROVIDED -> filePath.get();
|
||||
case CANCELED -> throw new UnlockCancelledException("Choosing masterkey file cancelled.");
|
||||
};
|
||||
} else {
|
||||
return filePath.get();
|
||||
if (unlockedSuccessfully && savePassphrase) {
|
||||
savePasswordToSystemkeychain(passphrase);
|
||||
}
|
||||
if (passphrase != null) {
|
||||
passphrase.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private MasterkeyFileLoadingModule.MasterkeyFileProvision askUserForMasterkeyFilePath() throws InterruptedException {
|
||||
private void savePasswordToSystemkeychain(Passphrase passphrase) {
|
||||
if (keychain.isSupported()) {
|
||||
try {
|
||||
keychain.storePassphrase(vault.getId(), vault.getDisplayName(), passphrase);
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to store passphrase in system keychain.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Path askUserForMasterkeyFilePath() throws InterruptedException {
|
||||
var comp = masterkeyFileChoice.build();
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(selectMasterkeyFileScene.get());
|
||||
window.setScene(comp.chooseMasterkeyScene());
|
||||
window.setTitle(resourceBundle.getString("unlock.chooseMasterkey.title").formatted(vault.getDisplayName()));
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
@@ -126,24 +134,20 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
window.centerOnScreen();
|
||||
}
|
||||
});
|
||||
return masterkeyFileProvisionLock.awaitInteraction();
|
||||
}
|
||||
|
||||
private CharSequence getPassphrase() throws UnlockCancelledException, InterruptedException {
|
||||
if (password.get() == null) {
|
||||
return switch (askForPassphrase()) {
|
||||
case PASSWORD_ENTERED -> CharBuffer.wrap(password.get());
|
||||
case CANCELED -> throw new UnlockCancelledException("Password entry cancelled.");
|
||||
};
|
||||
} else {
|
||||
// e.g. pre-filled from keychain or previous unlock attempt
|
||||
return CharBuffer.wrap(password.get());
|
||||
try {
|
||||
return comp.result().get();
|
||||
} catch (CancellationException e) {
|
||||
throw new UnlockCancelledException("Choosing masterkey file cancelled.");
|
||||
} catch (ExecutionException e) {
|
||||
throw new MasterkeyLoadingFailedException("Failed to select masterkey file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private MasterkeyFileLoadingModule.PasswordEntry askForPassphrase() throws InterruptedException {
|
||||
private void askForPassphrase() throws InterruptedException {
|
||||
var comp = passphraseEntry.savedPassword(passphrase).build();
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(passphraseEntryScene.get());
|
||||
window.setScene(comp.passphraseEntryScene());
|
||||
window.setTitle(resourceBundle.getString("unlock.title").formatted(vault.getDisplayName()));
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
@@ -152,11 +156,19 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
} else {
|
||||
window.centerOnScreen();
|
||||
}
|
||||
if (wrongPassword) {
|
||||
if (wrongPassphrase) {
|
||||
Animations.createShakeWindowAnimation(window).play();
|
||||
}
|
||||
});
|
||||
return passwordEntryLock.awaitInteraction();
|
||||
try {
|
||||
var result = comp.result().get();
|
||||
this.passphrase = result.passphrase();
|
||||
this.savePassphrase = result.savePassphrase();
|
||||
} catch (CancellationException e) {
|
||||
throw new UnlockCancelledException("Password entry cancelled.");
|
||||
} catch (ExecutionException e) {
|
||||
throw new MasterkeyLoadingFailedException("Failed to ask for password.", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Subcomponent;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javafx.scene.Scene;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@PassphraseEntryScoped
|
||||
@Subcomponent(modules = {PassphraseEntryModule.class})
|
||||
public interface PassphraseEntryComponent {
|
||||
|
||||
@PassphraseEntryScoped
|
||||
Scene passphraseEntryScene();
|
||||
|
||||
@PassphraseEntryScoped
|
||||
CompletableFuture<PassphraseEntryResult> result();
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
PassphraseEntryComponent.Builder savedPassword(@Nullable @Named("savedPassword") Passphrase savedPassword);
|
||||
|
||||
PassphraseEntryComponent build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
import org.cryptomator.ui.common.WeakBindings;
|
||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingModule.PasswordEntry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -21,8 +19,8 @@ import javafx.animation.Interpolator;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.binding.ObjectBinding;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
@@ -37,33 +35,27 @@ import javafx.scene.transform.Translate;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import javafx.util.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@KeyLoadingScoped
|
||||
@PassphraseEntryScoped
|
||||
public class PassphraseEntryController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PassphraseEntryController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final AtomicReference<char[]> password;
|
||||
private final AtomicBoolean savePassword;
|
||||
private final Optional<char[]> savedPassword;
|
||||
private final UserInteractionLock<PasswordEntry> passwordEntryLock;
|
||||
private final CompletableFuture<PassphraseEntryResult> result;
|
||||
private final Passphrase savedPassword;
|
||||
private final ForgetPasswordComponent.Builder forgetPassword;
|
||||
private final KeychainManager keychain;
|
||||
private final ObjectBinding<ContentDisplay> unlockButtonContentDisplay;
|
||||
private final BooleanBinding userInteractionDisabled;
|
||||
private final BooleanProperty unlockButtonDisabled;
|
||||
private final StringBinding vaultName;
|
||||
private final BooleanProperty unlockInProgress = new SimpleBooleanProperty();
|
||||
private final ObjectBinding<ContentDisplay> unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, unlockInProgress);
|
||||
private final BooleanProperty unlockButtonDisabled = new SimpleBooleanProperty();
|
||||
|
||||
/* FXML */
|
||||
public NiceSecurePasswordField passwordField;
|
||||
public CheckBox savePasswordCheckbox;
|
||||
public FontAwesome5IconView unlockInProgressView;
|
||||
public ImageView face;
|
||||
public ImageView leftArm;
|
||||
public ImageView rightArm;
|
||||
@@ -72,29 +64,25 @@ public class PassphraseEntryController implements FxController {
|
||||
public Animation unlockAnimation;
|
||||
|
||||
@Inject
|
||||
public PassphraseEntryController(@KeyLoading Stage window, @KeyLoading Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, KeychainManager keychain) {
|
||||
public PassphraseEntryController(@KeyLoading Stage window, @KeyLoading Vault vault, CompletableFuture<PassphraseEntryResult> result, @Nullable @Named("savedPassword") Passphrase savedPassword, ForgetPasswordComponent.Builder forgetPassword, KeychainManager keychain) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.password = password;
|
||||
this.savePassword = savePassword;
|
||||
this.result = result;
|
||||
this.savedPassword = savedPassword;
|
||||
this.passwordEntryLock = passwordEntryLock;
|
||||
this.forgetPassword = forgetPassword;
|
||||
this.keychain = keychain;
|
||||
this.unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, passwordEntryLock.awaitingInteraction());
|
||||
this.userInteractionDisabled = passwordEntryLock.awaitingInteraction().not();
|
||||
this.unlockButtonDisabled = new SimpleBooleanProperty();
|
||||
this.vaultName = WeakBindings.bindString(vault.displayNameProperty());
|
||||
this.window.setOnHiding(this::windowClosed);
|
||||
window.setOnHiding(this::windowClosed);
|
||||
result.whenCompleteAsync((r, t) -> unlockInProgress.set(false), Platform::runLater);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
savePasswordCheckbox.setSelected(savedPassword.isPresent());
|
||||
if (password.get() != null) {
|
||||
passwordField.setPassword(password.get());
|
||||
if (savedPassword != null) {
|
||||
savePasswordCheckbox.setSelected(true);
|
||||
passwordField.setPassword(savedPassword);
|
||||
}
|
||||
unlockButtonDisabled.bind(userInteractionDisabled.or(passwordField.textProperty().isEmpty()));
|
||||
unlockButtonDisabled.bind(unlockInProgress.or(passwordField.textProperty().isEmpty()));
|
||||
|
||||
var leftArmTranslation = new Translate(24, 0);
|
||||
var leftArmRotation = new Rotate(60, 16, 30, 0);
|
||||
@@ -132,7 +120,7 @@ public class PassphraseEntryController implements FxController {
|
||||
new KeyFrame(Duration.millis(1000), faceVisible) //
|
||||
);
|
||||
|
||||
passwordEntryLock.awaitingInteraction().addListener(observable -> stopUnlockAnimation());
|
||||
result.whenCompleteAsync((r, t) -> stopUnlockAnimation());
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -141,26 +129,20 @@ public class PassphraseEntryController implements FxController {
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
// if not already interacted, mark this workflow as cancelled:
|
||||
if (passwordEntryLock.awaitingInteraction().get()) {
|
||||
if(!result.isDone()) {
|
||||
result.cancel(true);
|
||||
LOG.debug("Unlock canceled by user.");
|
||||
passwordEntryLock.interacted(PasswordEntry.CANCELED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void unlock() {
|
||||
LOG.trace("UnlockController.unlock()");
|
||||
unlockInProgress.set(true);
|
||||
CharSequence pwFieldContents = passwordField.getCharacters();
|
||||
char[] newPw = new char[pwFieldContents.length()];
|
||||
for (int i = 0; i < pwFieldContents.length(); i++) {
|
||||
newPw[i] = pwFieldContents.charAt(i);
|
||||
}
|
||||
char[] oldPw = password.getAndSet(newPw);
|
||||
if (oldPw != null) {
|
||||
Arrays.fill(oldPw, ' ');
|
||||
}
|
||||
passwordEntryLock.interacted(PasswordEntry.PASSWORD_ENTERED);
|
||||
Passphrase pw = Passphrase.copyOf(pwFieldContents);
|
||||
result.complete(new PassphraseEntryResult(pw, savePasswordCheckbox.isSelected()));
|
||||
startUnlockAnimation();
|
||||
}
|
||||
|
||||
@@ -184,8 +166,7 @@ public class PassphraseEntryController implements FxController {
|
||||
|
||||
@FXML
|
||||
private void didClickSavePasswordCheckbox() {
|
||||
savePassword.set(savePasswordCheckbox.isSelected());
|
||||
if (!savePasswordCheckbox.isSelected() && savedPassword.isPresent()) {
|
||||
if (!savePasswordCheckbox.isSelected() && savedPassword != null) {
|
||||
forgetPassword.vault(vault).owner(window).build().showForgetPassword().thenAccept(forgotten -> savePasswordCheckbox.setSelected(!forgotten));
|
||||
}
|
||||
}
|
||||
@@ -205,15 +186,15 @@ public class PassphraseEntryController implements FxController {
|
||||
}
|
||||
|
||||
public ContentDisplay getUnlockButtonContentDisplay() {
|
||||
return passwordEntryLock.awaitingInteraction().get() ? ContentDisplay.TEXT_ONLY : ContentDisplay.LEFT;
|
||||
return unlockInProgress.get() ? ContentDisplay.LEFT : ContentDisplay.TEXT_ONLY;
|
||||
}
|
||||
|
||||
public BooleanBinding userInteractionDisabledProperty() {
|
||||
return userInteractionDisabled;
|
||||
public ReadOnlyBooleanProperty userInteractionDisabledProperty() {
|
||||
return unlockInProgress;
|
||||
}
|
||||
|
||||
public boolean isUserInteractionDisabled() {
|
||||
return userInteractionDisabled.get();
|
||||
return unlockInProgress.get();
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty unlockButtonDisabledProperty() {
|
||||
@@ -227,4 +208,6 @@ public class PassphraseEntryController implements FxController {
|
||||
public boolean isKeychainAccessAvailable() {
|
||||
return keychain.isSupported();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Module
|
||||
interface PassphraseEntryModule {
|
||||
|
||||
@Provides
|
||||
@PassphraseEntryScoped
|
||||
static CompletableFuture<PassphraseEntryResult> provideResult() {
|
||||
return new CompletableFuture<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@PassphraseEntryScoped
|
||||
static Scene provideUnlockScene(PassphraseEntryController controller, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return FxmlLoaderFactory.forController(controller, sceneFactory, resourceBundle).createScene(FxmlFile.UNLOCK_ENTER_PASSWORD);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.common.Passphrase;
|
||||
|
||||
// TODO: change to package-private, as soon as this works for Dagger -.-
|
||||
public record PassphraseEntryResult(Passphrase passphrase, boolean savePassphrase) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import javax.inject.Scope;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface PassphraseEntryScoped {
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingModule.MasterkeyFileProvision;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@KeyLoadingScoped
|
||||
public class SelectMasterkeyFileController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SelectMasterkeyFileController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final AtomicReference<Path> masterkeyPath;
|
||||
private final UserInteractionLock<MasterkeyFileProvision> masterkeyFileProvisionLock;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
@Inject
|
||||
public SelectMasterkeyFileController(@KeyLoading Stage window, AtomicReference<Path> masterkeyPath, UserInteractionLock<MasterkeyFileProvision> masterkeyFileProvisionLock, ResourceBundle resourceBundle) {
|
||||
this.window = window;
|
||||
this.masterkeyPath = masterkeyPath;
|
||||
this.masterkeyFileProvisionLock = masterkeyFileProvisionLock;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.window.setOnHiding(this::windowClosed);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
// if not already interacted, mark this workflow as cancelled:
|
||||
if (masterkeyFileProvisionLock.awaitingInteraction().get()) {
|
||||
LOG.debug("Unlock canceled by user.");
|
||||
masterkeyFileProvisionLock.interacted(MasterkeyFileProvision.CANCELED);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void proceed() {
|
||||
LOG.trace("proceed()");
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle(resourceBundle.getString("unlock.chooseMasterkey.filePickerTitle"));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Cryptomator Masterkey", "*.cryptomator"));
|
||||
File masterkeyFile = fileChooser.showOpenDialog(window);
|
||||
if (masterkeyFile != null) {
|
||||
LOG.debug("Chose masterkey file: {}", masterkeyFile);
|
||||
masterkeyPath.set(masterkeyFile.toPath());
|
||||
masterkeyFileProvisionLock.interacted(MasterkeyFileProvision.MASTERKEYFILE_PROVIDED);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,56 +2,48 @@ package org.cryptomator.ui.lock;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@LockScoped
|
||||
public class LockForcedController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LockForcedController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock;
|
||||
private final AtomicReference<CompletableFuture<Boolean>> forceRetryDecision;
|
||||
|
||||
@Inject
|
||||
public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock) {
|
||||
public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, AtomicReference<CompletableFuture<Boolean>> forceRetryDecision) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.forceLockDecisionLock = forceLockDecisionLock;
|
||||
this.forceRetryDecision = forceRetryDecision;
|
||||
this.window.setOnHiding(this::windowClosed);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL);
|
||||
window.close();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void retry() {
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.RETRY);
|
||||
forceRetryDecision.get().complete(false);
|
||||
window.close();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void force() {
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.FORCE);
|
||||
forceRetryDecision.get().complete(true);
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
// if not already interacted, set the decision to CANCEL
|
||||
if (forceLockDecisionLock.awaitingInteraction().get()) {
|
||||
LOG.debug("Lock canceled in force-lock-phase by user.");
|
||||
forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL);
|
||||
}
|
||||
forceRetryDecision.get().cancel(true);
|
||||
}
|
||||
|
||||
// ----- Getter & Setter -----
|
||||
|
||||
@@ -6,13 +6,12 @@ import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
@@ -22,20 +21,16 @@ import javafx.stage.Stage;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Module
|
||||
abstract class LockModule {
|
||||
|
||||
enum ForceLockDecision {
|
||||
CANCEL,
|
||||
RETRY,
|
||||
FORCE;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@LockScoped
|
||||
static UserInteractionLock<LockModule.ForceLockDecision> provideForceLockDecisionLock() {
|
||||
return new UserInteractionLock<>(null);
|
||||
static AtomicReference<CompletableFuture<Boolean>> provideForceRetryDecisionRef() {
|
||||
return new AtomicReference<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.cryptomator.common.vaults.Volume;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -18,6 +17,10 @@ import javafx.concurrent.Task;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* The sequence of actions performed and checked during lock of a vault.
|
||||
@@ -34,43 +37,48 @@ public class LockWorkflow extends Task<Void> {
|
||||
|
||||
private final Stage lockWindow;
|
||||
private final Vault vault;
|
||||
private final UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock;
|
||||
private final AtomicReference<CompletableFuture<Boolean>> forceRetryDecision;
|
||||
private final Lazy<Scene> lockForcedScene;
|
||||
private final Lazy<Scene> lockFailedScene;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
|
||||
@Inject
|
||||
public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, UserInteractionLock<LockModule.ForceLockDecision> forceLockDecisionLock, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy<Scene> lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy<Scene> lockFailedScene, ErrorComponent.Builder errorComponent) {
|
||||
public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, AtomicReference<CompletableFuture<Boolean>> forceRetryDecision, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy<Scene> lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy<Scene> lockFailedScene, ErrorComponent.Builder errorComponent) {
|
||||
this.lockWindow = lockWindow;
|
||||
this.vault = vault;
|
||||
this.forceLockDecisionLock = forceLockDecisionLock;
|
||||
this.forceRetryDecision = forceRetryDecision;
|
||||
this.lockForcedScene = lockForcedScene;
|
||||
this.lockFailedScene = lockFailedScene;
|
||||
this.errorComponent = errorComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void call() throws Volume.VolumeException, InterruptedException, LockNotCompletedException {
|
||||
protected Void call() throws Volume.VolumeException, InterruptedException, LockNotCompletedException, ExecutionException {
|
||||
lock(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void lock(boolean forced) throws InterruptedException {
|
||||
private void lock(boolean forced) throws InterruptedException, ExecutionException {
|
||||
try {
|
||||
vault.lock(forced);
|
||||
} catch (Volume.VolumeException | LockNotCompletedException e) {
|
||||
LOG.info("Locking {} failed (forced: {}).", vault.getDisplayName(), forced, e);
|
||||
var decision = askUserForAction();
|
||||
switch (decision) {
|
||||
case RETRY -> lock(false);
|
||||
case FORCE -> lock(true);
|
||||
case CANCEL -> cancel(false);
|
||||
}
|
||||
retryOrCancel();
|
||||
}
|
||||
}
|
||||
|
||||
private LockModule.ForceLockDecision askUserForAction() throws InterruptedException {
|
||||
forceLockDecisionLock.reset(null);
|
||||
private void retryOrCancel() throws ExecutionException, InterruptedException {
|
||||
try {
|
||||
boolean forced = askWhetherToUseTheForce().get();
|
||||
lock(forced);
|
||||
} catch (CancellationException e) {
|
||||
cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Boolean> askWhetherToUseTheForce() {
|
||||
var decision = new CompletableFuture<Boolean>();
|
||||
forceRetryDecision.set(decision);
|
||||
// show forcedLock dialogue ...
|
||||
Platform.runLater(() -> {
|
||||
lockWindow.setScene(lockForcedScene.get());
|
||||
@@ -83,8 +91,7 @@ public class LockWorkflow extends Task<Void> {
|
||||
lockWindow.centerOnScreen();
|
||||
}
|
||||
});
|
||||
// ... and wait for answer
|
||||
return forceLockDecisionLock.awaitInteraction();
|
||||
return decision;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,6 +91,8 @@ class TrayMenuController {
|
||||
unlockItem.addActionListener(createActionListenerForVault(vault, this::unlockVault));
|
||||
submenu.add(unlockItem);
|
||||
} else if (vault.isUnlocked()) {
|
||||
submenu.setLabel("* ".concat(submenu.getLabel()));
|
||||
|
||||
MenuItem lockItem = new MenuItem(resourceBundle.getString("traymenu.vault.lock"));
|
||||
lockItem.addActionListener(createActionListenerForVault(vault, this::lockVault));
|
||||
submenu.add(lockItem);
|
||||
|
||||
@@ -24,6 +24,7 @@ import javafx.stage.DirectoryChooser;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.StringConverter;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ResourceBundle;
|
||||
@@ -122,8 +123,11 @@ public class MountOptionsController implements FxController {
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setTitle(resourceBundle.getString("vaultOptions.mount.mountPoint.directoryPickerTitle"));
|
||||
try {
|
||||
var initialDir = vault.getVaultSettings().getCustomMountPath().orElse(System.getProperty("user.home"));
|
||||
directoryChooser.setInitialDirectory(Path.of(initialDir).toFile());
|
||||
var initialDir = Path.of(vault.getVaultSettings().getCustomMountPath().orElse(System.getProperty("user.home")));
|
||||
|
||||
if(Files.exists(initialDir)) {
|
||||
directoryChooser.setInitialDirectory(initialDir.toFile());
|
||||
}
|
||||
} catch (InvalidPathException e) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.masterkeyfile.SelectMasterkeyFileController"
|
||||
fx:controller="org.cryptomator.ui.keyloading.masterkeyfile.ChooseMasterkeyFileController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
@@ -34,7 +34,7 @@
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
|
||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#proceed"/>
|
||||
<Button text="%unlock.chooseMasterkey.chooseBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#proceed"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
|
||||
@@ -106,6 +106,7 @@ unlock.unlockBtn=Unlock
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Select Masterkey of "%s"
|
||||
unlock.chooseMasterkey.prompt=Could not find the masterkey file for this vault at its expected location. Please choose the key file manually.
|
||||
unlock.chooseMasterkey.chooseBtn=Choose…
|
||||
unlock.chooseMasterkey.filePickerTitle=Select Masterkey File
|
||||
## Success
|
||||
unlock.success.message=Unlocked "%s" successfully! Your vault is now accessible via its virtual drive.
|
||||
|
||||
@@ -94,7 +94,8 @@ forgetPassword.confirmBtn=نسيت كلمة المرور
|
||||
unlock.passwordPrompt=أدخل كلمة السر لـ "%s":
|
||||
unlock.savePassword=تذكر كلمة المرور
|
||||
unlock.unlockBtn=افتح
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=اختر…
|
||||
unlock.chooseMasterkey.filePickerTitle=اختر ملف الـ Masterkey
|
||||
## Success
|
||||
unlock.success.message=تم فتح "%s" بنجاح! يمكنك الآن الوصول لمخزنك عن طريق القرص الافتراضي الخاص به.
|
||||
|
||||
143
src/main/resources/i18n/strings_bn.properties
Normal file
143
src/main/resources/i18n/strings_bn.properties
Normal file
@@ -0,0 +1,143 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=প্রয়োগ করুন
|
||||
generic.button.back=পিছনে
|
||||
generic.button.cancel=বাতিল করুন
|
||||
generic.button.change=পরিবর্তন করুন
|
||||
generic.button.close=বন্ধ করুন
|
||||
generic.button.copy=কপি
|
||||
generic.button.copied=কপি হয়েছে!
|
||||
generic.button.done=সম্পন্ন হয়েছে
|
||||
generic.button.next=পরবর্তী
|
||||
generic.button.print=প্রিন্ট
|
||||
## Error
|
||||
generic.error.title=ত্রুটি %s
|
||||
generic.error.instruction=ওহো! ক্রিপ্টোমেটর এটা যে হবে তা আশা করেনি. আপনি এই ত্রুটির সমাধানটি খুঁজে দেখুন. ত্রুটিটি সম্পর্কে যদি বিবরণ না পান, আপনি সেটি রিপোর্ট করতে পারেন.
|
||||
generic.error.hyperlink.lookup=ত্রুটিটি খুঁজে দেখুন
|
||||
generic.error.hyperlink.report=ত্রুটিটি রিপোর্ট করুন
|
||||
generic.error.technicalDetails=বিস্তারিত:
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=ভোল্ট
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=দেখান
|
||||
traymenu.lockAllVaults=সব লক করুন
|
||||
traymenu.quitApplication=বের হোন
|
||||
traymenu.vault.unlock=আনলক করুন
|
||||
traymenu.vault.lock=লক করুন
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=ভোল্ট যুক্ত করুন
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=নতুন ভোল্ট তৈরি করুন
|
||||
addvaultwizard.welcome.existingButton=বিদ্যমান কোনো ভোল্ট খুলুন
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=ভোল্ট এর একটি নাম দেন
|
||||
addvaultwizard.new.namePrompt=ভোল্ট এর নাম
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=ভোল্ট এর এনক্রিপ্টেড ফাইলগুলো ক্রিপ্টোমেটর কোথায় সংরক্ষণ করবে?
|
||||
addvaultwizard.new.locationLabel=স্টোরেজ লোকেশন
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerButton=নির্বাচন করুন…
|
||||
addvaultwizard.new.directoryPickerTitle=ডিরেক্টরি নির্বাচন
|
||||
addvaultwizard.new.locationDoesNotExist=নিদিষ্ট করা পথে একটি ডিরেক্টরি বিদ্যমান নয় অথবা প্রবেশ করা যাচ্ছে না
|
||||
addvaultwizard.new.locationIsNotWritable=নিদিষ্ট করা পথে কোনো কিছু পরিবর্তন করার অনুমতি নেই
|
||||
addvaultwizard.new.locationIsOk=আপনার ভোল্টের জন্য উপযুক্ত ঠিকানা
|
||||
addvaultwizard.new.invalidName=ভোল্টের নাম অনুপযুক্ত. অনুগ্রহ করে ভোল্টের জন্য একটি সাধারণ নাম ব্যবহার করুন.
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=ভোল্ট তৈরি করুন
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=পাসওয়ার্ড ছাড়া আপনি আপনার তথ্যগুলো ব্যবহার করতে পারবেন না. তাই আপনি কি একটি পুনরুদ্ধার চাবি চান যদি আপনি পাসওয়ার্ড হারিয়ে ফেলেন?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=হ্যাঁ অবশ্যই, দুঃখিত হওয়ার চেয়ে নিরাপদ থাকাই ভালো
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=না ধন্যবাদ, আমি আমার পাসওয়ার্ড হারাবো না
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=গুরুত্বপূর্ণ.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ ভোল্ট ফাইলস ⚠️
|
||||
addvault.new.readme.storageLocation.2=এটি হচ্ছে আপনার ভোল্টের স্টোরেজ ঠিকানা.
|
||||
addvault.new.readme.storageLocation.3=যা করবেন না
|
||||
addvault.new.readme.storageLocation.4=• কোন ফাইলে কোন ধরনের পরিবর্তন
|
||||
addvault.new.readme.storageLocation.5=• এনক্রিপশনের জন্য কোন ফাইল এই ডিরেক্টরিতে পেশ করা.
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=নির্বাচন করুন…
|
||||
## Success
|
||||
|
||||
# Remove Vault
|
||||
|
||||
# Change Password
|
||||
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
unlock.unlockBtn=আনলক করুন
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=নির্বাচন করুন…
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.retryBtn=পুনরায় চেষ্টা করুন
|
||||
## Failure
|
||||
|
||||
# Migration
|
||||
## Start
|
||||
## Run
|
||||
## Success
|
||||
## Missing file system capabilities
|
||||
## Impossible
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
## Start Failure
|
||||
## Check Selection
|
||||
## Detail view
|
||||
## Fix Application
|
||||
|
||||
# Preferences
|
||||
## General
|
||||
## Volume
|
||||
## Updates
|
||||
## Contribution
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
# Vault Statistics
|
||||
## Read
|
||||
## Write
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=বন্ধ করুন
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.lock=লক করুন
|
||||
main.vaultlist.addVaultBtn=ভোল্ট যুক্ত করুন
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
### Unlocked
|
||||
main.vaultDetail.lockBtn=লক করুন
|
||||
### Missing
|
||||
### Needs Migration
|
||||
### Error
|
||||
|
||||
# Wrong File Alert
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general.vaultName=ভোল্ট এর নাম
|
||||
|
||||
## Mount
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=নির্বাচন করুন…
|
||||
## Master Key
|
||||
|
||||
|
||||
# Recovery Key
|
||||
|
||||
# New Password
|
||||
|
||||
# Quit
|
||||
@@ -94,7 +94,8 @@ forgetPassword.confirmBtn=Zaboravili ste šifru
|
||||
unlock.passwordPrompt=Unesite lozinku za "%s":
|
||||
unlock.savePassword=Zapamti šifru
|
||||
unlock.unlockBtn=Otključaj
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Odaberi…
|
||||
unlock.chooseMasterkey.filePickerTitle=Odaberite Masterkey Datoteku
|
||||
## Success
|
||||
unlock.success.message=Uspješno ste otključali "%s"! Vaš sef je sada dostupan putem svog virtualnog diska.
|
||||
|
||||
@@ -102,8 +102,9 @@ unlock.title=Desbloca "%s"
|
||||
unlock.passwordPrompt=Introduïu la contrasenya de "%s":
|
||||
unlock.savePassword=Recorda la contrasenya
|
||||
unlock.unlockBtn=Desbloqueja
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.prompt=No es pot trobar el fitxer de clau mestra per aquesta bòveda a la ubicació esperada. Escull el fixer manualment.
|
||||
unlock.chooseMasterkey.chooseBtn=Trieu…
|
||||
unlock.chooseMasterkey.filePickerTitle=Seleccioneu el fitxer de Clau Mestra
|
||||
## Success
|
||||
unlock.success.message=S'ha desblocat %s correctament! Podeu accedir a la vostra caixa forta a través de la unitat virtual.
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Odemknout "%s"
|
||||
unlock.passwordPrompt=Zadejte heslo pro "%s":
|
||||
unlock.savePassword=Zapamatovat heslo
|
||||
unlock.unlockBtn=Odemknout
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Vyberte soubor s hlavním klíčem "%s"
|
||||
unlock.chooseMasterkey.prompt=Nepodařilo se najít soubor hlavního klíče pro tento trezor v očekávaném umístění. Vyberte prosím soubor klíče ručně.
|
||||
unlock.chooseMasterkey.chooseBtn=Vybrat...
|
||||
unlock.chooseMasterkey.filePickerTitle=Vyberte soubor s hlavním klíčem
|
||||
## Success
|
||||
unlock.success.message=Trezor "%s" byl úspěšně odemčen a nyní je dostupný jako virtuální jednotka.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Nelze odemknout trezor
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Připojovací bod %s není složkou, není prázdný nebo neexistuje.
|
||||
unlock.error.invalidMountPoint.existing=Připojovací bod %s již existuje nebo nadřazená složka chybí.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Písmeno „%s“ už je používáno pro jiný disk.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -301,6 +304,7 @@ main.vaultDetail.missing.changeLocation=Změnit umístění trezoru…
|
||||
main.vaultDetail.migrateButton=Upgrade trezoru
|
||||
main.vaultDetail.migratePrompt=Váš trezor musí být aktualizován na nový formát, než k němu budete mít přístup
|
||||
### Error
|
||||
main.vaultDetail.error.info=Došlo k chybě při načítání trezoru z disku.
|
||||
main.vaultDetail.error.reload=Obnovit
|
||||
main.vaultDetail.error.windowTitle=Chyba při načítání trezoru
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ traymenu.vault.reveal=Anzeigen
|
||||
addvaultwizard.title=Tresor hinzufügen
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Neuen Tresor erstellen
|
||||
addvaultwizard.welcome.existingButton=Existierenden Tresor öffnen
|
||||
addvaultwizard.welcome.existingButton=Bestehenden Tresor öffnen
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Wähle einen Namen für den Tresor
|
||||
@@ -44,10 +44,10 @@ addvaultwizard.new.namePrompt=Tresorname
|
||||
addvaultwizard.new.locationInstruction=Wo soll Cryptomator die verschlüsselten Dateien deines Tresors ablegen?
|
||||
addvaultwizard.new.locationLabel=Speicherort
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=Eigener Ort
|
||||
addvaultwizard.new.directoryPickerLabel=Benutzerdefinierter Ort
|
||||
addvaultwizard.new.directoryPickerButton=Durchsuchen …
|
||||
addvaultwizard.new.directoryPickerTitle=Verzeichnis auswählen
|
||||
addvaultwizard.new.fileAlreadyExists=Eine Datei oder ein Ordner mit diesem Namen ist bereits vorhanden
|
||||
addvaultwizard.new.fileAlreadyExists=Eine Datei oder ein Ordner dieses Namens besteht bereits
|
||||
addvaultwizard.new.locationDoesNotExist=Ein Ordner im angegebenen Pfad existiert nicht oder kann nicht geöffnet werden
|
||||
addvaultwizard.new.locationIsNotWritable=Kein Schreibzugriff auf den angegebenen Pfad
|
||||
addvaultwizard.new.locationIsOk=Geeigneter Ort für deinen Tresor
|
||||
@@ -59,7 +59,7 @@ addvaultwizard.new.generateRecoveryKeyChoice.yes=Ja bitte, sicher ist sicher
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Nein danke, ich werde mein Passwort nicht verlieren
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=WICHTIG.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ TRESOR-DATEIEN ⚠️
|
||||
addvault.new.readme.storageLocation.1=⚠️ TRESORDATEIEN ⚠️
|
||||
addvault.new.readme.storageLocation.2=Dies ist der Speicherort deines Tresors.
|
||||
addvault.new.readme.storageLocation.3=NICHT
|
||||
addvault.new.readme.storageLocation.4=• Dateien in diesem Verzeichnis ändern oder
|
||||
@@ -68,16 +68,16 @@ addvault.new.readme.storageLocation.6=Falls du Dateien verschlüsseln und den In
|
||||
addvault.new.readme.storageLocation.7=1. Füge diesen Tresor zu Cryptomator hinzu.
|
||||
addvault.new.readme.storageLocation.8=2. Entsperre den Tresor in Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Öffne den Zugangsort durch Klicken auf die Schaltfläche „Anzeigen“.
|
||||
addvault.new.readme.storageLocation.10=Falls Du Hilfe brauchst, lies die Dokumentation: %s
|
||||
addvault.new.readme.storageLocation.10=Falls du Hilfe brauchst, lies die Dokumentation: %s
|
||||
addvault.new.readme.accessLocation.fileName=WILLKOMMEN.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ VERSCHLÜSSELTES LAUFWERK 🔐️
|
||||
addvault.new.readme.accessLocation.2=Dies ist der Zugangsort deines Tresors.
|
||||
addvault.new.readme.accessLocation.3=Alle zu diesem Laufwerk hinzugefügten Dateien werden von Cryptomator verschlüsselt. Du kannst mit diesem arbeiten wie mit jedem anderen Laufwerk bzw. Ordner. Dies ist lediglich eine unverschlüsselte Ansicht des Laufwerkinhalts; auf deiner Festplatte bleiben deine Dateien weiterhin verschlüsselt.
|
||||
addvault.new.readme.accessLocation.4=Diese Datei kannst du löschen.
|
||||
addvault.new.readme.accessLocation.4=Du kannst diese Datei löschen.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Wähle die Datei "vault.cryptomator" deines bestehenden Tresors aus. Falls nur eine Datei mit der Bezeichnung "masterkey.cryptomator" vorhanden ist, nutze stattdessen diese.
|
||||
addvaultwizard.existing.chooseBtn=Durchsuchen…
|
||||
addvaultwizard.existing.filePickerTitle=Tresor Datei auswählen
|
||||
addvaultwizard.existing.instruction=Wähle die Datei „vault.cryptomator“ deines bestehenden Tresors aus. Falls nur eine Datei mit der Bezeichnung „masterkey.cryptomator“ vorhanden ist, nutze stattdessen diese.
|
||||
addvaultwizard.existing.chooseBtn=Durchsuchen …
|
||||
addvaultwizard.existing.filePickerTitle=Tresordatei auswählen
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Tresor „%s“ hinzugefügt.\nUm auf Inhalte zuzugreifen oder welche hinzuzufügen, musst du den Tresor entsperren. Du kannst ihn aber auch zu jedem späteren Zeitpunkt entsperren.
|
||||
addvaultwizard.success.unlockNow=Jetzt entsperren
|
||||
@@ -98,22 +98,25 @@ forgetPassword.information=Dies löscht das gespeicherte Passwort dieses Tresors
|
||||
forgetPassword.confirmBtn=Passwort vergessen
|
||||
|
||||
# Unlock
|
||||
unlock.title="%s" entsperren
|
||||
unlock.title=„%s“ entsperren
|
||||
unlock.passwordPrompt=Gib das Passwort für „%s“ ein:
|
||||
unlock.savePassword=Passwort merken
|
||||
unlock.unlockBtn=Entsperren
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Masterkey von „%s“ auswählen
|
||||
unlock.chooseMasterkey.prompt=Die Masterkey-Datei dieses Tresors konnte nicht gefunden werden. Bitte wähle die Masterkey-Datei manuell aus.
|
||||
unlock.chooseMasterkey.chooseBtn=Durchsuchen …
|
||||
unlock.chooseMasterkey.filePickerTitle=Masterkey-Datei auswählen
|
||||
## Success
|
||||
unlock.success.message=„%s“ erfolgreich entsperrt! Nun kannst du über das virtuelle Laufwerk auf deinen Tresor zugreifen.
|
||||
unlock.success.message=„%s“ erfolgreich entsperrt! Du kannst nun über das virtuelle Laufwerk auf deinen Tresor zugreifen.
|
||||
unlock.success.rememberChoice=Auswahl speichern und nicht mehr anzeigen
|
||||
unlock.success.revealBtn=Laufwerk anzeigen
|
||||
## Failure
|
||||
unlock.error.heading=Tresor konnte nicht entsperrt werden
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Einhängepunkt ist kein leeres Verzeichnis oder existiert nicht: %s
|
||||
unlock.error.invalidMountPoint.existing=Einhängepunkt/Ordner bereits vorhanden oder übergeordneter Ordner fehlt: %s.
|
||||
unlock.error.invalidMountPoint.notExisting=Einhängepunkt „%s“ ist kein leeres Verzeichnis oder existiert nicht.
|
||||
unlock.error.invalidMountPoint.existing=Einhängepunkt „%s“ besteht bereits oder übergeordneter Ordner fehlt.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Laufwerksbuchstabe „%s“ wird bereits verwendet.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -151,11 +154,11 @@ migration.impossible.moreInfo=Der Tresor kann auch jetzt noch mit einer älteren
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
health.title=Integritätstest von "%s"
|
||||
health.intro.header=Zustandsprüfung
|
||||
health.intro.text=Der Zustandscheck ist eine Sammlung von Tests, um Probleme mit der internen Struktur deines Tresores zu finden und möglicherweise zu reparieren. Bitte bedenke:
|
||||
health.title=Integritätsprüfung von „%s“
|
||||
health.intro.header=Integritätsprüfung
|
||||
health.intro.text=Die Integritätsprüfung ist eine Sammlung von Tests, um Probleme mit der internen Struktur deines Tresors zu finden und möglicherweise zu reparieren. Bitte bedenke:
|
||||
health.intro.remarkSync=Stelle sicher, dass alle Geräte vollständig synchronisiert sind. Dies löst die meisten Probleme.
|
||||
health.intro.remarkFix=Nicht alle Probleme können gelöst werden.
|
||||
health.intro.remarkFix=Nicht alle Probleme können behoben werden.
|
||||
health.intro.remarkBackup=Wenn Daten beschädigt sind, kann nur ein Backup helfen.
|
||||
health.intro.affirmation=Ich habe die obenstehende Information gelesen und verstanden
|
||||
## Start Failure
|
||||
@@ -164,24 +167,24 @@ health.fail.ioError=Beim Lesezugriff auf die Konfigurationsdatei ist ein Fehler
|
||||
health.fail.parseError=Beim Parsen der Tresor-Konfiguration ist ein Fehler aufgetreten.
|
||||
health.fail.moreInfo=Weitere Informationen
|
||||
## Check Selection
|
||||
health.checkList.description=Markiere Prüfungen in der linken Liste oder benutze die Knöpfe darunter.
|
||||
health.checkList.description=Markiere Prüfungen in der linken Liste oder benutze die Schaltflächen darunter.
|
||||
health.checkList.selectAllButton=Alle Prüfungen auswählen
|
||||
health.checkList.deselectAllButton=Alle Prüfungen abwählen
|
||||
health.check.runBatchBtn=Ausgewählte Prüfungen ausführen
|
||||
## Detail view
|
||||
health.check.detail.noSelectedCheck=Wähle für die Ergebnisse eine abgeschlossene Integritätsprüfung in der Liste links aus.
|
||||
health.check.detail.noSelectedCheck=Wähle für die Ergebnisse eine abgeschlossene Intregritätsprüfung in der Liste links aus.
|
||||
health.check.detail.checkScheduled=Die Prüfung ist geplant.
|
||||
health.check.detail.checkRunning=Prüfung läuft…
|
||||
health.check.detail.checkRunning=Die Prüfung läuft derzeit …
|
||||
health.check.detail.checkSkipped=Die Prüfung wurde nicht zur Ausführung ausgewählt.
|
||||
health.check.detail.checkFinished=Die Prüfung wurde erfolgreich abgeschlossen.
|
||||
health.check.detail.checkFinishedAndFound=Die Überprüfung wurde beendet. Bitte sichte die Ergebnisse.
|
||||
health.check.detail.checkFailed=Die Prüfung wurde wegen eines Fehlers beendet.
|
||||
health.check.detail.checkFinishedAndFound=Die Prüfung wurde beendet. Bitte überprüfe die Ergebnisse.
|
||||
health.check.detail.checkFailed=Die Prüfung wurde wegen eines Fehlers abgebrochen.
|
||||
health.check.detail.checkCancelled=Die Prüfung wurde abgebrochen.
|
||||
health.check.exportBtn=Bericht exportieren
|
||||
## Fix Application
|
||||
health.fix.fixBtn=Beheben
|
||||
health.fix.successTip=Fehlerbehebung erfolgreich
|
||||
health.fix.failTip=Reparatur fehlgeschlagen, siehe Log für Details
|
||||
health.fix.failTip=Reparatur fehlgeschlagen, siehe Protokoll für Details
|
||||
|
||||
# Preferences
|
||||
preferences.title=Einstellungen
|
||||
@@ -216,7 +219,7 @@ preferences.updates.updateAvailable=Update auf Version %s verfügbar.
|
||||
## Contribution
|
||||
preferences.contribute=Unterstütze uns
|
||||
preferences.contribute.registeredFor=Supporter-Zertifikat registriert für %s
|
||||
preferences.contribute.noCertificate=Unterstütze Cryptomator und erhalte ein Supporter-Zertifikat. Es ist wie ein Lizenzschlüssel, aber für großartige Menschen, die freie Software verwenden. ;-)
|
||||
preferences.contribute.noCertificate=Unterstütze Cryptomator und erhalte ein Supporter-Zertifikat. Es ist eine Art Lizenzschlüssel, aber für großartige Menschen, die freie Software verwenden. ;-)
|
||||
preferences.contribute.getCertificate=Du hast noch keines? Erfahre, wie du es erhalten kannst.
|
||||
preferences.contribute.promptText=Code des Supporter-Zertifikats hier einfügen
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
@@ -228,9 +231,9 @@ preferences.about=Über
|
||||
stats.title=Statistiken für %s
|
||||
stats.cacheHitRate=Cache-Trefferrate
|
||||
## Read
|
||||
stats.read.throughput.idle=Lesen: Leerlauf
|
||||
stats.read.throughput.kibs=Lesen: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Lesen: %.2f MiB/s
|
||||
stats.read.throughput.idle=Leserate: inaktiv
|
||||
stats.read.throughput.kibs=Leserate: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Leserate: %.2f MiB/s
|
||||
stats.read.total.data.none=Gelesen: -
|
||||
stats.read.total.data.kib=Gelesen: %.1f kiB
|
||||
stats.read.total.data.mib=Gelesen: %.1f MiB
|
||||
@@ -241,9 +244,9 @@ stats.decr.total.data.mib=Entschlüsselt: %.1f MiB
|
||||
stats.decr.total.data.gib=Entschlüsselt: %.1f GiB
|
||||
stats.read.accessCount=Lesezugriffe: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Schreiben: Leerlauf
|
||||
stats.write.throughput.kibs=Schreiben: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Schreiben: %.2f MiB/s
|
||||
stats.write.throughput.idle=Schreibrate: inaktiv
|
||||
stats.write.throughput.kibs=Schreibrate: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Schreibrate: %.2f MiB/s
|
||||
stats.write.total.data.none=Geschrieben: -
|
||||
stats.write.total.data.kib=Geschrieben: %.1f kiB
|
||||
stats.write.total.data.mib=Geschrieben: %.1f MiB
|
||||
@@ -286,9 +289,9 @@ main.vaultDetail.unlockedStatus=ENTSPERRT
|
||||
main.vaultDetail.accessLocation=Dein Tresorinhalt ist hier erreichbar:
|
||||
main.vaultDetail.revealBtn=Laufwerk anzeigen
|
||||
main.vaultDetail.lockBtn=Sperren
|
||||
main.vaultDetail.bytesPerSecondRead=Gelesen:
|
||||
main.vaultDetail.bytesPerSecondWritten=Schreiben:
|
||||
main.vaultDetail.throughput.idle=Leerlauf
|
||||
main.vaultDetail.bytesPerSecondRead=Leserate:
|
||||
main.vaultDetail.bytesPerSecondWritten=Schreibrate:
|
||||
main.vaultDetail.throughput.idle=inaktiv
|
||||
main.vaultDetail.throughput.kbps=%.1f kiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
main.vaultDetail.stats=Tresorstatistik
|
||||
@@ -302,7 +305,7 @@ main.vaultDetail.migrateButton=Tresor aktualisieren
|
||||
main.vaultDetail.migratePrompt=Dein Tresor muss auf ein neues Format aktualisiert werden, bevor du auf ihn zugreifen kannst
|
||||
### Error
|
||||
main.vaultDetail.error.info=Beim Laden des Tresors von der Festplatte ist ein Fehler aufgetreten.
|
||||
main.vaultDetail.error.reload=Erneut laden
|
||||
main.vaultDetail.error.reload=Neu laden
|
||||
main.vaultDetail.error.windowTitle=Fehler beim Laden des Tresors
|
||||
|
||||
# Wrong File Alert
|
||||
@@ -334,7 +337,7 @@ vaultOptions.mount.readonly=Schreibgeschützt
|
||||
vaultOptions.mount.customMountFlags=Benutzerdefinierte Einhänge-Optionen
|
||||
vaultOptions.mount.winDriveLetterOccupied=belegt
|
||||
vaultOptions.mount.mountPoint=Einhängepunkt
|
||||
vaultOptions.mount.mountPoint.auto=Wähle automatisch einen geeigneten Ort aus
|
||||
vaultOptions.mount.mountPoint.auto=Automatisch einen geeigneten Ort auswählen
|
||||
vaultOptions.mount.mountPoint.driveLetter=Laufwerksbuchstaben zuweisen
|
||||
vaultOptions.mount.mountPoint.custom=Eigener Pfad
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Durchsuchen …
|
||||
@@ -343,7 +346,7 @@ vaultOptions.mount.mountPoint.directoryPickerTitle=Wähle ein leeres Verzeichnis
|
||||
vaultOptions.masterkey=Passwort
|
||||
vaultOptions.masterkey.changePasswordBtn=Passwort ändern
|
||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Gespeichertes Passwort vergessen
|
||||
vaultOptions.masterkey.recoveryKeyExplanation=Dein Wiederherstellungsschlüssel gehört nur dir! Dieser wird benötigt, um deinen Tresor wiederherzustellen, für den Fall das du dein Passwort verloren hast.
|
||||
vaultOptions.masterkey.recoveryKeyExplanation=Ein Wiederherstellungsschlüssel ist bei Passwortverlust deine einzige Möglichkeit, den Zugriff auf einen Tresor wiederherzustellen.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Wiederherstellungsschlüssel anzeigen
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Passwort wiederherstellen
|
||||
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Ξεκλειδώστε "%s"
|
||||
unlock.passwordPrompt=Εισάγετε τον κωδικό για "%s":
|
||||
unlock.savePassword=Απομνημόνευση κωδικού πρόσβασης
|
||||
unlock.unlockBtn=Ξεκλείδωμα
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Επιλέξτε το Masterkey του "%s"
|
||||
unlock.chooseMasterkey.prompt=Αδυναμία εύρεσης του αρχείου masterkey για αυτό το vault στην αναμενόμενη τοποθεσία. Παρακαλώ επιλέξτε το αρχείο χειροκίνητα.
|
||||
unlock.chooseMasterkey.chooseBtn=Επιλογή…
|
||||
unlock.chooseMasterkey.filePickerTitle=Επιλέξτε το αρχείο Masterkey
|
||||
## Success
|
||||
unlock.success.message=Ξεκλειδώθηκε "%s" επιτυχώς! Το vault σας είναι διαθέσιμο μέσω του εικονικού δίσκου του.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Αδυναμία ξεκλειδώματος vault
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Το σημείο προσάρτησης δεν είναι κενός φάκελος ή δεν υπάρχει: %s
|
||||
unlock.error.invalidMountPoint.existing=Το σημείο/φάκελος προσάρτησης υπάρχει ήδη ή ο γονικός φάκελος λείπει: %s
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Το Γράμμα Δίσκου "%s" χρησιμοποιείται ήδη.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -68,7 +68,7 @@ addvault.new.readme.storageLocation.6=Cuando se quiere cifrar archivos y ver el
|
||||
addvault.new.readme.storageLocation.7=1. Agregar esta bóveda a Cryptomator.
|
||||
addvault.new.readme.storageLocation.8=2. Desbloquear la bóveda en Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Abrir el lugar de acceso haciendo clic en el botón "Revelar".
|
||||
addvault.new.readme.storageLocation.10=Si se necesita ayuda, visitar la documentación: %s
|
||||
addvault.new.readme.storageLocation.10=Si necesita ayuda, visite la documentación: %s
|
||||
addvault.new.readme.accessLocation.fileName=BIENVENIDA.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ VOLUMEN CIFRADO 🔐️
|
||||
addvault.new.readme.accessLocation.2=Este es el lugar de acceso de la bóveda.
|
||||
@@ -102,8 +102,10 @@ unlock.title=Desbloquear "%s"
|
||||
unlock.passwordPrompt=Ingresar contraseña para "%s":
|
||||
unlock.savePassword=Recordar contraseña
|
||||
unlock.unlockBtn=Desbloquear
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Seleccionar clave maestra de "%s"
|
||||
unlock.chooseMasterkey.prompt=No se pudo encontrar el archivo de la clave maestra de esta bóveda en la ubicación esperada. Por favor, elija manualmente el archivo de la clave.
|
||||
unlock.chooseMasterkey.chooseBtn=Elegir…
|
||||
unlock.chooseMasterkey.filePickerTitle=Seleccione el archivo de la clave maestra
|
||||
## Success
|
||||
unlock.success.message=¡Desbloqueo de "%s" exitoso! Su bóveda ahora es accesible a través de su unidad virtual.
|
||||
@@ -112,8 +114,9 @@ unlock.success.revealBtn=Revelar unidad
|
||||
## Failure
|
||||
unlock.error.heading=No se puede desbloquear la bóveda
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=El punto de montaje no es un directorio vacío o no existe: %s
|
||||
unlock.error.invalidMountPoint.existing=El punto de montaje/carpeta ya existe o falta la carpeta padre: %s
|
||||
unlock.error.invalidMountPoint.notExisting=El punto de montaje "%s"no es un directorio, no está vacío o no existe.
|
||||
unlock.error.invalidMountPoint.existing=El punto de montaje "%s" ya existe o falta la carpeta padre.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=La letra de unidad "%s" ya está en uso.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -122,7 +125,7 @@ lock.forced.message=El bloqueo de "%s" fue bloqueado por operaciones pendientes
|
||||
lock.forced.retryBtn=Reintentar
|
||||
lock.forced.forceBtn=Forzar bloqueo
|
||||
## Failure
|
||||
lock.fail.heading=Falló al bloquear la bóveda.
|
||||
lock.fail.heading=Error al bloquear la bóveda.
|
||||
lock.fail.message=No se pudo bloquear la bóveda "%s". Asegúrese de que el trabajo no guardado se ha guardado en otro lugar y las operaciones de lectura/escritura importantes han finalizado. Para cerrar la bóveda termine el proceso de Cryptomator.
|
||||
|
||||
# Migration
|
||||
@@ -169,7 +172,7 @@ health.checkList.selectAllButton=Seleccionar todas las comprobaciones
|
||||
health.checkList.deselectAllButton=Deseleccionar todas las comprobaciones
|
||||
health.check.runBatchBtn=Ejecutar las comprobaciones seleccionadas
|
||||
## Detail view
|
||||
health.check.detail.noSelectedCheck=Para los resultados seleccione una comprobación del estado en la lista de la izquierda
|
||||
health.check.detail.noSelectedCheck=Para los resultados seleccione una comprobación del estado finalizada en la lista de la izquierda.
|
||||
health.check.detail.checkScheduled=La comprobación está programada.
|
||||
health.check.detail.checkRunning=La comprobación se está ejecutando…
|
||||
health.check.detail.checkSkipped=No se ha seleccionado la comprobación para ejecutarse.
|
||||
@@ -217,7 +220,7 @@ preferences.updates.updateAvailable=Actualización a la versión %s disponible.
|
||||
preferences.contribute=Apóyenos
|
||||
preferences.contribute.registeredFor=Certificado de soporte registrado para %s
|
||||
preferences.contribute.noCertificate=Apoye a Cryptomator y reciba un certificado de seguidor. Es como una clave de licencia, pero para gente asombrosa usando software libre. ;-)
|
||||
preferences.contribute.getCertificate=¿Aún no tiene una? Aprenda cómo puede obtenerlo.
|
||||
preferences.contribute.getCertificate=¿Aún no tiene uno? Aprenda cómo puede obtenerlo.
|
||||
preferences.contribute.promptText=Pegue aquí el código de certificado de seguidor
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
@@ -244,7 +247,7 @@ stats.read.accessCount=Total leídos: %d
|
||||
stats.write.throughput.idle=Escritura: inactivo
|
||||
stats.write.throughput.kibs=Escritura: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Escritura: %.2f MiB/s
|
||||
stats.write.total.data.none=Datos escritos:-
|
||||
stats.write.total.data.none=Datos escritos: -
|
||||
stats.write.total.data.kib=Datos escritos: %.1f kiB
|
||||
stats.write.total.data.mib=Datos escritos: %.1f MiB
|
||||
stats.write.total.data.gib=Datos escritos: %.1f GiB
|
||||
@@ -259,12 +262,12 @@ main.closeBtn.tooltip=Cerrar
|
||||
main.minimizeBtn.tooltip=Minimizar
|
||||
main.preferencesBtn.tooltip=Preferencias
|
||||
main.debugModeEnabled.tooltip=Modo de depuración activado
|
||||
main.donationKeyMissing.tooltip=Por favor, considera donar
|
||||
main.donationKeyMissing.tooltip=Por favor, considere donar
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Añadir esta bóveda
|
||||
main.dropZone.unknownDragboardContent=Si desea añadir una bóveda, arrástrela a esta ventana
|
||||
## Vault List
|
||||
main.vaultlist.emptyList.onboardingInstruction=Hacer clic aquí para añadir una bóveda
|
||||
main.vaultlist.emptyList.onboardingInstruction=Haga clic aquí para añadir una bóveda
|
||||
main.vaultlist.contextMenu.remove=Eliminar…
|
||||
main.vaultlist.contextMenu.lock=Bloquear
|
||||
main.vaultlist.contextMenu.unlock=Desbloquear…
|
||||
@@ -274,9 +277,9 @@ main.vaultlist.contextMenu.reveal=Revelar unidad
|
||||
main.vaultlist.addVaultBtn=Añadir bóveda
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
main.vaultDetail.welcomeOnboarding=Gracias por elegir Cryptomator para proteger los archivos. En caso de necesitar ayuda, revisar nuestras guías:
|
||||
main.vaultDetail.welcomeOnboarding=Gracias por elegir Cryptomator para proteger sus archivos. En caso de necesitar ayuda, revise nuestras guías:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=BLOQUEADO
|
||||
main.vaultDetail.lockedStatus=BLOQUEADA
|
||||
main.vaultDetail.unlockBtn=Desbloquear…
|
||||
main.vaultDetail.unlockNowBtn=Desbloquear ahora
|
||||
main.vaultDetail.optionsBtn=Opciones de la bóveda
|
||||
@@ -286,7 +289,7 @@ main.vaultDetail.unlockedStatus=DESBLOQUEADO
|
||||
main.vaultDetail.accessLocation=El contenido de la bóveda es accesible aquí:
|
||||
main.vaultDetail.revealBtn=Revelar unidad
|
||||
main.vaultDetail.lockBtn=Bloquear
|
||||
main.vaultDetail.bytesPerSecondRead=Leído:
|
||||
main.vaultDetail.bytesPerSecondRead=Lectura:
|
||||
main.vaultDetail.bytesPerSecondWritten=Escritura:
|
||||
main.vaultDetail.throughput.idle=inactivo
|
||||
main.vaultDetail.throughput.kbps=%.1f kiB/s
|
||||
@@ -298,7 +301,7 @@ main.vaultDetail.missing.recheck=Volver a comprobar
|
||||
main.vaultDetail.missing.remove=Eliminar de la lista de bóveda…
|
||||
main.vaultDetail.missing.changeLocation=Cambiar ubicación de la bóveda…
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=Mejorar bóveda
|
||||
main.vaultDetail.migrateButton=Actualizar bóveda
|
||||
main.vaultDetail.migratePrompt=Su bóveda necesita ser actualizada a un formato nuevo antes de poder acceder a ella
|
||||
### Error
|
||||
main.vaultDetail.error.info=Se produjo un error al cargar la bóveda del disco.
|
||||
@@ -306,13 +309,13 @@ main.vaultDetail.error.reload=Recargar
|
||||
main.vaultDetail.error.windowTitle=Error al cargar la bóveda
|
||||
|
||||
# Wrong File Alert
|
||||
wrongFileAlert.title=Cómo encriptar archivos
|
||||
wrongFileAlert.header.title=¿Se intentan cifrar estos archivos?
|
||||
wrongFileAlert.title=Cómo cifrar archivos
|
||||
wrongFileAlert.header.title=¿Intenta cifrar estos archivos?
|
||||
wrongFileAlert.header.lead=Para este propósito, Cryptomator proporciona un volumen en su administrador de archivos del sistema.
|
||||
wrongFileAlert.instruction.0=Para cifrar archivos, seguir estos pasos:
|
||||
wrongFileAlert.instruction.1=1. Desbloquear la bóveda.
|
||||
wrongFileAlert.instruction.2=2. Hacer clic en "Revelar" para abrir el volumen en el administrador de archivos.
|
||||
wrongFileAlert.instruction.3=3. Añadir los archivos a este volumen.
|
||||
wrongFileAlert.instruction.0=Para cifrar archivos, siga estos pasos:
|
||||
wrongFileAlert.instruction.1=1. Desbloquee su bóveda.
|
||||
wrongFileAlert.instruction.2=2. Haga clic en "Revelar" para abrir el volumen en el administrador de archivos.
|
||||
wrongFileAlert.instruction.3=3. Añada los archivos a este volumen.
|
||||
wrongFileAlert.link=Para más ayuda, visite
|
||||
|
||||
# Vault Options
|
||||
@@ -322,7 +325,7 @@ vaultOptions.general.vaultName=Nombre de la bóveda
|
||||
vaultOptions.general.autoLock.lockAfterTimePart1=Bloquear después de
|
||||
vaultOptions.general.autoLock.lockAfterTimePart2=minutos
|
||||
vaultOptions.general.unlockAfterStartup=Desbloquear bóveda al iniciar Cryptomator
|
||||
vaultOptions.general.actionAfterUnlock=Después de desbloquear exitosamente
|
||||
vaultOptions.general.actionAfterUnlock=Después de desbloquear con éxito
|
||||
vaultOptions.general.actionAfterUnlock.ignore=No hacer nada
|
||||
vaultOptions.general.actionAfterUnlock.reveal=Revelar unidad
|
||||
vaultOptions.general.actionAfterUnlock.ask=Preguntar
|
||||
@@ -362,7 +365,7 @@ newPassword.promptText=Ingrese una contraseña nueva
|
||||
newPassword.reenterPassword=Confirme la contraseña nueva
|
||||
newPassword.passwordsMatch=¡Las contraseñas coinciden!
|
||||
newPassword.passwordsDoNotMatch=Las contraseñas no coinciden
|
||||
passwordStrength.messageLabel.tooShort=Usar al menos %d caracteres
|
||||
passwordStrength.messageLabel.tooShort=Use al menos %d caracteres
|
||||
passwordStrength.messageLabel.0=Muy débil
|
||||
passwordStrength.messageLabel.1=Débil
|
||||
passwordStrength.messageLabel.2=Aceptable
|
||||
|
||||
@@ -61,7 +61,8 @@ addvaultwizard.existing.chooseBtn=Mamili…
|
||||
|
||||
# Unlock
|
||||
unlock.unlockBtn=I-unlock
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Mamili…
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
@@ -63,7 +63,7 @@ addvault.new.readme.storageLocation.1=Fichiers de coffre-fort
|
||||
addvault.new.readme.storageLocation.2=Ceci est le chemin de votre coffre-fort.
|
||||
addvault.new.readme.storageLocation.3=NE PAS
|
||||
addvault.new.readme.storageLocation.4=Modifier n'importe quel fichier dans ce répertoire ou
|
||||
addvault.new.readme.storageLocation.5=Collez n'importe quel fichier à chiffrer dans ce répertoire.
|
||||
addvault.new.readme.storageLocation.5=• coller de fichier à chiffrer dans ce répertoire.
|
||||
addvault.new.readme.storageLocation.6=Si vous voulez chiffrer les fichiers et afficher le contenu du coffre, faites ce qui suit :
|
||||
addvault.new.readme.storageLocation.7=1. Ajouter ce coffre à Cryptomator.
|
||||
addvault.new.readme.storageLocation.8=2. Déverrouillez le coffre-fort dans Cryptomator.
|
||||
@@ -102,8 +102,10 @@ unlock.title=Déverrouiller %s
|
||||
unlock.passwordPrompt=Entrez le mot de passe pour “%s” :
|
||||
unlock.savePassword=Mémoriser le mot de passe
|
||||
unlock.unlockBtn=Déverrouiller
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Sélectionner la clé principale de "%s"
|
||||
unlock.chooseMasterkey.prompt=Impossible de trouver le fichier clef à l'adresse attendue pour ce coffre. Veuillez sélectionner le fichier clef manuellement.
|
||||
unlock.chooseMasterkey.chooseBtn=Choisir...
|
||||
unlock.chooseMasterkey.filePickerTitle=Sélectionner le fichier clef
|
||||
## Success
|
||||
unlock.success.message=“%s” déverrouillé ! Le contenu de votre coffre est maintenant accessible par son lecteur virtuel.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Impossible de déverrouiller le coffre
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Le point de montage «%s» n'est pas un répertoire, n'est pas vide ou n'existe pas.
|
||||
unlock.error.invalidMountPoint.existing=Le point de montage/le répertoire existe déjà ou le répertoire parent est manquant: %s
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Le lecteur "%s" est en déjà utilisé.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -318,7 +321,7 @@ wrongFileAlert.link=Pour toute aide supplémentaire, visitez
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=Général
|
||||
vaultOptions.general.vaultName=Nom de voûte
|
||||
vaultOptions.general.vaultName=Nom du coffre-fort
|
||||
vaultOptions.general.autoLock.lockAfterTimePart1=Verrouiler en cas d'inactivité pendant
|
||||
vaultOptions.general.autoLock.lockAfterTimePart2=minutes
|
||||
vaultOptions.general.unlockAfterStartup=Déverrouiller le coffre au démarrage
|
||||
|
||||
89
src/main/resources/i18n/strings_gl.properties
Normal file
89
src/main/resources/i18n/strings_gl.properties
Normal file
@@ -0,0 +1,89 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
## Error
|
||||
|
||||
# Defaults
|
||||
|
||||
# Tray Menu
|
||||
|
||||
# Add Vault Wizard
|
||||
## Welcome
|
||||
## New
|
||||
### Name
|
||||
### Location
|
||||
### Password
|
||||
### Information
|
||||
## Existing
|
||||
## Success
|
||||
|
||||
# Remove Vault
|
||||
|
||||
# Change Password
|
||||
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
## Select
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.retryBtn=Tentar de novo
|
||||
## Failure
|
||||
|
||||
# Migration
|
||||
## Start
|
||||
## Run
|
||||
## Success
|
||||
## Missing file system capabilities
|
||||
## Impossible
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
## Start Failure
|
||||
## Check Selection
|
||||
## Detail view
|
||||
## Fix Application
|
||||
|
||||
# Preferences
|
||||
## General
|
||||
## Volume
|
||||
## Updates
|
||||
## Contribution
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
# Vault Statistics
|
||||
## Read
|
||||
## Write
|
||||
|
||||
# Main Window
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
### Unlocked
|
||||
### Missing
|
||||
### Needs Migration
|
||||
### Error
|
||||
|
||||
# Wrong File Alert
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
|
||||
## Mount
|
||||
## Master Key
|
||||
|
||||
|
||||
# Recovery Key
|
||||
|
||||
# New Password
|
||||
|
||||
# Quit
|
||||
@@ -32,7 +32,7 @@ traymenu.vault.lock=נעילה
|
||||
traymenu.vault.reveal=חשוף
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=הוסף כספת
|
||||
addvaultwizard.title=יצירת כספת
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=צור כספת חדשה
|
||||
addvaultwizard.welcome.existingButton=פתח כספת קיימת
|
||||
@@ -43,9 +43,10 @@ addvaultwizard.new.namePrompt=שם הכספת
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=היכן Cryptomator צריך לשמור את הקבצים המוצפנים של הכספת שלך?
|
||||
addvaultwizard.new.locationLabel=מיקום אחסון
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=מיקום מותאם אישית
|
||||
addvaultwizard.new.directoryPickerButton=בחר...
|
||||
addvaultwizard.new.directoryPickerTitle=בחירת ספרייה
|
||||
addvaultwizard.new.directoryPickerTitle=בחירת תיקייה
|
||||
addvaultwizard.new.fileAlreadyExists=שם הקובץ או שם התיקייה עם שם הכספת כבר קיים
|
||||
addvaultwizard.new.locationDoesNotExist=מחיצה בנתיב הנקוב לא קיימת או אין אפשרות לקבל אליה גישה
|
||||
addvaultwizard.new.locationIsNotWritable=אין הרשאת כתיבה בנתיב הנקוב
|
||||
@@ -74,32 +75,74 @@ addvault.new.readme.accessLocation.2=זהו מיקום גישה לכספת של
|
||||
addvault.new.readme.accessLocation.3=כל קובץ אשר יצורף לספרייה זו יעבור הצפנה באמצעות Cryptomator. את/ה תוכל/י לעבוד עליו כמו עם כל קבוץ/מחיצה רגילים. זהו מצב הצגה מפוענח של התוכן, הקבצים שלך נשארים מוצפנים על הדיסק הקשיח שלך בכל רגע.
|
||||
addvault.new.readme.accessLocation.4=תרגיש/י בנוח להסיר את הקובץ הזה.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=בחר את קובץ "vault.cryptomator" של כספת קיימת. אם קיים קובץ בשם "masterkey.cryptomator" בלבד, בחר/י אותו במקום.
|
||||
addvaultwizard.existing.chooseBtn=בחר...
|
||||
addvaultwizard.existing.filePickerTitle=בחר קובץ כספת
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=נוספה כספת "%s".\nהנך צריך/ה לבטל נעילת כספת זו בכדי לקבל גישה או להוסיף קבצים. לחילופין תוכל/י לבטל נעילה בכל נקודת זמן מאוחרת יותר.
|
||||
addvaultwizard.success.unlockNow=בטל נעילה כעת
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=הסר כספת
|
||||
removeVault.information=זה יגרום ל-Cryptomator לשכוח מהכספת הזו. תוכל/י להוסיף אותה שוב מאוחר יותר. קבצים מוצפנים לא ימחקו מהכונן שלך.
|
||||
removeVault.confirmBtn=הסר כספת
|
||||
|
||||
# Change Password
|
||||
changepassword.title=שנה סיסמה
|
||||
changepassword.enterOldPassword=הקש את הסיסמה הנוכחית ל-"%s"
|
||||
changepassword.finalConfirmation=אני מבין/ה שלא אוכל לגשת למידע שלי במקרה ואשכח את הסיסמה שלי
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=שכח סיסמה
|
||||
forgetPassword.information=זה ימחק את הסיסמה השמורה של הכספת הזו ממחזיק מפתחות המערכת.
|
||||
forgetPassword.confirmBtn=שכח סיסמה
|
||||
|
||||
# Unlock
|
||||
unlock.title=בטל/י נעילה ל-"%s"
|
||||
unlock.passwordPrompt=הכנס/י סיסמה ל-"%s":
|
||||
unlock.savePassword=זכור סיסמה
|
||||
unlock.unlockBtn=בטל נעילה
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=בחר/י מפתח מאסטר של "%s"
|
||||
unlock.chooseMasterkey.prompt=מפתח מאסטר של כספת זו לא נמצא במיקום הצפוי. בחר/י בבקשה את המפתח באופן ידני.
|
||||
unlock.chooseMasterkey.chooseBtn=בחר...
|
||||
unlock.chooseMasterkey.filePickerTitle=בחר/י קובץ מפתח מאסטר
|
||||
## Success
|
||||
unlock.success.message=הנעילה ל-"%s" בוטלה בהצלחה! הכספת שלך נגישה כעת דרך כונן ווירטואלי.
|
||||
unlock.success.rememberChoice=זכור בחירה, אל תראה שוב
|
||||
unlock.success.revealBtn=חשוף את הכונן
|
||||
## Failure
|
||||
unlock.error.heading=לא מתאפשר לבטל נעילת הכספת
|
||||
### Invalid Mount Point
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=הנעילה נכשלה
|
||||
lock.forced.retryBtn=נסה שנית
|
||||
lock.forced.forceBtn=הכרח נעילה
|
||||
## Failure
|
||||
lock.fail.heading=נעילת הכספת נשכלה.
|
||||
|
||||
# Migration
|
||||
migration.title=שדרג הכספת
|
||||
## Start
|
||||
migration.start.confirm=כן, הכספת שלי מסונכרנת במלואה
|
||||
## Run
|
||||
migration.run.enterPassword=הכנס/י סיסמה עבור "%s"
|
||||
migration.run.startMigrationBtn=העבר הכספת
|
||||
migration.run.progressHint=הדבר יקח זמן מה…
|
||||
## Success
|
||||
migration.success.nextStepsInstructions="%s" הועברה בהצלחה.\nהנך יכול/ה לפתוח את הכספת שלך.
|
||||
migration.success.unlockNow=בטל נעילה כעת
|
||||
## Missing file system capabilities
|
||||
migration.error.missingFileSystemCapabilities.title=מערכת קבצים אינה נתמכת
|
||||
migration.error.missingFileSystemCapabilities.description=העברה לא החלה, כיוון שהכספת שלך נמצאת במערכת קבצים לא מתאימה.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=מערכת קבצים אינה תומכת בשמות קבצים ארוכים.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=מערכת קבצים אינה תומכת בנתיבים ארוכים.
|
||||
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=מערכת הקבצים אינה מאפשרת את קריאתה.
|
||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=מערכת הקבצים אינה מאפשרת את הכתיבה אליה.
|
||||
## Impossible
|
||||
migration.impossible.heading=לא יכול להעביר את הכספת
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
@@ -128,14 +171,19 @@ main.preferencesBtn.tooltip=העדפות
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.lock=נעילה
|
||||
main.vaultlist.addVaultBtn=הוסף כספת
|
||||
main.vaultlist.contextMenu.unlockNow=בטל נעילה כעת
|
||||
main.vaultlist.contextMenu.reveal=חשוף את הכונן
|
||||
main.vaultlist.addVaultBtn=יצירת כספת
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
main.vaultDetail.unlockNowBtn=בטל נעילה כעת
|
||||
### Unlocked
|
||||
main.vaultDetail.revealBtn=חשוף את הכונן
|
||||
main.vaultDetail.lockBtn=נעילה
|
||||
### Missing
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=שדרג הכספת
|
||||
### Error
|
||||
|
||||
# Wrong File Alert
|
||||
@@ -143,10 +191,12 @@ main.vaultDetail.lockBtn=נעילה
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general.vaultName=שם הכספת
|
||||
vaultOptions.general.actionAfterUnlock.reveal=חשוף את הכונן
|
||||
|
||||
## Mount
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=בחר...
|
||||
## Master Key
|
||||
vaultOptions.masterkey.changePasswordBtn=שנה סיסמה
|
||||
|
||||
|
||||
# Recovery Key
|
||||
|
||||
@@ -58,6 +58,7 @@ addvault.new.readme.storageLocation.5=• • इस डायरेक्ट
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=चुनें…
|
||||
## Success
|
||||
addvaultwizard.success.unlockNow=अब अनलॉक करें
|
||||
|
||||
# Remove Vault
|
||||
|
||||
@@ -68,7 +69,8 @@ changepassword.title=पासवर्ड बदलें
|
||||
|
||||
# Unlock
|
||||
unlock.unlockBtn=अनलॉक करें
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=चुनें…
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
@@ -83,6 +85,7 @@ migration.title=वाउल्ट को अपग्रेड करें
|
||||
## Start
|
||||
## Run
|
||||
## Success
|
||||
migration.success.unlockNow=अब अनलॉक करें
|
||||
## Missing file system capabilities
|
||||
## Impossible
|
||||
|
||||
@@ -114,10 +117,12 @@ main.preferencesBtn.tooltip=प्राथमिकताएं
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.lock=लॉक करें
|
||||
main.vaultlist.contextMenu.unlockNow=अब अनलॉक करें
|
||||
main.vaultlist.addVaultBtn=वाउल्ट डालें
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
main.vaultDetail.unlockNowBtn=अब अनलॉक करें
|
||||
main.vaultDetail.optionsBtn=वॉल्ट के विकल्प
|
||||
### Unlocked
|
||||
main.vaultDetail.accessLocation=आपके वॉल्ट की चीजें यहाँ एक्सेस कर सकतें हैं:
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
##
|
||||
## Select
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
@@ -102,8 +102,9 @@ unlock.title="%s" feloldása
|
||||
unlock.passwordPrompt=Írja be a jelszavát a következő széfhez "%s":
|
||||
unlock.savePassword=Jelszó megjegyzése
|
||||
unlock.unlockBtn=Feloldás
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.prompt=Nem található a tároló kulcsfájlja a várt helyen. Kérjük válassza ki a kulcsfájlt manuálisan.
|
||||
unlock.chooseMasterkey.chooseBtn=Választás…
|
||||
unlock.chooseMasterkey.filePickerTitle=Mesterkulcs fájl kiválasztása
|
||||
## Success
|
||||
unlock.success.message="%s" sikreresen feloldásra került! Mostmár hozzáférhet a virtuális trezorhoz.
|
||||
|
||||
@@ -13,66 +13,66 @@ generic.button.done=Selesai
|
||||
generic.button.next=Lanjut
|
||||
generic.button.print=Cetak
|
||||
## Error
|
||||
generic.error.title=Kesalahan %s
|
||||
generic.error.instruction=Ups! Cryptomator tidak mengharapkan ini terjadi. Anda dapat mencari solusi yang ada untuk kesalahan ini. Atau jika belum dilaporkan, jangan ragu untuk melakukannya.
|
||||
generic.error.hyperlink.lookup=Cari kesalahan
|
||||
generic.error.hyperlink.report=Laporkan kesalahan
|
||||
generic.error.title=Error %s
|
||||
generic.error.instruction=Ups! Cryptomator tidak menyangka hal ini terjadi. Anda dapat mencari solusi yang tersedia untuk error ini. Atau jika error ini belum pernah dilaporkan, tidak perlu sungkan untuk melaporkannya.
|
||||
generic.error.hyperlink.lookup=Cari error berikut
|
||||
generic.error.hyperlink.report=Laporkan error berikut
|
||||
generic.error.technicalDetails=Rincian:
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Brankas
|
||||
defaults.vault.vaultName=Vault
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Tampilkan
|
||||
traymenu.showPreferencesWindow=Preferensi
|
||||
traymenu.lockAllVaults=Gembok Semua
|
||||
traymenu.lockAllVaults=Kunci Semua
|
||||
traymenu.quitApplication=Keluar
|
||||
traymenu.vault.unlock=Buka Gembok
|
||||
traymenu.vault.lock=Gembok
|
||||
traymenu.vault.unlock=Buka Kunci
|
||||
traymenu.vault.lock=Kunci
|
||||
traymenu.vault.reveal=Perlihatkan
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=Tambah Brankas
|
||||
addvaultwizard.title=Tambah Vault
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Buat Brankas Baru
|
||||
addvaultwizard.welcome.existingButton=Buka Brankas yg Sudah Ada
|
||||
addvaultwizard.welcome.newButton=Buat Vault Baru
|
||||
addvaultwizard.welcome.existingButton=Buka Vault yang Tersedia
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Buat sebuah nama untuk brankas
|
||||
addvaultwizard.new.namePrompt=Nama Brankas
|
||||
addvaultwizard.new.nameInstruction=Beri nama untuk vault berikut
|
||||
addvaultwizard.new.namePrompt=Nama Vault
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Dimana Cryptomator seharusnya menyimpan brankas berkas terenkripsi kamu?
|
||||
addvaultwizard.new.locationInstruction=Dimana Cryptomator seharusnya menyimpan vault berisi file enkripsi Anda?
|
||||
addvaultwizard.new.locationLabel=Lokasi penyimpanan
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=Sesuaikan Lokasi
|
||||
addvaultwizard.new.directoryPickerLabel=Lokasi khusus
|
||||
addvaultwizard.new.directoryPickerButton=Pilih…
|
||||
addvaultwizard.new.directoryPickerTitle=Pilih Folder
|
||||
addvaultwizard.new.fileAlreadyExists=Sudah ada file atau direktori dengan nama yang sama
|
||||
addvaultwizard.new.locationDoesNotExist=Direktori pada path yang dipilih tidak ada atau tidak dapat diakses
|
||||
addvaultwizard.new.directoryPickerTitle=Pilih Direktori
|
||||
addvaultwizard.new.fileAlreadyExists=Sudah ada file atau direktori dengan nama vault tersebut
|
||||
addvaultwizard.new.locationDoesNotExist=Direktori pada path yang dipilih tidak tersedia atau tidak dapat diakses
|
||||
addvaultwizard.new.locationIsNotWritable=Anda tidak memiliki hak akses untuk menulis pada path yang dipilih
|
||||
addvaultwizard.new.locationIsOk=Lokasi yang sesuai dengan vault Anda
|
||||
addvaultwizard.new.invalidName=Nama brankas salah. Harap pilih nama folder yang umum.
|
||||
addvaultwizard.new.invalidName=Nama vault tidak sesuai. Harap pilih nama direktori yang umum digunakan.
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Buat Brankas
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Kamu tidak dapat mengakses data tanpa kata sandi kamu. Apa kamu ingin sebuah kunci pemulihan buat jaga-jaga?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Ya, sedia payung sebelum hujan
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Tidak, terima kasih, Saya tidak akan kehilangan kata sandi saya
|
||||
addvaultwizard.new.createVaultBtn=Buat Vault
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Anda tidak dapat mengakses data tanpa kata sandi yang Anda miliki. Apa Anda ingin sebuah kunci pemulihan untuk berjaga-jaga jika seandainya Anda kehilangan kata sandi?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Ya tolong, Lebih baik aman daripada menyesal
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Tidak terima kasih, Saya tidak akan kehilangan kata sandi saya
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=PENTING.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ BERKAS BRANKAS ⚠️
|
||||
addvault.new.readme.storageLocation.2=Ini adalah lokasi penyimpanan brankas kamu.
|
||||
addvault.new.readme.storageLocation.3=JANGAN
|
||||
addvault.new.readme.storageLocation.4=• mengubah file dalam direktori ini, atau
|
||||
addvault.new.readme.storageLocation.5=• menempelkan file untuk dienkripsi ke dalam direktori ini.
|
||||
addvault.new.readme.storageLocation.6=Jika kamu ingin mengenkripsi berkas dan melihat isi brankas, lakukan hal berikut:
|
||||
addvault.new.readme.storageLocation.7=1. Tambahkan brankas ini ke Cryptomator.
|
||||
addvault.new.readme.storageLocation.8=2. Buka gembok brankas di Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Buka akses lokasi dengan mengklik tombol "Perlihatkan".
|
||||
addvault.new.readme.storageLocation.10=Jika kamu butuh bantuan, kunjungi dokumentasi: %s
|
||||
addvault.new.readme.accessLocation.fileName=SELAMAT_DATANG.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ ISI TERENKRIPSI 🔐️
|
||||
addvault.new.readme.accessLocation.2=Ini adalah lokasi akses brankas kamu.
|
||||
addvault.new.readme.accessLocation.3=File yang ditambahkan ke volume ini akan dienkripsi oleh Cryptomator. Anda dapat mempergunakan isi vault seperti dalam folder lain. Saat ini Anda sedang mengakses tampilan versi dekripsi, file Anda selalu terenkripsi di dalam cakram keras Anda.
|
||||
addvault.new.readme.storageLocation.1=⚠️ FILE VAULT ⚠️
|
||||
addvault.new.readme.storageLocation.2=Ini adalah lokasi penyimpanan vault Anda.
|
||||
addvault.new.readme.storageLocation.3=DILARANG
|
||||
addvault.new.readme.storageLocation.4=• mengubah file apapun di direktori ini, atau
|
||||
addvault.new.readme.storageLocation.5=• menyalin file untuk dienkripsi ke dalam direktori ini.
|
||||
addvault.new.readme.storageLocation.6=Jika Anda ingin mengenkripsi file dan melihat isi konten dari vault, lakukan hal berikut:
|
||||
addvault.new.readme.storageLocation.7=1. Tambahkan vault ini ke Cryptomator.
|
||||
addvault.new.readme.storageLocation.8=2. Buka vault melalui Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Buka lokasi akses dengan mengklik tombol "Perlihatkan".
|
||||
addvault.new.readme.storageLocation.10=Jika Anda butuh bantuan, kunjungi dokumentasi: %s
|
||||
addvault.new.readme.accessLocation.fileName=SELAMAT DATANG.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ VOLUME TERENKRIPSI 🔐️
|
||||
addvault.new.readme.accessLocation.2=Ini adalah lokasi akses dari vault Anda.
|
||||
addvault.new.readme.accessLocation.3=Seluruh file yang ditambahkan ke volume ini akan dienkripsi oleh Cryptomator. Anda dapat mempergunakan isi vault seperti dalam folder/drive lain pada umumnya. Tampilan yang saat ini Anda lihat adalah tampilan dalam bentuk terdekripsi, yang sebenarnya terjadi adalah file-file Anda selalu dalam kondisi terenkripsi di dalam hard drive Anda.
|
||||
addvault.new.readme.accessLocation.4=Anda dapat menghapus file ini.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Pilih file "vault.cryptomator" Anda dari vault yang ada. Jika hanya ada file bernama "masterkey.cryptomator", pilih file tersebut.
|
||||
@@ -84,46 +84,49 @@ addvaultwizard.success.unlockNow=Buka Kunci Sekarang
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Hapus Vault
|
||||
removeVault.information=Cryptomator hanya akan melupakan vault ini. Anda dapat menambahkan vault ini lagi nantinya. File yang telah dienkripsi tidak akan dihapus dari cakram keras Anda.
|
||||
removeVault.information=Tindakan ini hanya akan membuat Cryptomator melupakan vault ini. Anda dapat menambahkan vault ini lagi nanti. File yang telah dienkripsi tidak akan dihapus dari hard drive Anda.
|
||||
removeVault.confirmBtn=Hapus Vault
|
||||
|
||||
# Change Password
|
||||
changepassword.title=Ubah Kata Sandi
|
||||
changepassword.enterOldPassword=Masukkan kata sandi untuk "%s" saat ini
|
||||
changepassword.enterOldPassword=Masukkan kata sandi "%s" saat ini
|
||||
changepassword.finalConfirmation=Saya mengerti bahwa saya tidak akan dapat mengakses data saya apabila saya lupa kata sandi saya
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=Lupa Kata Sandi
|
||||
forgetPassword.information=Kata sandi vault yang tersimpan akan dihapus dari keychain.
|
||||
forgetPassword.information=Tindakan ini akan menghapus kata sandi vault berikut yang tersimpan dari sistem keychain Anda.
|
||||
forgetPassword.confirmBtn=Lupa Kata Sandi
|
||||
|
||||
# Unlock
|
||||
unlock.title=Membuka "%s"
|
||||
unlock.passwordPrompt=Masukkan kata sandi untuk "%s":
|
||||
unlock.savePassword=Simpan Kata Sandi
|
||||
unlock.unlockBtn=Buka Gembok
|
||||
##
|
||||
unlock.title=Buka Kunci "%s"
|
||||
unlock.passwordPrompt=Masukkan kata sandi "%s":
|
||||
unlock.savePassword=Ingat Kata Sandi
|
||||
unlock.unlockBtn=Buka Kunci
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Pilih Masterkey of "%s"
|
||||
unlock.chooseMasterkey.prompt=Tidak dapat menemukan file masterkey untuk vault ini pada lokasi yang dicari. Mohon pilih file kunci secara manual.
|
||||
unlock.chooseMasterkey.filePickerTitle=Pilih File Kunci Induk
|
||||
unlock.chooseMasterkey.chooseBtn=Pilih…
|
||||
unlock.chooseMasterkey.filePickerTitle=Pilih File Masterkey
|
||||
## Success
|
||||
unlock.success.message="%s" telat terbuka! Vault Anda sekarang dapat diakses melalui drive virtual.
|
||||
unlock.success.message="%s" berhasil dibuka! Vault Anda sekarang dapat diakses melalui drive virtual.
|
||||
unlock.success.rememberChoice=Ingat pilihan saya, jangan perlihatkan lagi
|
||||
unlock.success.revealBtn=Buka Drive
|
||||
unlock.success.revealBtn=Tampilkan Drive
|
||||
## Failure
|
||||
unlock.error.heading=Tidak dapat membuka vault
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Poin mount "%s" bukan direktori, dan tidak kosong atau tidak ada.
|
||||
unlock.error.invalidMountPoint.existing=Poin mount "%s" sudah ada atau folder induknya tidak ada.
|
||||
unlock.error.invalidMountPoint.notExisting=Mount point "%s" bukanlah sebuah direktori, tidak sedang kosong, atau bahkan tidak ada sama sekali.
|
||||
unlock.error.invalidMountPoint.existing=Mount point "%s" sudah ada atau folder induknya tidak ditemukan.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Drive Letter "%s" sedang digunakan.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Gagal mengunci
|
||||
lock.forced.message=Penguncian "%s" terblokir oleh operasi yang sedang berjalan atau file yang masih terbuka. Anda dapat mengunci paksa vault ini, namun ada kemungkinan mengganggu I/O akan menghilangkan data yang belum disimpan.
|
||||
lock.forced.message=Penguncian "%s" terblokir oleh operasi yang sedang berjalan atau file yang masih terbuka. Anda dapat mengunci paksa vault ini, namun ada kemungkinan mengganggu I/O yang berakibat kehilangan data yang belum disimpan.
|
||||
lock.forced.retryBtn=Coba lagi
|
||||
lock.forced.forceBtn=Kunci Paksa
|
||||
lock.forced.forceBtn=Paksa Kunci
|
||||
## Failure
|
||||
lock.fail.heading=Gagal mengunci vault.
|
||||
lock.fail.message=Vault "%s" tidak dapat dikunci. Pastikan bahwa file yang belum tersimpan telah disimpan di lokasi lain, dan operasi Baca/Tulis yang penting telah selesai. Untuk menutup vault ini, matikan proses Cryptomator.
|
||||
lock.fail.message=Vault "%s" tidak dapat dikunci. Pastikan bahwa file yang belum tersimpan telah disimpan di lokasi lain, dan operasi Baca/Tulis telah selesai dilakukan. Untuk menutup vault ini, matikan proses Cryptomator.
|
||||
|
||||
# Migration
|
||||
migration.title=Tingkatkan Vault
|
||||
@@ -146,17 +149,17 @@ migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Sistem file tid
|
||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Sistem file tidak mengizinkan untuk ditulis.
|
||||
## Impossible
|
||||
migration.impossible.heading=Tidak dapat memindahkan vault
|
||||
migration.impossible.reason=Vault tidak dapat dipindahkan secara otomatis karena lokasi penyimpanan atau poin akses tidak sesuai.
|
||||
migration.impossible.moreInfo=Vault dapat dibuka dengan program versi lebih lama. Apabila Anda ingin memindahkan vault secara manual, silahkan buka
|
||||
migration.impossible.reason=Vault tidak dapat dipindahkan secara otomatis karena lokasi penyimpanan atau access point tidak sesuai.
|
||||
migration.impossible.moreInfo=Vault masih bisa dibuka dengan aplikasi versi terdahulu. Untuk panduan memindahkan vault secara manual, silahkan buka
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
health.title=Pemeriksaan Kesehatan "%s"
|
||||
health.intro.header=Pemeriksaan Kesehatan
|
||||
health.intro.text=Pemeriksaan Kesehatan adalah kumpulan pemeriksaan untuk mendeteksi dan mungkin memperbaiki masalah dalam struktur internal brankas Anda. Harap diingat:
|
||||
health.intro.remarkSync=Pastikan semua perangkat disinkronkan sepenuhnya, ini menyelesaikan sebagian besar masalah.
|
||||
health.intro.text=Pemeriksaan Kesehatan adalah kumpulan pemeriksaan untuk mendeteksi dan memperbaiki masalah di dalam struktur internal vault Anda. Perlu diperhatikan:
|
||||
health.intro.remarkSync=Pastikan semua perangkat tersinkronisasi sepenuhnya, sebagian besar masalah teratasi dengan cara ini.
|
||||
health.intro.remarkFix=Tidak semua masalah bisa diperbaiki.
|
||||
health.intro.remarkBackup=Jika data rusak, hanya cadangan yang dapat membantu.
|
||||
health.intro.remarkBackup=Jika data rusak, hanya cadangan yang dapat memulihkannya.
|
||||
health.intro.affirmation=Saya telah membaca dan memahami informasi di atas
|
||||
## Start Failure
|
||||
health.fail.header=Kesalahan saat memuat Konfigurasi Vault
|
||||
@@ -167,14 +170,14 @@ health.fail.moreInfo=Info Selengkapnya
|
||||
health.checkList.description=Centang daftar di bagian kiri atau gunakan tombol di bawah.
|
||||
health.checkList.selectAllButton=Centang Semua
|
||||
health.checkList.deselectAllButton=Jangan Centang Semua
|
||||
health.check.runBatchBtn=Cek Jalankan yang dipilih
|
||||
health.check.runBatchBtn=Jalankan Centang yang Terpilih
|
||||
## Detail view
|
||||
health.check.detail.noSelectedCheck=Untuk hasil, pilih pemeriksaan kesehatan yang sudah selesai di sebelah kiri.
|
||||
health.check.detail.checkScheduled=Pemeriksaan dijadwalkan.
|
||||
health.check.detail.noSelectedCheck=Pilih pemeriksaan kesehatan yang sudah selesai di sebelah kiri untuk melihat hasilnya.
|
||||
health.check.detail.checkScheduled=Pemeriksaan telah terjadwal.
|
||||
health.check.detail.checkRunning=Saat ini pemeriksaan sedang berjalan…
|
||||
health.check.detail.checkSkipped=Pemeriksaan tidak dipilih untuk dijalankan.
|
||||
health.check.detail.checkFinished=Pemeriksaan berhasil diselesaikan.
|
||||
health.check.detail.checkFinishedAndFound=Pemeriksaan selesai berjalan. Harap tinjau hasilnya.
|
||||
health.check.detail.checkSkipped=Pemeriksaan tidak dajalankan karena tidak dipilih.
|
||||
health.check.detail.checkFinished=Pemeriksaan berhasil dilakukan.
|
||||
health.check.detail.checkFinishedAndFound=Pemeriksaan selesai. Silahkan tinjau hasilnya.
|
||||
health.check.detail.checkFailed=Pemeriksaan terhenti karena terjadi kesalahan.
|
||||
health.check.detail.checkCancelled=Pemeriksaan dibatalkan.
|
||||
health.check.exportBtn=Ekspor Laporan
|
||||
@@ -187,17 +190,17 @@ health.fix.failTip=Perbaikan gagal, lihat log untuk detailnya
|
||||
preferences.title=Preferensi
|
||||
## General
|
||||
preferences.general=Umum
|
||||
preferences.general.theme=Lihat dan rasakan
|
||||
preferences.general.theme=Tampilan & Suasana
|
||||
preferences.general.theme.automatic=Otomatis
|
||||
preferences.general.theme.light=Terang
|
||||
preferences.general.theme.dark=Gelap
|
||||
preferences.general.unlockThemes=Buka mode gelap
|
||||
preferences.general.showMinimizeButton=Perkecil tampilan tombol
|
||||
preferences.general.showTrayIcon=\nTampilkan ikon baki (memerlukan mulai ulang)
|
||||
preferences.general.startHidden=Sembunyikan halaman saat memulai Cryptomator
|
||||
preferences.general.showMinimizeButton=Tampilkan tombol perkecil
|
||||
preferences.general.showTrayIcon=Tampilkan tray icon (diperlukan muat ulang)
|
||||
preferences.general.startHidden=Sembunyikan jendela saat memulai Cryptomator
|
||||
preferences.general.debugLogging=Aktifkan pencatatan debug
|
||||
preferences.general.debugDirectory=Buka file log
|
||||
preferences.general.autoStart=Luncurkan Cryptomator pada awal sistem
|
||||
preferences.general.debugDirectory=Perlihatkan file log
|
||||
preferences.general.autoStart=Jalankan Cryptomator saat sistem dimulai
|
||||
preferences.general.keychainBackend=Simpan kata sandi dengan
|
||||
preferences.general.interfaceOrientation=Orientasi Antarmuka
|
||||
preferences.general.interfaceOrientation.ltr=Kiri ke kanan
|
||||
@@ -205,20 +208,20 @@ preferences.general.interfaceOrientation.rtl=Kanan ke kiri
|
||||
## Volume
|
||||
preferences.volume=Drive Virtual
|
||||
preferences.volume.type=Jenis Volume
|
||||
preferences.volume.webdav.port=Kabel WebDAV
|
||||
preferences.volume.webdav.port=Port WebDAV
|
||||
preferences.volume.webdav.scheme=Skema WebDAV
|
||||
## Updates
|
||||
preferences.updates=Pembaharuan
|
||||
preferences.updates.currentVersion=Versi Sekarang: %s
|
||||
preferences.updates.autoUpdateCheck=Periksa untuk update otomatis
|
||||
preferences.updates.currentVersion=Versi Saat Ini: %s
|
||||
preferences.updates.autoUpdateCheck=Otomatis periksa update
|
||||
preferences.updates.checkNowBtn=Periksa Sekarang
|
||||
preferences.updates.updateAvailable=Pembaharuan ke versi %s tersedia.
|
||||
## Contribution
|
||||
preferences.contribute=Dukung Kami
|
||||
preferences.contribute.registeredFor=Sertifikat pendukung terdaftar untuk %s
|
||||
preferences.contribute.noCertificate=Dukung Cryptomator dan terima sertifikat pendukung. Ini seperti kunci lisensi tetapi untuk orang-orang hebat yang menggunakan perangkat lunak gratis. ;-)
|
||||
preferences.contribute.registeredFor=Sertifikat supporter terdaftar atas nama %s
|
||||
preferences.contribute.noCertificate=Dukung Cryptomator dan terima sebuah sertifikat supporter. Sertifikat ini layaknya kunci lisensi, tetapi hanya untuk orang-orang hebat yang menggunakan aplikasi versi gratis. ;-)
|
||||
preferences.contribute.getCertificate=Belum punya? Pelajari bagaimana Anda bisa mendapatkannya.
|
||||
preferences.contribute.promptText=Tempel kode sertifikat pendukung di sini
|
||||
preferences.contribute.promptText=Tempel kode sertifikat supporter di sini
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
@@ -228,22 +231,22 @@ preferences.about=Tentang
|
||||
stats.title=Statistik untuk %s
|
||||
stats.cacheHitRate=Tingkat Hit Cache
|
||||
## Read
|
||||
stats.read.throughput.idle=Read: idle
|
||||
stats.read.throughput.kibs=Read: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Read: %.2f MiB/s
|
||||
stats.read.total.data.none=Data read: -
|
||||
stats.read.total.data.kib=Data read: %.1f kiB
|
||||
stats.read.total.data.mib=Data read: %.1f MiB
|
||||
stats.read.total.data.gib=Data read: %.1f GiB
|
||||
stats.decr.total.data.none=Data decrypted: -
|
||||
stats.decr.total.data.kib=Data decrypted: %.1f kiB
|
||||
stats.decr.total.data.mib=Data decrypted: %.1f MiB
|
||||
stats.decr.total.data.gib=Data decrypted: %.1f GiB
|
||||
stats.read.accessCount=Total reads: %d
|
||||
stats.read.throughput.idle=Baca: diam
|
||||
stats.read.throughput.kibs=Baca: %.2f kiB/detik
|
||||
stats.read.throughput.mibs=Baca: %.2f MiB/detik
|
||||
stats.read.total.data.none=Data dibaca: -
|
||||
stats.read.total.data.kib=Data dibaca: %.1f kiB
|
||||
stats.read.total.data.mib=Data dibaca: %.1f MiB
|
||||
stats.read.total.data.gib=Data dibaca: %.1f GiB
|
||||
stats.decr.total.data.none=Data terdekripsi: -
|
||||
stats.decr.total.data.kib=Data terdekripsi: %.1f kiB
|
||||
stats.decr.total.data.mib=Data terdeksripsi: %.1f MiB
|
||||
stats.decr.total.data.gib=Data terdeksripsi: %.1f GiB
|
||||
stats.read.accessCount=Total dibaca: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Write: idle
|
||||
stats.write.throughput.kibs=Write: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Write: %.2f MiB/s
|
||||
stats.write.throughput.idle=Tulis: diam
|
||||
stats.write.throughput.kibs=Tulis: %.2f kiB/detik
|
||||
stats.write.throughput.mibs=Tulis: %.2f MiB/detik
|
||||
stats.write.total.data.none=Data tertulis: -
|
||||
stats.write.total.data.kib=Data tertulis: %.1f kiB
|
||||
stats.write.total.data.mib=Data tertulis: %.1f MiB
|
||||
@@ -252,22 +255,22 @@ stats.encr.total.data.none=Data terenkripsi: -
|
||||
stats.encr.total.data.kib=Data terenkripsi: %.1f kiB
|
||||
stats.encr.total.data.mib=Data terenkripsi: %.1f MiB
|
||||
stats.encr.total.data.gib=Data terenkripsi: %.1f GiB
|
||||
stats.write.accessCount=Total menulis: %d
|
||||
stats.write.accessCount=Total ditulis: %d
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Tutup
|
||||
main.minimizeBtn.tooltip=Minimalkan
|
||||
main.minimizeBtn.tooltip=Perkecil
|
||||
main.preferencesBtn.tooltip=Preferensi
|
||||
main.debugModeEnabled.tooltip=Mode Debug diaktifkan
|
||||
main.donationKeyMissing.tooltip=Pertimbangjan untuk donasi
|
||||
main.donationKeyMissing.tooltip=Tolong pertimbangkan untuk melakukan donasi
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Tambah vault ini
|
||||
main.dropZone.unknownDragboardContent=Jika Anda ingin menambahkan vault, seret ke jendela ini
|
||||
## Vault List
|
||||
main.vaultlist.emptyList.onboardingInstruction=Klik untuk tambah vault
|
||||
main.vaultlist.emptyList.onboardingInstruction=Klik di sini untuk menambahkan vault
|
||||
main.vaultlist.contextMenu.remove=Hapus…
|
||||
main.vaultlist.contextMenu.lock=Gembok
|
||||
main.vaultlist.contextMenu.unlock=Membuka…
|
||||
main.vaultlist.contextMenu.lock=Kunci
|
||||
main.vaultlist.contextMenu.unlock=Buka Kunci…
|
||||
main.vaultlist.contextMenu.unlockNow=Buka Kunci Sekarang
|
||||
main.vaultlist.contextMenu.vaultoptions=Tampilkan Opsi Vault
|
||||
main.vaultlist.contextMenu.reveal=Buka Drive
|
||||
@@ -277,7 +280,7 @@ main.vaultlist.addVaultBtn=Tambah Brankas
|
||||
main.vaultDetail.welcomeOnboarding=Terima kasih telah memilih Cryptomator untuk melindungi file Anda. Jika Anda memerlukan bantuan, lihat panduan awal kami:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=TERKUNCI
|
||||
main.vaultDetail.unlockBtn=Membuka…
|
||||
main.vaultDetail.unlockBtn=Buka Kunci…
|
||||
main.vaultDetail.unlockNowBtn=Buka Kunci Sekarang
|
||||
main.vaultDetail.optionsBtn=Opsi Vault
|
||||
main.vaultDetail.passwordSavedInKeychain=Kata Sandi tersimpan
|
||||
@@ -332,10 +335,10 @@ vaultOptions.general.startHealthCheckBtn=Mulai Pemeriksaan Kesehatan
|
||||
vaultOptions.mount=Pemasangan
|
||||
vaultOptions.mount.readonly=Read-Only
|
||||
vaultOptions.mount.customMountFlags=Custom Mount Flags
|
||||
vaultOptions.mount.winDriveLetterOccupied=terisi
|
||||
vaultOptions.mount.winDriveLetterOccupied=terpakai
|
||||
vaultOptions.mount.mountPoint=Titik Pasang
|
||||
vaultOptions.mount.mountPoint.auto=Secara otomatis memilih lokasi yang sesuai
|
||||
vaultOptions.mount.mountPoint.driveLetter=Gunakan huruf drive yang ditetapkan
|
||||
vaultOptions.mount.mountPoint.driveLetter=Gunakan drive letter yang sudah ditetapkan
|
||||
vaultOptions.mount.mountPoint.custom=Path khusus
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Pilih…
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Pilih direktori kosong
|
||||
@@ -370,5 +373,5 @@ passwordStrength.messageLabel.3=Kuat
|
||||
passwordStrength.messageLabel.4=Sangat kuat
|
||||
|
||||
# Quit
|
||||
quit.prompt=Keluar aplikasi? Terdapat brankas yg belum digembok.
|
||||
quit.lockAndQuit=Gembok dan Keluar
|
||||
quit.prompt=Keluar aplikasi? Masih ada vault yg belum dikunci.
|
||||
quit.lockAndQuit=Kunci dan Keluar
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Sblocca "%s"
|
||||
unlock.passwordPrompt=Inserisci la password per "%s":
|
||||
unlock.savePassword=Ricorda la Password
|
||||
unlock.unlockBtn=Sblocca
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Seleziona Masterkey di "%s"
|
||||
unlock.chooseMasterkey.prompt=Impossibile trovare il file Masterkey per questa cassaforte alla sua posizione prevista. Sei pregato di sceglierlo manualmente.
|
||||
unlock.chooseMasterkey.chooseBtn=Scegli…
|
||||
unlock.chooseMasterkey.filePickerTitle=Seleziona il File Masterkey
|
||||
## Success
|
||||
unlock.success.message="%s" sbloccato correttamente! La tua cassaforte è ora accessibile tramite la sua unità virtuale.
|
||||
@@ -114,11 +116,14 @@ unlock.error.heading=Impossibile sbloccare la cassaforte
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Il punto di montaggio "%s" non è una cartella, non è vuoto o non esiste.
|
||||
unlock.error.invalidMountPoint.existing=Il punto di montaggio "%s" esiste già o la cartella madre è mancante.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=La lettera di unità "%s" è già in uso.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Blocco non riuscito
|
||||
lock.forced.message=Il bloccaggio di "%s" è stato impedito dalle operazioni in sospeso o dai file aperti. Puoi forzare il blocco di questa cassaforte, tuttavia, interrompere I/O potrebbe risultare nella perdita dei dati non salvati.
|
||||
lock.forced.retryBtn=Riprova
|
||||
lock.forced.forceBtn=Forza Blocco
|
||||
## Failure
|
||||
lock.fail.heading=Blocco della cassaforte fallito.
|
||||
lock.fail.message=Impossibile bloccare la cassaforte "%s". Assicurati che il lavoro non salvato sia salvato altrove e che le importanti operazioni di Lettura/Scrittura siano terminate. Per chiudere la cassaforte, termina il processo di Cryptomator.
|
||||
|
||||
@@ -35,7 +35,7 @@ traymenu.vault.reveal=表示
|
||||
addvaultwizard.title=金庫を追加
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=新しい金庫を作成
|
||||
addvaultwizard.welcome.existingButton=すでにある金庫を開く
|
||||
addvaultwizard.welcome.existingButton=既存の金庫を開く
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=金庫の名前を入力してください
|
||||
@@ -51,7 +51,7 @@ addvaultwizard.new.fileAlreadyExists=金庫名と同じ名前のファイルま
|
||||
addvaultwizard.new.locationDoesNotExist=指定されたパスのディレクトリが存在しないかアクセスできません
|
||||
addvaultwizard.new.locationIsNotWritable=指定されたパスに書き込み権限がありません
|
||||
addvaultwizard.new.locationIsOk=金庫に適した場所
|
||||
addvaultwizard.new.invalidName=無効な金庫の名前です。一般的なディレクトリの名前を検討してください。
|
||||
addvaultwizard.new.invalidName=使用できない金庫の名前です。一般的なディレクトリの名前にしてください。
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=金庫を作成
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=データにアクセスするにはパスワードが必須です。パスワードを紛失したときのためにリカバリーキーは必要ですか?
|
||||
@@ -102,18 +102,21 @@ unlock.title="%s" を解錠
|
||||
unlock.passwordPrompt="%s" のパスワードを入力してください:
|
||||
unlock.savePassword=パスワードを記憶させる
|
||||
unlock.unlockBtn=解錠
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title="%s" の Masterkey ファイルを選択
|
||||
unlock.chooseMasterkey.prompt=必要な場所にこの金庫の masterkey ファイルがありませんでした。ファイルを手動で選択してください。
|
||||
unlock.chooseMasterkey.chooseBtn=選択...
|
||||
unlock.chooseMasterkey.filePickerTitle=Masterkey ファイルを選択
|
||||
## Success
|
||||
unlock.success.message="%s" の解錠に成功しました! 仮想ドライブから金庫にアクセス可能です。
|
||||
unlock.success.rememberChoice=選択を記憶させて、再度表示しない
|
||||
unlock.success.revealBtn=ドライブを表示
|
||||
unlock.success.revealBtn=金庫内を表示
|
||||
## Failure
|
||||
unlock.error.heading=金庫の解錠に失敗
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=マウントポイントが空のディレクトリか存在していません: %s
|
||||
unlock.error.invalidMountPoint.existing=マウント ポイント "%s" が既に存在するか、親フォルダーがありません。
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=ドライブレター「%s」は既に使用されています。
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -187,21 +190,21 @@ health.fix.failTip=修正に失敗しました。詳細はログを参照して
|
||||
preferences.title=設定
|
||||
## General
|
||||
preferences.general=基本設定
|
||||
preferences.general.theme=外見 & 操作性
|
||||
preferences.general.theme=外見と操作性
|
||||
preferences.general.theme.automatic=自動
|
||||
preferences.general.theme.light=ライト
|
||||
preferences.general.theme.dark=ダーク
|
||||
preferences.general.unlockThemes=ダークモードの解錠
|
||||
preferences.general.unlockThemes=ダークモードを解除
|
||||
preferences.general.showMinimizeButton=最小化ボタンを表示
|
||||
preferences.general.showTrayIcon=トレイアイコンを表示 (再起動が必要)
|
||||
preferences.general.startHidden=Cryptomator を開始したときウィンドウを隠す
|
||||
preferences.general.debugLogging=ログを有効にする
|
||||
preferences.general.debugDirectory=ログ ファイルを表示
|
||||
preferences.general.debugDirectory=ログファイルを表示
|
||||
preferences.general.autoStart=システム開始時にCryptomatorを起動する
|
||||
preferences.general.keychainBackend=次を利用してパスワードを保存する
|
||||
preferences.general.interfaceOrientation=インターフェイスの向き
|
||||
preferences.general.interfaceOrientation.ltr=左から右
|
||||
preferences.general.interfaceOrientation.rtl=右から左
|
||||
preferences.general.interfaceOrientation.ltr=左横書き
|
||||
preferences.general.interfaceOrientation.rtl=右横書き
|
||||
## Volume
|
||||
preferences.volume=仮想ドライブ
|
||||
preferences.volume.type=マウント方法
|
||||
@@ -214,11 +217,11 @@ preferences.updates.autoUpdateCheck=自動的に更新を確認する
|
||||
preferences.updates.checkNowBtn=今すぐ確認
|
||||
preferences.updates.updateAvailable=利用可能なバージョン %s に更新します。
|
||||
## Contribution
|
||||
preferences.contribute=サポートする
|
||||
preferences.contribute=支援する
|
||||
preferences.contribute.registeredFor=サポーター証明書が %s に登録されました
|
||||
preferences.contribute.noCertificate=Cryptomator を支援し、サポーター証明書を受け取りましょう。ライセンスキーに似ていますがフリーソフトを使う寄付者向けのキーです。 ;-)
|
||||
preferences.contribute.noCertificate=Cryptomator を支援し、サポーター証明書を受け取りましょう。ライセンスキーに似ていますが自由ソフトウェアを使う寄付者向けのキーです。 ;-)
|
||||
preferences.contribute.getCertificate=まだ証明書を手に入れていませんか? 詳細はこちらから確認できます。
|
||||
preferences.contribute.promptText=サポーター証明書をここに張り付けてください
|
||||
preferences.contribute.promptText=サポーター証明書をここに貼り付け
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
@@ -274,7 +277,7 @@ main.vaultlist.contextMenu.reveal=ドライブを表示
|
||||
main.vaultlist.addVaultBtn=金庫を追加
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
main.vaultDetail.welcomeOnboarding=ファイル保護するために Cryptomator を選んでいただきありがとうございます。ヘルプが必要であれば、スタートガイドをご覧ください:
|
||||
main.vaultDetail.welcomeOnboarding=ファイルを保護するために Cryptomator を選んでいただきありがとうございます。ヘルプが必要であれば、スタートガイドをご覧ください:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=施錠済み
|
||||
main.vaultDetail.unlockBtn=解錠...
|
||||
@@ -293,7 +296,7 @@ main.vaultDetail.throughput.kbps=%.1f kiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
main.vaultDetail.stats=金庫の統計情報
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=Cryptomator はこのパスの金庫を見つけることができませんでした。
|
||||
main.vaultDetail.missing.info=Cryptomator はこの場所に金庫を見つけることができませんでした。
|
||||
main.vaultDetail.missing.recheck=再確認
|
||||
main.vaultDetail.missing.remove=金庫のリストから削除...
|
||||
main.vaultDetail.missing.changeLocation=金庫の場所を変更...
|
||||
@@ -343,7 +346,7 @@ vaultOptions.mount.mountPoint.directoryPickerTitle=空のディレクトリを
|
||||
vaultOptions.masterkey=パスワード
|
||||
vaultOptions.masterkey.changePasswordBtn=パスワードの変更
|
||||
vaultOptions.masterkey.forgetSavedPasswordBtn=保存したパスワードを削除する
|
||||
vaultOptions.masterkey.recoveryKeyExplanation=回復キーはパスワードを忘れてしまった場合でも、金庫へのアクセスを回復する唯一の手段です。
|
||||
vaultOptions.masterkey.recoveryKeyExplanation=回復キーはパスワードを忘れてしまった場合に、金庫へのアクセスを回復する唯一の手段です。
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=回復キーを表示
|
||||
vaultOptions.masterkey.recoverPasswordBtn=パスワードの回復
|
||||
|
||||
@@ -351,8 +354,8 @@ vaultOptions.masterkey.recoverPasswordBtn=パスワードの回復
|
||||
# Recovery Key
|
||||
recoveryKey.title=回復キー
|
||||
recoveryKey.enterPassword.prompt="%s" の回復キーを表示するためのパスワードを入力してください:
|
||||
recoveryKey.display.message="%s" へのアクセス権限を復元するリカバリーキー:
|
||||
recoveryKey.display.StorageHints=とても安全な場所に保存してください、例えば:\n • パスワード管理ソフトに保存\n • USB フラッシュドライブに保存\n • 紙に印刷
|
||||
recoveryKey.display.message="%s" へのアクセス権限を復元する回復キー:
|
||||
recoveryKey.display.StorageHints=十分に安全な場所に保存してください。例えば:\n • パスワード管理ソフトに保存\n • USB フラッシュドライブに保存\n • 紙に印刷
|
||||
recoveryKey.recover.prompt="%s" の回復キーを入力してください:
|
||||
recoveryKey.recover.validKey=有効な回復キー
|
||||
recoveryKey.printout.heading=Cryptomator 回復キー\n"%s"\n
|
||||
|
||||
@@ -98,8 +98,9 @@ unlock.title="%s" 잠금 해제
|
||||
unlock.passwordPrompt="%s"의 비밀번호를 입력하십시요.
|
||||
unlock.savePassword=비밀번호 기억
|
||||
unlock.unlockBtn=잠금해제
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.prompt=추정되는 위치에서 이 Vault의 마스터 키를 찾지 못했습니다. 마스터 키 위치를 수동으로 선택하여 주십시요.
|
||||
unlock.chooseMasterkey.chooseBtn=선택
|
||||
unlock.chooseMasterkey.filePickerTitle=마스터키 파일 선택
|
||||
## Success
|
||||
unlock.success.message="%s"이(가) 성공적으로 잠금해제되었습니다. 이제 이 Vault를 가상드라이브로 접근할 수 있습니다.
|
||||
|
||||
@@ -88,7 +88,8 @@ forgetPassword.confirmBtn=Aizmirst paroli
|
||||
# Unlock
|
||||
unlock.passwordPrompt=Ievadiet "%s" paroli:
|
||||
unlock.unlockBtn=Atslēgt
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Izvēlies...
|
||||
unlock.chooseMasterkey.filePickerTitle=Atlasīt galveno atslēgas datni
|
||||
## Success
|
||||
unlock.success.revealBtn=Atklāt disku
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
##
|
||||
## Select
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
@@ -13,6 +13,11 @@ generic.button.done=Ferdig
|
||||
generic.button.next=Neste
|
||||
generic.button.print=Skriv ut
|
||||
## Error
|
||||
generic.error.title=Feilkode %s
|
||||
generic.error.instruction=Oops! Cryptomator forventet ikke at dette skulle skje. Du kan slå opp mulige løsninger for denne feilen. Hvis feilen ikke er rapportert så kan du gjerne gjøre det.
|
||||
generic.error.hyperlink.lookup=Slå opp denne feilen
|
||||
generic.error.hyperlink.report=Rapporter denne feilen
|
||||
generic.error.technicalDetails=Detaljer:
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Hvelv
|
||||
@@ -33,7 +38,7 @@ addvaultwizard.welcome.newButton=Lag et nytt hvelv
|
||||
addvaultwizard.welcome.existingButton=Åpne et eksisterende hvelv
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Velg et navn på hvelvet
|
||||
addvaultwizard.new.nameInstruction=Navngi hvelvet
|
||||
addvaultwizard.new.namePrompt=Navn på hvelvet
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Hvor skal Cryptomator lagre de krypterte filene dine?
|
||||
@@ -43,6 +48,8 @@ addvaultwizard.new.directoryPickerLabel=Tilpasset lagringssted
|
||||
addvaultwizard.new.directoryPickerButton=Velg…
|
||||
addvaultwizard.new.directoryPickerTitle=Velg mappe
|
||||
addvaultwizard.new.fileAlreadyExists=En fil eller mappe med det hvelvnavnet finnes allerede
|
||||
addvaultwizard.new.locationDoesNotExist=En mappe i den angitte stien finnes ikke eller kan ikke nås
|
||||
addvaultwizard.new.locationIsNotWritable=Ingen skrivetilgang på den angitte stien
|
||||
addvaultwizard.new.locationIsOk=Egnet sted for hvelvet ditt
|
||||
addvaultwizard.new.invalidName=Ugyldig navn på hvelvet. Vennligst vurder et vanlig mappenavn.
|
||||
### Password
|
||||
@@ -55,13 +62,13 @@ addvault.new.readme.storageLocation.fileName=VIKTIG.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ HVELVFILER ⚠️
|
||||
addvault.new.readme.storageLocation.2=Dette er hvelvets lagringssted.
|
||||
addvault.new.readme.storageLocation.3=IKKE
|
||||
addvault.new.readme.storageLocation.4=• endre hvilke filer som helst i denne mappen eller
|
||||
addvault.new.readme.storageLocation.5=• i denne mappen limer du inn alle filer du ønsker skal krypteres.
|
||||
addvault.new.readme.storageLocation.4=• endre noen filer i denne mappen eller
|
||||
addvault.new.readme.storageLocation.5=• lim inn filer du ønsker skal krypteres.
|
||||
addvault.new.readme.storageLocation.6=Hvis du vil kryptere filer og se innholdet i hvelvet, gjør du følgende:
|
||||
addvault.new.readme.storageLocation.7=1. Legg til dette hvelvet i Cryptomator.
|
||||
addvault.new.readme.storageLocation.8=2. Lås opp hvelvet i Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Åpne tilgangspunktet ved å klikke på "Gjør synlig" -knappen.
|
||||
addvault.new.readme.storageLocation.10=Hvis du trenger hjelp, kan du gå til dokumentasjonen: %s
|
||||
addvault.new.readme.storageLocation.10=Hvis du trenger hjelp, kan du se på dokumentasjonen: %s
|
||||
addvault.new.readme.accessLocation.fileName=VELKOMMEN.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ KRYPTERT VOLUM 🔐️
|
||||
addvault.new.readme.accessLocation.2=Dette er hvelvets lagringssted.
|
||||
@@ -69,6 +76,7 @@ addvault.new.readme.accessLocation.3=Alle filer som er lagt til i dette volumet,
|
||||
addvault.new.readme.accessLocation.4=Denne filen kan fjernes hvis ønskelig.
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=Velg…
|
||||
addvaultwizard.existing.filePickerTitle=Velg hvelvfil
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Lagt til hvelvet "%s".\nDu må låse opp dette hvelvet for å få tilgang til eller legge til innhold. Alternativt kan du låse det opp på et hvilket som helst senere tidspunkt.
|
||||
addvaultwizard.success.unlockNow=Lås opp nå
|
||||
@@ -93,7 +101,8 @@ unlock.title=Lås opp "%s"
|
||||
unlock.passwordPrompt=Skriv inn passordet for "%s":
|
||||
unlock.savePassword=Husk passord
|
||||
unlock.unlockBtn=Lås opp
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Velg…
|
||||
unlock.chooseMasterkey.filePickerTitle=Velg hovednøkkelfil
|
||||
## Success
|
||||
unlock.success.rememberChoice=Husk valget - ikke vis dette igjen
|
||||
@@ -106,8 +115,10 @@ unlock.error.invalidMountPoint.existing=Monteringspunktet "%s" finnes enten alle
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Låsing mislyktes
|
||||
lock.forced.message=Låsing "%s" ble blokkert av ventende operasjoner eller åpne filer. Du kan tvinge låsing av dette hvelvet, men avbrytelse av I/O kan føre til tap av ulagrede data.
|
||||
lock.forced.retryBtn=Prøv igjen
|
||||
lock.forced.forceBtn=Tving låsing
|
||||
## Failure
|
||||
lock.fail.heading=Låsing av hvelvet mislyktes.
|
||||
lock.fail.message=Hvelvet "%s" kunne ikke låses. Forsikre deg om at ulagrede arbeider lagres andre steder, og at viktige lese/skrive-operasjoner er fullført. For å lukke hvelvet må du avbryte Cryptomatorprosessen.
|
||||
@@ -119,22 +130,22 @@ migration.start.prompt=Hvelvet ditt "%s" må oppdateres til et nyere format. Fø
|
||||
migration.start.confirm=Ja, hvelvet mitt er fullstendig synkronisert
|
||||
## Run
|
||||
migration.run.enterPassword=Skriv inn passordet for "%s"
|
||||
migration.run.startMigrationBtn=Overfør hvelv
|
||||
migration.run.startMigrationBtn=Oppgrader hvelv
|
||||
migration.run.progressHint=Dette kan ta litt tid…
|
||||
## Success
|
||||
migration.success.nextStepsInstructions=Vellykket overføring av "%s".\nDu kan nå låse opp hvelvet ditt.
|
||||
migration.success.nextStepsInstructions=Vellykket oppgradering av "%s".\nDu kan nå låse opp hvelvet ditt.
|
||||
migration.success.unlockNow=Lås opp nå
|
||||
## Missing file system capabilities
|
||||
migration.error.missingFileSystemCapabilities.title=Filsystemet er ikke støttet
|
||||
migration.error.missingFileSystemCapabilities.description=Overføringen ble ikke startet fordi hvelvet ditt ligger i et mangelfullt filsystem.
|
||||
migration.error.missingFileSystemCapabilities.description=Oppgraderingen ble ikke startet fordi hvelvet ditt ligger i et mangelfullt filsystem.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Filsystemet støtter ikke lange filnavn.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Filsystemet støtter ikke lange søkestier.
|
||||
migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=Filsystemet tillater ikke lesing.
|
||||
migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=Filsystemet tillater ikke å bli skrevet på.
|
||||
## Impossible
|
||||
migration.impossible.heading=Kunne ikke overføre hvelvet
|
||||
migration.impossible.heading=Kunne ikke oppgradere hvelvet
|
||||
migration.impossible.reason=Hvelvet kan ikke overføres automatisk fordi lagringsstedet eller tilgangspunkt ikke er kompatibelt.
|
||||
migration.impossible.moreInfo=Hvelvet kan fortsatt åpnes hvis du bruker en eldre versjon. For instruksjoner om hvordan man overfører et hvelv, besøk
|
||||
migration.impossible.moreInfo=Hvelvet kan fortsatt åpnes hvis du bruker en eldre versjon. For veiledning om hvordan man oppgraderer et hvelv, besøk
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
@@ -143,6 +154,7 @@ health.intro.remarkFix=Ikke alle problemer kan løses.
|
||||
health.fail.moreInfo=Mer informasjon
|
||||
## Check Selection
|
||||
## Detail view
|
||||
health.check.exportBtn=Eksporter rapport
|
||||
## Fix Application
|
||||
health.fix.fixBtn=Reparer
|
||||
health.fix.successTip=Vellykket reparering
|
||||
@@ -175,7 +187,7 @@ preferences.volume.webdav.scheme=WebDAV-ordning
|
||||
## Updates
|
||||
preferences.updates=Oppdateringer
|
||||
preferences.updates.currentVersion=Gjeldende versjon: %s
|
||||
preferences.updates.autoUpdateCheck=Se etter oppdateringer automatisk
|
||||
preferences.updates.autoUpdateCheck=Se automatisk etter oppdateringer
|
||||
preferences.updates.checkNowBtn=Sjekk nå
|
||||
preferences.updates.updateAvailable=Oppdatering til versjon %s er tilgjengelig.
|
||||
## Contribution
|
||||
@@ -220,7 +232,7 @@ main.closeBtn.tooltip=Lukk
|
||||
main.minimizeBtn.tooltip=Minimer
|
||||
main.preferencesBtn.tooltip=Innstillinger
|
||||
main.debugModeEnabled.tooltip=Feilsøkingsmodus er aktivert
|
||||
main.donationKeyMissing.tooltip=Vennligst vurder å donere
|
||||
main.donationKeyMissing.tooltip=Gjerne vurdér en donasjon
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Legg til dette hvelvet
|
||||
main.dropZone.unknownDragboardContent=Hvis du vil legge til et hvelv, kan du dra det til dette vinduet
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Ontgrendel "%s"
|
||||
unlock.passwordPrompt=Voer wachtwoord voor "%s" in:
|
||||
unlock.savePassword=Wachtwoord Onthouden
|
||||
unlock.unlockBtn=Ontgrendel
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Selecteer Masterkey van "%s"
|
||||
unlock.chooseMasterkey.prompt=Kon het sleutelbestand voor deze kluis niet vinden op de gewenste locatie. Kies het sleutelbestand handmatig.
|
||||
unlock.chooseMasterkey.chooseBtn=Kies…
|
||||
unlock.chooseMasterkey.filePickerTitle=Selecteer het Masterkey-bestand
|
||||
## Success
|
||||
unlock.success.message="%s" is met succes ontgrendeld! Uw kluis is nu toegankelijk via zijn virtuele schijf.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Kan kluis niet ontgrendelen
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Koppelpunt "%s" is geen map, is niet leeg of bestaat niet.
|
||||
unlock.error.invalidMountPoint.existing=Koppelpunt "%s" bestaat reeds of de bovenliggende map ontbreekt.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Schijf "%s" is al in gebruik.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -88,7 +88,8 @@ forgetPassword.confirmBtn=Gløym passord
|
||||
# Unlock
|
||||
unlock.passwordPrompt=Skriv inn passordet for "%s":
|
||||
unlock.unlockBtn=Låse opp
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Vel…
|
||||
unlock.chooseMasterkey.filePickerTitle=Vel hovudnøkkelfil
|
||||
## Success
|
||||
unlock.success.rememberChoice=Hugs valet - ikkje vis dette igjen
|
||||
|
||||
@@ -90,7 +90,8 @@ forgetPassword.confirmBtn=ਪਾਸਵਰਡ ਭੁੱਲ ਗਏ
|
||||
unlock.passwordPrompt="%s" ਲਈ ਪਾਸਵਰਡ ਦਿਓ:
|
||||
unlock.savePassword=ਪਾਸਵਰਡ ਯਾਦ ਰੱਖੋ
|
||||
unlock.unlockBtn=ਅਣ-ਲਾਕ ਕਰੋ
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=…ਚੁਣੋ
|
||||
unlock.chooseMasterkey.filePickerTitle=ਮਾਸਟਰ-ਕੁੰਜੀ ਫਾਇਲ ਚੁਣੋ
|
||||
## Success
|
||||
unlock.success.rememberChoice=ਚੋਣਾਂ ਯਾਦ ਰੱਖੋ, ਇਹ ਮੁੜ ਕੇ ਨਾ ਵੇਖਾਓ
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Odblokuj "%s"
|
||||
unlock.passwordPrompt=Wprowadź hasło dla "%s":
|
||||
unlock.savePassword=Zapamiętaj hasło
|
||||
unlock.unlockBtn=Odblokuj
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Wybierz Masterkey z "%s"
|
||||
unlock.chooseMasterkey.prompt=Brak pliku Masterkey dla tego sejfu w oczekiwanej lokalizacji. Proszę wybrać plik klucza ręcznie.
|
||||
unlock.chooseMasterkey.chooseBtn=Wybierz…
|
||||
unlock.chooseMasterkey.filePickerTitle=Wybierz plik Masterkey
|
||||
## Success
|
||||
unlock.success.message=Odblokowano "%s" pomyślnie! Twój sejf jest teraz dostępny za pomocą dysku wirtualnego.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Nie można odblokować sejfu
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Punkt montowania nie jest pustym katalogiem lub nie istnieje: %s
|
||||
unlock.error.invalidMountPoint.existing=Punkt montowania już istnieje lub brakuje katalogu nadrzędnego: %s
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Litera dysku "%s" jest już w użyciu.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -95,12 +95,15 @@ forgetPassword.confirmBtn=Esqueci a Senha
|
||||
# Unlock
|
||||
unlock.passwordPrompt=Insira a senha para "%s":
|
||||
unlock.unlockBtn=Destrancar
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Selecione a Masterkey de "%s"
|
||||
unlock.chooseMasterkey.chooseBtn=Escolher…
|
||||
unlock.chooseMasterkey.filePickerTitle=Selecionar ficheiro MasterKey
|
||||
## Success
|
||||
unlock.success.rememberChoice=Lembrar escolha, não mostrar isto novamente
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=A letra de unidade "%s" já está sendo usada.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Desbloquear "%s"
|
||||
unlock.passwordPrompt=Digite a senha para "%s":
|
||||
unlock.savePassword=Lembrar Senha
|
||||
unlock.unlockBtn=Desbloquear
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Selecione o Masterkey de "%s"
|
||||
unlock.chooseMasterkey.prompt=Não foi possível encontrar o arquivo Masterkey deste cofre no local esperado. Por favor selecione o arquivo chave manualmente.
|
||||
unlock.chooseMasterkey.chooseBtn=Escolher…
|
||||
unlock.chooseMasterkey.filePickerTitle=Selecionar Arquivo Masterkey
|
||||
## Success
|
||||
unlock.success.message="%s" desbloqueado com êxito! Seu cofre agora está acessível na unidade virtual.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Não foi possível desbloquear o cofre
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=O ponto de montagem não é um diretório vazio ou não existe: %s
|
||||
unlock.error.invalidMountPoint.existing=Ponto de montagem/pasta já existe ou a pasta pai está faltando: %s
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Letra de unidade "%s" já está em uso.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -95,8 +95,9 @@ unlock.title=Deblocare "%s"
|
||||
unlock.passwordPrompt=Introduceți parola pentru "%s":
|
||||
unlock.savePassword=Memorează parola
|
||||
unlock.unlockBtn=Deblocați
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.prompt=Nu s-a putut găsi fișierul masterkey pentru acest seif la locația așteptată. Vă rugăm să alegeți manual fișierul cheie.
|
||||
unlock.chooseMasterkey.chooseBtn=Alege…
|
||||
unlock.chooseMasterkey.filePickerTitle=Selectaţi fişierul Masterkey
|
||||
## Success
|
||||
unlock.success.message=Deblocat "%s" cu succes! Seiful dvs. este acum accesibil prin unitatea sa virtuală.
|
||||
|
||||
@@ -14,7 +14,7 @@ generic.button.next=Далее
|
||||
generic.button.print=Печать
|
||||
## Error
|
||||
generic.error.title=Ошибка: %s
|
||||
generic.error.instruction=Ой! Криптоматор не ожидал, что так произойдет. Вы можете поискать существующие решения этой ошибки. Или если об этом еще не сообщалось, не стесняйтесь сделать это.
|
||||
generic.error.instruction=Произошла непредвиденная ситуация. Попробуйте найти уже имеющиеся решения этой ошибки. Если об этой ошибке ещё не сообщали, то сделайте это.
|
||||
generic.error.hyperlink.lookup=Искать ошибку
|
||||
generic.error.hyperlink.report=Сообщить об ошибке
|
||||
generic.error.technicalDetails=Подробности:
|
||||
@@ -95,15 +95,17 @@ changepassword.finalConfirmation=Я понимаю, что не смогу по
|
||||
# Forget Password
|
||||
forgetPassword.title=Не помню пароль
|
||||
forgetPassword.information=Сохранённый пароль от этого хранилища будет удалён из вашей связки ключей.
|
||||
forgetPassword.confirmBtn=Забыть сохранённый пароль
|
||||
forgetPassword.confirmBtn=Забыть пароль
|
||||
|
||||
# Unlock
|
||||
unlock.title=Разблокировать "%s"
|
||||
unlock.passwordPrompt=Введите пароль для "%s"
|
||||
unlock.savePassword=Запомнить пароль
|
||||
unlock.unlockBtn=Разблокировать
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Выберите файл MasterKey для "%s"
|
||||
unlock.chooseMasterkey.prompt=Не удалось найти файл MasterKey для этого хранилища в ожидаемом месте. Выберите ключевой файл вручную.
|
||||
unlock.chooseMasterkey.chooseBtn=Выбрать…
|
||||
unlock.chooseMasterkey.filePickerTitle=Выберите файл MasterKey
|
||||
## Success
|
||||
unlock.success.message=Разблокировка "%s" успешно выполнена! Доступ в хранилище открыт через его виртуальный диск.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Невозможно разблокировать хран
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Точка монтирования %s - не папка, не пуста или не существует.
|
||||
unlock.error.invalidMountPoint.existing=Точка монтирования %s уже существует, либо отсутствует родительская папка.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Буква диска "%s" уже используется.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Odomknúť "%s"
|
||||
unlock.passwordPrompt=Zadajte heslo pre "%s":
|
||||
unlock.savePassword=Odomknúť.uložiťHeslo
|
||||
unlock.unlockBtn=Odomknúť
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Vyberte súbor s hlavným kľúčom "%s"
|
||||
unlock.chooseMasterkey.prompt=Nemožno nájsť hlavný kľúčový súbor pre tento trezor na jeho očakávanom mieste. Prosím zvoľte kľúčový súbor manuálne.
|
||||
unlock.chooseMasterkey.chooseBtn=Vybrať…
|
||||
unlock.chooseMasterkey.filePickerTitle=Zvoľte hlavný kľúčový súbor
|
||||
## Success
|
||||
unlock.success.message=Odomknutie "%s" úspešné! Váš trezor je už prístupný cez jeho virtuálny disk.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Nie je možné odomknúť trezor
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Bod pripojenia "%s" nie je adresár, nie je prázdny alebo neexistuje.
|
||||
unlock.error.invalidMountPoint.existing=Bod pripojenia "%s" už existuje alebo chýba nadradený adresár.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Písmeno disku %s sa už používa.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -94,7 +94,8 @@ forgetPassword.confirmBtn=Заборави лозинку
|
||||
unlock.passwordPrompt=Унесите лозинку за "%s":
|
||||
unlock.savePassword=Запамти лозинку
|
||||
unlock.unlockBtn=Откључај
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Изабери…
|
||||
unlock.chooseMasterkey.filePickerTitle=Изабери "Masterkey" датотеку
|
||||
## Success
|
||||
unlock.success.message=Успешно сте откључали "%s"! Ваш сеф је сада доступан путем свог виртуелног диска.
|
||||
|
||||
@@ -94,7 +94,8 @@ forgetPassword.confirmBtn=Zaboravi lozinku
|
||||
unlock.passwordPrompt=Unesite lozinku za "%s":
|
||||
unlock.savePassword=Zapamti lozinku
|
||||
unlock.unlockBtn=Otključaj
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Izaberi…
|
||||
unlock.chooseMasterkey.filePickerTitle=Izaberi "Masterkey" datoteku
|
||||
## Success
|
||||
unlock.success.message=Uspešno ste otključali "%s"! Vaš sef je sada dostupan putem ovog virtuelnog diska.
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title=Lås upp "%s"
|
||||
unlock.passwordPrompt=Ange lösenord för "%s":
|
||||
unlock.savePassword=Kom ihåg lösenord
|
||||
unlock.unlockBtn=Lås upp
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=Välj Masterkey för "%s"
|
||||
unlock.chooseMasterkey.prompt=Kunde inte hitta Masterkey-filen för detta valv på förväntad plats. Välj filen manuellt.
|
||||
unlock.chooseMasterkey.chooseBtn=Välj…
|
||||
unlock.chooseMasterkey.filePickerTitle=Välj Masterkey-fil
|
||||
## Success
|
||||
unlock.success.message="%s" upplåst! Ditt valv är nu åtkomligt från den virtuella enheten.
|
||||
@@ -114,11 +116,14 @@ unlock.error.heading=Kan inte låsa upp valvet
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Monteringspunkten "%s" saknas eller är inte tom.
|
||||
unlock.error.invalidMountPoint.existing=Monteringspunkten "%s" finns redan eller så saknas överordnad mapp.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Enhetsbokstav "%s" används redan.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=Kunde inte låsa
|
||||
lock.forced.message=Låsning av "%s" förhindras av pågående operationer eller öppna filer. Du kan tvinga låsning av detta valv, men det kan resultera i förlust av osparade data.
|
||||
lock.forced.retryBtn=Försök igen
|
||||
lock.forced.forceBtn=Tvinga låsning
|
||||
## Failure
|
||||
lock.fail.heading=Låsning av valv misslyckades.
|
||||
lock.fail.message=Valvet "%s" kunde inte låsas. Se till att osparat arbete sparas någon annanstans och viktiga läs- och skrivfunktioner är klara. För att stänga valvet, avsluta Cryptomator-processen.
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
##
|
||||
## Select
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
##
|
||||
## Select
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
@@ -2,20 +2,78 @@
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=นำไปใช้
|
||||
generic.button.back=ย้อนกลับ
|
||||
generic.button.cancel=ยกเลิก
|
||||
generic.button.change=เปลี่ยน
|
||||
generic.button.close=ปิด
|
||||
generic.button.copy=คัดลอก
|
||||
generic.button.copied=คัดลอกแล้ว!
|
||||
generic.button.done=เสร็จสิ้น
|
||||
generic.button.next=ถัดไป
|
||||
generic.button.print=พิมพ์
|
||||
## Error
|
||||
generic.error.title=ข้อผิดพลาด: %s
|
||||
generic.error.instruction=ไม่นะ! Cryptomator ไม่ได้ต้องการให้สิ่งนี้เกิดขึ้น คุณสามารถค้นหาข้อผิดพลาดนี้ได้ หากค้นหาไม่เจอ โปรดรายงาน
|
||||
generic.error.hyperlink.lookup=ค้นหาข้อผิดพลาดนี้
|
||||
generic.error.hyperlink.report=รายงานข้อผิดพลาดนี้
|
||||
generic.error.technicalDetails=รายละเอียด:
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Vault
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=แสดง
|
||||
traymenu.showPreferencesWindow=การตั้งค่า
|
||||
traymenu.lockAllVaults=ล็อกทั้งหมด
|
||||
traymenu.quitApplication=ออก
|
||||
traymenu.vault.unlock=ปลดล็อก
|
||||
traymenu.vault.lock=ล็อก
|
||||
traymenu.vault.reveal=เปิดเผย
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=เพิ่ม Vault
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=สร้าง Vault ใหม่
|
||||
addvaultwizard.welcome.existingButton=เปิด Vault
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=เลือกชื่อให้ Vault
|
||||
addvaultwizard.new.namePrompt=ชื่อ Vault
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Cryptomator ควรเก็บไฟล์ของคุณไว้ที่ไหน?
|
||||
addvaultwizard.new.locationLabel=ที่จัดเก็บข้อมูล
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=ตำแหน่งที่กำหนดเอง
|
||||
addvaultwizard.new.directoryPickerButton=เลือก...
|
||||
addvaultwizard.new.directoryPickerTitle=เลือกไดเรกทอรี
|
||||
addvaultwizard.new.fileAlreadyExists=คำเตือน: มีชื่อแฟ้มหรือไดเรกทอรีนี้อยู่แล้ว
|
||||
addvaultwizard.new.locationDoesNotExist=ไม่มีไดเรกทอรีในตำแหน่งที่คุณเลือก หรือไม่สามารถเข้าถึงได้
|
||||
addvaultwizard.new.locationIsNotWritable=ไม่มีสิทธิ์ในการเขียนตำแหน่งที่คุณเลือก
|
||||
addvaultwizard.new.locationIsOk=ตำแหน่งนี้เหมาะสมสำหรับ Vault ของคุณ
|
||||
addvaultwizard.new.invalidName=ไม่สามารถใช้ชื่อนี้ได้
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=สร้าง Vault
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=หากคุณลืมรหัสผ่าน คุณจะไม่สามารถเข้าถึงข้อมูลเหล่านี้ได้ คุณต้องการที่จะสร้างรหัสกู้คืนหรือไม่?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=สร้างเลย ปลอดภัยเอาไว้ดีกว่า
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=ไม่สร้าง ฉันจะไม่ลืมรหัสผ่าน
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=โปรดอ่านข้อความนี้.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ ไฟล์ Vault ⚠️
|
||||
addvault.new.readme.storageLocation.2=นี่คือตำแหน่งจัดเก็บ Vault ของคุณ
|
||||
addvault.new.readme.storageLocation.3=ห้าม
|
||||
addvault.new.readme.storageLocation.4=• แก้ไขไฟล์ในนี้
|
||||
addvault.new.readme.storageLocation.5=• หรือวางไฟล์ในนี้
|
||||
addvault.new.readme.storageLocation.6=หากคุณต้องการที่จะเก็บไฟล์หรือดูไฟล์ใน Vault นี้ โปรด:
|
||||
addvault.new.readme.storageLocation.7=1. เพิ่ม Vault นี้ไปใน Cryptomator
|
||||
addvault.new.readme.storageLocation.8=2. ปลดล็อก Vault
|
||||
addvault.new.readme.storageLocation.9=3. เปิดตำแหน่งเข้าถึง โดยการกดปุ่ม "เปิดเผย"
|
||||
addvault.new.readme.storageLocation.10=หากคุณต้องการความช่วยเหลือ โปรดอ่านเอกสารอ้างอิง: %s
|
||||
addvault.new.readme.accessLocation.fileName=ยินดีต้อนรับ.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ พื้นที่นี้เข้ารหัสแล้ว 🔐️
|
||||
addvault.new.readme.accessLocation.2=นี่คือตำแหน่งจัดเก็บ Vault ของคุณ
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=เลือก...
|
||||
## Success
|
||||
|
||||
# Remove Vault
|
||||
@@ -25,7 +83,9 @@
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
##
|
||||
unlock.unlockBtn=ปลดล็อก
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=เลือก...
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
@@ -49,6 +109,7 @@
|
||||
## Fix Application
|
||||
|
||||
# Preferences
|
||||
preferences.title=การตั้งค่า
|
||||
## General
|
||||
## Volume
|
||||
## Updates
|
||||
@@ -62,12 +123,17 @@
|
||||
## Write
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=ปิด
|
||||
main.preferencesBtn.tooltip=การตั้งค่า
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.lock=ล็อก
|
||||
main.vaultlist.addVaultBtn=เพิ่ม Vault
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
### Unlocked
|
||||
main.vaultDetail.lockBtn=ล็อก
|
||||
### Missing
|
||||
### Needs Migration
|
||||
### Error
|
||||
@@ -76,8 +142,10 @@
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general.vaultName=ชื่อ Vault
|
||||
|
||||
## Mount
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=เลือก...
|
||||
## Master Key
|
||||
|
||||
|
||||
|
||||
@@ -102,8 +102,10 @@ unlock.title="%s" kilidini aç
|
||||
unlock.passwordPrompt="%s" için şifre girin:
|
||||
unlock.savePassword=Şifreyi Hatırla
|
||||
unlock.unlockBtn=Kilidi Aç
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title="%s" ait Ana anahtarı seçin
|
||||
unlock.chooseMasterkey.prompt=Bu kasa için masterkey dosyası beklenen konumda bulunamadı. Lütfen anahtar dosyasını manuel olarak seçin.
|
||||
unlock.chooseMasterkey.chooseBtn=Seç…
|
||||
unlock.chooseMasterkey.filePickerTitle=Masterkey Dosyasını Seç
|
||||
## Success
|
||||
unlock.success.message="%s" 'nin kilidi başarıyla açıldı! Kasanız şimdi sanal sürücüsü ile erişilebilir durumda.
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=Kasanın kilidi açılamıyor
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=Bağlantı noktası boş bir dizin değil veya mevcut değil: %s
|
||||
unlock.error.invalidMountPoint.existing=Bağlama noktası / klasör zaten var veya ana klasör eksik: %s
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied="%s" sürücü adı zaten kullanılıyor.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
|
||||
@@ -62,7 +62,8 @@ addvaultwizard.existing.chooseBtn=Обрати…
|
||||
|
||||
# Unlock
|
||||
unlock.unlockBtn=Розблокувати
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.chooseBtn=Обрати…
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
@@ -55,7 +55,7 @@ addvaultwizard.new.invalidName=无效的保险库名称,请考虑一个常规
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=创建保险库
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=如果没有密码,您将无法访问您的数据。您想要一个恢复密钥来以防您丢失密码吗?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=是的请,有备无患
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=好的,有备无患
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=不,谢谢。我不会丢失密码的
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=重要.rtf
|
||||
@@ -102,8 +102,10 @@ unlock.title=解锁 "%s"
|
||||
unlock.passwordPrompt=输入 "%s" 的密码
|
||||
unlock.savePassword=记住密码
|
||||
unlock.unlockBtn=解锁
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=选择 %s 的 Masterkey 文件
|
||||
unlock.chooseMasterkey.prompt=在指定路径找不到该保险库的 masterkey 文件,请手动选择密钥文件
|
||||
unlock.chooseMasterkey.chooseBtn=选择...
|
||||
unlock.chooseMasterkey.filePickerTitle=选择 Masterkey 文件
|
||||
## Success
|
||||
unlock.success.message=已成功解锁 "%s"! 您现在可以通过其虚拟驱动器访问它
|
||||
@@ -114,6 +116,7 @@ unlock.error.heading=无法解锁保险库
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=挂载点 "%s" 不是目录、非空或不存在
|
||||
unlock.error.invalidMountPoint.existing=挂载点 "%s" 已存在或缺少父文件夹
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=驱动器号 %s 已被占用。
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -215,10 +218,10 @@ preferences.updates.checkNowBtn=立即检查
|
||||
preferences.updates.updateAvailable=可更新到版本 %s
|
||||
## Contribution
|
||||
preferences.contribute=支持我们
|
||||
preferences.contribute.registeredFor=已为 %s 注册支持者证书
|
||||
preferences.contribute.registeredFor=已注册署名 %s 的赞助者证书
|
||||
preferences.contribute.noCertificate=支持 Cryptomator 并获得一份支持者证书。它类似于许可证密钥,特别之处是提供给使用免费软件的牛人的 ;-)
|
||||
preferences.contribute.getCertificate=还没有该证书吗?了解您如何获取
|
||||
preferences.contribute.promptText=请在此粘贴支持者证书代码
|
||||
preferences.contribute.promptText=在这里粘贴赞助者证书码
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
88
src/main/resources/i18n/strings_zh_HK.properties
Normal file
88
src/main/resources/i18n/strings_zh_HK.properties
Normal file
@@ -0,0 +1,88 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
## Error
|
||||
|
||||
# Defaults
|
||||
|
||||
# Tray Menu
|
||||
|
||||
# Add Vault Wizard
|
||||
## Welcome
|
||||
## New
|
||||
### Name
|
||||
### Location
|
||||
### Password
|
||||
### Information
|
||||
## Existing
|
||||
## Success
|
||||
|
||||
# Remove Vault
|
||||
|
||||
# Change Password
|
||||
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
## Select
|
||||
## Success
|
||||
## Failure
|
||||
### Invalid Mount Point
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
## Failure
|
||||
|
||||
# Migration
|
||||
## Start
|
||||
## Run
|
||||
## Success
|
||||
## Missing file system capabilities
|
||||
## Impossible
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
## Start Failure
|
||||
## Check Selection
|
||||
## Detail view
|
||||
## Fix Application
|
||||
|
||||
# Preferences
|
||||
## General
|
||||
## Volume
|
||||
## Updates
|
||||
## Contribution
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
# Vault Statistics
|
||||
## Read
|
||||
## Write
|
||||
|
||||
# Main Window
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
### Unlocked
|
||||
### Missing
|
||||
### Needs Migration
|
||||
### Error
|
||||
|
||||
# Wrong File Alert
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
|
||||
## Mount
|
||||
## Master Key
|
||||
|
||||
|
||||
# Recovery Key
|
||||
|
||||
# New Password
|
||||
|
||||
# Quit
|
||||
@@ -102,8 +102,10 @@ unlock.title=解鎖 %s
|
||||
unlock.passwordPrompt=輸入 "%s" 的密碼:
|
||||
unlock.savePassword=記住密碼
|
||||
unlock.unlockBtn=解鎖
|
||||
##
|
||||
## Select
|
||||
unlock.chooseMasterkey.title=选择“%s"的主密钥
|
||||
unlock.chooseMasterkey.prompt=無法在其預期位置找到此保管庫的主密鑰文件。請手動選擇密鑰文件。
|
||||
unlock.chooseMasterkey.chooseBtn=選取
|
||||
unlock.chooseMasterkey.filePickerTitle=選擇主金鑰檔案
|
||||
## Success
|
||||
unlock.success.message=成功解鎖 "%s"!您現在可以存存取您的加密檔案庫。
|
||||
@@ -114,11 +116,14 @@ unlock.error.heading=無法解鎖加密檔案庫
|
||||
### Invalid Mount Point
|
||||
unlock.error.invalidMountPoint.notExisting=掛載點不是空目錄或是不存在:%s
|
||||
unlock.error.invalidMountPoint.existing=掛載點已經存在或上層資料夾不存在:%s
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=磁碟代號 "%s" 已被使用
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.heading=鎖定失敗
|
||||
lock.forced.message=仍有未完成的操作或開啟中的檔案以致無法鎖定 "%s"。您可以強制鎖定這個加密檔案庫,不過中斷讀寫可能會導致資料遺失或未被儲存。
|
||||
lock.forced.retryBtn=重試
|
||||
lock.forced.forceBtn=強制鎖定
|
||||
## Failure
|
||||
lock.fail.heading=鎖定加密檔案庫失敗。
|
||||
lock.fail.message=加密檔案庫 "%s" 無法被鎖定。請確保未存檔的工作已儲存在別的地方以及重要的讀寫工作都已經完成。請強制結束 Cryptomator 以關閉加密檔案庫。
|
||||
|
||||
@@ -17,23 +17,23 @@ Cryptomator uses 40 third-party dependencies under the following licenses:
|
||||
- jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
|
||||
- jnr-constants (com.github.jnr:jnr-constants:0.10.2 - http://github.com/jnr/jnr-constants)
|
||||
- jnr-ffi (com.github.jnr:jnr-ffi:2.2.7 - http://github.com/jnr/jnr-ffi)
|
||||
- Dagger (com.google.dagger:dagger:2.40.3 - https://github.com/google/dagger)
|
||||
- Dagger (com.google.dagger:dagger:2.41 - https://github.com/google/dagger)
|
||||
- Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
|
||||
- Guava: Google Core Libraries for Java (com.google.guava:guava:31.0-jre - https://github.com/google/guava)
|
||||
- Guava: Google Core Libraries for Java (com.google.guava:guava:31.1-jre - https://github.com/google/guava)
|
||||
- Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
|
||||
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
||||
- Apache Commons Lang (org.apache.commons:commons-lang3:3.12.0 - https://commons.apache.org/proper/commons-lang/)
|
||||
- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.14 - http://hc.apache.org/httpcomponents-core-ga)
|
||||
- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.5 - http://jackrabbit.apache.org/jackrabbit-webdav/)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.6 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.6 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.6 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.6 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.6 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.6 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.8 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.8 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.8 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.8 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.8 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.8 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
|
||||
Apache-2.0:
|
||||
- Gson (com.google.code.gson:gson:2.8.9 - https://github.com/google/gson/gson)
|
||||
- Gson (com.google.code.gson:gson:2.9.0 - https://github.com/google/gson/gson)
|
||||
- Java Native Access (net.java.dev.jna:jna:5.9.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.9.0 - https://github.com/java-native-access/jna)
|
||||
BSD-3-Clause:
|
||||
@@ -45,38 +45,38 @@ Cryptomator uses 40 third-party dependencies under the following licenses:
|
||||
Eclipse Public License - Version 1.0:
|
||||
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
|
||||
Eclipse Public License - Version 2.0:
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.6 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.6 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.6 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.6 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.6 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.6 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.8 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.8 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.8 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.8 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.8 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.8 - https://eclipse.org/jetty/jetty-util)
|
||||
Eclipse Public License - v 1.0:
|
||||
- Logback Classic Module (ch.qos.logback:logback-classic:1.2.9 - http://logback.qos.ch/logback-classic)
|
||||
- Logback Core Module (ch.qos.logback:logback-core:1.2.9 - http://logback.qos.ch/logback-core)
|
||||
- Logback Classic Module (ch.qos.logback:logback-classic:1.2.11 - http://logback.qos.ch/logback-classic)
|
||||
- Logback Core Module (ch.qos.logback:logback-core:1.2.11 - http://logback.qos.ch/logback-core)
|
||||
Eclipse Public License - v 2.0:
|
||||
- jnr-posix (com.github.jnr:jnr-posix:3.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
GNU Lesser General Public License:
|
||||
- Logback Classic Module (ch.qos.logback:logback-classic:1.2.9 - http://logback.qos.ch/logback-classic)
|
||||
- Logback Core Module (ch.qos.logback:logback-core:1.2.9 - http://logback.qos.ch/logback-core)
|
||||
- Logback Classic Module (ch.qos.logback:logback-classic:1.2.11 - http://logback.qos.ch/logback-classic)
|
||||
- Logback Core Module (ch.qos.logback:logback-core:1.2.11 - http://logback.qos.ch/logback-core)
|
||||
GPLv2:
|
||||
- jnr-posix (com.github.jnr:jnr-posix:3.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
GPLv2+CE:
|
||||
- javafx-base (org.openjfx:javafx-base:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-base/)
|
||||
- javafx-controls (org.openjfx:javafx-controls:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
|
||||
- javafx-fxml (org.openjfx:javafx-fxml:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
|
||||
- javafx-graphics (org.openjfx:javafx-graphics:17.0.2 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
|
||||
- javafx-base (org.openjfx:javafx-base:18 - https://openjdk.java.net/projects/openjfx/javafx-base/)
|
||||
- javafx-controls (org.openjfx:javafx-controls:18 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
|
||||
- javafx-fxml (org.openjfx:javafx-fxml:18 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
|
||||
- javafx-graphics (org.openjfx:javafx-graphics:18 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
|
||||
LGPL 2.1:
|
||||
- jnr-posix (com.github.jnr:jnr-posix:3.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
LGPL-2.1-or-later:
|
||||
- Java Native Access (net.java.dev.jna:jna:5.9.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.9.0 - https://github.com/java-native-access/jna)
|
||||
MIT License:
|
||||
- java jwt (com.auth0:java-jwt:3.18.2 - https://github.com/auth0/java-jwt)
|
||||
- java jwt (com.auth0:java-jwt:3.19.1 - https://github.com/auth0/java-jwt)
|
||||
- jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
|
||||
- jnr-fuse (com.github.serceman:jnr-fuse:0.5.7 - https://github.com/SerCeMan/jnr-fuse)
|
||||
- zxcvbn4j (com.nulab-inc:zxcvbn:1.5.2 - https://github.com/nulab/zxcvbn4j)
|
||||
- SLF4J API Module (org.slf4j:slf4j-api:1.7.32 - http://www.slf4j.org)
|
||||
- SLF4J API Module (org.slf4j:slf4j-api:1.7.36 - http://www.slf4j.org)
|
||||
The BSD 2-Clause License:
|
||||
- EasyBind (com.tobiasdiez:easybind:2.2 - https://github.com/tobiasdiez/EasyBind)
|
||||
|
||||
|
||||
129
src/test/java/org/cryptomator/common/PassphraseTest.java
Normal file
129
src/test/java/org/cryptomator/common/PassphraseTest.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
public class PassphraseTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"-1, 0",
|
||||
"0, -1",
|
||||
"0, 10",
|
||||
"10, 0",
|
||||
"10, 10"
|
||||
})
|
||||
public void testInvalidConstructorArgs(int offset, int length) {
|
||||
char[] data = "test".toCharArray();
|
||||
Assertions.assertThrows(IndexOutOfBoundsException.class, () -> {
|
||||
new Passphrase(data, offset, length);
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"0, 4",
|
||||
"0, 0",
|
||||
"0, 1",
|
||||
"1, 1",
|
||||
"2, 2"
|
||||
})
|
||||
public void testValidConstructorArgs(int offset, int length) {
|
||||
char[] data = "test".toCharArray();
|
||||
var pw = new Passphrase(data, offset, length);
|
||||
Assertions.assertEquals(length, pw.length());
|
||||
Assertions.assertEquals("test".substring(offset, offset + length), pw.toString());
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class InstanceMethods {
|
||||
|
||||
private Passphrase pw1;
|
||||
private Passphrase pw2;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
char[] foo = "test test".toCharArray();
|
||||
pw1 = new Passphrase(foo, 5, 4);
|
||||
pw2 = Passphrase.copyOf("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
Assertions.assertEquals("test", pw1.toString());
|
||||
Assertions.assertEquals("test", pw2.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
Assertions.assertEquals(pw1, pw2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashcode() {
|
||||
Assertions.assertEquals(pw1.hashCode(), pw2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLength() {
|
||||
Assertions.assertEquals(4, pw1.length());
|
||||
Assertions.assertEquals(4, pw2.length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCharAt() {
|
||||
Assertions.assertEquals('s', pw1.charAt(2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {-1, 4, 5})
|
||||
public void testInvalidCharAt(int idx) {
|
||||
Assertions.assertThrows(IndexOutOfBoundsException.class, () -> pw1.charAt(idx));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1, 2, 3})
|
||||
public void testValidCharAt(int idx) {
|
||||
Assertions.assertEquals("test".charAt(idx), pw1.charAt(idx));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"-1, 0",
|
||||
"0, -1",
|
||||
"-1, -1",
|
||||
"0, 5",
|
||||
"3, 2"
|
||||
})
|
||||
public void testInvalidSubSequence(int start, int end) {
|
||||
Assertions.assertThrows(IndexOutOfBoundsException.class, () -> pw1.subSequence(start, end));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"0, 4",
|
||||
"1, 4",
|
||||
"0, 2",
|
||||
"2, 4",
|
||||
"4, 4",
|
||||
})
|
||||
public void testValidSubSequence(int start, int end) {
|
||||
Assertions.assertEquals("test".substring(start, end), pw1.subSequence(start, end).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroy() {
|
||||
pw2.destroy();
|
||||
Assertions.assertFalse(pw1.isDestroyed());
|
||||
Assertions.assertTrue(pw2.isDestroyed());
|
||||
Assertions.assertNotEquals(pw1, pw2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package org.cryptomator.common.keychain;
|
||||
|
||||
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
@@ -32,7 +34,8 @@ public class KeychainManagerTest {
|
||||
public static void startup() throws InterruptedException {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Platform.startup(latch::countDown);
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
var javafxStarted = latch.await(5, TimeUnit.SECONDS);
|
||||
Assumptions.assumeTrue(javafxStarted);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -33,7 +33,7 @@ public class CustomMountPointChooserTest {
|
||||
this.volume = Mockito.mock(Volume.class);
|
||||
this.vaultSettings = Mockito.mock(VaultSettings.class);
|
||||
this.environment = Mockito.mock(Environment.class);
|
||||
this.customMpc = new CustomMountPointChooser(vaultSettings, environment);
|
||||
this.customMpc = new CustomMountPointChooser(vaultSettings);
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -31,8 +31,8 @@ public class LaunchBasedTriggeringPolicyTest {
|
||||
triggered = policy.isTriggeringEvent(activeFile, event);
|
||||
Assertions.assertFalse(triggered);
|
||||
|
||||
Mockito.verifyZeroInteractions(activeFile);
|
||||
Mockito.verifyZeroInteractions(event);
|
||||
Mockito.verifyNoInteractions(activeFile);
|
||||
Mockito.verifyNoInteractions(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cryptomator.ui.controls;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -8,7 +9,6 @@ import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -18,13 +18,10 @@ public class SecurePasswordFieldTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void initJavaFx() throws InterruptedException {
|
||||
Assumptions.assumeFalse(GraphicsEnvironment.isHeadless());
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Platform.startup(latch::countDown);
|
||||
|
||||
if (!latch.await(5L, TimeUnit.SECONDS)) {
|
||||
throw new ExceptionInInitializerError();
|
||||
}
|
||||
var javafxStarted = latch.await(5, TimeUnit.SECONDS);
|
||||
Assumptions.assumeTrue(javafxStarted);
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -11,13 +11,12 @@ import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class RecoveryKeyFactoryTest {
|
||||
|
||||
private WordEncoder wordEncoder = new WordEncoder();
|
||||
private MasterkeyFileAccess masterkeyFileAccess = Mockito.mock(MasterkeyFileAccess.class);
|
||||
private RecoveryKeyFactory inTest = new RecoveryKeyFactory(wordEncoder, masterkeyFileAccess);
|
||||
private final WordEncoder wordEncoder = new WordEncoder();
|
||||
private final MasterkeyFileAccess masterkeyFileAccess = Mockito.mock(MasterkeyFileAccess.class);
|
||||
private final RecoveryKeyFactory inTest = new RecoveryKeyFactory(wordEncoder, masterkeyFileAccess);
|
||||
|
||||
@Test
|
||||
@DisplayName("createRecoveryKey() creates 44 words")
|
||||
|
||||
Reference in New Issue
Block a user