diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 93066b9d9..722c63d44 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -20,6 +20,10 @@
Translations are not managed directly in this repository. Instead, we use [Crowdin](https://translate.cryptomator.org/), which automatically synchronizes translations with this repository. If you want to help us with translations, please visit our translation project on Crowdin.
+## Use of Generative AI
+
+AI tools may assist your work, but every contribution must be fully understood, reviewed, and tested by you. Only submit changes you can clearly explain and justify. Unverified or low-quality AI output that wastes our time and resources will be closed without further review.
+
## Code of Conduct
Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md).
diff --git a/.github/actions/win-sign-action/action.yml b/.github/actions/win-sign-action/action.yml
new file mode 100644
index 000000000..ce4423883
--- /dev/null
+++ b/.github/actions/win-sign-action/action.yml
@@ -0,0 +1,76 @@
+name: 'Windows Code Signing'
+description: 'Sign files on Windows with the Azure Trusted Signing'
+inputs:
+ base-dir:
+ description: 'Absolute path to the base directory to search for files'
+ required: true
+ recursive:
+ description: 'Whether to search recursively in subdirectories'
+ required: false
+ default: 'false'
+ file-extensions:
+ description: 'List of file extensions to sign, separated by comma'
+ required: true
+ default: 'exe,dll,ps1'
+ description:
+ description: 'Signature description'
+ required: true
+ default: 'Cryptomator'
+ url:
+ description: 'Signature URL'
+ required: false
+ default: 'https://cryptomator.org'
+ append-signature:
+ description: 'Whether to append the signature to existing signatures'
+ required: false
+ default: 'false'
+ tenant-id:
+ description: 'Azure Tenant ID'
+ required: true
+ client-id:
+ description: 'Azure Client ID'
+ required: true
+ client-secret:
+ description: 'Azure Client Secret'
+ required: true
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Generate, mask, and output the input secrets
+ id: set-secrets
+ run: |
+ echo "::add-mask::${{ inputs.tenant-id }}"
+ echo "::add-mask::${{ inputs.client-id }}"
+ echo "::add-mask::${{ inputs.client-secret }}"
+ echo "tenant-id=${{ inputs.tenant-id }}" >> "$GITHUB_OUTPUT"
+ echo "client-id=${{ inputs.client-id }}" >> "$GITHUB_OUTPUT"
+ echo "client-secret=${{ inputs.client-secret }}" >> "$GITHUB_OUTPUT"
+ shell: bash
+ - name: Sign DLLs with Azure Trusted Signing
+ uses: azure/trusted-signing-action@fc390cf8ed0f14e248a542af1d838388a47c7a7c # v0.5.10
+ with:
+ files-folder: ${{ inputs.base-dir }}
+ files-folder-filter: ${{ inputs.file-extensions }}
+ files-folder-recurse: ${{ inputs.recursive }}
+ append-signature: ${{ inputs.append-signature }}
+ description: ${{ inputs.description }}
+ description-url: ${{ inputs.url }}
+ azure-tenant-id: ${{ steps.set-secrets.outputs.tenant-id }}
+ azure-client-id: ${{ steps.set-secrets.outputs.client-id }}
+ azure-client-secret: ${{ steps.set-secrets.outputs.client-secret }}
+ trusted-signing-account-name: cryptomatorSigning
+ certificate-profile-name: production
+ endpoint: https://weu.codesigning.azure.net/
+ timestamp-rfc3161: http://timestamp.acs.microsoft.com
+ timestamp-digest: SHA256
+ exclude-environment-credential: false
+ exclude-workload-identity-credential: true
+ exclude-managed-identity-credential: true
+ exclude-shared-token-cache-credential: true
+ exclude-visual-studio-credential: true
+ exclude-visual-studio-code-credential: true
+ exclude-azure-cli-credential: true
+ exclude-azure-powershell-credential: true
+ exclude-azure-developer-cli-credential: true
+ exclude-interactive-browser-credential: true
diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml
index 11206ca54..20fea5c58 100644
--- a/.github/workflows/appimage.yml
+++ b/.github/workflows/appimage.yml
@@ -19,7 +19,7 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: '24.0.1+9'
+ JAVA_VERSION: '25.0.1+8.0.LTS'
jobs:
get-version:
@@ -42,7 +42,7 @@ jobs:
- os: ubuntu-24.04-arm
appimage-suffix: aarch64
openjfx-url: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-aarch64_bin-jmods.zip'
- openjfx-sha: '951c52481af0ec5885b06f1ebaa8a10da7e8ea23c5e1ef3e2f6f11fa1b3a7ce1'
+ openjfx-sha: '9ad4ca7b769ca4ee6419f1e99143dd6ff812f8be4fddb46a7d7cacbeea148af4'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Java
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b528cfb49..c9a0ea0c9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -11,7 +11,7 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: 24
+ JAVA_VERSION: 25
defaults:
run:
diff --git a/.github/workflows/check-jdk-updates.yml b/.github/workflows/check-jdk-updates.yml
index 432cf16b7..cad852dc1 100644
--- a/.github/workflows/check-jdk-updates.yml
+++ b/.github/workflows/check-jdk-updates.yml
@@ -6,7 +6,7 @@ on:
workflow_dispatch:
env:
- JDK_VERSION: '24.0.1+9'
+ JDK_VERSION: '25.0.1+8.0.LTS'
JDK_VENDOR: temurin
RUNTIME_VERSION_HELPER: >
public class Test {
@@ -23,7 +23,7 @@ jobs:
JDK_MAJOR_VERSION: 'toBeFilled'
steps:
- name: Determine current major version
- run: echo 'JDK_MAJOR_VERSION=${{ env.JDK_VERSION }}'.substring(0,20) >> "$env:GITHUB_ENV"
+ run: echo 'JDK_MAJOR_VERSION=${{ env.JDK_VERSION }}'.substring(0,2) >> "$env:GITHUB_ENV"
shell: pwsh
- name: Checkout latest JDK ${{ env.JDK_MAJOR_VERSION }}
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml
index 715fde74d..17a3d487f 100644
--- a/.github/workflows/debian.yml
+++ b/.github/workflows/debian.yml
@@ -23,13 +23,12 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: '24.0.1+9'
- COFFEELIBS_JDK: 24
- COFFEELIBS_JDK_VERSION: '24.0.1+9-0ppa3'
+ JAVA_VERSION: '25.0.1+8.0.LTS'
+ DEB_BUILD_DEPENDS: 'debhelper (>=10), openjdk-25-jdk (>= 25+36), libgtk-3-0 (>= 3.20.0), libxxf86vm1, libgl1'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: '96e520f48610d8ffb94ca30face1f11ffe8a977ddc1c4ff80b1a9e9f048bd94e'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-aarch64_bin-jmods.zip'
- OPENJFX_JMODS_AARCH64_HASH: '951c52481af0ec5885b06f1ebaa8a10da7e8ea23c5e1ef3e2f6f11fa1b3a7ce1'
+ OPENJFX_JMODS_AARCH64_HASH: '9ad4ca7b769ca4ee6419f1e99143dd6ff812f8be4fddb46a7d7cacbeea148af4'
jobs:
get-version:
@@ -55,9 +54,11 @@ jobs:
fi
- name: Install build tools
run: |
- sudo add-apt-repository ppa:coffeelibs/openjdk
sudo apt-get update
- sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.COFFEELIBS_JDK }}=${{ env.COFFEELIBS_JDK_VERSION }}
+ sudo apt-get install devscripts dput
+ sudo apt-get satisfy "${DEB_BUILD_DEPENDS}"
+ env:
+ DEB_BUILD_DEPENDS: ${{ env.DEB_BUILD_DEPENDS }}
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml
index ddce37384..22d2a5fc5 100644
--- a/.github/workflows/dependency-check.yml
+++ b/.github/workflows/dependency-check.yml
@@ -11,7 +11,7 @@ jobs:
with:
runner-os: 'ubuntu-latest'
java-distribution: 'temurin'
- java-version: 24
+ java-version: 25
secrets:
nvd-api-key: ${{ secrets.NVD_API_KEY }}
ossindex-username: ${{ secrets.OSSINDEX_USERNAME }}
diff --git a/.github/workflows/get-version.yml b/.github/workflows/get-version.yml
index 5585d7ac5..b1c728fa8 100644
--- a/.github/workflows/get-version.yml
+++ b/.github/workflows/get-version.yml
@@ -23,7 +23,7 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: 24
+ JAVA_VERSION: 25
jobs:
determine-version:
diff --git a/.github/workflows/mac-dmg-x64.yml b/.github/workflows/mac-dmg-x64.yml
index 9e6f48a7c..6a9c3f644 100644
--- a/.github/workflows/mac-dmg-x64.yml
+++ b/.github/workflows/mac-dmg-x64.yml
@@ -24,7 +24,7 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: '24.0.1+9'
+ JAVA_VERSION: '25.0.1+8.0.LTS'
jobs:
get-version:
diff --git a/.github/workflows/mac-dmg.yml b/.github/workflows/mac-dmg.yml
index c47b4309a..4f9ff6e71 100644
--- a/.github/workflows/mac-dmg.yml
+++ b/.github/workflows/mac-dmg.yml
@@ -22,7 +22,7 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: '24.0.1+9'
+ JAVA_VERSION: '25.0.1+8.0.LTS'
jobs:
get-version:
diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index 8bfddf2d4..cfb013c05 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -5,7 +5,7 @@ on:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: 24
+ JAVA_VERSION: 25
defaults:
run:
diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml
index e1739326e..e6c12a2d1 100644
--- a/.github/workflows/release-check.yml
+++ b/.github/workflows/release-check.yml
@@ -12,7 +12,7 @@ defaults:
env:
JAVA_DIST: 'temurin'
- JAVA_VERSION: 23
+ JAVA_VERSION: 25
jobs:
check-preconditions:
diff --git a/.github/workflows/win-exe.yml b/.github/workflows/win-exe.yml
index bf2e5cce7..95bc6aed0 100644
--- a/.github/workflows/win-exe.yml
+++ b/.github/workflows/win-exe.yml
@@ -8,10 +8,6 @@ on:
version:
description: 'Version'
required: false
- isDebug:
- description: 'Build debug version with console output'
- type: boolean
- default: false
sign:
description: 'Sign binaries'
required: false
@@ -51,8 +47,8 @@ jobs:
include:
- arch: x64
os: windows-latest
- java-dist: 'zulu'
- java-version: '24.0.1+9'
+ java-dist: 'zulu' #cannot use temurin, see https://github.com/cryptomator/cryptomator/issues/3824#issuecomment-2829827427
+ java-version: '25.0.1+8'
java-package: 'jdk'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -192,6 +188,16 @@ jobs:
New-Item -Path appdir/jpackage-jmod -ItemType Directory
& $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir"
+ - name: Sign DLLs with Azure Trusted Signing
+ if: inputs.sign || github.event_name == 'release'
+ uses: ./.github/actions/win-sign-action
+ with:
+ base-dir: ${{ github.workspace }}\appdir
+ recursive: true
+ append-signature: true
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign DLLs with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
@@ -251,16 +257,16 @@ jobs:
env:
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
- - name: Sign msi with Actalis CodeSigner
+ - name: Sign MSI with Azure Trusted Signing
if: inputs.sign || github.event_name == 'release'
- uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
+ uses: ./.github/actions/win-sign-action
with:
- base-dir: 'installer'
- file-extensions: 'msi'
- sign-description: 'Cryptomator Installer'
- sign-url: 'https://cryptomator.org'
- username: ${{ secrets.WIN_CODESIGN_USERNAME }}
- password: ${{ secrets.WIN_CODESIGN_PW }}
+ base-dir: ${{ github.workspace }}\installer
+ file-extensions: msi
+ description: 'Cryptomator Installer'
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Add possible alpha/beta tags and architecture to installer name
run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.arch }}.msi
- name: Create detached GPG signature with key 615D449FE6E6A235
@@ -357,6 +363,17 @@ jobs:
- name: Detach burn engine in preparation to sign
run: >
wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe
+ - name: Sign WiX burn engine with Azure Trusted Signing
+ if: inputs.sign || github.event_name == 'release'
+ uses: ./.github/actions/win-sign-action
+ with:
+ base-dir: ${{ github.workspace }}\tmp
+ file-extensions: exe
+ append-signature: true
+ description: 'Cryptomator Bundle Installer'
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign burn engine with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
@@ -370,6 +387,17 @@ jobs:
- name: Reattach signed burn engine to installer
run: >
wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
+ - name: Sign EXE installer with Azure Trusted Signing
+ if: inputs.sign || github.event_name == 'release'
+ uses: ./.github/actions/win-sign-action
+ with:
+ base-dir: ${{ github.workspace }}\installer
+ file-extensions: exe
+ append-signature: true
+ description: 'Cryptomator Bundle Installer'
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign installer with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 1256745d3..2d9504948 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -14,16 +14,15 @@
-
-
+
+
-
-
+
-
-
-
+
+
+
@@ -31,14 +30,16 @@
-
-
+
-
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index cc61ae273..52746672a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -8,7 +8,7 @@
-
+
\ No newline at end of file
diff --git a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
index e986431a8..8654f7156 100644
--- a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
+++ b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
@@ -83,6 +83,9 @@
+
+ https://github.com/cryptomator/cryptomator/releases/1.18.0
+
https://github.com/cryptomator/cryptomator/releases/1.17.1
diff --git a/dist/linux/debian/control b/dist/linux/debian/control
index 95c8c6871..713f03972 100644
--- a/dist/linux/debian/control
+++ b/dist/linux/debian/control
@@ -2,7 +2,7 @@ Source: cryptomator
Maintainer: Cryptobot
Section: utils
Priority: optional
-Build-Depends: debhelper (>=10), coffeelibs-jdk-24 (>= 24.0.1+9-0ppa3), libgtk-3-0 (>= 3.20.0), libxxf86vm1, libgl1
+Build-Depends: debhelper (>=10), openjdk-25-jdk (>= 25+36), libgtk-3-0 (>= 3.20.0), libxxf86vm1, libgl1
Standards-Version: 4.5.0
Homepage: https://cryptomator.org
Vcs-Git: https://github.com/cryptomator/cryptomator.git
diff --git a/dist/linux/debian/rules b/dist/linux/debian/rules
index c6e697283..456a97e89 100755
--- a/dist/linux/debian/rules
+++ b/dist/linux/debian/rules
@@ -4,11 +4,12 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
-JAVA_HOME = /usr/lib/jvm/java-24-coffeelibs
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
ifeq ($(DEB_BUILD_ARCH),amd64)
+JAVA_HOME = /usr/lib/jvm/java-25-openjdk-amd64
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
else ifeq ($(DEB_BUILD_ARCH),arm64)
+JAVA_HOME = /usr/lib/jvm/java-25-openjdk-arm64
JMODS_PATH = jmods/aarch64:${JAVA_HOME}/jmods
endif
diff --git a/license/merges b/license/merges
index eb3a32a5b..a47203dfa 100644
--- a/license/merges
+++ b/license/merges
@@ -1,6 +1,6 @@
-Apache License v2.0|Apache License, Version 2.0|The Apache Software License, Version 2.0|Apache 2.0|Apache Software License - Version 2.0|Apache-2.0
-MIT License|The MIT License (MIT)|The MIT License|MIT license
-LGPL 2.1|LGPL, version 2.1|GNU Lesser/Library General Public License version 2|GNU Lesser General Public License Version 2.1
+Apache License v2.0|Apache License, Version 2.0|The Apache License, Version 2.0|The Apache Software License, Version 2.0|Apache 2.0|Apache Software License - Version 2.0|Apache-2.0
+MIT License|MIT|The MIT License (MIT)|The MIT License|MIT license
+LGPL 2.1|LGPL, version 2.1|GNU Lesser/Library General Public License version 2|GNU Lesser General Public License Version 2.1|GNU Lesser General Public License
GPLv2|GNU General Public License Version 2
GPLv2+CE|CDDL + GPLv2 with classpath exception
Eclipse Public License - Version 1.0|Eclipse Public License - v 1.0
diff --git a/pom.xml b/pom.xml
index 7c8e5c7a1..412375ce5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.cryptomator
cryptomator
- 1.18.0-SNAPSHOT
+ 1.19.0-SNAPSHOT
Cryptomator Desktop App
@@ -26,7 +26,7 @@
UTF-8
- 24
+ 25
@@ -62,7 +62,7 @@
26.0.2-1
12.1.5
- 0.8.13
+ 0.8.14
2.7.0
1.4.0
3.14.1
diff --git a/src/main/java/org/cryptomator/common/recovery/BackupRestorer.java b/src/main/java/org/cryptomator/common/recovery/BackupRestorer.java
new file mode 100644
index 000000000..e5afc5112
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/recovery/BackupRestorer.java
@@ -0,0 +1,53 @@
+package org.cryptomator.common.recovery;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileTime;
+import java.util.stream.Stream;
+
+import static org.cryptomator.common.Constants.MASTERKEY_BACKUP_SUFFIX;
+
+public final class BackupRestorer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BackupRestorer.class);
+
+ private BackupRestorer() {}
+
+ public static void restoreIfBackupPresent(Path vaultPath, String filePrefix) {
+ Path targetFile = vaultPath.resolve(filePrefix);
+
+ try (Stream files = Files.list(vaultPath)) {
+ files.filter(file -> isFileMatchingPattern(file.getFileName().toString(), filePrefix))
+ .max((f1, f2) -> {
+ try {
+ FileTime time1 = Files.getLastModifiedTime(f1);
+ FileTime time2 = Files.getLastModifiedTime(f2);
+ return time1.compareTo(time2);
+ } catch (IOException e) {
+ return 0;
+ }
+ })
+ .ifPresent(backupFile -> copyBackupFile(backupFile, targetFile));
+ } catch (IOException e) {
+ LOG.info("Unable to restore backup files in '{}'", vaultPath, e);
+ }
+ }
+
+ private static boolean isFileMatchingPattern(String fileName, String filePrefix) {
+ return fileName.startsWith(filePrefix) && fileName.endsWith(MASTERKEY_BACKUP_SUFFIX);
+ }
+
+ private static void copyBackupFile(Path backupFile, Path configPath) {
+ try {
+ Files.copy(backupFile, configPath, StandardCopyOption.REPLACE_EXISTING);
+ LOG.debug("Backup restored - file: '{}' path: '{}'", backupFile, configPath);
+ } catch (IOException e) {
+ LOG.warn("Unable to copy backup file from '{}' to '{}'", backupFile, configPath, e);
+ }
+ }
+}
diff --git a/src/main/java/org/cryptomator/common/recovery/CryptoFsInitializer.java b/src/main/java/org/cryptomator/common/recovery/CryptoFsInitializer.java
new file mode 100644
index 000000000..359405d15
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/recovery/CryptoFsInitializer.java
@@ -0,0 +1,33 @@
+package org.cryptomator.common.recovery;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import org.cryptomator.cryptofs.CryptoFileSystemProperties;
+import org.cryptomator.cryptofs.CryptoFileSystemProvider;
+import org.cryptomator.cryptolib.api.Masterkey;
+import org.cryptomator.cryptolib.api.CryptorProvider;
+import org.cryptomator.cryptolib.api.CryptoException;
+import org.cryptomator.cryptolib.api.MasterkeyLoader;
+
+import static org.cryptomator.common.Constants.DEFAULT_KEY_ID;
+
+public final class CryptoFsInitializer {
+
+ private CryptoFsInitializer() {}
+
+ public static void init(Path recoveryPath,
+ Masterkey masterkey,
+ int shorteningThreshold,
+ CryptorProvider.Scheme scheme) throws IOException, CryptoException {
+
+ MasterkeyLoader loader = ignored -> masterkey.copy();
+ CryptoFileSystemProperties fsProps = CryptoFileSystemProperties //
+ .cryptoFileSystemProperties() //
+ .withCipherCombo(scheme) //
+ .withKeyLoader(loader) //
+ .withShorteningThreshold(shorteningThreshold) //
+ .build();
+ CryptoFileSystemProvider.initialize(recoveryPath, fsProps, DEFAULT_KEY_ID);
+ }
+}
diff --git a/src/main/java/org/cryptomator/common/recovery/MasterkeyService.java b/src/main/java/org/cryptomator/common/recovery/MasterkeyService.java
new file mode 100644
index 000000000..7d487ec54
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/recovery/MasterkeyService.java
@@ -0,0 +1,101 @@
+package org.cryptomator.common.recovery;
+
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.cryptolib.api.CryptoException;
+import org.cryptomator.cryptolib.api.Cryptor;
+import org.cryptomator.cryptolib.api.CryptorProvider;
+import org.cryptomator.cryptolib.api.Masterkey;
+import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
+import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
+import static org.cryptomator.cryptofs.common.Constants.DATA_DIR_NAME;
+
+public final class MasterkeyService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MasterkeyService.class);
+
+ private MasterkeyService() {}
+
+ public static void recoverFromRecoveryKey(String recoveryKey, RecoveryKeyFactory recoveryKeyFactory, Path recoveryPath, CharSequence newPassword) throws IOException {
+ recoveryKeyFactory.newMasterkeyFileWithPassphrase(recoveryPath, recoveryKey, newPassword);
+ }
+
+ public static Masterkey load(MasterkeyFileAccess masterkeyFileAccess, Path masterkeyFilePath, CharSequence password) throws IOException {
+ return masterkeyFileAccess.load(masterkeyFilePath, password);
+ }
+
+ public static CryptorProvider.Scheme validateRecoveryKeyAndDetectCombo(RecoveryKeyFactory recoveryKeyFactory, //
+ Vault vault, String recoveryKey, //
+ MasterkeyFileAccess masterkeyFileAccess) throws IOException, CryptoException, NoSuchElementException {
+ String tmpPass = UUID.randomUUID().toString();
+ try (RecoveryDirectory recoveryDirectory = RecoveryDirectory.create(vault.getPath())) {
+ Path tempRecoveryPath = recoveryDirectory.getRecoveryPath();
+ recoverFromRecoveryKey(recoveryKey, recoveryKeyFactory, tempRecoveryPath, tmpPass);
+ Path masterkeyFilePath = tempRecoveryPath.resolve(MASTERKEY_FILENAME);
+
+ try (Masterkey mk = load(masterkeyFileAccess, masterkeyFilePath, tmpPass)) {
+ return detect(mk, vault.getPath()).orElseThrow();
+ }
+ }
+ }
+
+ public static Optional detect(Masterkey masterkey, Path vaultPath) {
+ try (Stream paths = Files.walk(vaultPath.resolve(DATA_DIR_NAME))) {
+ Optional c9rFile = paths //
+ .filter(p -> p.toString().endsWith(".c9r")) //
+ .filter(p -> !p.endsWith("dir.c9r")) //
+ .findFirst();
+ if (c9rFile.isEmpty()) {
+ LOG.info("Unable to detect Crypto scheme: No *.c9r file found in {}", vaultPath);
+ return Optional.empty();
+ }
+ return determineScheme(c9rFile.get(), masterkey);
+ } catch (IOException e) {
+ LOG.info("Unable to detect Crypto scheme: Failed to inspect vault", e);
+ return Optional.empty();
+ }
+ }
+
+ private static Optional determineScheme(Path c9rFile, Masterkey masterkey) {
+ return Arrays.stream(CryptorProvider.Scheme.values()).filter(scheme -> {
+ try (Cryptor cryptor = CryptorProvider.forScheme(scheme).provide(masterkey.copy(), SecureRandom.getInstanceStrong())) {
+ int headerSize = cryptor.fileHeaderCryptor().headerSize();
+
+ ByteBuffer headerBuf = ByteBuffer.allocate(headerSize);
+
+ try (FileChannel channel = FileChannel.open(c9rFile, StandardOpenOption.READ)) {
+ channel.read(headerBuf, 0);
+ }
+
+ headerBuf.flip();
+ cryptor.fileHeaderCryptor().decryptHeader(headerBuf.duplicate());
+ LOG.debug("Detected Crypto scheme: {}", scheme);
+ return true;
+ } catch (IllegalArgumentException | CryptoException e) {
+ LOG.debug("Could not decrypt with scheme: {}", scheme);
+ return false;
+ } catch (IOException | NoSuchAlgorithmException e) {
+ LOG.warn("Unable to detect Crypto scheme: Failed to decrypt .c9r file", e);
+ return false;
+ }
+ }).findFirst();
+ }
+
+}
diff --git a/src/main/java/org/cryptomator/common/recovery/RecoveryActionType.java b/src/main/java/org/cryptomator/common/recovery/RecoveryActionType.java
new file mode 100644
index 000000000..a05073dad
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/recovery/RecoveryActionType.java
@@ -0,0 +1,10 @@
+package org.cryptomator.common.recovery;
+
+public enum RecoveryActionType {
+ RESTORE_ALL,
+ RESTORE_MASTERKEY,
+ RESTORE_VAULT_CONFIG,
+ RESET_PASSWORD,
+ SHOW_KEY,
+ CONVERT_VAULT
+}
diff --git a/src/main/java/org/cryptomator/common/recovery/RecoveryDirectory.java b/src/main/java/org/cryptomator/common/recovery/RecoveryDirectory.java
new file mode 100644
index 000000000..be2af245b
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/recovery/RecoveryDirectory.java
@@ -0,0 +1,56 @@
+package org.cryptomator.common.recovery;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Comparator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class RecoveryDirectory implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RecoveryDirectory.class);
+
+ private final Path recoveryPath;
+ private final Path vaultPath;
+
+ private RecoveryDirectory(Path vaultPath, Path recoveryPath) {
+ this.vaultPath = vaultPath;
+ this.recoveryPath = recoveryPath;
+ }
+
+ public static RecoveryDirectory create(Path vaultPath) throws IOException {
+ Path tempDir = Files.createTempDirectory("cryptomator");
+ return new RecoveryDirectory(vaultPath, tempDir);
+ }
+
+ public void moveRecoveredFile(String file) throws IOException {
+ Files.move(recoveryPath.resolve(file), vaultPath.resolve(file), StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ private void deleteRecoveryDirectory() {
+ try (var paths = Files.walk(recoveryPath)) {
+ paths.sorted(Comparator.reverseOrder()).forEach(p -> {
+ try {
+ Files.delete(p);
+ } catch (IOException e) {
+ LOG.info("Unable to delete {}. Please delete it manually.", p);
+ }
+ });
+ } catch (IOException e) {
+ LOG.error("Failed to clean up recovery directory", e);
+ }
+ }
+
+ @Override
+ public void close() {
+ deleteRecoveryDirectory();
+ }
+
+ public Path getRecoveryPath() {
+ return recoveryPath;
+ }
+
+}
diff --git a/src/main/java/org/cryptomator/common/recovery/VaultPreparator.java b/src/main/java/org/cryptomator/common/recovery/VaultPreparator.java
new file mode 100644
index 000000000..d99ba50a0
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/recovery/VaultPreparator.java
@@ -0,0 +1,54 @@
+package org.cryptomator.common.recovery;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.settings.VaultSettings;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultComponent;
+import org.cryptomator.common.vaults.VaultConfigCache;
+import org.cryptomator.common.vaults.VaultListManager;
+import org.cryptomator.integrations.mount.MountService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
+
+public final class VaultPreparator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VaultPreparator.class);
+
+ private VaultPreparator() {}
+
+ public static Vault prepareVault(Path selectedDirectory, //
+ VaultComponent.Factory vaultComponentFactory, //
+ List mountServices, //
+ ResourceBundle resourceBundle) {
+ VaultSettings vaultSettings = VaultSettings.withRandomId();
+ vaultSettings.path.set(selectedDirectory);
+ if (selectedDirectory.getFileName() != null) {
+ vaultSettings.displayName.set(selectedDirectory.getFileName().toString());
+ } else {
+ vaultSettings.displayName.set(resourceBundle.getString("defaults.vault.vaultName"));
+ }
+
+ var wrapper = new VaultConfigCache(vaultSettings);
+ Vault vault = vaultComponentFactory.create(vaultSettings, wrapper, LOCKED, null).vault();
+ try {
+ VaultListManager.determineVaultState(vault.getPath());
+ } catch (IOException e) {
+ LOG.warn("Failed to determine vault state for {}", vaultSettings.path.get(), e);
+ }
+
+ //due to https://github.com/cryptomator/cryptomator/issues/2880#issuecomment-1680313498
+ var nameOfWinfspLocalMounter = "org.cryptomator.frontend.fuse.mount.WinFspMountProvider";
+ if (SystemUtils.IS_OS_WINDOWS && vaultSettings.path.get().toString().contains("Dropbox") && mountServices.stream().anyMatch(s -> s.getClass().getName().equals(nameOfWinfspLocalMounter))) {
+ vaultSettings.mountService.setValue(nameOfWinfspLocalMounter);
+ }
+
+ return vault;
+ }
+}
diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java
index 7b1267df8..75790507c 100644
--- a/src/main/java/org/cryptomator/common/vaults/Vault.java
+++ b/src/main/java/org/cryptomator/common/vaults/Vault.java
@@ -23,7 +23,6 @@ import org.cryptomator.cryptofs.event.FilesystemEvent;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
-import org.cryptomator.event.VaultEvent;
import org.cryptomator.integrations.mount.MountFailedException;
import org.cryptomator.integrations.mount.Mountpoint;
import org.cryptomator.integrations.mount.UnmountFailedException;
@@ -35,7 +34,6 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
-import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@@ -75,6 +73,7 @@ public class Vault {
private final BooleanBinding missing;
private final BooleanBinding needsMigration;
private final BooleanBinding unknownError;
+ private final BooleanBinding missingVaultConfig;
private final ObjectBinding mountPoint;
private final Mounter mounter;
private final Settings settings;
@@ -103,6 +102,7 @@ public class Vault {
this.processing = Bindings.createBooleanBinding(this::isProcessing, state);
this.unlocked = Bindings.createBooleanBinding(this::isUnlocked, state);
this.missing = Bindings.createBooleanBinding(this::isMissing, state);
+ this.missingVaultConfig = Bindings.createBooleanBinding(this::isMissingVaultConfig, state);
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
@@ -337,6 +337,14 @@ public class Vault {
return state.get() == VaultState.Value.ERROR;
}
+ public BooleanBinding missingVaultConfigProperty() {
+ return missingVaultConfig;
+ }
+
+ public boolean isMissingVaultConfig() {
+ return state.get() == VaultState.Value.VAULT_CONFIG_MISSING || state.get() == VaultState.Value.ALL_MISSING;
+ }
+
public ReadOnlyStringProperty displayNameProperty() {
return vaultSettings.displayName;
}
diff --git a/src/main/java/org/cryptomator/common/vaults/VaultConfigCache.java b/src/main/java/org/cryptomator/common/vaults/VaultConfigCache.java
index b879b1f81..4a95fe50b 100644
--- a/src/main/java/org/cryptomator/common/vaults/VaultConfigCache.java
+++ b/src/main/java/org/cryptomator/common/vaults/VaultConfigCache.java
@@ -20,7 +20,7 @@ public class VaultConfigCache {
private final VaultSettings settings;
private final AtomicReference config;
- VaultConfigCache(VaultSettings settings) {
+ public VaultConfigCache(VaultSettings settings) {
this.settings = settings;
this.config = new AtomicReference<>(null);
}
diff --git a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
index ce1b2433c..e73075d0d 100644
--- a/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
+++ b/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
@@ -9,6 +9,7 @@
package org.cryptomator.common.vaults;
import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.recovery.BackupRestorer;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
@@ -34,9 +35,7 @@ import java.util.ResourceBundle;
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
-import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
-import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
-import static org.cryptomator.common.vaults.VaultState.Value.NEEDS_MIGRATION;
+import static org.cryptomator.common.vaults.VaultState.Value.*;
@Singleton
public class VaultListManager {
@@ -67,6 +66,12 @@ public class VaultListManager {
autoLocker.init();
}
+ public boolean isAlreadyAdded(Path vaultPath) {
+ assert vaultPath.isAbsolute();
+ assert vaultPath.normalize().equals(vaultPath);
+ return vaultList.stream().anyMatch(v -> vaultPath.equals(v.getPath()));
+ }
+
public Vault add(Path pathToVault) throws IOException {
Path normalizedPathToVault = pathToVault.normalize().toAbsolutePath();
if (CryptoFileSystemProvider.checkDirStructureForVault(normalizedPathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) == DirStructure.UNRELATED) {
@@ -114,59 +119,122 @@ public class VaultListManager {
.findAny();
}
+ public void addVault(Vault vault) {
+ Path path = vault.getPath().normalize().toAbsolutePath();
+ if (!isAlreadyAdded(path)) {
+ vaultList.add(vault);
+ }
+ }
+
private Vault create(VaultSettings vaultSettings) {
var wrapper = new VaultConfigCache(vaultSettings);
try {
var vaultState = determineVaultState(vaultSettings.path.get());
- if (vaultState == LOCKED) { //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
- wrapper.reloadConfig();
- if (Objects.isNull(vaultSettings.lastKnownKeyLoader.get())) {
- var keyIdScheme = wrapper.get().getKeyId().getScheme();
- vaultSettings.lastKnownKeyLoader.set(keyIdScheme);
- }
- } else if (vaultState == NEEDS_MIGRATION) {
- vaultSettings.lastKnownKeyLoader.set(MasterkeyFileLoadingStrategy.SCHEME);
- }
+ initializeLastKnownKeyLoaderIfPossible(vaultSettings, vaultState, wrapper);
+
return vaultComponentFactory.create(vaultSettings, wrapper, vaultState, null).vault();
} catch (IOException e) {
- LOG.warn("Failed to determine vault state for " + vaultSettings.path.get(), e);
+ LOG.warn("Failed to determine vault state for {}", vaultSettings.path.get(), e);
return vaultComponentFactory.create(vaultSettings, wrapper, ERROR, e).vault();
}
}
+ private void initializeLastKnownKeyLoaderIfPossible(VaultSettings vaultSettings, VaultState.Value vaultState, VaultConfigCache wrapper) throws IOException {
+ if (vaultSettings.lastKnownKeyLoader.get() != null) {
+ return;
+ }
+
+ switch (vaultState) {
+ case LOCKED -> {
+ wrapper.reloadConfig();
+ vaultSettings.lastKnownKeyLoader.set(wrapper.get().getKeyId().getScheme());
+ }
+ case NEEDS_MIGRATION -> {
+ //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
+ vaultSettings.lastKnownKeyLoader.set(MasterkeyFileLoadingStrategy.SCHEME);
+ }
+ case VAULT_CONFIG_MISSING -> {
+ //Nothing to do here, since there is no config to read
+ }
+ case MISSING, ALL_MISSING, ERROR, PROCESSING -> {
+ // no config available or not safe to load
+ }
+ default -> {
+ if (Files.exists(vaultSettings.path.get().resolve(VAULTCONFIG_FILENAME))) {
+ try {
+ wrapper.reloadConfig();
+ vaultSettings.lastKnownKeyLoader.set(wrapper.get().getKeyId().getScheme());
+ } catch (IOException e) {
+ LOG.debug("Unable to load config for {}", vaultSettings.path.get(), e);
+ }
+ }
+ }
+ }
+ }
+
public static VaultState.Value redetermineVaultState(Vault vault) {
VaultState state = vault.stateProperty();
- VaultState.Value previousState = state.getValue();
- return switch (previousState) {
- case LOCKED, NEEDS_MIGRATION, MISSING -> {
- try {
- var determinedState = determineVaultState(vault.getPath());
- if (determinedState == LOCKED) {
- vault.getVaultConfigCache().reloadConfig();
- }
- state.set(determinedState);
- yield determinedState;
- } catch (IOException e) {
- LOG.warn("Failed to determine vault state for " + vault.getPath(), e);
- state.set(ERROR);
- vault.setLastKnownException(e);
- yield ERROR;
- }
+ VaultState.Value previous = state.getValue();
+
+ if (previous.equals(UNLOCKED) || previous.equals(PROCESSING)) {
+ return previous;
+ }
+
+ try {
+ VaultState.Value determined = determineVaultState(vault.getPath());
+
+ if (determined == LOCKED) {
+ vault.getVaultConfigCache().reloadConfig();
}
- case ERROR, UNLOCKED, PROCESSING -> previousState;
- };
+
+ state.set(determined);
+ return determined;
+ } catch (IOException e) {
+ LOG.warn("Failed to (re)determine vault state for {}", vault.getPath(), e);
+ vault.setLastKnownException(e);
+ state.set(ERROR);
+ return ERROR;
+ }
}
- private static VaultState.Value determineVaultState(Path pathToVault) throws IOException {
+ public static VaultState.Value determineVaultState(Path pathToVault) throws IOException {
if (!Files.exists(pathToVault)) {
- return VaultState.Value.MISSING;
+ return MISSING;
}
+
+ VaultState.Value structureResult = checkDirStructure(pathToVault);
+
+ if (structureResult == LOCKED || structureResult == NEEDS_MIGRATION) {
+ return structureResult;
+ }
+
+ Path pathToVaultConfig = pathToVault.resolve(VAULTCONFIG_FILENAME);
+ Path pathToMasterkey = pathToVault.resolve(MASTERKEY_FILENAME);
+
+ if (!Files.exists(pathToVaultConfig)) {
+ BackupRestorer.restoreIfBackupPresent(pathToVault, VAULTCONFIG_FILENAME);
+ }
+ if (!Files.exists(pathToMasterkey)) {
+ BackupRestorer.restoreIfBackupPresent(pathToVault, MASTERKEY_FILENAME);
+ }
+
+ boolean hasConfig = Files.exists(pathToVaultConfig);
+
+ if (!hasConfig && !Files.exists(pathToMasterkey)) {
+ return ALL_MISSING;
+ }
+ if (!hasConfig) {
+ return VAULT_CONFIG_MISSING;
+ }
+
+ return checkDirStructure(pathToVault);
+ }
+
+ private static VaultState.Value checkDirStructure(Path pathToVault) throws IOException {
return switch (CryptoFileSystemProvider.checkDirStructureForVault(pathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME)) {
- case VAULT -> VaultState.Value.LOCKED;
- case UNRELATED -> VaultState.Value.MISSING;
- case MAYBE_LEGACY -> Migrators.get().needsMigration(pathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) ? //
- VaultState.Value.NEEDS_MIGRATION //
- : VaultState.Value.MISSING;
+ case VAULT -> LOCKED;
+ case UNRELATED -> MISSING;
+ case MAYBE_LEGACY -> Migrators.get().needsMigration(pathToVault, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) ? NEEDS_MIGRATION : MISSING;
};
}
diff --git a/src/main/java/org/cryptomator/common/vaults/VaultState.java b/src/main/java/org/cryptomator/common/vaults/VaultState.java
index ff09c8b82..f8b9b412a 100644
--- a/src/main/java/org/cryptomator/common/vaults/VaultState.java
+++ b/src/main/java/org/cryptomator/common/vaults/VaultState.java
@@ -25,6 +25,16 @@ public class VaultState extends ObservableValueBase implements
*/
MISSING,
+ /**
+ * No vault config found at the provided path
+ */
+ VAULT_CONFIG_MISSING,
+
+ /**
+ * No vault config and masterkey found at the provided path
+ */
+ ALL_MISSING,
+
/**
* Vault requires migration to a newer vault format
*/
diff --git a/src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java b/src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java
index 202e2f9cb..4889a32f1 100644
--- a/src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java
+++ b/src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java
@@ -20,7 +20,6 @@ import java.util.ResourceBundle;
public class PasswordStrengthUtil {
private static final int PW_TRUNC_LEN = 100; // truncate very long passwords, since zxcvbn memory and runtime depends vastly on the length
- private static final String RESSOURCE_PREFIX = "passwordStrength.messageLabel.";
private static final List SANITIZED_INPUTS = List.of("cryptomator");
private final ResourceBundle resourceBundle;
@@ -48,13 +47,15 @@ public class PasswordStrengthUtil {
}
public String getStrengthDescription(Number score) {
- if (score.intValue() == -1) {
- return String.format(resourceBundle.getString(RESSOURCE_PREFIX + "tooShort"), minPwLength);
- } else if (resourceBundle.containsKey(RESSOURCE_PREFIX + score.intValue())) {
- return resourceBundle.getString(RESSOURCE_PREFIX + score.intValue());
- } else {
- return "";
- }
+ return switch (score.intValue()) {
+ case -1 -> String.format(resourceBundle.getString("passwordStrength.messageLabel.tooShort"), minPwLength);
+ case 0 -> resourceBundle.getString("passwordStrength.messageLabel.0");
+ case 1 -> resourceBundle.getString("passwordStrength.messageLabel.1");
+ case 2 -> resourceBundle.getString("passwordStrength.messageLabel.2");
+ case 3 -> resourceBundle.getString("passwordStrength.messageLabel.3");
+ case 4 -> resourceBundle.getString("passwordStrength.messageLabel.4");
+ default -> "";
+ };
}
}
diff --git a/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/src/main/java/org/cryptomator/ui/common/FxmlFile.java
index ce8c65a37..68607808d 100644
--- a/src/main/java/org/cryptomator/ui/common/FxmlFile.java
+++ b/src/main/java/org/cryptomator/ui/common/FxmlFile.java
@@ -42,9 +42,10 @@ public enum FxmlFile {
QUIT("/fxml/quit.fxml"), //
QUIT_FORCED("/fxml/quit_forced.fxml"), //
RECOVERYKEY_CREATE("/fxml/recoverykey_create.fxml"), //
+ RECOVERYKEY_EXPERT_SETTINGS("/fxml/recoverykey_expert_settings.fxml"), //
+ RECOVERYKEY_ONBOARDING("/fxml/recoverykey_onboarding.fxml"), //
RECOVERYKEY_RECOVER("/fxml/recoverykey_recover.fxml"), //
RECOVERYKEY_RESET_PASSWORD("/fxml/recoverykey_reset_password.fxml"), //
- RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), //
RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
SHARE_VAULT("/fxml/share_vault.fxml"), //
SIMPLE_DIALOG("/fxml/simple_dialog.fxml"), //
diff --git a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java
index f70242d2b..d010ede43 100644
--- a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java
+++ b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java
@@ -4,8 +4,10 @@ import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.VaultConfig;
+import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.ui.changepassword.NewPasswordController;
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
import org.cryptomator.ui.common.DefaultSceneFactory;
@@ -20,6 +22,7 @@ import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController;
import javax.inject.Named;
import javax.inject.Provider;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
@@ -119,8 +122,8 @@ abstract class ConvertVaultModule {
@Provides
@IntoMap
@FxControllerKey(RecoveryKeyValidateController.class)
- static FxController bindRecoveryKeyValidateController(@ConvertVaultWindow Vault vault, @ConvertVaultWindow VaultConfig.UnverifiedVaultConfig vaultConfig, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
- return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory);
+ static FxController provideRecoveryKeyValidateController(@ConvertVaultWindow Vault vault, @ConvertVaultWindow VaultConfig.UnverifiedVaultConfig vaultConfig, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, MasterkeyFileAccess masterkeyFileAccess) {
+ return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory, masterkeyFileAccess, new SimpleObjectProperty<>(RecoveryActionType.CONVERT_VAULT), new SimpleObjectProperty<>(null));
}
}
diff --git a/src/main/java/org/cryptomator/ui/decryptname/DecryptFileNamesViewController.java b/src/main/java/org/cryptomator/ui/decryptname/DecryptFileNamesViewController.java
index 453762f55..5450e1d48 100644
--- a/src/main/java/org/cryptomator/ui/decryptname/DecryptFileNamesViewController.java
+++ b/src/main/java/org/cryptomator/ui/decryptname/DecryptFileNamesViewController.java
@@ -194,7 +194,7 @@ public class DecryptFileNamesViewController implements FxController {
}
}
- //obvservable getter
+ //observable getter
public ObservableValue dropZoneTextProperty() {
return dropZoneText;
diff --git a/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java b/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java
index 837bea012..07ce3c4f6 100644
--- a/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java
+++ b/src/main/java/org/cryptomator/ui/dialogs/Dialogs.java
@@ -2,6 +2,7 @@ package org.cryptomator.ui.dialogs;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
@@ -19,17 +20,21 @@ public class Dialogs {
private final ResourceBundle resourceBundle;
private final StageFactory stageFactory;
+ private final DefaultSceneFactory sceneFactory;
+
+ private static final String BUTTON_KEY_CLOSE = "generic.button.close";
@Inject
- public Dialogs(ResourceBundle resourceBundle, StageFactory stageFactory) {
+ public Dialogs(ResourceBundle resourceBundle, StageFactory stageFactory, DefaultSceneFactory sceneFactory) {
this.resourceBundle = resourceBundle;
this.stageFactory = stageFactory;
+ this.sceneFactory = sceneFactory;
}
private static final Logger LOG = LoggerFactory.getLogger(Dialogs.class);
private SimpleDialog.Builder createDialogBuilder() {
- return new SimpleDialog.Builder(resourceBundle, stageFactory);
+ return new SimpleDialog.Builder(resourceBundle, stageFactory, sceneFactory);
}
public SimpleDialog.Builder prepareRemoveVaultDialog(Stage window, Vault vault, ObservableList vaults) {
@@ -47,6 +52,43 @@ public class Dialogs {
});
}
+ public SimpleDialog.Builder prepareContactHubVaultOwner(Stage window) {
+ return createDialogBuilder().setOwner(window) //
+ .setTitleKey("contactHubVaultOwner.title") //
+ .setMessageKey("contactHubVaultOwner.message") //
+ .setDescriptionKey("contactHubVaultOwner.description") //
+ .setIcon(FontAwesome5Icon.EXCLAMATION)//
+ .setOkButtonKey(BUTTON_KEY_CLOSE);
+ }
+
+ public SimpleDialog.Builder prepareRecoveryVaultAdded(Stage window, String displayName) {
+ return createDialogBuilder().setOwner(window) //
+ .setTitleKey("recover.existing.title") //
+ .setMessageKey("recover.existing.message") //
+ .setDescriptionKey("recover.existing.description", displayName) //
+ .setIcon(FontAwesome5Icon.CHECK)//
+ .setOkButtonKey(BUTTON_KEY_CLOSE);
+ }
+ public SimpleDialog.Builder prepareRecoveryVaultAlreadyExists(Stage window, String displayName) {
+ return createDialogBuilder().setOwner(window) //
+ .setTitleKey("recover.alreadyExists.title") //
+ .setMessageKey("recover.alreadyExists.message") //
+ .setDescriptionKey("recover.alreadyExists.description", displayName) //
+ .setIcon(FontAwesome5Icon.EXCLAMATION)//
+ .setOkButtonKey(BUTTON_KEY_CLOSE);
+ }
+
+ public SimpleDialog.Builder prepareRecoverPasswordSuccess(Stage window) {
+ return createDialogBuilder()
+ .setOwner(window) //
+ .setTitleKey("recoveryKey.recover.title") //
+ .setMessageKey("recoveryKey.recover.resetSuccess.message") //
+ .setDescriptionKey("recoveryKey.recover.resetSuccess.description") //
+ .setIcon(FontAwesome5Icon.CHECK)
+ .setOkAction(Stage::close)
+ .setOkButtonKey(BUTTON_KEY_CLOSE);
+ }
+
public SimpleDialog.Builder prepareRemoveCertDialog(Stage window, Settings settings) {
return createDialogBuilder() //
.setOwner(window) //
@@ -69,7 +111,7 @@ public class Dialogs {
.setMessageKey("dokanySupportEnd.message") //
.setDescriptionKey("dokanySupportEnd.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION) //
- .setOkButtonKey("generic.button.close") //
+ .setOkButtonKey(BUTTON_KEY_CLOSE) //
.setCancelButtonKey("dokanySupportEnd.preferencesBtn") //
.setOkAction(Stage::close) //
.setCancelAction(cancelAction);
@@ -83,8 +125,20 @@ public class Dialogs {
.setDescriptionKey("retryIfReadonly.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION) //
.setOkButtonKey("retryIfReadonly.retry") //
- .setCancelButtonKey("generic.button.close") //
+ .setCancelButtonKey(BUTTON_KEY_CLOSE) //
.setOkAction(okAction) //
.setCancelAction(Stage::close);
}
+
+ public SimpleDialog.Builder prepareNoDDirectorySelectedDialog(Stage window) {
+ return createDialogBuilder() //
+ .setOwner(window) //
+ .setTitleKey("recover.invalidSelection.title") //
+ .setMessageKey("recover.invalidSelection.message") //
+ .setDescriptionKey("recover.invalidSelection.description") //
+ .setIcon(FontAwesome5Icon.EXCLAMATION) //
+ .setOkButtonKey("generic.button.change") //
+ .setOkAction(Stage::close);
+ }
+
}
diff --git a/src/main/java/org/cryptomator/ui/dialogs/SimpleDialog.java b/src/main/java/org/cryptomator/ui/dialogs/SimpleDialog.java
index 08f77849e..2c447300d 100644
--- a/src/main/java/org/cryptomator/ui/dialogs/SimpleDialog.java
+++ b/src/main/java/org/cryptomator/ui/dialogs/SimpleDialog.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.dialogs;
+import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.StageFactory;
@@ -30,15 +31,15 @@ public class SimpleDialog {
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController( //
new SimpleDialogController(resolveText(builder.messageKey, null), //
- resolveText(builder.descriptionKey, null), //
+ resolveText(builder.descriptionKey, builder.descriptionArgs), //
builder.icon, //
resolveText(builder.okButtonKey, null), //
builder.cancelButtonKey != null ? resolveText(builder.cancelButtonKey, null) : null, //
() -> builder.okAction.accept(dialogStage), //
() -> builder.cancelAction.accept(dialogStage)), //
- Scene::new, builder.resourceBundle);
+ builder.sceneFactory, builder.resourceBundle);
- dialogStage.setScene(new Scene(loaderFactory.load(FxmlFile.SIMPLE_DIALOG.getRessourcePathString()).getRoot()));
+ dialogStage.setScene(loaderFactory.createScene(FxmlFile.SIMPLE_DIALOG));
}
public void showAndWait() {
@@ -62,19 +63,22 @@ public class SimpleDialog {
private Stage owner;
private final ResourceBundle resourceBundle;
private final StageFactory stageFactory;
+ private final DefaultSceneFactory sceneFactory;
private String titleKey;
private String[] titleArgs;
private String messageKey;
private String descriptionKey;
+ private String[] descriptionArgs;
private String okButtonKey;
private String cancelButtonKey;
private FontAwesome5Icon icon;
private Consumer okAction = Stage::close;
private Consumer cancelAction = Stage::close;
- public Builder(ResourceBundle resourceBundle, StageFactory stageFactory) {
+ public Builder(ResourceBundle resourceBundle, StageFactory stageFactory, DefaultSceneFactory sceneFactory) {
this.resourceBundle = resourceBundle;
this.stageFactory = stageFactory;
+ this.sceneFactory = sceneFactory;
}
public Builder setOwner(Stage owner) {
@@ -93,8 +97,9 @@ public class SimpleDialog {
return this;
}
- public Builder setDescriptionKey(String descriptionKey) {
+ public Builder setDescriptionKey(String descriptionKey, String... args) {
this.descriptionKey = descriptionKey;
+ this.descriptionArgs = args;
return this;
}
diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java
index 8eb221883..74abac546 100644
--- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java
+++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java
@@ -15,15 +15,13 @@ import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
import org.cryptomator.ui.preferences.PreferencesComponent;
import org.cryptomator.ui.quit.QuitComponent;
+import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.cryptomator.ui.sharevault.ShareVaultComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.cryptomator.ui.unlock.UnlockComponent;
import org.cryptomator.ui.updatereminder.UpdateReminderComponent;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
-import javax.inject.Named;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.image.Image;
import java.io.IOException;
import java.io.InputStream;
@@ -40,7 +38,8 @@ import java.io.InputStream;
HealthCheckComponent.class, //
UpdateReminderComponent.class, //
ShareVaultComponent.class, //
- EventViewComponent.class})
+ EventViewComponent.class, //
+ RecoveryKeyComponent.class})
abstract class FxApplicationModule {
private static Image createImageFromResource(String resourceName) throws IOException {
diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationTerminator.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationTerminator.java
index 89258dc6c..91ff918e3 100644
--- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationTerminator.java
+++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationTerminator.java
@@ -28,7 +28,7 @@ import static org.cryptomator.common.vaults.VaultState.Value.*;
@FxApplicationScoped
public class FxApplicationTerminator {
- private static final Set STATES_ALLOWING_TERMINATION = EnumSet.of(LOCKED, NEEDS_MIGRATION, MISSING, ERROR);
+ private static final Set STATES_ALLOWING_TERMINATION = EnumSet.of(LOCKED, NEEDS_MIGRATION, MISSING, ERROR, VAULT_CONFIG_MISSING, ALL_MISSING);
private static final Set STATES_PREVENT_TERMINATION = EnumSet.of(PROCESSING);
private static final Logger LOG = LoggerFactory.getLogger(FxApplicationTerminator.class);
diff --git a/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/ChooseMasterkeyFileController.java b/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/ChooseMasterkeyFileController.java
index 9b2231921..4e1c663e9 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/ChooseMasterkeyFileController.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/ChooseMasterkeyFileController.java
@@ -1,14 +1,18 @@
package org.cryptomator.ui.keyloading.masterkeyfile;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
-import javafx.beans.binding.StringBinding;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
@@ -27,17 +31,41 @@ public class ChooseMasterkeyFileController implements FxController {
private final Stage window;
private final Vault vault;
private final CompletableFuture result;
+ private final RecoveryKeyComponent.Factory recoveryKeyWindow;
private final ResourceBundle resourceBundle;
+ @FXML
+ private CheckBox restoreInsteadCheckBox;
+ @FXML
+ private Button forwardButton;
+
@Inject
- public ChooseMasterkeyFileController(@KeyLoading Stage window, @KeyLoading Vault vault, CompletableFuture result, ResourceBundle resourceBundle) {
+ public ChooseMasterkeyFileController(@KeyLoading Stage window, //
+ @KeyLoading Vault vault, //
+ CompletableFuture result, //
+ RecoveryKeyComponent.Factory recoveryKeyWindow, //
+ ResourceBundle resourceBundle) {
this.window = window;
this.vault = vault;
this.result = result;
+ this.recoveryKeyWindow = recoveryKeyWindow;
this.resourceBundle = resourceBundle;
this.window.setOnHiding(this::windowClosed);
}
+ @FXML
+ private void initialize() {
+ restoreInsteadCheckBox.selectedProperty().addListener((_, _, newVal) -> {
+ if (newVal) {
+ forwardButton.setText(resourceBundle.getString("addvaultwizard.existing.restore"));
+ forwardButton.setOnAction(_ -> restoreMasterkey());
+ } else {
+ forwardButton.setText(resourceBundle.getString("generic.button.choose"));
+ forwardButton.setOnAction(_ -> proceed());
+ }
+ });
+ }
+
@FXML
public void cancel() {
window.close();
@@ -47,6 +75,13 @@ public class ChooseMasterkeyFileController implements FxController {
result.cancel(true);
}
+ @FXML
+ void restoreMasterkey() {
+ Stage ownerStage = (Stage) window.getOwner();
+ window.close();
+ recoveryKeyWindow.create(vault, ownerStage, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_MASTERKEY)).showOnboardingDialogWindow();
+ }
+
@FXML
public void proceed() {
LOG.trace("proceed()");
@@ -62,7 +97,7 @@ public class ChooseMasterkeyFileController implements FxController {
//--- Setter & Getter ---
- public String getDisplayName(){
+ public String getDisplayName() {
return vault.getDisplayName();
}
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java
index fa1b441d9..a186fbe71 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java
@@ -18,6 +18,7 @@ import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.fxapp.FxApplicationTerminator;
import org.cryptomator.ui.fxapp.PrimaryStage;
import org.cryptomator.ui.migration.MigrationComponent;
+import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.cryptomator.ui.stats.VaultStatisticsComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
@@ -32,7 +33,7 @@ import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
-@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class, ErrorComponent.class})
+@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class, ErrorComponent.class, RecoveryKeyComponent.class})
abstract class MainWindowModule {
@Provides
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
index 7e309fdaf..be4f7f78c 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java
@@ -52,7 +52,7 @@ public class VaultDetailController implements FxController {
case LOCKED -> FontAwesome5Icon.LOCK;
case PROCESSING -> FontAwesome5Icon.SPINNER;
case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
- case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ case NEEDS_MIGRATION, MISSING, VAULT_CONFIG_MISSING, ALL_MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
};
} else {
return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java
index 6f57a0d17..85e71937b 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailMissingVaultController.java
@@ -1,20 +1,26 @@
package org.cryptomator.ui.mainwindow;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.dialogs.Dialogs;
+import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
+import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
+import java.nio.file.Files;
import java.util.ResourceBundle;
import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB;
+import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
@MainWindowScoped
public class VaultDetailMissingVaultController implements FxController {
@@ -23,6 +29,7 @@ public class VaultDetailMissingVaultController implements FxController {
private final ObservableList vaults;
private final ResourceBundle resourceBundle;
private final Stage window;
+ private final RecoveryKeyComponent.Factory recoveryKeyWindow;
private final Dialogs dialogs;
@Inject
@@ -30,11 +37,13 @@ public class VaultDetailMissingVaultController implements FxController {
ObservableList vaults, //
ResourceBundle resourceBundle, //
@MainWindow Stage window, //
- Dialogs dialogs) {
+ Dialogs dialogs, //
+ RecoveryKeyComponent.Factory recoveryKeyWindow) {
this.vault = vault;
this.vaults = vaults;
this.resourceBundle = resourceBundle;
this.window = window;
+ this.recoveryKeyWindow = recoveryKeyWindow;
this.dialogs = dialogs;
}
@@ -48,6 +57,19 @@ public class VaultDetailMissingVaultController implements FxController {
dialogs.prepareRemoveVaultDialog(window, vault.get(), vaults).build().showAndWait();
}
+ @FXML
+ void restoreVaultConfig() {
+ if(KeyLoadingStrategy.isHubVault(vault.get().getVaultSettings().lastKnownKeyLoader.get())){
+ dialogs.prepareContactHubVaultOwner(window).build().showAndWait();
+ }
+ else if(Files.exists(vault.get().getPath().resolve(MASTERKEY_FILENAME))){
+ recoveryKeyWindow.create(vault.get(), window, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)).showOnboardingDialogWindow();
+ }
+ else {
+ recoveryKeyWindow.create(vault.get(), window, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)).showOnboardingDialogWindow();
+ }
+ }
+
@FXML
void changeLocation() {
// copied from ChooseExistingVaultController class
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
index 75ce21dfe..9324c8c7b 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java
@@ -55,7 +55,7 @@ public class VaultListCellController implements FxController {
case LOCKED -> FontAwesome5Icon.LOCK;
case PROCESSING -> FontAwesome5Icon.SPINNER;
case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN;
- case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
+ case NEEDS_MIGRATION, MISSING, VAULT_CONFIG_MISSING, ALL_MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
};
} else {
return FontAwesome5Icon.EXCLAMATION_TRIANGLE;
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java
index 5e1fb8c35..db667f111 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java
@@ -20,11 +20,13 @@ import javafx.stage.Stage;
import java.util.EnumSet;
import java.util.Objects;
+import static org.cryptomator.common.vaults.VaultState.Value.ALL_MISSING;
import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
import static org.cryptomator.common.vaults.VaultState.Value.MISSING;
import static org.cryptomator.common.vaults.VaultState.Value.NEEDS_MIGRATION;
import static org.cryptomator.common.vaults.VaultState.Value.UNLOCKED;
+import static org.cryptomator.common.vaults.VaultState.Value.VAULT_CONFIG_MISSING;
@MainWindowScoped
public class VaultListContextMenuController implements FxController {
@@ -63,7 +65,7 @@ public class VaultListContextMenuController implements FxController {
this.selectedVaultState = selectedVault.flatMap(Vault::stateProperty).orElse(null);
this.selectedVaultPassphraseStored = selectedVault.map(this::isPasswordStored).orElse(false);
- this.selectedVaultRemovable = selectedVaultState.map(EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION)::contains).orElse(false);
+ this.selectedVaultRemovable = selectedVaultState.map(EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION, ALL_MISSING, VAULT_CONFIG_MISSING)::contains).orElse(false);
this.selectedVaultUnlockable = selectedVaultState.map(LOCKED::equals).orElse(false);
this.selectedVaultLockable = selectedVaultState.map(UNLOCKED::equals).orElse(false);
}
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
index a457ade3f..f25528498 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
@@ -1,11 +1,16 @@
package org.cryptomator.ui.mainwindow;
import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.recovery.RecoveryActionType;
+import org.cryptomator.common.recovery.VaultPreparator;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.DirStructure;
+import org.cryptomator.cryptofs.common.Constants;
+import org.cryptomator.integrations.mount.MountService;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.VaultService;
@@ -13,6 +18,7 @@ import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxFSEventList;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
+import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,6 +28,7 @@ import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
@@ -37,11 +44,14 @@ import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
+import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.EnumSet;
+import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.Set;
@@ -50,10 +60,12 @@ import java.util.stream.Collectors;
import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_EXT;
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
+import static org.cryptomator.common.vaults.VaultState.Value.ALL_MISSING;
import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
import static org.cryptomator.common.vaults.VaultState.Value.MISSING;
import static org.cryptomator.common.vaults.VaultState.Value.NEEDS_MIGRATION;
+import static org.cryptomator.common.vaults.VaultState.Value.VAULT_CONFIG_MISSING;
@MainWindowScoped
public class VaultListController implements FxController {
@@ -75,6 +87,10 @@ public class VaultListController implements FxController {
private final ObservableValue cellSize;
private final Dialogs dialogs;
+ private final VaultComponent.Factory vaultComponentFactory;
+ private final RecoveryKeyComponent.Factory recoveryKeyWindow;
+ private final List mountServices;
+
public ListView vaultList;
public StackPane root;
@FXML
@@ -94,6 +110,9 @@ public class VaultListController implements FxController {
FxApplicationWindows appWindows, //
Settings settings, //
Dialogs dialogs, //
+ RecoveryKeyComponent.Factory recoveryKeyWindow, //
+ VaultComponent.Factory vaultComponentFactory, //
+ List mountServices, //
FxFSEventList fxFSEventList) {
this.mainWindow = mainWindow;
this.vaults = vaults;
@@ -105,6 +124,9 @@ public class VaultListController implements FxController {
this.resourceBundle = resourceBundle;
this.appWindows = appWindows;
this.dialogs = dialogs;
+ this.recoveryKeyWindow = recoveryKeyWindow;
+ this.vaultComponentFactory = vaultComponentFactory;
+ this.mountServices = mountServices;
this.emptyVaultList = Bindings.isEmpty(vaults);
this.unreadEvents = fxFSEventList.unreadEventsProperty();
@@ -204,6 +226,26 @@ public class VaultListController implements FxController {
VaultListManager.redetermineVaultState(newValue);
}
+ private Optional chooseValidVaultDirectory() {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ File selectedDirectory;
+
+ do {
+ selectedDirectory = directoryChooser.showDialog(mainWindow);
+ if (selectedDirectory == null) {
+ return Optional.empty();
+ }
+
+ Path selectedPath = selectedDirectory.toPath();
+ if (!Files.isDirectory(selectedPath.resolve(Constants.DATA_DIR_NAME))) {
+ dialogs.prepareNoDDirectorySelectedDialog(mainWindow).build().showAndWait();
+ selectedDirectory = null;
+ }
+ } while (selectedDirectory == null);
+
+ return Optional.of(selectedDirectory.toPath());
+ }
+
@FXML
public void didClickAddNewVault() {
addVaultWizard.build().showAddNewVaultWizard(resourceBundle);
@@ -214,9 +256,40 @@ public class VaultListController implements FxController {
addVaultWizard.build().showAddExistingVaultWizard(resourceBundle);
}
+ @FXML
+ public void didClickRecoverExistingVault() {
+ Optional selectedDirectory = chooseValidVaultDirectory();
+ if (selectedDirectory.isEmpty()) {
+ return;
+ }
+
+ Path path = selectedDirectory.get();
+ Optional matchingVaultListEntry = vaultListManager.get(path);
+ if (matchingVaultListEntry.isPresent()) {
+ dialogs.prepareRecoveryVaultAlreadyExists(mainWindow, matchingVaultListEntry.get().getDisplayName()) //
+ .setOkAction(Stage::close) //
+ .build().showAndWait();
+ return;
+ }
+
+ Vault preparedVault = VaultPreparator.prepareVault(path, vaultComponentFactory, mountServices, resourceBundle);
+ VaultListManager.redetermineVaultState(preparedVault);
+
+ switch (preparedVault.getState()) {
+ case VAULT_CONFIG_MISSING -> recoveryKeyWindow.create(preparedVault, mainWindow, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)).showOnboardingDialogWindow();
+ case ALL_MISSING -> recoveryKeyWindow.create(preparedVault, mainWindow, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)).showOnboardingDialogWindow();
+ case LOCKED, NEEDS_MIGRATION -> {
+ vaultListManager.addVault(preparedVault);
+ dialogs.prepareRecoveryVaultAdded(mainWindow, preparedVault.getDisplayName()).setOkAction(Stage::close).build().showAndWait();
+ }
+ default -> LOG.warn("Unhandled vault state during recovery: {}", preparedVault.getState());
+ }
+
+ }
+
private void pressedShortcutToRemoveVault() {
final var vault = selectedVault.get();
- if (vault != null && EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION).contains(vault.getState())) {
+ if (vault != null && EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION, ALL_MISSING, VAULT_CONFIG_MISSING).contains(vault.getState())) {
dialogs.prepareRemoveVaultDialog(mainWindow, vault, vaults).build().showAndWait();
}
}
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java
index 3986fa01d..6bfe36a4f 100644
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java
@@ -3,11 +3,13 @@ package org.cryptomator.ui.recoverykey;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javax.inject.Named;
+import javafx.beans.property.ObjectProperty;
import javafx.scene.Scene;
import javafx.stage.Stage;
@@ -24,6 +26,9 @@ public interface RecoveryKeyComponent {
@FxmlScene(FxmlFile.RECOVERYKEY_RECOVER)
Lazy recoverScene();
+ @FxmlScene(FxmlFile.RECOVERYKEY_ONBOARDING)
+ Lazy recoverOnboardingScene();
+
default void showRecoveryKeyCreationWindow() {
Stage stage = window();
stage.setScene(creationScene().get());
@@ -38,11 +43,19 @@ public interface RecoveryKeyComponent {
stage.show();
}
+ default void showOnboardingDialogWindow() {
+ Stage stage = window();
+ stage.setScene(recoverOnboardingScene().get());
+ stage.sizeToScene();
+ stage.show();
+ }
@Subcomponent.Factory
interface Factory {
- RecoveryKeyComponent create(@BindsInstance @RecoveryKeyWindow Vault vault, @BindsInstance @Named("keyRecoveryOwner") Stage owner);
+ RecoveryKeyComponent create(@BindsInstance @RecoveryKeyWindow Vault vault, //
+ @BindsInstance @Named("keyRecoveryOwner") Stage owner, //
+ @BindsInstance @Named("recoverType") ObjectProperty recoverType);
}
}
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyCreationController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyCreationController.java
index 77f191015..456de11f4 100644
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyCreationController.java
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyCreationController.java
@@ -1,28 +1,45 @@
package org.cryptomator.ui.recoverykey;
import dagger.Lazy;
+import org.cryptomator.common.recovery.CryptoFsInitializer;
+import org.cryptomator.common.recovery.MasterkeyService;
+import org.cryptomator.common.recovery.RecoveryActionType;
+import org.cryptomator.common.recovery.RecoveryDirectory;
import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
+import org.cryptomator.cryptolib.api.Masterkey;
+import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
+import org.cryptomator.ui.controls.FormattedLabel;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
+import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
+import javax.inject.Named;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.Scene;
+import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
+import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
+import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
+
@RecoveryKeyScoped
public class RecoveryKeyCreationController implements FxController {
@@ -30,23 +47,71 @@ public class RecoveryKeyCreationController implements FxController {
private final Stage window;
private final Lazy successScene;
+ private final Lazy recoverykeyExpertSettingsScene;
+ private final MasterkeyFileAccess masterkeyFileAccess;
private final Vault vault;
private final ExecutorService executor;
private final RecoveryKeyFactory recoveryKeyFactory;
private final StringProperty recoveryKeyProperty;
private final FxApplicationWindows appWindows;
public NiceSecurePasswordField passwordField;
+ private final IntegerProperty shorteningThreshold;
+ private final ObjectProperty recoverType;
+ private final ResourceBundle resourceBundle;
+ public FormattedLabel descriptionLabel;
+ public Button cancelButton;
+ public Button nextButton;
+ private final VaultListManager vaultListManager;
+ private final Dialogs dialogs;
@Inject
- public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS) Lazy successScene, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, FxApplicationWindows appWindows, ResourceBundle resourceBundle) {
+ public RecoveryKeyCreationController(FxApplicationWindows appWindows, //
+ @RecoveryKeyWindow Stage window, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS) Lazy successScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_EXPERT_SETTINGS) Lazy recoverykeyExpertSettingsScene, //
+ @RecoveryKeyWindow Vault vault, //
+ RecoveryKeyFactory recoveryKeyFactory, //
+ MasterkeyFileAccess masterkeyFileAccess, //
+ ExecutorService executor, //
+ @RecoveryKeyWindow StringProperty recoveryKey, //
+ @Named("shorteningThreshold") IntegerProperty shorteningThreshold, //
+ @Named("recoverType") ObjectProperty recoverType, //
+ VaultListManager vaultListManager, //
+ ResourceBundle resourceBundle, //
+ Dialogs dialogs) {
this.window = window;
- window.setTitle(resourceBundle.getString("recoveryKey.display.title"));
this.successScene = successScene;
+ this.recoverykeyExpertSettingsScene = recoverykeyExpertSettingsScene;
this.vault = vault;
this.executor = executor;
this.recoveryKeyFactory = recoveryKeyFactory;
this.recoveryKeyProperty = recoveryKey;
this.appWindows = appWindows;
+ this.recoverType = recoverType;
+ this.resourceBundle = resourceBundle;
+ this.masterkeyFileAccess = masterkeyFileAccess;
+ this.shorteningThreshold = shorteningThreshold;
+ this.vaultListManager = vaultListManager;
+ this.dialogs = dialogs;
+ }
+
+ @FXML
+ public void initialize() {
+ if (recoverType.get() == RecoveryActionType.SHOW_KEY) {
+ window.setTitle(resourceBundle.getString("recoveryKey.display.title"));
+ } else if (recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG) {
+ window.setTitle(resourceBundle.getString("recover.recoverVaultConfig.title"));
+ descriptionLabel.formatProperty().set(resourceBundle.getString("recoveryKey.recover.description"));
+ cancelButton.setOnAction((_) -> back());
+ cancelButton.setText(resourceBundle.getString("generic.button.back"));
+ nextButton.setOnAction((_) -> restoreWithPassword());
+ }
+ }
+
+ @FXML
+ public void back() {
+ window.setScene(recoverykeyExpertSettingsScene.get());
+ window.centerOnScreen();
}
@FXML
@@ -71,6 +136,42 @@ public class RecoveryKeyCreationController implements FxController {
executor.submit(task);
}
+ @FXML
+ public void restoreWithPassword() {
+
+ try (RecoveryDirectory recoveryDirectory = RecoveryDirectory.create(vault.getPath())) {
+ Path recoveryPath = recoveryDirectory.getRecoveryPath();
+
+ Path masterkeyFilePath = vault.getPath().resolve(MASTERKEY_FILENAME);
+
+ try (Masterkey masterkey = MasterkeyService.load(masterkeyFileAccess, masterkeyFilePath, passwordField.getCharacters())) {
+ var combo = MasterkeyService.detect(masterkey, vault.getPath())
+ .orElseThrow(() -> new IllegalStateException("Could not detect combo for vault path: " + vault.getPath()));
+
+ CryptoFsInitializer.init(recoveryPath, masterkey, shorteningThreshold.get(), combo);
+ }
+
+ recoveryDirectory.moveRecoveredFile(VAULTCONFIG_FILENAME);
+
+ if (!vaultListManager.isAlreadyAdded(vault.getPath())) {
+ vaultListManager.add(vault.getPath());
+ }
+ window.close();
+ dialogs.prepareRecoverPasswordSuccess((Stage)window.getOwner()) //
+ .setTitleKey("recover.recoverVaultConfig.title") //
+ .setMessageKey("recoveryKey.recover.resetVaultConfigSuccess.message") //
+ .setDescriptionKey("recoveryKey.recover.resetMasterkeyFileSuccess.description")
+ .build().showAndWait();
+
+ } catch (InvalidPassphraseException e) {
+ LOG.info("Password invalid", e);
+ Animations.createShakeWindowAnimation(window).play();
+ } catch (IOException | CryptoException | IllegalStateException e) {
+ LOG.error("Recovery process failed", e);
+ appWindows.showErrorWindow(e, window, null);
+ }
+ }
+
@FXML
public void close() {
window.close();
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyExpertSettingsController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyExpertSettingsController.java
new file mode 100644
index 000000000..5e72b8969
--- /dev/null
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyExpertSettingsController.java
@@ -0,0 +1,123 @@
+package org.cryptomator.ui.recoverykey;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javafx.application.Application;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.BooleanBinding;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.fxml.FXML;
+import javafx.scene.Scene;
+import javafx.scene.control.CheckBox;
+import javafx.stage.Stage;
+
+import dagger.Lazy;
+import org.cryptomator.common.recovery.RecoveryActionType;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultState;
+import org.cryptomator.ui.addvaultwizard.CreateNewVaultExpertSettingsController;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlScene;
+import org.cryptomator.ui.controls.NumericTextField;
+
+@RecoveryKeyScoped
+public class RecoveryKeyExpertSettingsController implements FxController {
+
+ public static final int MAX_SHORTENING_THRESHOLD = 220;
+ public static final int MIN_SHORTENING_THRESHOLD = 36;
+ private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/security/vault/#name-shortening";
+
+ private final Stage window;
+ private final Lazy application;
+ private final Vault vault;
+ private final ObjectProperty recoverType;
+ private final IntegerProperty shorteningThreshold;
+ private final Lazy resetPasswordScene;
+ private final Lazy createScene;
+ private final Lazy onBoardingScene;
+ private final Lazy recoverScene;
+ private final BooleanBinding validShorteningThreshold;
+
+ @FXML
+ public CheckBox expertSettingsCheckBox;
+ @FXML
+ public NumericTextField shorteningThresholdTextField;
+
+ @Inject
+ public RecoveryKeyExpertSettingsController(@RecoveryKeyWindow Stage window, //
+ Lazy application, //
+ @RecoveryKeyWindow Vault vault, //
+ @Named("recoverType") ObjectProperty recoverType, //
+ @Named("shorteningThreshold") IntegerProperty shorteningThreshold, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy resetPasswordScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_CREATE) Lazy createScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_ONBOARDING) Lazy onBoardingScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_RECOVER) Lazy recoverScene) {
+ this.window = window;
+ this.application = application;
+ this.vault = vault;
+ this.recoverType = recoverType;
+ this.shorteningThreshold = shorteningThreshold;
+ this.resetPasswordScene = resetPasswordScene;
+ this.createScene = createScene;
+ this.onBoardingScene = onBoardingScene;
+ this.recoverScene = recoverScene;
+ this.validShorteningThreshold = Bindings.createBooleanBinding(this::isValidShorteningThreshold, shorteningThreshold);
+ }
+
+ @FXML
+ public void initialize() {
+ shorteningThresholdTextField.setPromptText(MIN_SHORTENING_THRESHOLD + "-" + MAX_SHORTENING_THRESHOLD);
+ shorteningThresholdTextField.setText(Integer.toString(MAX_SHORTENING_THRESHOLD));
+ shorteningThresholdTextField.textProperty().addListener((_, _, newValue) -> {
+ try {
+ int intValue = Integer.parseInt(newValue);
+ shorteningThreshold.set(intValue);
+ } catch (NumberFormatException e) {
+ shorteningThreshold.set(0); //the value is set to 0 to ensure that an invalid value assignment is detected during a NumberFormatException
+ }
+ });
+ }
+
+ @FXML
+ public void toggleUseExpertSettings() {
+ if (!expertSettingsCheckBox.isSelected()) {
+ shorteningThresholdTextField.setText(Integer.toString(CreateNewVaultExpertSettingsController.MAX_SHORTENING_THRESHOLD));
+ }
+ }
+
+ public void openDocs() {
+ application.get().getHostServices().showDocument(DOCS_NAME_SHORTENING_URL);
+ }
+
+ public BooleanBinding validShorteningThresholdProperty() {
+ return validShorteningThreshold;
+ }
+
+ public boolean isValidShorteningThreshold() {
+ var value = shorteningThreshold.get();
+ return value >= MIN_SHORTENING_THRESHOLD && value <= MAX_SHORTENING_THRESHOLD;
+ }
+
+ @FXML
+ public void back() {
+ if (recoverType.get() == RecoveryActionType.RESTORE_ALL && vault.getState() == VaultState.Value.VAULT_CONFIG_MISSING) {
+ window.setScene(recoverScene.get());
+ } else if (recoverType.get() == RecoveryActionType.RESTORE_ALL && vault.getState() == VaultState.Value.ALL_MISSING) {
+ window.setScene(recoverScene.get());
+ } else if (recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG) {
+ window.setScene(onBoardingScene.get());
+ }
+ }
+
+ @FXML
+ public void next() {
+ if (recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG) {
+ window.setScene(createScene.get());
+ } else {
+ window.setScene(resetPasswordScene.get());
+ }
+ }
+}
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java
index 06095eebc..809d16b61 100644
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java
@@ -5,8 +5,12 @@ import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.common.Nullable;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.VaultConfig;
+import org.cryptomator.cryptolib.api.CryptorProvider;
+import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
+import org.cryptomator.ui.addvaultwizard.CreateNewVaultExpertSettingsController;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
@@ -19,6 +23,10 @@ import org.cryptomator.ui.common.StageFactory;
import javax.inject.Named;
import javax.inject.Provider;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
@@ -99,12 +107,18 @@ abstract class RecoveryKeyModule {
}
@Provides
- @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD_SUCCESS)
+ @FxmlScene(FxmlFile.RECOVERYKEY_ONBOARDING)
@RecoveryKeyScoped
- static Scene provideRecoveryKeyResetPasswordSuccessScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
- return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD_SUCCESS);
+ static Scene provideRecoveryKeyOnboardingScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
+ return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_ONBOARDING);
}
+ @Provides
+ @FxmlScene(FxmlFile.RECOVERYKEY_EXPERT_SETTINGS)
+ @RecoveryKeyScoped
+ static Scene provideRecoveryKeyExpertSettingsScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
+ return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_EXPERT_SETTINGS);
+ }
// ------------------
@@ -120,6 +134,25 @@ abstract class RecoveryKeyModule {
return new RecoveryKeyDisplayController(window, vault.getDisplayName(), recoveryKey.get(), localization);
}
+ @Provides
+ @Named("shorteningThreshold")
+ @RecoveryKeyScoped
+ static IntegerProperty provideShorteningThreshold() {
+ return new SimpleIntegerProperty(CreateNewVaultExpertSettingsController.MAX_SHORTENING_THRESHOLD);
+ }
+
+ @Provides
+ @Named("cipherCombo")
+ @RecoveryKeyScoped
+ static ObjectProperty provideCipherCombo() {
+ return new SimpleObjectProperty<>();
+ }
+
+ @Binds
+ @IntoMap
+ @FxControllerKey(RecoveryKeyExpertSettingsController.class)
+ abstract FxController provideRecoveryKeyExpertSettingsController(RecoveryKeyExpertSettingsController controller);
+
@Binds
@IntoMap
@FxControllerKey(RecoveryKeyRecoverController.class)
@@ -137,14 +170,14 @@ abstract class RecoveryKeyModule {
@Binds
@IntoMap
- @FxControllerKey(RecoveryKeyResetPasswordSuccessController.class)
- abstract FxController bindRecoveryKeyResetPasswordSuccessController(RecoveryKeyResetPasswordSuccessController controller);
+ @FxControllerKey(RecoveryKeyOnboardingController.class)
+ abstract FxController bindRecoveryKeyOnboardingController(RecoveryKeyOnboardingController controller);
@Provides
@IntoMap
@FxControllerKey(RecoveryKeyValidateController.class)
- static FxController bindRecoveryKeyValidateController(@RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
- return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory);
+ static FxController bindRecoveryKeyValidateController(@RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, @Named("recoverType") ObjectProperty recoverType, @Named("cipherCombo") ObjectProperty cipherCombo, @Nullable MasterkeyFileAccess masterkeyFileAccess) {
+ return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory, masterkeyFileAccess, recoverType, cipherCombo);
}
@Provides
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyOnboardingController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyOnboardingController.java
new file mode 100644
index 000000000..dd15413d8
--- /dev/null
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyOnboardingController.java
@@ -0,0 +1,176 @@
+package org.cryptomator.ui.recoverykey;
+
+import dagger.Lazy;
+import org.cryptomator.common.recovery.RecoveryActionType;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultState;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.FxmlFile;
+import org.cryptomator.ui.common.FxmlScene;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.BooleanBinding;
+import javafx.beans.property.ObjectProperty;
+import javafx.fxml.FXML;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.RadioButton;
+import javafx.scene.control.Toggle;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+import java.util.ResourceBundle;
+
+import static org.cryptomator.common.recovery.RecoveryActionType.RESTORE_ALL;
+import static org.cryptomator.common.recovery.RecoveryActionType.RESTORE_VAULT_CONFIG;
+
+@RecoveryKeyScoped
+public class RecoveryKeyOnboardingController implements FxController {
+
+ private final Stage window;
+ private final Vault vault;
+ private final Lazy recoverykeyRecoverScene;
+ private final Lazy recoverykeyExpertSettingsScene;
+ private final ObjectProperty recoverType;
+ private final ResourceBundle resourceBundle;
+
+ public Label titleLabel;
+ public Label messageLabel;
+ public Label pleaseConfirm;
+ public Label secondTextDesc;
+
+ @FXML
+ private CheckBox affirmationBox;
+ @FXML
+ private RadioButton recoveryKeyRadio;
+ @FXML
+ private RadioButton passwordRadio;
+ @FXML
+ private Button nextButton;
+ @FXML
+ private VBox chooseMethodeBox;
+ @FXML
+ private ToggleGroup methodToggleGroup = new ToggleGroup();
+ @FXML
+ private HBox hBox;
+
+ @Inject
+ public RecoveryKeyOnboardingController(@RecoveryKeyWindow Stage window, //
+ @RecoveryKeyWindow Vault vault, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_RECOVER) Lazy recoverykeyRecoverScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_EXPERT_SETTINGS) Lazy recoverykeyExpertSettingsScene, //
+ @Named("recoverType") ObjectProperty recoverType, //
+ ResourceBundle resourceBundle) {
+ this.window = window;
+ this.vault = vault;
+ this.recoverykeyRecoverScene = recoverykeyRecoverScene;
+ this.recoverykeyExpertSettingsScene = recoverykeyExpertSettingsScene;
+ this.recoverType = recoverType;
+ this.resourceBundle = resourceBundle;
+ }
+
+ @FXML
+ public void initialize() {
+ recoveryKeyRadio.setToggleGroup(methodToggleGroup);
+ passwordRadio.setToggleGroup(methodToggleGroup);
+
+ BooleanBinding showMethodSelection = Bindings.createBooleanBinding(
+ () -> recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG, recoverType);
+ chooseMethodeBox.visibleProperty().bind(showMethodSelection);
+ chooseMethodeBox.managedProperty().bind(showMethodSelection);
+
+ nextButton.disableProperty().bind(
+ affirmationBox.selectedProperty().not()
+ .or(methodToggleGroup.selectedToggleProperty().isNull().and(showMethodSelection))
+ );
+
+ switch (recoverType.get()) {
+ case RESTORE_MASTERKEY -> {
+ window.setTitle(resourceBundle.getString("recover.recoverMasterkey.title"));
+ messageLabel.setVisible(false);
+ messageLabel.setManaged(false);
+ pleaseConfirm.setText(resourceBundle.getString("recover.onBoarding.pleaseConfirm"));
+ }
+ case RESTORE_ALL -> {
+ window.setTitle(resourceBundle.getString("recover.recoverVaultConfig.title"));
+ messageLabel.setVisible(true);
+ messageLabel.setManaged(true);
+ pleaseConfirm.setText(resourceBundle.getString("recover.onBoarding.otherwisePleaseConfirm"));
+ }
+ case RESTORE_VAULT_CONFIG -> {
+ window.setTitle(resourceBundle.getString("recover.recoverVaultConfig.title"));
+ messageLabel.setVisible(false);
+ messageLabel.setManaged(false);
+ pleaseConfirm.setText(resourceBundle.getString("recover.onBoarding.pleaseConfirm"));
+ }
+ default -> window.setTitle("");
+ }
+
+ if (vault.getState() == VaultState.Value.ALL_MISSING) {
+ messageLabel.setText(resourceBundle.getString("recover.onBoarding.allMissing.intro"));
+ } else {
+ messageLabel.setText(resourceBundle.getString("recover.onBoarding.intro"));
+ }
+
+ titleLabel.textProperty().bind(Bindings.createStringBinding(() ->
+ recoverType.get() == RecoveryActionType.RESTORE_MASTERKEY
+ ? resourceBundle.getString("recover.recoverMasterkey.title")
+ : resourceBundle.getString("recover.recoverVaultConfig.title"), recoverType));
+
+ BooleanBinding isRestoreMasterkey = Bindings.createBooleanBinding(
+ () -> recoverType.get() == RecoveryActionType.RESTORE_MASTERKEY, recoverType);
+ hBox.minHeightProperty().bind(Bindings.when(isRestoreMasterkey).then(206.0).otherwise(Region.USE_COMPUTED_SIZE));
+
+ secondTextDesc.textProperty().bind(Bindings.createStringBinding(() -> {
+ RecoveryActionType type = recoverType.get();
+ Toggle sel = methodToggleGroup.getSelectedToggle();
+ return switch (type) {
+ case RESTORE_VAULT_CONFIG -> resourceBundle.getString(sel == passwordRadio
+ ? "recover.onBoarding.intro.password"
+ : "recover.onBoarding.intro.recoveryKey");
+ case RESTORE_MASTERKEY -> resourceBundle.getString("recover.onBoarding.intro.masterkey.recoveryKey");
+ case RESTORE_ALL -> resourceBundle.getString("recover.onBoarding.intro.recoveryKey");
+ default -> "";
+ };
+ }, recoverType, methodToggleGroup.selectedToggleProperty()));
+
+ showMethodSelection.addListener((_, _, nowShown) -> {
+ if (nowShown && methodToggleGroup.getSelectedToggle() == null) {
+ methodToggleGroup.selectToggle(recoveryKeyRadio);
+ }
+ });
+ }
+
+ @FXML
+ public void close() {
+ window.close();
+ }
+
+ @FXML
+ public void next() {
+ switch (recoverType.get()) {
+ case RESTORE_VAULT_CONFIG, RESTORE_ALL -> {
+ Object selectedToggle = methodToggleGroup.getSelectedToggle();
+ if (selectedToggle == recoveryKeyRadio) {
+ recoverType.set(RESTORE_ALL);
+ window.setScene(recoverykeyRecoverScene.get());
+ } else if (selectedToggle == passwordRadio) {
+ recoverType.set(RESTORE_VAULT_CONFIG);
+ window.setScene(recoverykeyExpertSettingsScene.get());
+ } else {
+ window.setScene(recoverykeyRecoverScene.get());
+ }
+ }
+ case RESTORE_MASTERKEY -> window.setScene(recoverykeyRecoverScene.get());
+ default -> window.setScene(recoverykeyRecoverScene.get()); // Fallback
+ }
+ window.centerOnScreen();
+ }
+
+}
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java
index 944c52043..8eb505d47 100644
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java
@@ -1,54 +1,105 @@
package org.cryptomator.ui.recoverykey;
import dagger.Lazy;
-import org.cryptomator.common.Nullable;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.cryptofs.VaultConfig;
+import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import javax.inject.Inject;
-import javafx.beans.Observable;
-import javafx.beans.property.StringProperty;
-import javafx.beans.value.ObservableValue;
+import javax.inject.Named;
+import javafx.beans.property.ObjectProperty;
import javafx.fxml.FXML;
import javafx.scene.Scene;
+import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.util.ResourceBundle;
@RecoveryKeyScoped
public class RecoveryKeyRecoverController implements FxController {
- private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
-
private final Stage window;
- private final Lazy resetPasswordScene;
+ private final Vault vault;
+ private final Lazy nextScene;
+ private final Lazy onBoardingScene;
+ private final ResourceBundle resourceBundle;
+ public ObjectProperty recoverType;
+
+ @FXML
+ private Button cancelButton;
@FXML
RecoveryKeyValidateController recoveryKeyValidateController;
@Inject
- public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow StringProperty recoveryKey, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy resetPasswordScene, ResourceBundle resourceBundle) {
+ public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, //
+ @RecoveryKeyWindow Vault vault, //
+ ResourceBundle resourceBundle, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy resetPasswordScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_EXPERT_SETTINGS) Lazy expertSettingsScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_ONBOARDING) Lazy onBoardingScene, //
+ @Named("recoverType") ObjectProperty recoverType) {
this.window = window;
- window.setTitle(resourceBundle.getString("recoveryKey.recover.title"));
- this.resetPasswordScene = resetPasswordScene;
+ this.vault = vault;
+ this.resourceBundle = resourceBundle;
+ this.onBoardingScene = onBoardingScene;
+ this.recoverType = recoverType;
+ this.nextScene = switch (recoverType.get()) {
+ case RESTORE_ALL, RESTORE_VAULT_CONFIG -> {
+ window.setTitle(resourceBundle.getString("recover.recoverVaultConfig.title"));
+ yield expertSettingsScene;
+ }
+ case RESTORE_MASTERKEY -> {
+ window.setTitle(resourceBundle.getString("recover.recoverMasterkey.title"));
+ yield resetPasswordScene;
+ }
+ case RESET_PASSWORD -> {
+ window.setTitle(resourceBundle.getString("recoveryKey.recover.title"));
+ yield resetPasswordScene;
+ }
+ case SHOW_KEY -> {
+ window.setTitle(resourceBundle.getString("recoveryKey.display.title"));
+ yield resetPasswordScene;
+ }
+ default -> throw new IllegalArgumentException("Unexpected recovery action type: " + recoverType.get());
+ };
}
@FXML
public void initialize() {
+ if (recoverType.get() == RecoveryActionType.RESET_PASSWORD) {
+ cancelButton.setText(resourceBundle.getString("generic.button.cancel"));
+ } else {
+ cancelButton.setText(resourceBundle.getString("generic.button.back"));
+ }
}
@FXML
- public void close() {
- window.close();
+ public void closeOrReturn() {
+ switch (recoverType.get()) {
+ case RESET_PASSWORD -> window.close();
+ case RESTORE_MASTERKEY -> {
+ window.setScene(onBoardingScene.get());
+ window.centerOnScreen();
+ }
+ default -> {
+ if(vault.getState().equals(VaultState.Value.ALL_MISSING)){
+ recoverType.set(RecoveryActionType.RESTORE_ALL);
+ }
+ else {
+ recoverType.set(RecoveryActionType.RESTORE_VAULT_CONFIG);
+ }
+ window.setScene(onBoardingScene.get());
+ window.centerOnScreen();
+ }
+ }
}
@FXML
public void recover() {
- window.setScene(resetPasswordScene.get());
+ window.setScene(nextScene.get());
}
/* Getter/Setter */
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java
index 18a952ea5..0c06ba9b2 100644
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java
@@ -1,25 +1,44 @@
package org.cryptomator.ui.recoverykey;
import dagger.Lazy;
+import org.cryptomator.common.recovery.CryptoFsInitializer;
+import org.cryptomator.common.recovery.MasterkeyService;
+import org.cryptomator.common.recovery.RecoveryActionType;
+import org.cryptomator.common.recovery.RecoveryDirectory;
import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultListManager;
+import org.cryptomator.cryptolib.api.CryptoException;
+import org.cryptomator.cryptolib.api.CryptorProvider;
+import org.cryptomator.cryptolib.api.Masterkey;
+import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
+import org.cryptomator.ui.changepassword.NewPasswordController;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
-import org.cryptomator.ui.changepassword.NewPasswordController;
+import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
+import javax.inject.Named;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.Scene;
+import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
+import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
+import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
+
@RecoveryKeyScoped
public class RecoveryKeyResetPasswordController implements FxController {
@@ -30,48 +49,140 @@ public class RecoveryKeyResetPasswordController implements FxController {
private final RecoveryKeyFactory recoveryKeyFactory;
private final ExecutorService executor;
private final StringProperty recoveryKey;
- private final Lazy recoverResetPasswordSuccessScene;
+ private final Lazy recoverExpertSettingsScene;
+ private final Lazy recoverykeyRecoverScene;
private final FxApplicationWindows appWindows;
+ private final MasterkeyFileAccess masterkeyFileAccess;
+ private final VaultListManager vaultListManager;
+ private final IntegerProperty shorteningThreshold;
+ private final ObjectProperty recoverType;
+ private final ObjectProperty cipherCombo;
+ private final ResourceBundle resourceBundle;
+ private final Dialogs dialogs;
public NewPasswordController newPasswordController;
+ public Button nextButton;
@Inject
- public RecoveryKeyResetPasswordController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD_SUCCESS) Lazy recoverResetPasswordSuccessScene, FxApplicationWindows appWindows) {
+ public RecoveryKeyResetPasswordController(@RecoveryKeyWindow Stage window, //
+ @RecoveryKeyWindow Vault vault, //
+ RecoveryKeyFactory recoveryKeyFactory, //
+ ExecutorService executor, //
+ @RecoveryKeyWindow StringProperty recoveryKey, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_EXPERT_SETTINGS) Lazy recoverExpertSettingsScene, //
+ @FxmlScene(FxmlFile.RECOVERYKEY_RECOVER) Lazy recoverykeyRecoverScene, //
+ FxApplicationWindows appWindows, //
+ MasterkeyFileAccess masterkeyFileAccess, //
+ VaultListManager vaultListManager, //
+ @Named("shorteningThreshold") IntegerProperty shorteningThreshold, //
+ @Named("recoverType") ObjectProperty recoverType, //
+ @Named("cipherCombo") ObjectProperty cipherCombo, //
+ ResourceBundle resourceBundle, //
+ Dialogs dialogs) {
this.window = window;
this.vault = vault;
this.recoveryKeyFactory = recoveryKeyFactory;
this.executor = executor;
this.recoveryKey = recoveryKey;
- this.recoverResetPasswordSuccessScene = recoverResetPasswordSuccessScene;
+ this.recoverExpertSettingsScene = recoverExpertSettingsScene;
+ this.recoverykeyRecoverScene = recoverykeyRecoverScene;
this.appWindows = appWindows;
+ this.masterkeyFileAccess = masterkeyFileAccess;
+ this.vaultListManager = vaultListManager;
+ this.shorteningThreshold = shorteningThreshold;
+ this.cipherCombo = cipherCombo;
+ this.recoverType = recoverType;
+ this.resourceBundle = resourceBundle;
+ this.dialogs = dialogs;
+ }
+
+ @FXML
+ public void initialize() {
+ switch (recoverType.get()) {
+ case RESTORE_MASTERKEY, RESTORE_ALL -> nextButton.setText(resourceBundle.getString("recoveryKey.recover.recoverBtn"));
+ case RESET_PASSWORD -> nextButton.setText(resourceBundle.getString("recoveryKey.recover.resetBtn"));
+ default -> nextButton.setText(resourceBundle.getString("recoveryKey.recover.recoverBtn")); // Fallback
+ }
}
@FXML
public void close() {
- window.close();
+ switch (recoverType.get()) {
+ case RESTORE_ALL -> window.setScene(recoverExpertSettingsScene.get());
+ case RESTORE_MASTERKEY, RESET_PASSWORD -> window.setScene(recoverykeyRecoverScene.get());
+ default -> window.close();
+ }
+ }
+
+ @FXML
+ public void next() {
+ switch (recoverType.get()) {
+ case RESTORE_ALL -> restorePassword();
+ case RESTORE_MASTERKEY, RESET_PASSWORD -> resetPassword();
+ default -> resetPassword(); // Fallback
+ }
+ }
+
+ @FXML
+ public void restorePassword() {
+ try (RecoveryDirectory recoveryDirectory = RecoveryDirectory.create(vault.getPath())) {
+ Path recoveryPath = recoveryDirectory.getRecoveryPath();
+ MasterkeyService.recoverFromRecoveryKey(recoveryKey.get(), recoveryKeyFactory, recoveryPath, newPasswordController.passwordField.getCharacters());
+
+ try (Masterkey masterkey = MasterkeyService.load(masterkeyFileAccess, recoveryPath.resolve(MASTERKEY_FILENAME), newPasswordController.passwordField.getCharacters())) {
+ CryptoFsInitializer.init(recoveryPath, masterkey, shorteningThreshold.get(), cipherCombo.get());
+ }
+
+ recoveryDirectory.moveRecoveredFile(MASTERKEY_FILENAME);
+ recoveryDirectory.moveRecoveredFile(VAULTCONFIG_FILENAME);
+
+ if (!vaultListManager.isAlreadyAdded(vault.getPath())) {
+ vaultListManager.add(vault.getPath());
+ }
+ window.close();
+ dialogs.prepareRecoverPasswordSuccess((Stage)window.getOwner()) //
+ .setTitleKey("recover.recoverVaultConfig.title") //
+ .setMessageKey("recoveryKey.recover.resetVaultConfigSuccess.message") //
+ .build().showAndWait();
+
+ } catch (IOException | CryptoException e) {
+ LOG.error("Recovery process failed", e);
+ appWindows.showErrorWindow(e, window, null);
+ }
}
@FXML
public void resetPassword() {
Task task = new ResetPasswordTask();
- task.setOnScheduled(event -> {
+
+ task.setOnScheduled(_ -> {
LOG.debug("Using recovery key to reset password for {}.", vault.getDisplayablePath());
});
- task.setOnSucceeded(event -> {
- LOG.info("Used recovery key to reset password for {}.", vault.getDisplayablePath());
- window.setScene(recoverResetPasswordSuccessScene.get());
+
+ task.setOnSucceeded(_ -> {
+ LOG.debug("Used recovery key to reset password for {}.", vault.getDisplayablePath());
+ window.close();
+ switch (recoverType.get()){
+ case RESET_PASSWORD -> dialogs.prepareRecoverPasswordSuccess((Stage)window.getOwner()).build().showAndWait();
+ case RESTORE_MASTERKEY -> dialogs.prepareRecoverPasswordSuccess((Stage)window.getOwner()).setTitleKey("recover.recoverMasterkey.title").setMessageKey("recoveryKey.recover.resetMasterkeyFileSuccess.message").build().showAndWait();
+ default -> dialogs.prepareRecoverPasswordSuccess(window).build().showAndWait(); // Fallback
+ }
});
- task.setOnFailed(event -> {
+
+ task.setOnFailed(_ -> {
LOG.error("Resetting password failed.", task.getException());
appWindows.showErrorWindow(task.getException(), window, null);
});
+
executor.submit(task);
}
private class ResetPasswordTask extends Task {
- private ResetPasswordTask() {
- setOnFailed(event -> LOG.error("Failed to reset password", getException()));
+ private static final Logger LOG = LoggerFactory.getLogger(ResetPasswordTask.class);
+
+ public ResetPasswordTask() {
+ setOnFailed(_ -> LOG.error("Failed to reset password", getException()));
}
@Override
@@ -79,7 +190,6 @@ public class RecoveryKeyResetPasswordController implements FxController {
recoveryKeyFactory.newMasterkeyFileWithPassphrase(vault.getPath(), recoveryKey.get(), newPasswordController.passwordField.getCharacters());
return null;
}
-
}
/* Getter/Setter */
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordSuccessController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordSuccessController.java
deleted file mode 100644
index b8b106d8b..000000000
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordSuccessController.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.cryptomator.ui.recoverykey;
-
-import org.cryptomator.ui.common.FxController;
-
-import javax.inject.Inject;
-import javafx.fxml.FXML;
-import javafx.stage.Stage;
-
-@RecoveryKeyScoped
-public class RecoveryKeyResetPasswordSuccessController implements FxController {
-
- private final Stage window;
-
- @Inject
- public RecoveryKeyResetPasswordSuccessController(@RecoveryKeyWindow Stage window) {
- this.window = window;
- }
-
- @FXML
- public void close() {
- window.close();
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java
index 4a8224ffe..35f4c15ed 100644
--- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java
+++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java
@@ -1,18 +1,23 @@
package org.cryptomator.ui.recoverykey;
-
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import org.cryptomator.common.Nullable;
import org.cryptomator.common.ObservableUtil;
+import org.cryptomator.common.recovery.MasterkeyService;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.VaultConfig;
import org.cryptomator.cryptofs.VaultConfigLoadException;
import org.cryptomator.cryptofs.VaultKeyInvalidException;
+import org.cryptomator.cryptolib.api.CryptoException;
+import org.cryptomator.cryptolib.api.CryptorProvider;
+import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.inject.Named;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.StringProperty;
@@ -22,10 +27,12 @@ import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
+import java.io.IOException;
+import java.util.NoSuchElementException;
public class RecoveryKeyValidateController implements FxController {
- private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
+ private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyValidateController.class);
private static final CharMatcher ALLOWED_CHARS = CharMatcher.inRange('a', 'z').or(CharMatcher.is(' '));
private final Vault vault;
@@ -36,13 +43,23 @@ public class RecoveryKeyValidateController implements FxController {
private final ObservableValue recoveryKeyInvalid;
private final RecoveryKeyFactory recoveryKeyFactory;
private final ObjectProperty recoveryKeyState;
+ private final ObjectProperty cipherCombo;
private final AutoCompleter autoCompleter;
+ private final ObjectProperty recoverType;
+ private final MasterkeyFileAccess masterkeyFileAccess;
private volatile boolean isWrongKey;
public TextArea textarea;
- public RecoveryKeyValidateController(Vault vault, @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
+ public RecoveryKeyValidateController(Vault vault, //
+ @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, //
+ StringProperty recoveryKey, //
+ RecoveryKeyFactory recoveryKeyFactory, //
+ MasterkeyFileAccess masterkeyFileAccess, //
+ @Named("recoverType") ObjectProperty recoverType, //
+ @Named("cipherCombo") ObjectProperty cipherCombo
+ ) {
this.vault = vault;
this.unverifiedVaultConfig = vaultConfig;
this.recoveryKey = recoveryKey;
@@ -52,6 +69,9 @@ public class RecoveryKeyValidateController implements FxController {
this.recoveryKeyCorrect = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.CORRECT::equals, false);
this.recoveryKeyWrong = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.WRONG::equals, false);
this.recoveryKeyInvalid = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.INVALID::equals, false);
+ this.recoverType = recoverType;
+ this.cipherCombo = cipherCombo;
+ this.masterkeyFileAccess = masterkeyFileAccess;
}
@FXML
@@ -117,14 +137,37 @@ public class RecoveryKeyValidateController implements FxController {
}
private void validateRecoveryKey() {
- isWrongKey = false;
- var valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
- if (valid) {
- recoveryKeyState.set(RecoveryKeyState.CORRECT);
- } else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig()
- recoveryKeyState.set(RecoveryKeyState.WRONG);
- } else {
- recoveryKeyState.set(RecoveryKeyState.INVALID);
+ switch (recoverType.get()) {
+ case RESTORE_ALL, RESTORE_VAULT_CONFIG -> {
+ try {
+ var scheme = MasterkeyService.validateRecoveryKeyAndDetectCombo(recoveryKeyFactory, vault, recoveryKey.get(), masterkeyFileAccess);
+ cipherCombo.set(scheme);
+ recoveryKeyState.set(RecoveryKeyState.CORRECT);
+ } catch (CryptoException e) {
+ LOG.info("Recovery key is valid but crypto scheme couldn't be determined", e);
+ recoveryKeyState.set(RecoveryKeyState.WRONG);
+ } catch (IllegalArgumentException e) {
+ LOG.info("Recovery key is syntactically invalid", e);
+ recoveryKeyState.set(RecoveryKeyState.INVALID);
+ } catch (IOException e) {
+ LOG.warn("IO error while validating recovery key", e);
+ recoveryKeyState.set(RecoveryKeyState.INVALID);
+ } catch (NoSuchElementException e) {
+ LOG.warn("Could not determine scheme from masterkey during recovery key validation, because no valid *.c9r file is present in vault", e);
+ recoveryKeyState.set(RecoveryKeyState.INVALID);
+ }
+ }
+ case RESTORE_MASTERKEY, RESET_PASSWORD, SHOW_KEY, CONVERT_VAULT -> {
+ isWrongKey = false;
+ boolean valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
+ if (valid) {
+ recoveryKeyState.set(RecoveryKeyState.CORRECT);
+ } else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig()
+ recoveryKeyState.set(RecoveryKeyState.WRONG);
+ } else {
+ recoveryKeyState.set(RecoveryKeyState.INVALID);
+ }
+ }
}
}
diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java
index 93fb298ed..b0c490a3f 100644
--- a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java
+++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java
@@ -58,9 +58,15 @@ public class ShareVaultController implements FxController {
private static URI getHubUri(Vault vault) {
try {
- var keyID = new URI(vault.getVaultConfigCache().get().getKeyId().toString());
- assert keyID.getScheme().startsWith(SCHEME_PREFIX);
- return new URI(keyID.getScheme().substring(SCHEME_PREFIX.length()) + "://" + keyID.getHost() + "/app/vaults");
+ var keyId = new URI(vault.getVaultConfigCache().get().getKeyId().toString());
+ assert keyId.getScheme().startsWith(SCHEME_PREFIX);
+ var path = keyId.getPath();
+ var apiIdx = path.indexOf("/api/");
+ if (apiIdx < 0) {
+ throw new IllegalArgumentException("Path does not contain /api/: " + path);
+ }
+ var appPath = path.substring(0, apiIdx) + "/app/vaults";
+ return new URI(keyId.getScheme().substring(SCHEME_PREFIX.length()), keyId.getAuthority(), appPath, null, null);
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (URISyntaxException e) {
diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
index 95f13d383..1c8d758fc 100644
--- a/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
+++ b/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
@@ -15,6 +15,7 @@ import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.keyloading.KeyLoadingComponent;
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
+import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.jetbrains.annotations.Nullable;
import javax.inject.Named;
@@ -27,7 +28,7 @@ import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
-@Module(subcomponents = {KeyLoadingComponent.class})
+@Module(subcomponents = {KeyLoadingComponent.class, RecoveryKeyComponent.class})
abstract class UnlockModule {
@Provides
diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java
index dd003d93d..67ae2f42d 100644
--- a/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java
+++ b/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java
@@ -1,16 +1,16 @@
package org.cryptomator.ui.vaultoptions;
import org.cryptomator.common.keychain.KeychainManager;
+import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@@ -18,8 +18,6 @@ import javafx.stage.Stage;
@VaultOptionsScoped
public class MasterkeyOptionsController implements FxController {
- private static final Logger LOG = LoggerFactory.getLogger(MasterkeyOptionsController.class);
-
private final Vault vault;
private final Stage window;
private final ChangePasswordComponent.Builder changePasswordWindow;
@@ -51,12 +49,12 @@ public class MasterkeyOptionsController implements FxController {
@FXML
public void showRecoveryKey() {
- recoveryKeyWindow.create(vault, window).showRecoveryKeyCreationWindow();
+ recoveryKeyWindow.create(vault, window, new SimpleObjectProperty<>(RecoveryActionType.SHOW_KEY)).showRecoveryKeyCreationWindow();
}
@FXML
public void showRecoverVaultDialog() {
- recoveryKeyWindow.create(vault, window).showRecoveryKeyRecoverWindow();
+ recoveryKeyWindow.create(vault, window, new SimpleObjectProperty<>(RecoveryActionType.RESET_PASSWORD)).showRecoveryKeyRecoverWindow();
}
@FXML
diff --git a/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml b/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml
index 7ea190fd4..7797b41b2 100644
--- a/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml
+++ b/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml
@@ -6,7 +6,12 @@
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
@@ -26,7 +40,7 @@
-
-
-
+
+
diff --git a/src/main/resources/fxml/convertvault_hubtopassword_start.fxml b/src/main/resources/fxml/convertvault_hubtopassword_start.fxml
index d5c0a5e0b..27b6911f7 100644
--- a/src/main/resources/fxml/convertvault_hubtopassword_start.fxml
+++ b/src/main/resources/fxml/convertvault_hubtopassword_start.fxml
@@ -5,7 +5,10 @@
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/recoverykey_create.fxml b/src/main/resources/fxml/recoverykey_create.fxml
index 784ba49ed..2d9f0f418 100644
--- a/src/main/resources/fxml/recoverykey_create.fxml
+++ b/src/main/resources/fxml/recoverykey_create.fxml
@@ -40,7 +40,7 @@
-
+
@@ -49,8 +49,8 @@
-
-
+
+
diff --git a/src/main/resources/fxml/recoverykey_expert_settings.fxml b/src/main/resources/fxml/recoverykey_expert_settings.fxml
new file mode 100644
index 000000000..cceac8388
--- /dev/null
+++ b/src/main/resources/fxml/recoverykey_expert_settings.fxml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fxml/recoverykey_onboarding.fxml b/src/main/resources/fxml/recoverykey_onboarding.fxml
new file mode 100644
index 000000000..b1c701a9d
--- /dev/null
+++ b/src/main/resources/fxml/recoverykey_onboarding.fxml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/recoverykey_recover.fxml b/src/main/resources/fxml/recoverykey_recover.fxml
index 4c85f9356..5a9fddbdf 100644
--- a/src/main/resources/fxml/recoverykey_recover.fxml
+++ b/src/main/resources/fxml/recoverykey_recover.fxml
@@ -3,32 +3,46 @@
+
+
-
+
+
+
+
+ spacing="12">
+
+
+
+
+
+
+
+
+
-
+
+
-
+
-
-
+
-
+
-
+
diff --git a/src/main/resources/fxml/recoverykey_reset_password.fxml b/src/main/resources/fxml/recoverykey_reset_password.fxml
index 79827af35..8c28a1c9f 100644
--- a/src/main/resources/fxml/recoverykey_reset_password.fxml
+++ b/src/main/resources/fxml/recoverykey_reset_password.fxml
@@ -5,7 +5,12 @@
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
diff --git a/src/main/resources/fxml/recoverykey_reset_password_success.fxml b/src/main/resources/fxml/recoverykey_reset_password_success.fxml
deleted file mode 100644
index 16d96d21d..000000000
--- a/src/main/resources/fxml/recoverykey_reset_password_success.fxml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/fxml/recoverykey_validate.fxml b/src/main/resources/fxml/recoverykey_validate.fxml
index 920dcd2b0..b1420a899 100644
--- a/src/main/resources/fxml/recoverykey_validate.fxml
+++ b/src/main/resources/fxml/recoverykey_validate.fxml
@@ -2,48 +2,40 @@
-
-
-
-
-
+ spacing="12">
-
-
-
+
diff --git a/src/main/resources/fxml/unlock_select_masterkeyfile.fxml b/src/main/resources/fxml/unlock_select_masterkeyfile.fxml
index bfc995ceb..60934cdba 100644
--- a/src/main/resources/fxml/unlock_select_masterkeyfile.fxml
+++ b/src/main/resources/fxml/unlock_select_masterkeyfile.fxml
@@ -12,6 +12,7 @@
+
+
-
+
diff --git a/src/main/resources/fxml/vault_detail.fxml b/src/main/resources/fxml/vault_detail.fxml
index 8ca11a34f..cfae48d8b 100644
--- a/src/main/resources/fxml/vault_detail.fxml
+++ b/src/main/resources/fxml/vault_detail.fxml
@@ -53,5 +53,6 @@
+
diff --git a/src/main/resources/fxml/vault_detail_missing_vault_config.fxml b/src/main/resources/fxml/vault_detail_missing_vault_config.fxml
new file mode 100644
index 000000000..26fa3e096
--- /dev/null
+++ b/src/main/resources/fxml/vault_detail_missing_vault_config.fxml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fxml/vault_list.fxml b/src/main/resources/fxml/vault_list.fxml
index 6706ec293..e21237a43 100644
--- a/src/main/resources/fxml/vault_list.fxml
+++ b/src/main/resources/fxml/vault_list.fxml
@@ -13,8 +13,6 @@
-
-
+
diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties
index 6e8dc388a..66f473248 100644
--- a/src/main/resources/i18n/strings.properties
+++ b/src/main/resources/i18n/strings.properties
@@ -97,6 +97,7 @@ addvault.new.readme.accessLocation.4=Feel free to remove this file.
## Existing
addvaultwizard.existing.title=Add Existing Vault
addvaultwizard.existing.instruction=Choose the "vault.cryptomator" file of your existing vault. If only a file named "masterkey.cryptomator" exists, select that instead.
+addvaultwizard.existing.restore=Restore…
addvaultwizard.existing.chooseBtn=Choose…
addvaultwizard.existing.filePickerTitle=Select Vault File
addvaultwizard.existing.filePickerMimeDesc=Cryptomator Vault
@@ -128,6 +129,7 @@ unlock.unlockBtn=Unlock
## Select
unlock.chooseMasterkey.message=Masterkey file not found
unlock.chooseMasterkey.description=Cryptomator could not find the masterkey file for vault "%s". Please choose the key file manually.
+unlock.chooseMasterkey.restoreInstead=Restore the masterkey file instead
unlock.chooseMasterkey.filePickerTitle=Select Masterkey File
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
## Success
@@ -395,8 +397,9 @@ main.vaultlist.contextMenu.unlockNow=Unlock Now
main.vaultlist.contextMenu.vaultoptions=Show Vault Options
main.vaultlist.contextMenu.reveal=Reveal Drive
main.vaultlist.contextMenu.share=Share…
-main.vaultlist.addVaultBtn.menuItemNew=Create New Vault...
-main.vaultlist.addVaultBtn.menuItemExisting=Open Existing Vault...
+main.vaultlist.addVaultBtn.menuItemNew=Create New Vault…
+main.vaultlist.addVaultBtn.menuItemExisting=Open Existing Vault…
+main.vaultlist.addVaultBtn.menuItemRecover=Recover Existing Vault…
main.vaultlist.showEventsButton.tooltip=Open event view
##Notificaition
main.notification.updateAvailable=Update is available.
@@ -434,6 +437,9 @@ main.vaultDetail.missing.info=Cryptomator could not find a vault at this path.
main.vaultDetail.missing.recheck=Recheck
main.vaultDetail.missing.remove=Remove from Vault List…
main.vaultDetail.missing.changeLocation=Change Vault Location…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Vault config is missing.
+main.vaultDetail.missingVaultConfig.restore=Restore vault config
### Needs Migration
main.vaultDetail.migrateButton=Upgrade Vault
main.vaultDetail.migratePrompt=Your vault needs to be upgraded to a new format, before you can access it
@@ -498,6 +504,7 @@ vaultOptions.hub.convertBtn=Convert to Password-Based Vault
recoveryKey.display.title=Show Recovery Key
recoveryKey.create.message=Password required
recoveryKey.create.description=Enter the password for "%s" to show its recovery key.
+recoveryKey.recover.description=Enter the password for "%s" to recover the vault config.
recoveryKey.display.description=The following recovery key can be used to restore access to "%s":
recoveryKey.display.StorageHints=Keep it somewhere very secure, e.g.:\n • Store it using a password manager\n • Save it on a USB flash drive\n • Print it on paper
## Reset Password
@@ -510,9 +517,59 @@ recoveryKey.recover.invalidKey=This recovery key is not valid
recoveryKey.printout.heading=Cryptomator Recovery Key\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Reset
+recoveryKey.recover.recoverBtn=Recover
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Password reset successful
recoveryKey.recover.resetSuccess.description=You can unlock your vault with the new password.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetVaultConfigSuccess.message=Vault configuration recovered
+recoveryKey.recover.resetMasterkeyFileSuccess.message=Masterkey file recovered
+recoveryKey.recover.resetMasterkeyFileSuccess.description=You can unlock your vault with your password now.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Vault Added
+recover.existing.message=The vault was added successfully
+recover.existing.description=Your vault "%s" has been added to the vault list. No recovery process was necessary.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Vault Already Exists
+recover.alreadyExists.message=This vault has already been added
+recover.alreadyExists.description=Your vault "%s" is already present in your vault list and was therefore not added again.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Invalid Selection
+recover.invalidSelection.message=Your selection is not a vault
+recover.invalidSelection.description=The selected folder must be a valid Cryptomator vault.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Vault
+contactHubVaultOwner.message=This vault was created with Cryptomator Hub
+contactHubVaultOwner.description=Please reach out to the vault owner to restore the missing file. They can download the vault template from Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Recover Vault Config
+recover.recoverMasterkey.title=Recover Masterkey
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Choose recovery method:
+recover.onBoarding.useRecoveryKey=Use Recovery Key
+recover.onBoarding.usePassword=Use Password
+recover.onBoarding.intro=Make sure to check the following:
+recover.onBoarding.pleaseConfirm=Before proceeding, please confirm that:
+recover.onBoarding.otherwisePleaseConfirm=Otherwise, please confirm that:
+recover.onBoarding.allMissing.intro=If this vault is managed by Cryptomator Hub, the vault owner must restore it for you.
+recover.onBoarding.intro.ensure=All files are fully synced.
+recover.onBoarding.affirmation=I have read and understood these requirements
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=You have the recovery key and know if expert settings were used.
+recover.onBoarding.intro.password=You have the vault password and know if expert settings were used.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=You have the vault recovery key.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=This value must match the one used before recovery to ensure compatibility with previously encrypted data.
# Convert Vault
convertVault.title=Convert Vault
diff --git a/src/main/resources/i18n/strings_af.properties b/src/main/resources/i18n/strings_af.properties
index aa86df2bd..8c48fa5b9 100644
--- a/src/main/resources/i18n/strings_af.properties
+++ b/src/main/resources/i18n/strings_af.properties
@@ -87,6 +87,7 @@
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -105,6 +106,25 @@
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_ar.properties b/src/main/resources/i18n/strings_ar.properties
index ecf480be6..371a1d2d8 100644
--- a/src/main/resources/i18n/strings_ar.properties
+++ b/src/main/resources/i18n/strings_ar.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=افتح الان
main.vaultlist.contextMenu.vaultoptions=إظهار خيارات المخزن
main.vaultlist.contextMenu.reveal=اظهار القرص
main.vaultlist.contextMenu.share=مشاركة…
-main.vaultlist.addVaultBtn.menuItemNew=إنشاء مخزن جديد...
-main.vaultlist.addVaultBtn.menuItemExisting=افتح مخزن موجود...
main.vaultlist.showEventsButton.tooltip=عرض الإشعارات
##Notificaition
main.notification.updateAvailable=هناك تحديث متاح.
@@ -433,6 +431,7 @@ main.vaultDetail.missing.info=لم يتمكن Cryptomator من العثور عل
main.vaultDetail.missing.recheck=إعادة الفحص
main.vaultDetail.missing.remove=حذف من قائمة الخزنات…
main.vaultDetail.missing.changeLocation=تغيير موقع الخزنة…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=ترقية الحافظة
main.vaultDetail.migratePrompt=يجب ترقية المخزن الخاص بك إلى تنسيق جديد، قبل أن تتمكن من الوصول إليه
@@ -512,6 +511,26 @@ recoveryKey.recover.resetBtn=إعادة الضبط
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=تم إعادة تعيين كلمة المرور بنجاح
recoveryKey.recover.resetSuccess.description=يمكنك فتح الخزانة الخاصة بك بكلمة المرور الجديدة.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=خزانة Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=تحويل الخزانة
diff --git a/src/main/resources/i18n/strings_ba.properties b/src/main/resources/i18n/strings_ba.properties
index a4020caa5..f0cdaf0b8 100644
--- a/src/main/resources/i18n/strings_ba.properties
+++ b/src/main/resources/i18n/strings_ba.properties
@@ -394,6 +394,7 @@ main.vaultDetail.missing.info=Cryptomator был юлдан һаҡлағыс т
main.vaultDetail.missing.recheck=Яңынан тикшер
main.vaultDetail.missing.remove=Һаҡлағыс исемлегенән алып ташла…
main.vaultDetail.missing.changeLocation=Һаҡлағыс урынын үҙгәрт…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Һаҡлағысты яңыртыу
main.vaultDetail.migratePrompt=Һаҡлағысҡа инер алдынан уны яңы форматҡа тиклем яңыртыу кәрәк
@@ -472,6 +473,26 @@ recoveryKey.recover.resetBtn=Яңынан башла
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Серһүҙ яңыртыу уңышлы тамамланды
recoveryKey.recover.resetSuccess.description=Яңы серһүҙ менән һаҡлағысты аса алаһығыҙ.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Һаҡлағыс хабы
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Һаҡлағысты үҙгәртеү
diff --git a/src/main/resources/i18n/strings_be.properties b/src/main/resources/i18n/strings_be.properties
index 49794305e..cb7757370 100644
--- a/src/main/resources/i18n/strings_be.properties
+++ b/src/main/resources/i18n/strings_be.properties
@@ -381,6 +381,7 @@ main.vaultDetail.missing.info=Cryptomator ня змог знайсці скар
main.vaultDetail.missing.recheck=Пераправерыць
main.vaultDetail.missing.remove=Выдаліць са спісу скарбніц…
main.vaultDetail.missing.changeLocation=Змяніць месцазнаходжанне скарбніцы…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Абнавіць скарбніцу
main.vaultDetail.migratePrompt=Тваю скарбніцу трэба сканвертаваць у новы фармат, перад тым як ты зможаш атрымаць доступ да яе
@@ -454,6 +455,25 @@ recoveryKey.recover.resetBtn=Скінуць
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Пароль паспяхова скінуты
recoveryKey.recover.resetSuccess.description=Ты можаш разамкнуць сваю скарбніцу з дапамогаю новага паролю.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Перабудаваць скарбніцу
diff --git a/src/main/resources/i18n/strings_bg.properties b/src/main/resources/i18n/strings_bg.properties
index 1f366aa3b..ad9f55daf 100644
--- a/src/main/resources/i18n/strings_bg.properties
+++ b/src/main/resources/i18n/strings_bg.properties
@@ -395,6 +395,7 @@ main.vaultDetail.missing.info=Криптоматор не намира хран
main.vaultDetail.missing.recheck=Повторен опит
main.vaultDetail.missing.remove=Премахване от списъка с хранилищата…
main.vaultDetail.missing.changeLocation=Смяна на мястото на хранилището…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Надграждане на хранилище
main.vaultDetail.migratePrompt=Преди да можете да го достъпвате, хранилището трябва да бъде надградено до новия формат
@@ -473,6 +474,26 @@ recoveryKey.recover.resetBtn=Нулиране
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Паролата е променена
recoveryKey.recover.resetSuccess.description=Можете да отключите хранилището с новата парола.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Хранилище на Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Преобразуване на хранилище
diff --git a/src/main/resources/i18n/strings_bn.properties b/src/main/resources/i18n/strings_bn.properties
index 1e06f4043..c648e94d5 100644
--- a/src/main/resources/i18n/strings_bn.properties
+++ b/src/main/resources/i18n/strings_bn.properties
@@ -149,6 +149,7 @@ main.vaultlist.contextMenu.lock=লক করুন
### Unlocked
main.vaultDetail.lockBtn=লক করুন
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -169,6 +170,25 @@ vaultOptions.mount.mountPoint.directoryPickerButton=নির্বাচন ক
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_bs.properties b/src/main/resources/i18n/strings_bs.properties
index 7ccd204a5..660130a97 100644
--- a/src/main/resources/i18n/strings_bs.properties
+++ b/src/main/resources/i18n/strings_bs.properties
@@ -241,6 +241,7 @@ main.vaultDetail.missing.info=Cryptomator nije mogao pronaći disk na ovoj lokac
main.vaultDetail.missing.recheck=Provjeri ponovo
main.vaultDetail.missing.remove=Ukloni sa liste sefova…
main.vaultDetail.missing.changeLocation=Promijeni lokaciju sefa…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Nadogradi sef
main.vaultDetail.migratePrompt=Da biste mogli pristupiti svom sefu, morate ga nadograditi na novi format
@@ -294,6 +295,25 @@ recoveryKey.recover.correctKey=Ključ za oporavak je ispravan
recoveryKey.printout.heading=Cryptomator Ključ za oporavak za \n"%s"\n
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_ca.properties b/src/main/resources/i18n/strings_ca.properties
index 1a0ccbc57..4e564bcda 100644
--- a/src/main/resources/i18n/strings_ca.properties
+++ b/src/main/resources/i18n/strings_ca.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Desbloqueja ara
main.vaultlist.contextMenu.vaultoptions=Opcions de la caixa forta
main.vaultlist.contextMenu.reveal=Mostra la unitat
main.vaultlist.contextMenu.share=Compateix…
-main.vaultlist.addVaultBtn.menuItemNew=Crea una nova caixa forta…
-main.vaultlist.addVaultBtn.menuItemExisting=Obri una caixa forta existent...
##Notificaition
main.notification.updateAvailable=Hi ha una actualització disponible.
main.notification.support=Doneu suport a Cryptomator.
@@ -429,6 +427,7 @@ main.vaultDetail.missing.info=Cryptomator no ha trobat una caixa forta en aquest
main.vaultDetail.missing.recheck=Torna a comprovar
main.vaultDetail.missing.remove=Eliminar de la llista de la caixa forta…
main.vaultDetail.missing.changeLocation=Canvia la localització de la caixa forta…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Actualitza la caixa forta
main.vaultDetail.migratePrompt=Per accedir a la vostra caixa forta abans cal actualitzar-la al nou format
@@ -508,6 +507,26 @@ recoveryKey.recover.resetBtn=Reinicia
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=S'ha modificat la contrasenya correctament
recoveryKey.recover.resetSuccess.description=Pots desbloquejar la caixa forta amb la nova contrasenya.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Caixa forta de Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Convertir la caixa forta
diff --git a/src/main/resources/i18n/strings_cs.properties b/src/main/resources/i18n/strings_cs.properties
index 0fd46640a..4388e8815 100644
--- a/src/main/resources/i18n/strings_cs.properties
+++ b/src/main/resources/i18n/strings_cs.properties
@@ -396,6 +396,7 @@ main.vaultDetail.missing.info=Cryptomator nemohl najít trezor na této cestě.
main.vaultDetail.missing.recheck=Znovu zkontrolovat
main.vaultDetail.missing.remove=Odebrat ze seznamu trezorů…
main.vaultDetail.missing.changeLocation=Změnit umístění trezoru…
+### Missing Vault Config
### Needs Migration
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
@@ -473,6 +474,26 @@ recoveryKey.recover.resetBtn=Resetovat
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Resetování hesla bylo úspěšné
recoveryKey.recover.resetSuccess.description=Můžete odemknout váš trezor pomocí nového hesla.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub trezor
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Převést trezor
diff --git a/src/main/resources/i18n/strings_da.properties b/src/main/resources/i18n/strings_da.properties
index 0490cdfef..1fca59a3a 100644
--- a/src/main/resources/i18n/strings_da.properties
+++ b/src/main/resources/i18n/strings_da.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Fjern denne fil hvis du har lyst.
## Existing
addvaultwizard.existing.title=Tilføj Eksisterende Boks
addvaultwizard.existing.instruction=Vælgt filen "vault.cryptomator" i mappen med dine boks-filer. Hvis der kun findes en fil med navnet "masterkey.cryptomator", skal du vælge den i stedet.
+addvaultwizard.existing.restore=Gendan…
addvaultwizard.existing.chooseBtn=Vælg…
addvaultwizard.existing.filePickerTitle=Vælg boks-fil
addvaultwizard.existing.filePickerMimeDesc=Cryptomator boks
@@ -127,6 +128,7 @@ unlock.unlockBtn=Lås op
## Select
unlock.chooseMasterkey.message=Hovednøgle-fil ikke fundet
unlock.chooseMasterkey.description=Cryptomator kunne ikke finde hovednøgle-filen for boksen "%s". Vælg venligst filen manuelt.
+unlock.chooseMasterkey.restoreInstead=Gendan i stedet masterkey-filen
unlock.chooseMasterkey.filePickerTitle=Vælg hovednøgle-fil
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator hovednøgle
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Lås op nu
main.vaultlist.contextMenu.vaultoptions=Vis boksindstillinger
main.vaultlist.contextMenu.reveal=Vis drev
main.vaultlist.contextMenu.share=Del…
-main.vaultlist.addVaultBtn.menuItemNew=Opret ny boks...
-main.vaultlist.addVaultBtn.menuItemExisting=Åbn eksisterende boks...
+main.vaultlist.addVaultBtn.menuItemNew=Opret ny boks…
+main.vaultlist.addVaultBtn.menuItemExisting=Åbn eksisterende boks…
+main.vaultlist.addVaultBtn.menuItemRecover=Genopret eksisterende boks…
main.vaultlist.showEventsButton.tooltip=Åbn begivenhedsvisning
##Notificaition
main.notification.updateAvailable=Opdatering er tilgængelig.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator kunne ikke finde en boks på denne sti
main.vaultDetail.missing.recheck=Kontrollér igen
main.vaultDetail.missing.remove=Fjern fra listen over bokse…
main.vaultDetail.missing.changeLocation=Skift placering for boks…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Bokskonfiguration mangler.
+main.vaultDetail.missingVaultConfig.restore=Gendan bokskonfiguration
### Needs Migration
main.vaultDetail.migrateButton=Opgradér boks
main.vaultDetail.migratePrompt=Din boks skal opgraderes til et nyt format, før du kan tilgå den
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Konvertér til adgangskodebaseret boks
recoveryKey.display.title=Vis gendannelsesnøgle
recoveryKey.create.message=Adgangskode krævet
recoveryKey.create.description=Indtast adgangskoden for "%s", for at vise gendannelsesnøglen.
+recoveryKey.recover.description=Indtast adgangskoden for "%s" for at gendanne bokskonfiguration.
recoveryKey.display.description=Den følgende gendannelsesnøgle kan bruges til at genskabe adgang til "%s":
recoveryKey.display.StorageHints=Opbevar den et meget sikkert sted, som fx:\n • Gem den i din adgangskode-manager\n • Gem den på et USB-drev\n • Print den ud på papir
## Reset Password
@@ -509,9 +516,57 @@ recoveryKey.recover.invalidKey=Denne gendannelsesnøgle er ikke gyldig
recoveryKey.printout.heading=Cryptomator gendannelsesnøgle\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Nulstil
+recoveryKey.recover.recoverBtn=Gendan
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Adgangskod nulstillet
recoveryKey.recover.resetSuccess.description=Du kan nu låse din boks op med den nye adgangskode.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Du kan låse din boks op med din adgangskode nu.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Boks tilføjet
+recover.existing.message=Boksen blev tilføjet med succes
+recover.existing.description=Din boks "%s" er blevet tilføjet til bokslisten. Ingen genoprettelsesproces var nødvendig.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Boksen findes allerede
+recover.alreadyExists.message=Denne boks er allerede tilføjet
+recover.alreadyExists.description=Din boks "%s" er allerede til stede i din boksliste og blev derfor ikke tilføjet igen.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Ugyldigt valg
+recover.invalidSelection.message=Dit valg er ikke en boks
+recover.invalidSelection.description=Den valgte mappe skal være en gyldig Cryptomator boks.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Boks
+contactHubVaultOwner.message=Denne boks blev oprettet med Cryptomator Hub
+contactHubVaultOwner.description=Tag venligst kontakt til boksenejer for at gendanne den manglende fil. De kan downloade boksskabelon fra Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Gendan bokskonfiguration
+recover.recoverMasterkey.title=Gendan Masterkey
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Vælg genoprettelsesmetode:
+recover.onBoarding.useRecoveryKey=Brug gendannelsesnøgle
+recover.onBoarding.usePassword=Brug adgangskode
+recover.onBoarding.intro=Sørg for at tjekke følgende:
+recover.onBoarding.pleaseConfirm=Før der fortsættes, bekræftes at:
+recover.onBoarding.otherwisePleaseConfirm=I modsat fald bekræftes følgende:
+recover.onBoarding.allMissing.intro=Hvis denne boks administreres af Cryptomator Hub, skal boksejer gendanne den for dig.
+recover.onBoarding.intro.ensure=Alle filer er fuldt synkroniserede.
+recover.onBoarding.affirmation=Jeg har læst og forstået disse krav
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Du har gendannelsesnøglen og ved, om ekspertindstillinger blev brugt.
+recover.onBoarding.intro.password=Du har boksens adgangskode og ved, om ekspertindstillinger blev brugt.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Du har boksens gendannelsesnøgle.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Denne værdi skal matche den, der blev brugt før gendannelse for at sikre kompatibilitet med tidligere krypterede data.
# Convert Vault
convertVault.title=Konvertér boks
@@ -561,6 +616,7 @@ dokanySupportEnd.preferencesBtn=Åbn Indstillinger
retryIfReadonly.title=Begrænset boksadgang
retryIfReadonly.message=Ingen skriveadgang til boksens mappe
retryIfReadonly.description=Cryptomator kan ikke skrive til boksens mappe. Du kan ændre boksen til at være skrivebeskyttet og prøve igen. Denne indstilling kan være deaktiveret i boksens indstillinger.
+retryIfReadonly.retry=Skift og prøv igen
# Share Vault
shareVault.title=Del Boks
@@ -584,10 +640,39 @@ shareVault.hub.openHub=Åben Cryptomator Hub
# Decrypt File Names
decryptNames.title=Dekryptér Filnavne
+decryptNames.filePicker.title=Vælg krypteret fil
+decryptNames.filePicker.extensionDescription=Cryptomator krypteret fil
+decryptNames.copyTable.tooltip=Kopiér tabel
+decryptNames.clearTable.tooltip=Ryd tabel
decryptNames.copyHint=Kopiér celleindhold med %s
decryptNames.dropZone.message=Slip filer eller klik for at vælge
+decryptNames.dropZone.error.vaultInternalFiles=Boks interne filer med intet dekrypterbart navn valgt
+decryptNames.dropZone.error.foreignFiles=Filer hører ikke til boksen "%s"
+decryptNames.dropZone.error.noDirIdBackup=Mappe af valgte filer indeholder ikke dirId.c9r fil
+decryptNames.dropZone.error.generic=Kunne ikke dekryptere filnavne
# Event View
eventView.title=Begivenheder
+eventView.filter.allVaults=Alle
+eventView.clearListButton.tooltip=Ryd liste
## event list entries
+eventView.entry.vaultLocked.description=Lås "%s" op for detaljer
+eventView.entry.conflictResolved.message=Løst konflikt
+eventView.entry.conflictResolved.showDecrypted=Vis dekrypteret fil
+eventView.entry.conflictResolved.copyDecrypted=Kopiér dekrypteret sti
+eventView.entry.conflict.message=Konfliktløsning mislykkedes
+eventView.entry.conflict.showDecrypted=Vis dekrypteret, original fil
+eventView.entry.conflict.copyDecrypted=Kopier dekrypteret, original sti
+eventView.entry.conflict.showEncrypted=Vis modstridende, krypteret fil
+eventView.entry.conflict.copyEncrypted=Kopier modstridende, krypteret sti
+eventView.entry.decryptionFailed.message=Dekryptering mislykkedes
+eventView.entry.decryptionFailed.showEncrypted=Vis krypteret fil
+eventView.entry.decryptionFailed.copyEncrypted=Kopiér krypteret sti
+eventView.entry.brokenDirFile.message=Brudt mappelink
+eventView.entry.brokenDirFile.showEncrypted=Vis brudt, krypteret link
+eventView.entry.brokenDirFile.copyEncrypted=Kopiér sti til brudt link
+eventView.entry.brokenFileNode.message=Brudt filsystem-node
+eventView.entry.brokenFileNode.showEncrypted=Vis brudt, krypteret node
+eventView.entry.brokenFileNode.copyEncrypted=Kopiér sti af brudt, krypteret node
+eventView.entry.brokenFileNode.copyDecrypted=Kopiér dekrypteret sti
diff --git a/src/main/resources/i18n/strings_de.properties b/src/main/resources/i18n/strings_de.properties
index a7bc6bb3d..261e2f8d7 100644
--- a/src/main/resources/i18n/strings_de.properties
+++ b/src/main/resources/i18n/strings_de.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Du kannst diese Datei löschen.
## Existing
addvaultwizard.existing.title=Bestehenden Tresor hinzufügen
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.restore=Wiederherstellen…
addvaultwizard.existing.chooseBtn=Durchsuchen …
addvaultwizard.existing.filePickerTitle=Tresordatei auswählen
addvaultwizard.existing.filePickerMimeDesc=Cryptomator-Tresor
@@ -127,6 +128,7 @@ unlock.unlockBtn=Entsperren
## Select
unlock.chooseMasterkey.message=Masterkey-Datei nicht gefunden
unlock.chooseMasterkey.description=Cryptomator konnte die Masterkey-Datei des Tresors „%s“ nicht finden. Bitte wähle die Datei manuell aus.
+unlock.chooseMasterkey.restoreInstead=Masterkey Datei wiederherstellen
unlock.chooseMasterkey.filePickerTitle=Masterkey-Datei auswählen
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator-Masterkey
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Jetzt entsperren
main.vaultlist.contextMenu.vaultoptions=Tresoroptionen anzeigen
main.vaultlist.contextMenu.reveal=Laufwerk anzeigen
main.vaultlist.contextMenu.share=Teilen …
-main.vaultlist.addVaultBtn.menuItemNew=Neuen Tresor erstellen...
-main.vaultlist.addVaultBtn.menuItemExisting=Bestehenden Tresor öffnen...
+main.vaultlist.addVaultBtn.menuItemNew=Neuen Tresor erstellen…
+main.vaultlist.addVaultBtn.menuItemExisting=Bestehenden Tresor öffnen…
+main.vaultlist.addVaultBtn.menuItemRecover=Bestehenden Tresor wiederherstellen…
main.vaultlist.showEventsButton.tooltip=Ereignis-Ansicht öffnen
##Notificaition
main.notification.updateAvailable=Eine neue Version ist verfügbar.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator konnte keinen Tresor mit diesem Pfad f
main.vaultDetail.missing.recheck=Erneut prüfen
main.vaultDetail.missing.remove=Aus Tresorliste entfernen …
main.vaultDetail.missing.changeLocation=Speicherort des Tresors ändern …
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Tresorkonfiguration fehlt.
+main.vaultDetail.missingVaultConfig.restore=Tresorkonfiguration wiederherstellen
### Needs Migration
main.vaultDetail.migrateButton=Tresor upgraden
main.vaultDetail.migratePrompt=Dein Tresor muss in ein neues Format konvertiert werden, bevor du auf ihn zugreifen kannst
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=In passwortgeschützten Tresor umwandeln
recoveryKey.display.title=Wiederherstellungsschlüssel anzeigen
recoveryKey.create.message=Passwort erforderlich
recoveryKey.create.description=Gib das Passwort für „%s“ ein, um dessen Wiederherstellungsschlüssel anzuzeigen.
+recoveryKey.recover.description=Gib das Passwort für "%s" ein, um die Tresorkonfiguration wiederherzustellen.
recoveryKey.display.description=Mit folgendem Wiederherstellungsschlüssel kannst du den Zugriff auf „%s“ wiederherstellen:
recoveryKey.display.StorageHints=Bewahre ihn möglichst sicher auf, z. B.\n • in einem Passwortmanager\n • auf einem USB-Speicherstick\n • auf Papier ausgedruckt
## Reset Password
@@ -509,9 +516,59 @@ recoveryKey.recover.invalidKey=Dieser Wiederherstellungsschlüssel ist ungültig
recoveryKey.printout.heading=Cryptomator-Wiederherstellungsschlüssel\n„%s“\n
### Reset Password
recoveryKey.recover.resetBtn=Zurücksetzen
+recoveryKey.recover.recoverBtn=Wiederherstellen
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Passwort erfolgreich zurückgesetzt
recoveryKey.recover.resetSuccess.description=Du kannst deinen Tresor mit dem neuen Passwort entsperren.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetVaultConfigSuccess.message=Tresorkonfiguration wiederhergestellt
+recoveryKey.recover.resetMasterkeyFileSuccess.message=Masterkey-Datei wiederhergestellt
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Du kannst deinen Tresor mit dem neuen Passwort jetzt entsperren.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Tresor hinzugefügt
+recover.existing.message=Der Tresor wurde erfolgreich hinzugefügt
+recover.existing.description=Dein Tresor "%s" wurde zur Tresorliste hinzugefügt. Es war kein Wiederherstellungsprozess nötig.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Tresor existiert bereits
+recover.alreadyExists.message=Dieser Tresor wurde bereits hinzugefügt
+recover.alreadyExists.description=Dein Tresor "%s" ist bereits in der Tresorliste vorhanden und wurde daher nicht erneut hinzugefügt.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Ungültige Auswahl
+recover.invalidSelection.message=Der ausgewählte Ordner ist kein Tresor
+recover.invalidSelection.description=Der ausgewählte Ordner muss ein gültiger Cryptomator-Tresor sein.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hubtresor
+contactHubVaultOwner.message=Dieser Tresor wurde mit Cryptomator Hub erstellt
+contactHubVaultOwner.description=Bitte wenden dich an den Tresorbesitzer, um die fehlende Datei wiederherzustellen. Dieser kann die Tresorvorlage von Cryptomator Hub herunterladen.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Tresorkonfiguration wiederherstellen
+recover.recoverMasterkey.title=Masterkey wiederherstellen
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Wähle die Wiederherstellungsmethode:
+recover.onBoarding.useRecoveryKey=Wiederherstellungsschlüssel verwenden
+recover.onBoarding.usePassword=Passwort verwenden
+recover.onBoarding.intro=Stelle sicher, folgendes geprüft zu haben:
+recover.onBoarding.pleaseConfirm=Bevor es weiter geht, bestätige bitte:
+recover.onBoarding.otherwisePleaseConfirm=Andernfalls, bestätige bitte:
+recover.onBoarding.allMissing.intro=Wird der Tresor von Cryptomator Hub verwaltet, muss der Tresorbesitzer ihn für dich wiederherstellen.
+recover.onBoarding.intro.ensure=Alle Dateien sind vollständig synchronisiert.
+recover.onBoarding.affirmation=Ich habe die Anforderungen gelesen und verstanden
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Du besitzt den Wiederherstellungsschlüssel und weißt, ob Experteneinstellungen verwendet wurden.
+recover.onBoarding.intro.password=Du besitzt das Tresorpasswort und weißt, ob Experteneinstellungen verwendet wurden.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Du besitzt den Wiederherstellungsschlüssel.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Um Kompatibilität mit den verschlüsselten Dateien zu gewährleisten, muss der gleiche Wert wie zur Tresorerstellung verwendet werden.
# Convert Vault
convertVault.title=Tresor umwandeln
diff --git a/src/main/resources/i18n/strings_el.properties b/src/main/resources/i18n/strings_el.properties
index 1001d3912..f80ad234d 100644
--- a/src/main/resources/i18n/strings_el.properties
+++ b/src/main/resources/i18n/strings_el.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Ξεκλείδωμα τώρα
main.vaultlist.contextMenu.vaultoptions=Εμφάνιση επιλογών Vault
main.vaultlist.contextMenu.reveal=Αποκάλυψη εικονικού δίσκου
main.vaultlist.contextMenu.share=Κοινοποίηση…
-main.vaultlist.addVaultBtn.menuItemNew=Δημιουργία Νέας Κρύπτης...
-main.vaultlist.addVaultBtn.menuItemExisting=Άνοιγμα Υπάρχοντος Κρύπτης...
main.vaultlist.showEventsButton.tooltip=Άνοιγμα προβολής συμβάντων
##Notificaition
main.notification.updateAvailable=Η ενημέρωση είναι διαθέσιμη.
@@ -433,6 +431,7 @@ main.vaultDetail.missing.info=Cryptomator δεν βρήκε vault σε αυτό
main.vaultDetail.missing.recheck=Επανέλεγχος
main.vaultDetail.missing.remove=Κατάργηση από την λίστα των Vault…
main.vaultDetail.missing.changeLocation=Αλλαγή τοποθεσίας Vault…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Αναβάθμιση Vault
main.vaultDetail.migratePrompt=Το vault σας πρέπει να αναβαθμιστεί σε νέα μορφή, προτού να έχετε πρόσβαση σε αυτό
@@ -512,6 +511,26 @@ recoveryKey.recover.resetBtn=Επαναφορά
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Επιτυχής επαναφορά κωδικού πρόσβασης
recoveryKey.recover.resetSuccess.description=Μπορείτε να ξεκλειδώσετε την κρύπτη σας με το νέο κωδικό πρόσβασης.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Κρύπτη Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Μετατροπή Θησαυ/κιου
diff --git a/src/main/resources/i18n/strings_es.properties b/src/main/resources/i18n/strings_es.properties
index ba47d0131..9c090282d 100644
--- a/src/main/resources/i18n/strings_es.properties
+++ b/src/main/resources/i18n/strings_es.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=No dude en eliminar este archivo.
## Existing
addvaultwizard.existing.title=Añadir bóveda existente
addvaultwizard.existing.instruction=Elija el archivo "vault.cryptomator" de su bóveda existente. Si solo existe un archivo llamado "masterkey.cryptomator", selecciónelo en su lugar.
+addvaultwizard.existing.restore=…
addvaultwizard.existing.chooseBtn=Elegir…
addvaultwizard.existing.filePickerTitle=Seleccionar archivo de bóveda
addvaultwizard.existing.filePickerMimeDesc=Bóveda de Cryptomator
@@ -127,6 +128,7 @@ unlock.unlockBtn=Desbloquear
## Select
unlock.chooseMasterkey.message=Archivo de la clave maestra no encontrado
unlock.chooseMasterkey.description=No se pudo encontrar el archivo de la clave maestra para la bóveda "%s". Por favor, elija manualmente el archivo de la clave.
+unlock.chooseMasterkey.restoreInstead=
unlock.chooseMasterkey.filePickerTitle=Seleccione el archivo de la clave maestra
unlock.chooseMasterkey.filePickerMimeDesc=Clave maestra de Cryptomator
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Desbloquear ahora
main.vaultlist.contextMenu.vaultoptions=Mostrar opciones de la bóveda
main.vaultlist.contextMenu.reveal=Revelar unidad
main.vaultlist.contextMenu.share=Compartir…
-main.vaultlist.addVaultBtn.menuItemNew=Crear Bóveda Nueva...
-main.vaultlist.addVaultBtn.menuItemExisting=Abrir Bóveda Existente...
+main.vaultlist.addVaultBtn.menuItemNew=
+main.vaultlist.addVaultBtn.menuItemExisting=
+main.vaultlist.addVaultBtn.menuItemRecover=
main.vaultlist.showEventsButton.tooltip=Abrir vista de evento
##Notificaition
main.notification.updateAvailable=Existen actualizaciones disponibles.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator no pudo encontrar una bóveda en esta
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…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Falta la configuración de la bóveda.
+main.vaultDetail.missingVaultConfig.restore=
### Needs Migration
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
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Convertir a Bóveda con Contraseña
recoveryKey.display.title=Mostrar clave de recuperación
recoveryKey.create.message=Contraseña requerida
recoveryKey.create.description=Ingresar la contraseña para mostrar la clave de recuperación para "%s":
+recoveryKey.recover.description=
recoveryKey.display.description=La siguiente clave de recuperación puede usarse para restaurar el acceso a "%s":
recoveryKey.display.StorageHints=Manténgala en algún lugar seguro, p.ej.:\n • Almacenarla en un administrador de contraseñas\n • Guardarla en una llave USB\n • Imprimirla en un papel
## Reset Password
@@ -512,6 +519,26 @@ recoveryKey.recover.resetBtn=## Reiniciar contraseña\nrecoveryKey.recover.reset
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Contraseña restablecida con éxito
recoveryKey.recover.resetSuccess.description=Puede desbloquear su bóveda con la contraseña nueva.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Bóveda de Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Convertir bóveda
diff --git a/src/main/resources/i18n/strings_fa.properties b/src/main/resources/i18n/strings_fa.properties
index d88e3ce7b..118306ce7 100644
--- a/src/main/resources/i18n/strings_fa.properties
+++ b/src/main/resources/i18n/strings_fa.properties
@@ -183,6 +183,7 @@ main.vaultlist.contextMenu.reveal=نمایش درایو
main.vaultDetail.revealBtn=نمایش درایو
main.vaultDetail.lockBtn=قفل
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -204,6 +205,25 @@ vaultOptions.mount.mountPoint.directoryPickerButton=انتخاب کنید…
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_fi.properties b/src/main/resources/i18n/strings_fi.properties
index e6ec743e5..77d4765bd 100644
--- a/src/main/resources/i18n/strings_fi.properties
+++ b/src/main/resources/i18n/strings_fi.properties
@@ -393,8 +393,6 @@ main.vaultlist.contextMenu.unlockNow=Avaa Nyt
main.vaultlist.contextMenu.vaultoptions=Näytä holvin asetukset
main.vaultlist.contextMenu.reveal=Paljasta Asema
main.vaultlist.contextMenu.share=Jaa…
-main.vaultlist.addVaultBtn.menuItemNew=Luo uusi holvi...
-main.vaultlist.addVaultBtn.menuItemExisting=Avaa olemassa oleva holvi...
main.vaultlist.showEventsButton.tooltip=Avaa tapahtumanäkymä
##Notificaition
main.notification.updateAvailable=Päivitys on saatavilla.
@@ -432,6 +430,7 @@ main.vaultDetail.missing.info=Cryptomator ei löytänyt täältä holvia.
main.vaultDetail.missing.recheck=Tarkista uudelleen
main.vaultDetail.missing.remove=Poista holvilistalta…
main.vaultDetail.missing.changeLocation=Vaihda holvin sijaintia…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Päivitä Holvi
main.vaultDetail.migratePrompt=Holvisi täytyy muuntaa uuteen muotoon ennen kuin voit avata sen
@@ -511,6 +510,25 @@ recoveryKey.recover.resetBtn=Palauta
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Salasanan palautus onnistui
recoveryKey.recover.resetSuccess.description=Voit avata holvin uudella salasanalla.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Muunna holvi
diff --git a/src/main/resources/i18n/strings_fil.properties b/src/main/resources/i18n/strings_fil.properties
index b094e4943..148e36434 100644
--- a/src/main/resources/i18n/strings_fil.properties
+++ b/src/main/resources/i18n/strings_fil.properties
@@ -416,6 +416,7 @@ main.vaultDetail.missing.info=Hindi makahanap ng vault ang Cryptomator sa landas
main.vaultDetail.missing.recheck=Suriin muli
main.vaultDetail.missing.remove=Alisin sa Listahan ng Vault…
main.vaultDetail.missing.changeLocation=Baguhin ang Lokasyon ng Vault…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=I-upgrade ang Vault
main.vaultDetail.migratePrompt=Kailangang i-upgrade ang iyong vault sa bagong format, bago mo ito ma-access
@@ -495,6 +496,26 @@ recoveryKey.recover.resetBtn=I-reset
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Matagumpay ang pag-reset ng password
recoveryKey.recover.resetSuccess.description=Maaari mong i-unlock ang iyong vault gamit ang bagong password.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Vault
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=I-convert ang Vault
diff --git a/src/main/resources/i18n/strings_fr.properties b/src/main/resources/i18n/strings_fr.properties
index 081e79a45..26d27cd6a 100644
--- a/src/main/resources/i18n/strings_fr.properties
+++ b/src/main/resources/i18n/strings_fr.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Vous pouvez supprimer ce fichier.
## Existing
addvaultwizard.existing.title=Ajouter un coffre existant
addvaultwizard.existing.instruction=Choisissez le fichier « vault.cryptomator » de votre volume existant. Si seul le fichier « masterkey.cryptomator » est présent, sélectionnez celui-là.
+addvaultwizard.existing.restore=Restaurer…
addvaultwizard.existing.chooseBtn=Choisir…
addvaultwizard.existing.filePickerTitle=Sélectionnez le fichier correspondant au volume chiffré
addvaultwizard.existing.filePickerMimeDesc=Coffre-fort Cryptomator
@@ -127,6 +128,7 @@ unlock.unlockBtn=Déverrouiller
## Select
unlock.chooseMasterkey.message=Fichier Masterkey introuvable
unlock.chooseMasterkey.description=Impossible de trouver le fichier clef à l'adresse attendue pour l'espace chiffré "%s". Veuillez sélectionner le fichier clef manuellement.
+unlock.chooseMasterkey.restoreInstead=Restaurez le fichier masterkey à la place
unlock.chooseMasterkey.filePickerTitle=Sélectionner le fichier clef
unlock.chooseMasterkey.filePickerMimeDesc=Clé principale Cryptomator
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Déverrouiller maintenant
main.vaultlist.contextMenu.vaultoptions=Afficher les options du volume chiffré
main.vaultlist.contextMenu.reveal=Afficher le lecteur
main.vaultlist.contextMenu.share=Partager…
-main.vaultlist.addVaultBtn.menuItemNew=Créer un nouveau coffre...
-main.vaultlist.addVaultBtn.menuItemExisting=Ouvrir un coffre existant...
+main.vaultlist.addVaultBtn.menuItemNew=Créer un nouveau coffre…
+main.vaultlist.addVaultBtn.menuItemExisting=Ouvrir le coffre existant…
+main.vaultlist.addVaultBtn.menuItemRecover=Restaurer le coffre existant…
main.vaultlist.showEventsButton.tooltip=Ouvrir la vue Événements
##Notificaition
main.notification.updateAvailable=Mise à jour disponible.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator n'a pas pu trouver de volume chiffré
main.vaultDetail.missing.recheck=Revérifier
main.vaultDetail.missing.remove=Retirer de la liste des volumes…
main.vaultDetail.missing.changeLocation=Changer l'emplacement du volume…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=La configuration du coffre est manquante.
+main.vaultDetail.missingVaultConfig.restore=Restaurer la configuration du coffre
### Needs Migration
main.vaultDetail.migrateButton=Mettre le volume à jour
main.vaultDetail.migratePrompt=Votre coffre doit être converti dans un nouveau format avant d'y accéder
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Convertir en coffre-fort basé sur mot de passe
recoveryKey.display.title=Montrer la clé de récupération
recoveryKey.create.message=Mot de passe requis
recoveryKey.create.description=Entrez le mot de passe de "%s" pour afficher sa clé de récupération.
+recoveryKey.recover.description=Entrez le mot de passe pour "%s" pour restaurer la configuration du coffre.
recoveryKey.display.description=La clé de récupération suivante peut être utilisée pour restaurer l'accès à "%s " :
recoveryKey.display.StorageHints=Gardez-la dans un endroit sûr, par ex. :\n • Stockez-la en utilisant un gestionnaire de mots de passe\n • Enregistrez-la sur une clé USB\n • Imprimez-la
## Reset Password
@@ -509,9 +516,57 @@ recoveryKey.recover.invalidKey=Cette clé de récupération n'est pas valide
recoveryKey.printout.heading=Clé de récupération Cryptomator "%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Réinitialiser
+recoveryKey.recover.recoverBtn=Restaurer
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Réinitialisation du mot de passe réussie
recoveryKey.recover.resetSuccess.description=Vous pouvez déverrouiller votre coffre avec le nouveau mot de passe.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Vous pouvez maintenant déverrouiller votre coffre avec votre mot de passe.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Coffre ajouté
+recover.existing.message=Le coffre a été ajouté avec succès
+recover.existing.description=Votre coffre "%s" a été ajouté à la liste des coffres. Aucun processus de récupération n'a été nécessaire.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Le coffre-fort existe déjà
+recover.alreadyExists.message=Ce coffre a déjà été ajouté
+recover.alreadyExists.description=Votre coffre «%s» est déjà présent dans votre liste de coffres et n'a donc pas été ajouté à nouveau.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Sélection invalide
+recover.invalidSelection.message=Votre sélection n'est pas un coffre
+recover.invalidSelection.description=Le dossier sélectionné doit être un coffre Cryptomator valide.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Coffre dans Hub
+contactHubVaultOwner.message=Ce coffre a été créé avec le Hub Cryptomator
+contactHubVaultOwner.description=.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Récupérer la configuration du coffre
+recover.recoverMasterkey.title=Récupérer la clé principale
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Choisissez la méthode de récupération :
+recover.onBoarding.useRecoveryKey=Utiliser la clé de récupération
+recover.onBoarding.usePassword=Utiliser mot de passe
+recover.onBoarding.intro=Assurez-vous de vérifier ce qui suit :
+recover.onBoarding.pleaseConfirm=Avant de procéder, veuillez confirmer ceci :
+recover.onBoarding.otherwisePleaseConfirm=Sinon, veuillez confirmer ceci:
+recover.onBoarding.allMissing.intro=Si ce coffre est géré par Cryptomator Hub, le propriétaire du coffre doit le restaurer pour vous.
+recover.onBoarding.intro.ensure=.
+recover.onBoarding.affirmation=J'ai lu et compris ces prérequis
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Vous avez la clé de récupération et et savez si les paramètres experts ont été utilisés.
+recover.onBoarding.intro.password=Vous avez le mot de passe du coffre et savez si les paramètres experts ont été utilisés.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Vous avez la clé de récupération du coffre.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=
# Convert Vault
convertVault.title=Convertir le coffre
diff --git a/src/main/resources/i18n/strings_gl.properties b/src/main/resources/i18n/strings_gl.properties
index 67c6128b6..89979bfa5 100644
--- a/src/main/resources/i18n/strings_gl.properties
+++ b/src/main/resources/i18n/strings_gl.properties
@@ -101,6 +101,7 @@ lock.forced.retryBtn=Tentar de novo
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -119,6 +120,25 @@ lock.forced.retryBtn=Tentar de novo
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_he.properties b/src/main/resources/i18n/strings_he.properties
index 71769b20c..ced71d1c2 100644
--- a/src/main/resources/i18n/strings_he.properties
+++ b/src/main/resources/i18n/strings_he.properties
@@ -384,6 +384,7 @@ main.vaultDetail.missing.info=Cryptomator לא הצליח למצוא כספת ב
main.vaultDetail.missing.recheck=בדיקה נוספת
main.vaultDetail.missing.remove=הסר מרשימה הכספות…
main.vaultDetail.missing.changeLocation=שנה את מיקום הכספת…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=שדרג הכספת
main.vaultDetail.migratePrompt=צריך לשדרג את הכספת שלך לגרסה חדשה לפני שניתן לגשת אליה
@@ -455,6 +456,25 @@ recoveryKey.recover.resetBtn=איפוס
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=איפוס סיסמה הצליח
recoveryKey.recover.resetSuccess.description=ניתן לפתוח את הכספת עם הסיסמה החדשה.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.convert.convertBtn.before=להמיר
diff --git a/src/main/resources/i18n/strings_hi.properties b/src/main/resources/i18n/strings_hi.properties
index bcc83679d..659d85c1d 100644
--- a/src/main/resources/i18n/strings_hi.properties
+++ b/src/main/resources/i18n/strings_hi.properties
@@ -256,6 +256,7 @@ main.vaultDetail.lockBtn=लॉक करें
main.vaultDetail.stats=वॉल्ट के आंकड़े
### Missing
main.vaultDetail.missing.remove=वॉल्ट की सूची से हटाए।
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=वाउल्ट को अपग्रेड करें
### Error
@@ -291,6 +292,25 @@ recoveryKey.create.description=रिकवरी-की दिखाने क
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_hr.properties b/src/main/resources/i18n/strings_hr.properties
index a698cf329..6d4dff104 100644
--- a/src/main/resources/i18n/strings_hr.properties
+++ b/src/main/resources/i18n/strings_hr.properties
@@ -298,6 +298,7 @@ main.vaultDetail.missing.info=Cryptomator nije mogao pronaći trezor s ovom puta
main.vaultDetail.missing.recheck=Ponovo provjeri
main.vaultDetail.missing.remove=Ukloni iz liste trezora…
main.vaultDetail.missing.changeLocation=Promijeni lokaciju trezora…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Nadogradi trezor
main.vaultDetail.migratePrompt=Vaš trezor treba se nadograditi na novi format, prije nego mu možete pristupiti
@@ -357,6 +358,25 @@ recoveryKey.recover.correctKey=Ovo je valjani ključ za oporavak
recoveryKey.printout.heading=Cryptomator-ov ključ za oporavak\n"%s"\n
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_hu.properties b/src/main/resources/i18n/strings_hu.properties
index 982e36fbd..c0f11bd18 100644
--- a/src/main/resources/i18n/strings_hu.properties
+++ b/src/main/resources/i18n/strings_hu.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Azonnali feloldás
main.vaultlist.contextMenu.vaultoptions=Széf beállítások
main.vaultlist.contextMenu.reveal=Széf megjelenítése
main.vaultlist.contextMenu.share=Megosztás…
-main.vaultlist.addVaultBtn.menuItemNew=Új széf létrehozása...
-main.vaultlist.addVaultBtn.menuItemExisting=Meglévő széf megnyitása...
##Notificaition
main.notification.updateAvailable=Frissítés elérhető.
main.notification.support=Cryptomator támogatása.
@@ -429,6 +427,7 @@ main.vaultDetail.missing.info=A Cryptomator nem talált széfet ezen az útvonal
main.vaultDetail.missing.recheck=Ellenőrizze újra
main.vaultDetail.missing.remove=A széf eltávolítása a listából…
main.vaultDetail.missing.changeLocation=A széf helyének megváltoztatása…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Széf frissítése
main.vaultDetail.migratePrompt=A széfet új formátumra kell frissíteni, mielőtt hozzáférhet
@@ -508,6 +507,26 @@ recoveryKey.recover.resetBtn=Visszaállítás
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=A jelszó alaphelyzetbe állítása sikeresen megtörtént
recoveryKey.recover.resetSuccess.description=Feloldhatja a széfet az új jelszóval.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub széf
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Széf átalakítása
diff --git a/src/main/resources/i18n/strings_id.properties b/src/main/resources/i18n/strings_id.properties
index bfaa7afdb..5082ef7b1 100644
--- a/src/main/resources/i18n/strings_id.properties
+++ b/src/main/resources/i18n/strings_id.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Buka Kunci Sekarang
main.vaultlist.contextMenu.vaultoptions=Tampilkan Opsi Vault
main.vaultlist.contextMenu.reveal=Buka Drive
main.vaultlist.contextMenu.share=Bagikan…
-main.vaultlist.addVaultBtn.menuItemNew=Buat Vault Baru...
-main.vaultlist.addVaultBtn.menuItemExisting=Buka Vault yang Tersedia...
##Notificaition
main.notification.updateAvailable=Pembaruan tersedia.
main.notification.support=Dukung Cryptomator.
@@ -429,6 +427,7 @@ main.vaultDetail.missing.info=Cryptomator tidak dapat menemukan vault di path in
main.vaultDetail.missing.recheck=Periksa kembali
main.vaultDetail.missing.remove=Hapus dari Daftar Vault…
main.vaultDetail.missing.changeLocation=Ganti Lokasi Vault…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Tingkatkan Vault
main.vaultDetail.migratePrompt=Vault Anda perlu ditingkatkan ke format baru, sebelum Anda dapat mengaksesnya
@@ -508,6 +507,26 @@ recoveryKey.recover.resetBtn=Atur ulang
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Atur ulang kata sandi berhasil
recoveryKey.recover.resetSuccess.description=Anda dapat membuka kunci vault Anda dengan kata sandi baru.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Vault
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Konversi Vault
diff --git a/src/main/resources/i18n/strings_it.properties b/src/main/resources/i18n/strings_it.properties
index 7584e9bf1..ac90d3acb 100644
--- a/src/main/resources/i18n/strings_it.properties
+++ b/src/main/resources/i18n/strings_it.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Sentiti libero di rimuovere questo file.
## Existing
addvaultwizard.existing.title=Aggiungi una Cassaforte Esistente
addvaultwizard.existing.instruction=Scegliere il file "vault.cryptomator" della tua cassaforte. Se esiste solo un file chiamato "masterkey.cryptomator", allora scegli quello.
+addvaultwizard.existing.restore=Ripristina…
addvaultwizard.existing.chooseBtn=Scegli…
addvaultwizard.existing.filePickerTitle=Seleziona file cassaforte
addvaultwizard.existing.filePickerMimeDesc=Cassaforte di Cryptomator
@@ -127,6 +128,7 @@ unlock.unlockBtn=Sblocca
## Select
unlock.chooseMasterkey.message=File Masterkey non trovato
unlock.chooseMasterkey.description=Impossibile trovare il file Masterkey per questa cassaforte alla sua posizione prevista. Sei pregato di sceglierlo manualmente.
+unlock.chooseMasterkey.restoreInstead=Ripristina invece il file con la chiave principale
unlock.chooseMasterkey.filePickerTitle=Seleziona il File Masterkey
unlock.chooseMasterkey.filePickerMimeDesc=Chiave principale di Cryptomator
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Sblocca Ora
main.vaultlist.contextMenu.vaultoptions=Mostra le Opzioni della Cassaforte
main.vaultlist.contextMenu.reveal=Rivela Unità
main.vaultlist.contextMenu.share=Condividi…
-main.vaultlist.addVaultBtn.menuItemNew=Crea una nuova cassaforte...
-main.vaultlist.addVaultBtn.menuItemExisting=Apri una cassaforte esistente...
+main.vaultlist.addVaultBtn.menuItemNew=Crea una nuova cassaforte…
+main.vaultlist.addVaultBtn.menuItemExisting=Apri una cassaforte esistente…
+main.vaultlist.addVaultBtn.menuItemRecover=Recupera una cassaforte esistente…
main.vaultlist.showEventsButton.tooltip=Apri vista eventi
##Notificaition
main.notification.updateAvailable=Aggiornamento disponibile.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator non è riuscito a trovare una cassafor
main.vaultDetail.missing.recheck=Ricontrolla
main.vaultDetail.missing.remove=Rimuovi dall'elenco delle casseforti…
main.vaultDetail.missing.changeLocation=Cambia la Posizione della Cassaforte…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Manca la configurazione della cassaforte.
+main.vaultDetail.missingVaultConfig.restore=Ripristina la configurazione della cassaforte
### Needs Migration
main.vaultDetail.migrateButton=Aggiorna la Cassaforte
main.vaultDetail.migratePrompt=La tua cassaforte dev'esser aggiornata a un nuovo formato, prima di potervi accedere
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Converti in cassaforte basata su password
recoveryKey.display.title=Mostra Chiave Di Recupero
recoveryKey.create.message=Password richiesta
recoveryKey.create.description=Inserisci la password per visualizzare la chiave di recupero per "%s":
+recoveryKey.recover.description=Inserisci la password di "%s" per recuperare la configurazione della cassaforte.
recoveryKey.display.description=La seguente chiave di recupero può essere utilizzata per ripristinare l'accesso a %s":
recoveryKey.display.StorageHints=Conservala da qualche parte in modo sicuro, es.\n • Archiviarla usando un gestore di password\n • Salvarla su un'unità flash USB\n • Stamparla su carta
## Reset Password
@@ -509,9 +516,57 @@ recoveryKey.recover.invalidKey=Questa chiave di recupero non é valida
recoveryKey.printout.heading=Chiave di recupero Cryptomator\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Reimposta
+recoveryKey.recover.recoverBtn=Recupera
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Password reimpostata correttamente
recoveryKey.recover.resetSuccess.description=Puoi sbloccare la tua cassaforte con la nuova password.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Ora puoi sbloccare la cassaforte con la tua password.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Cassaforte aggiunta
+recover.existing.message=La cassaforte è stata aggiunta con successo
+recover.existing.description=La tua cassaforte "%s" è stata aggiunta alla lista. Non è stata necessaria alcuna azione di recupero.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=La cassaforte esiste già
+recover.alreadyExists.message=Questa cassaforte è già stata aggiunta
+recover.alreadyExists.description=La tua cassaforte "%s" è già presente nella lista, quindi non è stata aggiunta di nuovo.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Selezione non valida
+recover.invalidSelection.message=Quello che hai selezionato non è una cassaforte
+recover.invalidSelection.description=La cartella selezionata deve essere una cassaforte Cryptomator.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Centrale delle Casseforti
+contactHubVaultOwner.message=Questa cassaforte è stata creata con Cryptomator Hub
+contactHubVaultOwner.description=Contatta il proprietario della cassaforte per ripristinare il file mancante. Si può scaricare il modello di cassaforte da Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Ripristina la configurazione della cassaforte
+recover.recoverMasterkey.title=Recupera il file con la chiave principale
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Scegli metodo di recupero:
+recover.onBoarding.useRecoveryKey=Usa la chiave di recupero
+recover.onBoarding.usePassword=Utilizza la password
+recover.onBoarding.intro=Assicurati di controllare quanto segue:
+recover.onBoarding.pleaseConfirm=Prima di procedere, conferma che:
+recover.onBoarding.otherwisePleaseConfirm=In caso contrario, conferma che:
+recover.onBoarding.allMissing.intro=Se questa cassaforte è gestita da Cryptomator Hub, è il proprietario della cassaforte che deve ripristinarla.
+recover.onBoarding.intro.ensure=Tutti i file sono completamente sincronizzati.
+recover.onBoarding.affirmation=Ho letto e compreso questi requisiti
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Hai la chiave di recupero e sai se sono state utilizzate configurazioni avanzate.
+recover.onBoarding.intro.password=Hai la chiave di recupero e sai se sono state utilizzate configurazioni avanzate.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Hai la chiave di ripristino della cassaforte.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Questo valore deve corrispondere a quello usato prima del recupero per garantire la compatibilità con i dati precedentemente crittografati.
# Convert Vault
convertVault.title=Convertire Cassaforte
diff --git a/src/main/resources/i18n/strings_ja.properties b/src/main/resources/i18n/strings_ja.properties
index 8f636c3b4..b114ffa4b 100644
--- a/src/main/resources/i18n/strings_ja.properties
+++ b/src/main/resources/i18n/strings_ja.properties
@@ -391,8 +391,6 @@ main.vaultlist.contextMenu.unlockNow=今すぐ解錠
main.vaultlist.contextMenu.vaultoptions=金庫のオプションを表示
main.vaultlist.contextMenu.reveal=ドライブを表示
main.vaultlist.contextMenu.share=共有…
-main.vaultlist.addVaultBtn.menuItemNew=新しい金庫を作成…
-main.vaultlist.addVaultBtn.menuItemExisting=既存の金庫を開く…
##Notificaition
main.notification.updateAvailable=アップデートがあります。
main.notification.support=Cryptomator を支援する。
@@ -429,6 +427,7 @@ main.vaultDetail.missing.info=Cryptomator はこの場所に金庫を見つけ
main.vaultDetail.missing.recheck=再確認
main.vaultDetail.missing.remove=金庫のリストから削除...
main.vaultDetail.missing.changeLocation=金庫の場所を変更...
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=金庫をアップグレード
main.vaultDetail.migratePrompt=金庫にアクセスする前に、 金庫を新しい形式にアップグレードする必要があります
@@ -508,6 +507,32 @@ recoveryKey.recover.resetBtn=リセット
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=パスワードをリセットしました
recoveryKey.recover.resetSuccess.description=新しいパスワードで金庫の施錠ができます。
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=無効な選択
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=
+
+##Dialog Title
+
+## OnBoarding
+recover.onBoarding.useRecoveryKey=回復キーを利用
+recover.onBoarding.usePassword=パスワードを使用
+recover.onBoarding.pleaseConfirm=続行する前に、以下を確認してください:
+recover.onBoarding.intro.ensure=全てのファイルは完全に同期されています。
+recover.onBoarding.affirmation=私はこれらの要件を読み、理解しました
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=金庫を変換
diff --git a/src/main/resources/i18n/strings_ko.properties b/src/main/resources/i18n/strings_ko.properties
index f1d558447..c344a66e7 100644
--- a/src/main/resources/i18n/strings_ko.properties
+++ b/src/main/resources/i18n/strings_ko.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=지금 잠금 해제
main.vaultlist.contextMenu.vaultoptions=Vault 옵션 보기
main.vaultlist.contextMenu.reveal=드라이브 표시
main.vaultlist.contextMenu.share=공유하기…
-main.vaultlist.addVaultBtn.menuItemNew=새 Vault 생성...
-main.vaultlist.addVaultBtn.menuItemExisting=기존 Vault 열기...
main.vaultlist.showEventsButton.tooltip=이벤트 뷰어 열기
##Notificaition
main.notification.updateAvailable=업데이트가 있습니다.
@@ -433,6 +431,7 @@ main.vaultDetail.missing.info=Cryptomator가 이 경로에 있는 Vault를 찾
main.vaultDetail.missing.recheck=다시 시도
main.vaultDetail.missing.remove=Vault 목록에서 제거...
main.vaultDetail.missing.changeLocation=Vault 위치 변경
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Vault 업그레이드
main.vaultDetail.migratePrompt=Vault에 접근하기 전, 새로운 포맷으로 업그레이드가 필요합니다.
@@ -512,6 +511,26 @@ recoveryKey.recover.resetBtn=초기화
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=비밀번호 재설정 성공
recoveryKey.recover.resetSuccess.description=이제 해당 vault를 새 비밀번호로 잠금 해제할 수 있습니다.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Vault
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Vault 변환
diff --git a/src/main/resources/i18n/strings_lv.properties b/src/main/resources/i18n/strings_lv.properties
index 55657f1ef..8ea784adc 100644
--- a/src/main/resources/i18n/strings_lv.properties
+++ b/src/main/resources/i18n/strings_lv.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Šo datni var droši noņemt.
## Existing
addvaultwizard.existing.title=Pievienot esošu glabātavu
addvaultwizard.existing.instruction=Jāizvēlas esošas glabātavas datne "vault.cryptomator". Ja pastāv tikai datne ar nosaukumu "masterkey.cryptomator", tad jāatlasā tā.
+addvaultwizard.existing.restore=Atjaunot…
addvaultwizard.existing.chooseBtn=Izvēlēties…
addvaultwizard.existing.filePickerTitle=Atlasīt glabātavas datni
addvaultwizard.existing.filePickerMimeDesc=Cryptomator glabātava
@@ -127,6 +128,7 @@ unlock.unlockBtn=Atslēgt
## Select
unlock.chooseMasterkey.message=Galvenās atslēgas datne nav atrasta
unlock.chooseMasterkey.description=Cryptomator nevarēja atrast galvenās atslēgas datni glabātavai "%s". Lūgums pašrocīgi izvēlēties atslēgas datni.
+unlock.chooseMasterkey.restoreInstead=Tā vietā atjaunot galvenās atslēgas datni
unlock.chooseMasterkey.filePickerTitle=Atlasīt galvenās atslēgas datni
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator galvenā atslēga
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Atslēgt tagad
main.vaultlist.contextMenu.vaultoptions=Rādīt glabātavas iespējas
main.vaultlist.contextMenu.reveal=Atklāt disku
main.vaultlist.contextMenu.share=Kopīgot…
-main.vaultlist.addVaultBtn.menuItemNew=Izveidot jaunu glabātavu...
-main.vaultlist.addVaultBtn.menuItemExisting=Atvērt esošu glabātavu...
+main.vaultlist.addVaultBtn.menuItemNew=Izveidot jaunu glabātavu…
+main.vaultlist.addVaultBtn.menuItemExisting=Atvērt esošu glabātavu…
+main.vaultlist.addVaultBtn.menuItemRecover=Atjaunot esošu glabātavu…
main.vaultlist.showEventsButton.tooltip=Atvērt notikumu skatu
##Notificaition
main.notification.updateAvailable=Ir pieejams atjauninājums.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator šajā ceļā nevarēja atrast glabāt
main.vaultDetail.missing.recheck=Pārbaudīt atkārtoti
main.vaultDetail.missing.remove=Noņemt no glabātavu saraksta…
main.vaultDetail.missing.changeLocation=Mainīt glabātavas atrašanās vietu…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Trūkst glabātavas konfigurācijas.
+main.vaultDetail.missingVaultConfig.restore=Atjaunot glabātavas konfigurāciju
### Needs Migration
main.vaultDetail.migrateButton=Jaunināt glabātavu
main.vaultDetail.migratePrompt=Glabātavu ir nepieciešams jaunināt uz jaunu veidolu, pirms tai varēs piekļūt
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Pārveidot par uz paroli balstītu glabātavu
recoveryKey.display.title=Parādīt atkopes atslēgu
recoveryKey.create.message=Nepieciešama parole
recoveryKey.create.description=Jāievada "%s" parole, lai parādītu tās atkopes atslēgu.
+recoveryKey.recover.description=Jāievada “%s” parole, lai atkoptu glabātavas konfigurāciju.
recoveryKey.display.description=Zemāk esošā atkopes atslēga var tikt izmantota, lai atjaunotu piekļuvi "%s":
recoveryKey.display.StorageHints=Tā ir jātur ļoti drošā vietā, piemēram:\n • jāglabā paroļu pārvaldniekā;\n • jāsaglabā USB zibatmiņā;\n • jāizdrukā uz papīra.
## Reset Password
@@ -509,9 +516,57 @@ recoveryKey.recover.invalidKey=Šī atkopes atslēga nav derīga
recoveryKey.printout.heading=Cryptomator atkopes atslēga\n"%s" \n
### Reset Password
recoveryKey.recover.resetBtn=Atiestatīt
+recoveryKey.recover.recoverBtn=Atkopt
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Paroles atiestatīšana sekmīga
recoveryKey.recover.resetSuccess.description=Savu glabātavu var atslēgt ar jauno paroli.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Savu glabātavu tagad var atslēgt ar jauno paroli.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Glabātava pievienota
+recover.existing.message=Glabātava tika sekmīgi pievienota
+recover.existing.description=Glabātava “%s” tika pievienota glabātavu sarakstam. Atkope nebija nepieciešama.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Glabātava jau pastāv
+recover.alreadyExists.message=Šī glabātava jau ir pievienota
+recover.alreadyExists.description=Glabātava “%s” jau ir glabātavu sarakstā, tādējādi tā netika pievienota vēlreiz.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Nederīga atlase
+recover.invalidSelection.message=Atlasītais nav glabātava
+recover.invalidSelection.description=Atlasītajai mapei jābūt derīgai Cryptomator glabātavai.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub glabātava
+contactHubVaultOwner.message=Šī glabātava tika izveidota ar Cryptomator Hub
+contactHubVaultOwner.description=Lūgums vērsties pie glabātavas īpašnieka, lai atjaunotu trūkstošo datni. Glabātavas sagatavi var lejupielādēt no Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Atkopt glabātavas konfigurāciju
+recover.recoverMasterkey.title=Atkopt galveno atslēgu
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Jāizvēlas atkopes veids:
+recover.onBoarding.useRecoveryKey=Izmantot atkopes atslēgu
+recover.onBoarding.usePassword=Izmantot paroli
+recover.onBoarding.intro=Jāpārliecinās, ka ir pārbaudīts šis:
+recover.onBoarding.pleaseConfirm=Pirms turpināšanas lūgums apstiprināt, ka:
+recover.onBoarding.otherwisePleaseConfirm=Pretējā gadījumā lūgums apstiprināt, ka:
+recover.onBoarding.allMissing.intro=Ja šo glabātavu pārvalda Cryptomator Hub, tā ir jāatjauno glabātavas īpašniekam.
+recover.onBoarding.intro.ensure=Visas datnes ir pilnībā sinhronizētas.
+recover.onBoarding.affirmation=Es izlasīju un saprotu šīs prasības
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Tev ir atkopes atslēga, un Tu zini, vai tika izmantoti lietpratēju iestatījumi.
+recover.onBoarding.intro.password=Tev ir glabātavas atslēga, un Tu zini, vai tika izmantoti lietpratēju iestatījumi.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Tev ir glabātavas atkopes atslēga.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Šai vērtībai ir jāatbilst tai, kas tika izmantota pirms atkopes, lai nodrošinatu saderību ar iepriekš šifrētajiem datiem.
# Convert Vault
convertVault.title=Pārveidot glabātavu
diff --git a/src/main/resources/i18n/strings_mk.properties b/src/main/resources/i18n/strings_mk.properties
index f6766ee83..88af16c3b 100644
--- a/src/main/resources/i18n/strings_mk.properties
+++ b/src/main/resources/i18n/strings_mk.properties
@@ -135,6 +135,7 @@ main.vaultlist.contextMenu.lock=Заклучи
### Unlocked
main.vaultDetail.lockBtn=Заклучи
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -155,6 +156,25 @@ vaultOptions.mount.mountPoint.directoryPickerButton=Избор…
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_mr.properties b/src/main/resources/i18n/strings_mr.properties
index aa86df2bd..8c48fa5b9 100644
--- a/src/main/resources/i18n/strings_mr.properties
+++ b/src/main/resources/i18n/strings_mr.properties
@@ -87,6 +87,7 @@
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -105,6 +106,25 @@
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_nb.properties b/src/main/resources/i18n/strings_nb.properties
index 31e302d87..27cf1a23a 100644
--- a/src/main/resources/i18n/strings_nb.properties
+++ b/src/main/resources/i18n/strings_nb.properties
@@ -419,6 +419,7 @@ main.vaultDetail.missing.info=Cryptomator kunne ikke finne et hvelv på denne s
main.vaultDetail.missing.recheck=Kontroller igjen
main.vaultDetail.missing.remove=Fjern fra hvelvlisten…
main.vaultDetail.missing.changeLocation=Endre hvelvplassering…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Oppgrader hvelv
main.vaultDetail.migratePrompt=Hvelvet ditt må oppgraderes til et nytt format før du kan få tilgang til det
@@ -498,6 +499,26 @@ recoveryKey.recover.resetBtn=Nullstill
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Passordnullstillingen vellykket
recoveryKey.recover.resetSuccess.description=Du kan låse opp hvelvet med det nye passordet.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub hvelv
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Konverter hvelvet
diff --git a/src/main/resources/i18n/strings_nl.properties b/src/main/resources/i18n/strings_nl.properties
index 4b6f4ad82..845ca83e2 100644
--- a/src/main/resources/i18n/strings_nl.properties
+++ b/src/main/resources/i18n/strings_nl.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Voel je vrij om dit bestand te verwijderen.
## Existing
addvaultwizard.existing.title=Bestaande kluis toevoegen
addvaultwizard.existing.instruction=Kies het "vault.cryptomator"-bestand van uw bestaande kluis. Indien er enkel een bestand genaamd "masterkey.cryptomator" anwezig is, kies deze dan in de plaats.
+addvaultwizard.existing.restore=Herstel…
addvaultwizard.existing.chooseBtn=Kies…
addvaultwizard.existing.filePickerTitle=Kies kluisbestand
addvaultwizard.existing.filePickerMimeDesc=Cryptomator kluis
@@ -127,6 +128,7 @@ unlock.unlockBtn=Ontgrendel
## Select
unlock.chooseMasterkey.message=Masterkey-bestand niet gevonden
unlock.chooseMasterkey.description=Kon het sleutelbestand voor deze kluis niet vinden op de gewenste locatie. Kies het sleutelbestand handmatig.
+unlock.chooseMasterkey.restoreInstead=Herstel inplaats daarvan het hoofdsleutelbestand
unlock.chooseMasterkey.filePickerTitle=Selecteer het Masterkey-bestand
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Nu Ontgrendelen
main.vaultlist.contextMenu.vaultoptions=Laat kluisinstellingen zien
main.vaultlist.contextMenu.reveal=Toon Schijf
main.vaultlist.contextMenu.share=Delen…
-main.vaultlist.addVaultBtn.menuItemNew=Nieuwe Kluis Aanmaken...
-main.vaultlist.addVaultBtn.menuItemExisting=Open Bestaande Kluis...
+main.vaultlist.addVaultBtn.menuItemNew=Maak een nieuwe kluis aan…
+main.vaultlist.addVaultBtn.menuItemExisting=Open bestaande kluis…
+main.vaultlist.addVaultBtn.menuItemRecover=Herstel bestaande kluis…
main.vaultlist.showEventsButton.tooltip=Afspraakweergave openen
##Notificaition
main.notification.updateAvailable=Update beschikbaar.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator kon op dit pad geen kluis vinden.
main.vaultDetail.missing.recheck=Controleer nog eens
main.vaultDetail.missing.remove=Verwijderen van kluislijst…
main.vaultDetail.missing.changeLocation=Verander de locatie van de kluis…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Het configuratiebestand van de kluis ontbreekt.
+main.vaultDetail.missingVaultConfig.restore=Herstel het configuratiebestand van de kluis
### Needs Migration
main.vaultDetail.migrateButton=Kluis upgraden
main.vaultDetail.migratePrompt=Uw kluis moet worden bijgewerkt naar een nieuw formaat, voordat u deze kunt openen
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Converteren naar Wachtwoord-gebaseerde kluis
recoveryKey.display.title=Toon herstelsleutel
recoveryKey.create.message=Wachtwoord vereist
recoveryKey.create.description=Voer uw wachtwoord in om de herstelsleutel voor "%s" te tonen:
+recoveryKey.recover.description=Voer het wachtwoord voor "%s" in om de kluis te herstellen.
recoveryKey.display.description=De volgende herstelsleutel kan worden gebruikt om "%s" te herstellen:
recoveryKey.display.StorageHints=Bewaar het op een veilige plek, bv:\n • Bewaar het in een wachtwoordmanager\n • Sla het op op een USB-stick\n • Print het op papier
## Reset Password
@@ -509,9 +516,59 @@ recoveryKey.recover.invalidKey=Deze herstelsleutel is niet geldig
recoveryKey.printout.heading=Cryptomator herstelsleutel\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Resetten
+recoveryKey.recover.recoverBtn=Herstellen
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Wachtwoord resetten geslaagd
recoveryKey.recover.resetSuccess.description=Je kunt je kluis ontgrendelen met het nieuwe wachtwoord.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetVaultConfigSuccess.message=Kluis configuratie hersteld
+recoveryKey.recover.resetMasterkeyFileSuccess.message=Masterkey-bestand hersteld
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Je kunt je kluis nu ontgrendelen met je wachtwoord.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Kluis toegevoegd
+recover.existing.message=De kluis is met succes toegevoegd
+recover.existing.description=Uw kluis "%s" is toegevoegd aan de lijst van kluizen. Er was geen herstelproces nodig.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Kluis bestaat al
+recover.alreadyExists.message=Deze kluis is al toegevoegd
+recover.alreadyExists.description=Je kluis "%s" is al aanwezig in je kluis lijst en is daarom niet meer toegevoegd.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Ongeldige selectie
+recover.invalidSelection.message=Jouw selectie is geen kluis
+recover.invalidSelection.description=De geselecteerde map moet een geldige Cryptomator kluis zijn.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Kluis
+contactHubVaultOwner.message=Deze kluis is gemaakt met Cryptomator Hub
+contactHubVaultOwner.description=Neem contact op met de eigenaar van de kluis om het ontbrekende bestand te herstellen. Ze kunnen de kluissjabloon downloaden van Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Herstel het configuratiebestand van de kluis
+recover.recoverMasterkey.title=Masterkey herstellen
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Kies een herstelmethode:
+recover.onBoarding.useRecoveryKey=Herstelsleutel gebruiken
+recover.onBoarding.usePassword=Wachtwoord gebruiken
+recover.onBoarding.intro=Zorg ervoor dat je het volgende controleert:
+recover.onBoarding.pleaseConfirm=Vooraleer verder te gaan, bevestig dat:
+recover.onBoarding.otherwisePleaseConfirm=Anders bevestig dat:
+recover.onBoarding.allMissing.intro=Als deze kluis wordt beheerd door Cryptomator Hub, moet de eigenaar van de kluis deze voor je herstellen.
+recover.onBoarding.intro.ensure=Alle bestanden zijn volledig gesynchroniseerd.
+recover.onBoarding.affirmation=Ik heb deze vereisten gelezen en begrepen
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Je beschikt over de herstelsleutel en weet of de geavanceerde instellingen zijn gebruikt.
+recover.onBoarding.intro.password=Je beschikt over de herstelsleutel en weet of de geavanceerde instellingen zijn gebruikt.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Je hebt de kluis herstelsleutel.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Deze waarde moet overeenkomen met de waarde voor het herstel om de compatibiliteit met eerder versleutelde gegevens te waarborgen.
# Convert Vault
convertVault.title=Kluis converteren
diff --git a/src/main/resources/i18n/strings_nn.properties b/src/main/resources/i18n/strings_nn.properties
index 79672070d..f478d67e8 100644
--- a/src/main/resources/i18n/strings_nn.properties
+++ b/src/main/resources/i18n/strings_nn.properties
@@ -202,6 +202,7 @@ main.vaultDetail.throughput.mbps=%.1f MiB/s
### Missing
main.vaultDetail.missing.info=Cryptomator kunne ikkje finna ein kvelv på denne søkastien.
main.vaultDetail.missing.recheck=Kontroller igjen
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Oppgrader kvelv
main.vaultDetail.migratePrompt=Kvelven din må oppgraderast til eit nytt format før du kan få tilgang til det
@@ -254,6 +255,25 @@ recoveryKey.display.StorageHints=Ta vare på han ein veldig sikker stad, t.d. ve
recoveryKey.printout.heading=Cryptomator-gjenopprettingsnøkkel\n"%s"\n
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_no.properties b/src/main/resources/i18n/strings_no.properties
index aa86df2bd..8c48fa5b9 100644
--- a/src/main/resources/i18n/strings_no.properties
+++ b/src/main/resources/i18n/strings_no.properties
@@ -87,6 +87,7 @@
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -105,6 +106,25 @@
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_pa.properties b/src/main/resources/i18n/strings_pa.properties
index c0a714bda..4c59737c5 100644
--- a/src/main/resources/i18n/strings_pa.properties
+++ b/src/main/resources/i18n/strings_pa.properties
@@ -329,8 +329,6 @@ main.vaultlist.contextMenu.unlockNow=ਹੁਣੇ ਅਣ-ਲਾਕ ਕਰੋ
main.vaultlist.contextMenu.vaultoptions=ਵਾਲਟ ਚੋਣਾਂ ਨੂੰ ਵੇਖਾਓ
main.vaultlist.contextMenu.reveal=ਡਰਾਇਵ ਦਿਖਾਓ
main.vaultlist.contextMenu.share=…ਸਾਂਝਾ ਕਰੋ
-main.vaultlist.addVaultBtn.menuItemNew=...ਨਵਾਂ ਵਾਲਟ ਬਣਾਓ
-main.vaultlist.addVaultBtn.menuItemExisting=...ਮੌਜੂਦਾ ਵਾਲਟ ਨੂੰ ਖੋਲ੍ਹੋ
##Notificaition
main.notification.updateAvailable=ਅੱਪਡੇਟ ਮੌਜੂਦ ਹੈ।
main.notification.support=Cryptomator ਲਈ ਸਹਿਯੋਗ।
@@ -362,6 +360,7 @@ main.vaultDetail.missing.info=Cryptomator ਇਸ ਮਾਗਰ ਉੱਤੇ ਵ
main.vaultDetail.missing.recheck=ਮੁੜ-ਜਾਂਚੋ
main.vaultDetail.missing.remove=ਵਾਲਟ ਸੂਚੀ ਤੋਂ ਹਟਾਓ…
main.vaultDetail.missing.changeLocation=ਵਾਲਟ ਟਿਕਾਣੇ ਨੂੰ ਬਦਲੋ…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=ਵਾਲਟ ਅੱਪਗਰੇਡ ਕਰੋ
main.vaultDetail.migratePrompt=ਤੁਹਾਡੇ ਵਾਲਟ ਨੂੰ ਵਰਤੇ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਨਵੇਂ ਫਾਰਮੈਟ ਲਈ ਅੱਪਗਰੇਡ ਕਰਨ ਦੀ ਲੋੜ ਹੈ
@@ -439,6 +438,26 @@ recoveryKey.recover.resetBtn=ਰੀਸੈੱਟ ਕਰੋ
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=ਪਾਸਵਰਡ ਨੂੰ ਕਾਮਯਾਬੀ ਨਾਲ ਮੁੜ-ਸੈੱਟ ਕੀਤਾ ਗਿਆ
recoveryKey.recover.resetSuccess.description=ਤੁਸੀਂ ਆਪਣੇ ਵਾਲਟ ਨੂੰ ਨਵੇਂ ਪਾਸਵਰਡ ਨਾਲ ਖੋਲ੍ਹ ਸਕਦੇ ਹੋ
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub ਵਾਲਟ
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=ਵਾਲਟ ਨੂੰ ਬਦਲੋ
diff --git a/src/main/resources/i18n/strings_pl.properties b/src/main/resources/i18n/strings_pl.properties
index db7342d0e..600f15cbb 100644
--- a/src/main/resources/i18n/strings_pl.properties
+++ b/src/main/resources/i18n/strings_pl.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Odblokuj teraz
main.vaultlist.contextMenu.vaultoptions=Pokaż opcje sejfu
main.vaultlist.contextMenu.reveal=Otwórz lokalizację
main.vaultlist.contextMenu.share=Udostępnij…
-main.vaultlist.addVaultBtn.menuItemNew=Utwórz Nowy Sejf...
-main.vaultlist.addVaultBtn.menuItemExisting=Otwórz Istniejący Sejf...
main.vaultlist.showEventsButton.tooltip=Otwórz widok wydarzeń
##Notificaition
main.notification.updateAvailable=Dostępna aktualizacja.
@@ -433,6 +431,7 @@ main.vaultDetail.missing.info=Cryptomator nie mógł znaleźć sejfu w tej lokal
main.vaultDetail.missing.recheck=Ponów próbę
main.vaultDetail.missing.remove=Usuń z listy sejfów…
main.vaultDetail.missing.changeLocation=Zmień lokalizację sejfu…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Aktualizuj sejf
main.vaultDetail.migratePrompt=Twój sejf musi zostać zaktualizowany do nowego formatu, zanim będziesz mógł go używać
@@ -512,6 +511,26 @@ recoveryKey.recover.resetBtn=Resetuj
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Hasło zostało zresetowane
recoveryKey.recover.resetSuccess.description=Możesz odblokować sejf przy użyciu nowego hasła.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub sejfów
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Konwertuj sejf
diff --git a/src/main/resources/i18n/strings_pt.properties b/src/main/resources/i18n/strings_pt.properties
index fec088e48..e31e821c7 100644
--- a/src/main/resources/i18n/strings_pt.properties
+++ b/src/main/resources/i18n/strings_pt.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Sinta-se livre para remover este ficheiro.
## Existing
addvaultwizard.existing.title=Adicionar cofre existente
addvaultwizard.existing.instruction=Escolha o ficheiro "vault.cryptomator" do seu cofre. Se encontrar unicamente o ficheiro "masterkey.cryptomator", selecione-o.
+addvaultwizard.existing.restore=Restaurar…
addvaultwizard.existing.chooseBtn=Escolher…
addvaultwizard.existing.filePickerTitle=Selecionar o ficheiro do cofre
addvaultwizard.existing.filePickerMimeDesc=Cofre Cryptomator
@@ -127,6 +128,7 @@ unlock.unlockBtn=Desbloquear
## Select
unlock.chooseMasterkey.message=Chave Mestra não encontrada
unlock.chooseMasterkey.description=Não foi possível encontrar o ficheiro masterkey no local predefinido para este cofre. Por favor, escolha o ficheiro chave manualmente.
+unlock.chooseMasterkey.restoreInstead=Restaure o ficheiro da chave mestra
unlock.chooseMasterkey.filePickerTitle=Selecionar ficheiro MasterKey
unlock.chooseMasterkey.filePickerMimeDesc=Chave Mestra Cryptomator
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Desbloquear agora
main.vaultlist.contextMenu.vaultoptions=Mostrar opções do Cofre
main.vaultlist.contextMenu.reveal=Revelar unidade
main.vaultlist.contextMenu.share=Partilhar…
-main.vaultlist.addVaultBtn.menuItemNew=Criar novo cofre...
-main.vaultlist.addVaultBtn.menuItemExisting=Abrir cofre existente...
+main.vaultlist.addVaultBtn.menuItemNew=Criar novo cofre…
+main.vaultlist.addVaultBtn.menuItemExisting=Abrir cofre existente…
+main.vaultlist.addVaultBtn.menuItemRecover=Recuperar cofre existente…
main.vaultlist.showEventsButton.tooltip=Abrir visualização do evento
##Notificaition
main.notification.updateAvailable=A atualização está disponível.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=O Cryptomator não conseguiu encontrar um cofre ne
main.vaultDetail.missing.recheck=Verificar novamente
main.vaultDetail.missing.remove=Remover da Lista de Cofres…
main.vaultDetail.missing.changeLocation=Mudar localização do Cofre…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=A configuração do cofre está em falta.
+main.vaultDetail.missingVaultConfig.restore=Restaurar configuração do cofre
### Needs Migration
main.vaultDetail.migrateButton=Atualizar Cofre
main.vaultDetail.migratePrompt=O cofre precisa de ser atualizado para um novo formato, antes que possa acessá-lo
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Converter para cofre baseado em palavras-passe
recoveryKey.display.title=Mostrar chave de recuperação
recoveryKey.create.message=Palavra-passe necessária
recoveryKey.create.description=Inserir a palavra passe de "%s" para mostrar a chave de recuperação.
+recoveryKey.recover.description=Introduza a palavra-passe de "%s" para recuperar a configuração do cofre.
recoveryKey.display.description=Esta chave de recuperação pode ser usada para restaurar acesso a "%s":
recoveryKey.display.StorageHints=Guarde-a num lugar muito seguro, por exemplo:\n • Armazená-la usando um gerenciador de senhas\n • Guarde-a numa ‘pen’ USB\n • Imprima-a em papel
## Reset Password
@@ -509,9 +516,57 @@ recoveryKey.recover.invalidKey=Esta chave de recupreação não está certa
recoveryKey.printout.heading=A chave de recuperação do Cryptomator \n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Repor
+recoveryKey.recover.recoverBtn=Recuperar
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Palavra-passe redefinida com sucesso
recoveryKey.recover.resetSuccess.description=Você pode desbloquear o seu cofre com a nova senha.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Agora pode desbloquear o seu cofre com a sua palavra-passe.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Cofre adicionado
+recover.existing.message=O cofre foi adicionado com sucesso
+recover.existing.description=O seu cofre "%s" foi adicionado à lista de cofres. Nenhum processo de recuperação foi necessário.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=O cofre já existe
+recover.alreadyExists.message=Este cofre já foi adicionado
+recover.alreadyExists.description=O seu cofre "%s" já está presente na lista de cofres, por isso, não foi adicionado novamente.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Seleção inválida
+recover.invalidSelection.message=A sua seleção não é um cofre
+recover.invalidSelection.description=A pasta selecionada precisa ser um cofre válido do Cryptomator.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Cofre do Hub
+contactHubVaultOwner.message=Este cofre foi criado com o Cryptomator Hub
+contactHubVaultOwner.description=Contacte o proprietário do cofre para restaurar o ficheiro perdido. Pode descarregar o modelo do cofre no Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Recuperar configuração do cofre
+recover.recoverMasterkey.title=Recuperar chave mestra
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Escolher método de recuperação:
+recover.onBoarding.useRecoveryKey=Usar chave de recuperação
+recover.onBoarding.usePassword=Usar palavra-passe
+recover.onBoarding.intro=Certifique-se de verificar o seguinte:
+recover.onBoarding.pleaseConfirm=Antes de prosseguir, por favor confirme que:
+recover.onBoarding.otherwisePleaseConfirm=Caso contrário, confirme que:
+recover.onBoarding.allMissing.intro=Se este cofre for gerido pelo Cryptomator Hub, o proprietário do cofre deverá restaurá-lo para si.
+recover.onBoarding.intro.ensure=Todos os ficheiros estão totalmente sincronizados.
+recover.onBoarding.affirmation=Li e compreendi estes requisitos
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=Tem a chave de recuperação e sabe se foram utilizadas as definições de especialista.
+recover.onBoarding.intro.password=Tem a palavra-passe do cofre e sabe se foram usadas configurações de especialista.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=Você tem a chave de recuperação do cofre.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Este valor deve corresponder ao utilizado antes da recuperação para garantir a compatibilidade com os dados previamente encriptados.
# Convert Vault
convertVault.title=Converter cofre
diff --git a/src/main/resources/i18n/strings_pt_BR.properties b/src/main/resources/i18n/strings_pt_BR.properties
index 2dea3c44c..19ca593f0 100644
--- a/src/main/resources/i18n/strings_pt_BR.properties
+++ b/src/main/resources/i18n/strings_pt_BR.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Desbloquear Agora
main.vaultlist.contextMenu.vaultoptions=Exibir Opções de Cofre
main.vaultlist.contextMenu.reveal=Revelar Volume
main.vaultlist.contextMenu.share=Compartilhar…
-main.vaultlist.addVaultBtn.menuItemNew=Novo Cofre...
-main.vaultlist.addVaultBtn.menuItemExisting=Abrir Cofre Existente...
main.vaultlist.showEventsButton.tooltip=Abrir visualização de evento
##Notificaition
main.notification.updateAvailable=Atualização disponível.
@@ -433,6 +431,7 @@ main.vaultDetail.missing.info=O Cryptomator não encontrou um cofre neste caminh
main.vaultDetail.missing.recheck=Verificar novamente
main.vaultDetail.missing.remove=Remover da lista de cofres…
main.vaultDetail.missing.changeLocation=Alterar Localização do Cofre…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Atualizar Cofre
main.vaultDetail.migratePrompt=Seu cofre precisa ser atualizado para um novo formato antes de poder acessá-lo
@@ -512,6 +511,26 @@ recoveryKey.recover.resetBtn=Redefinir
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Senha redefinida com sucesso
recoveryKey.recover.resetSuccess.description=Você pode desbloquear o seu cofre com a nova senha.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Cofre do Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Converter Cofre
diff --git a/src/main/resources/i18n/strings_ro.properties b/src/main/resources/i18n/strings_ro.properties
index 308e09290..139d9e6fc 100644
--- a/src/main/resources/i18n/strings_ro.properties
+++ b/src/main/resources/i18n/strings_ro.properties
@@ -390,8 +390,6 @@ main.vaultlist.contextMenu.unlockNow=Deblochează acum
main.vaultlist.contextMenu.vaultoptions=Arată opțiunile seifului
main.vaultlist.contextMenu.reveal=Dezvăluie unitatea
main.vaultlist.contextMenu.share=Distribuie…
-main.vaultlist.addVaultBtn.menuItemNew=Creare seif nou...
-main.vaultlist.addVaultBtn.menuItemExisting=Deschide un seif existent...
##Notificaition
main.notification.updateAvailable=O nouă versiune este valabilă.
main.notification.support=Susține Cryptomator.
@@ -425,6 +423,7 @@ main.vaultDetail.missing.info=Cryptomator nu a putut găsi un seif pe această c
main.vaultDetail.missing.recheck=Verifică din nou
main.vaultDetail.missing.remove=Eliminați din lista de seifuri…
main.vaultDetail.missing.changeLocation=Schimbați locația seifului…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Îmbunătățește seiful
main.vaultDetail.migratePrompt=Înainte de a-l putea accesa, seiful dumneavoastră trebuie actualizat la format nou
@@ -504,6 +503,26 @@ recoveryKey.recover.resetBtn=Resetează
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Parola a fost resetată cu succes
recoveryKey.recover.resetSuccess.description=Puteți debloca seiful cu parola noua.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Seif Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Transformă seiful
diff --git a/src/main/resources/i18n/strings_ru.properties b/src/main/resources/i18n/strings_ru.properties
index 0ff9ea63a..22590df38 100644
--- a/src/main/resources/i18n/strings_ru.properties
+++ b/src/main/resources/i18n/strings_ru.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Этот файл можно удалить
## Existing
addvaultwizard.existing.title=Добавить имеющееся хранилище
addvaultwizard.existing.instruction=Выберите файл "vault.cryptomator" существующего хранилища. Если имеется только файл "masterkey.cryptomator", выберите его.
+addvaultwizard.existing.restore=Восстановить…
addvaultwizard.existing.chooseBtn=Выбрать…
addvaultwizard.existing.filePickerTitle=Выберите файл хранилища
addvaultwizard.existing.filePickerMimeDesc=Хранилище Cryptomator
@@ -127,6 +128,7 @@ unlock.unlockBtn=Разблокировать
## Select
unlock.chooseMasterkey.message=Файл Masterkey не найден
unlock.chooseMasterkey.description=Не удалось найти файл Masterkey для хранилища "%s". Выберите ключевой файл вручную.
+unlock.chooseMasterkey.restoreInstead=Восстановить файл Masterkey
unlock.chooseMasterkey.filePickerTitle=Выберите файл MasterKey
unlock.chooseMasterkey.filePickerMimeDesc=Мастер-ключ Cryptomator
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Разблокировать
main.vaultlist.contextMenu.vaultoptions=Параметры хранилища
main.vaultlist.contextMenu.reveal=Показать диск
main.vaultlist.contextMenu.share=Поделиться…
-main.vaultlist.addVaultBtn.menuItemNew=Создать хранилище...
-main.vaultlist.addVaultBtn.menuItemExisting=Открыть имеющееся хранилище...
+main.vaultlist.addVaultBtn.menuItemNew=Создать хранилище…
+main.vaultlist.addVaultBtn.menuItemExisting=Открыть имеющееся хранилище…
+main.vaultlist.addVaultBtn.menuItemRecover=Восстановить имеющееся хранилище…
main.vaultlist.showEventsButton.tooltip=Открыть просмотр события
##Notificaition
main.notification.updateAvailable=Есть обновление.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator не смог найти хранил
main.vaultDetail.missing.recheck=Перепроверить
main.vaultDetail.missing.remove=Удалить из списка хранилищ…
main.vaultDetail.missing.changeLocation=Изменить расположение хранилища…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Отсутствует конфигурация хранилища.
+main.vaultDetail.missingVaultConfig.restore=Восстановить настройки хранилища
### Needs Migration
main.vaultDetail.migrateButton=Обновить хранилище
main.vaultDetail.migratePrompt=Чтобы получить доступ к хранилищу, его нужно преобразовать в новый формат
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Преобразовать в хранилище с
recoveryKey.display.title=Показать ключ восстановления
recoveryKey.create.message=Требуется пароль
recoveryKey.create.description=Введите пароль для "%s", чтобы показать его ключ восстановления.
+recoveryKey.recover.description=Введите пароль для "%s", чтобы восстановить конфигурацию хранилища.
recoveryKey.display.description=Ключ для восстановления доступа к "%s":
recoveryKey.display.StorageHints=Храните его в надёжном месте, например:\n • в диспетчере паролей\n • на флеш-накопителе USB\n • распечатанным на бумаге
## Reset Password
@@ -509,9 +516,57 @@ recoveryKey.recover.invalidKey=Этот ключ восстановления н
recoveryKey.printout.heading=Ключ восстановления Cryptomator\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Сброс
+recoveryKey.recover.recoverBtn=Восстановить
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Пароль успешно сброшен
recoveryKey.recover.resetSuccess.description=Вы можете разблокировать хранилище новым паролем.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Теперь вы можете разблокировать хранилище с помощью пароля.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Хранилище добавлено
+recover.existing.message=Хранилище успешно добавлено
+recover.existing.description=Хранилище "%s" добавлено в список. Восстановление не потребовалось.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Хранилище уже существует
+recover.alreadyExists.message=Это хранилище уже добавлено
+recover.alreadyExists.description=Хранилище "%s" уже есть в списке и поэтому не было добавлено снова.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Неверный выбор
+recover.invalidSelection.message=Выбрано не хранилище
+recover.invalidSelection.description=Выбранная папка должна быть корректным хранилищем Cryptomator.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Хаб-хранилище
+contactHubVaultOwner.message=Это хранилище было создано с помощью хаба Cryptomator
+contactHubVaultOwner.description=Свяжитесь с владельцем хранилища для восстановления отсутствующего файла. Шаблон хранилища можно загрузить из хаба Cryptomator.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Восстановление конфигурации хранилища
+recover.recoverMasterkey.title=Восстановить Masterkey
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Выберите метод восстановления:
+recover.onBoarding.useRecoveryKey=Использовать ключ восстановления
+recover.onBoarding.usePassword=Использовать пароль
+recover.onBoarding.intro=Проверьте следующее:
+recover.onBoarding.pleaseConfirm=Прежде чем продолжить, подтвердите, что:
+recover.onBoarding.otherwisePleaseConfirm=В противном случае подтвердите, что:
+recover.onBoarding.allMissing.intro=Если это хранилище управляется хабом Cryptomator, владелец хранилища должен восстановить его для вас.
+recover.onBoarding.intro.ensure=Все файлы полностью синхронизированы.
+recover.onBoarding.affirmation=Требования прочитаны и понятны
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=У вас есть ключ восстановления и вы знаете, что были использованы экспертные настройки.
+recover.onBoarding.intro.password=У вас есть пароль хранилища и вы знаете, что были использованы экспертные настройки.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=У вас есть ключ восстановления хранилища.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Это значение должно соответствовать значению перед восстановлением, чтобы гарантировать совместимость с ранее зашифрованными данными.
# Convert Vault
convertVault.title=Преобразовать хранилище
diff --git a/src/main/resources/i18n/strings_si.properties b/src/main/resources/i18n/strings_si.properties
index e639f1f7f..b345a4fb7 100644
--- a/src/main/resources/i18n/strings_si.properties
+++ b/src/main/resources/i18n/strings_si.properties
@@ -104,6 +104,7 @@ hub.registerSuccess.unlockBtn=අගුළුහරින්න
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -122,6 +123,25 @@ hub.registerSuccess.unlockBtn=අගුළුහරින්න
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_sk.properties b/src/main/resources/i18n/strings_sk.properties
index ac8a91505..ecebb8be6 100644
--- a/src/main/resources/i18n/strings_sk.properties
+++ b/src/main/resources/i18n/strings_sk.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Tento súbor môžete kedykoľvek odstráni
## Existing
addvaultwizard.existing.title=Pridať existujúci trezor
addvaultwizard.existing.instruction=Zvoľte "vault.cryptomator" súbor Vášho existujúceho trezora. Ak existuje iba súbor s menom "masterkey.cryptomator", vyberte ho namiesto.
+addvaultwizard.existing.restore=Obnoviť…
addvaultwizard.existing.chooseBtn=Vybrať…
addvaultwizard.existing.filePickerTitle=Zvoľte súbor trezora
addvaultwizard.existing.filePickerMimeDesc=Trezor Cryptomátora
@@ -388,7 +389,6 @@ main.vaultlist.contextMenu.vaultoptions=Ukáž možnosti trezora
main.vaultlist.contextMenu.reveal=Odkry disk
main.vaultlist.contextMenu.share=Zdieľať…
main.vaultlist.addVaultBtn.menuItemNew=Vytvoriť Nový trezor…
-main.vaultlist.addVaultBtn.menuItemExisting=Otvoriť Existujúci trezor...
main.vaultlist.showEventsButton.tooltip=Otvoriť zobrazenie udalosti
##Notificaition
main.notification.updateAvailable=Aktualizácia je k dispozícii.
@@ -426,6 +426,7 @@ main.vaultDetail.missing.info=Cryptomator nevie nájsť trezor na tejto ceste.
main.vaultDetail.missing.recheck=Prekontrolovať
main.vaultDetail.missing.remove=Odstrániť zo zoznamu trezora…
main.vaultDetail.missing.changeLocation=Zmeniť umiestnenie trezora…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Aktualizácia trezora
main.vaultDetail.migratePrompt=Váš trezor vyžaduje aktualizáciu na nový formát predtým ako ho použijete
@@ -501,9 +502,37 @@ recoveryKey.recover.invalidKey=Toto je neplatný kľúč obnovy
recoveryKey.printout.heading=Kľúč obnovy Cryptomator-a\n "%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Resetovať
+recoveryKey.recover.recoverBtn=Obnov
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Heslo úspešne zresetované
recoveryKey.recover.resetSuccess.description=Môžte odomknúť trezor s novým heslom.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetVaultConfigSuccess.message=Konfigurácia peňaženky obnovená
+recoveryKey.recover.resetMasterkeyFileSuccess.message=Hlavný kľuč obnovený
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Teraz môžte odomknúť Váš trezor s heslom.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Trezor už existuje
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Neplatný výber
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub trezora
+
+##Dialog Title
+
+## OnBoarding
+recover.onBoarding.usePassword=Použite heslo
+recover.onBoarding.intro.ensure=Všetky súbory sú plne synchronizované.
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Konvertovať trezor
diff --git a/src/main/resources/i18n/strings_sl.properties b/src/main/resources/i18n/strings_sl.properties
index d62415d50..4cfc2d997 100644
--- a/src/main/resources/i18n/strings_sl.properties
+++ b/src/main/resources/i18n/strings_sl.properties
@@ -143,6 +143,7 @@ main.vaultDetail.share=Deli…
main.vaultDetail.lockBtn=Zakleni
main.vaultDetail.locateEncryptedFileBtn=Poišči šifrirano datoteko
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -166,6 +167,26 @@ recoveryKey.recover.wrongKey=Ta obnovitveni ključ se ujema z drugim trezorjem
recoveryKey.recover.invalidKey=Obnovitveni ključ ni pravilen
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub trezor
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_sr.properties b/src/main/resources/i18n/strings_sr.properties
index 72947efeb..7c6f77a8d 100644
--- a/src/main/resources/i18n/strings_sr.properties
+++ b/src/main/resources/i18n/strings_sr.properties
@@ -245,6 +245,7 @@ main.vaultDetail.missing.info=Cryptomator није пронашао сеф на
main.vaultDetail.missing.recheck=Провери поново
main.vaultDetail.missing.remove=Удаљи са листе сефова…
main.vaultDetail.missing.changeLocation=Промени локацију сефа…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Nadogradi sef
main.vaultDetail.migratePrompt=Да бисте приступили вашем сефу, он мора бити надограђен на нови формат
@@ -298,6 +299,25 @@ recoveryKey.recover.correctKey=Ово је исправан резервни к
recoveryKey.printout.heading=Cryptomator Резервни Кључ\n"%s"\n
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_sr_Latn.properties b/src/main/resources/i18n/strings_sr_Latn.properties
index a4e32a3a1..dbdc180af 100644
--- a/src/main/resources/i18n/strings_sr_Latn.properties
+++ b/src/main/resources/i18n/strings_sr_Latn.properties
@@ -204,6 +204,7 @@ main.vaultDetail.unlockNowBtn=Otključaj sada
main.vaultDetail.revealBtn=Otvori disk
main.vaultDetail.lockBtn=Zaključaj
### Missing
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Nadogradi sef
### Error
@@ -228,6 +229,25 @@ vaultOptions.masterkey.changePasswordBtn=Promena lozinke
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_sv.properties b/src/main/resources/i18n/strings_sv.properties
index 6b38e0d7c..5b56fd029 100644
--- a/src/main/resources/i18n/strings_sv.properties
+++ b/src/main/resources/i18n/strings_sv.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=Du kan ta bort denna fil.
## Existing
addvaultwizard.existing.title=Öppna befintligt valv
addvaultwizard.existing.instruction=Välj filen "vault.cryptomator" i ditt befintliga valv. Om det endast finns en fil som heter "masterkey.cryptomator", välj den istället.
+addvaultwizard.existing.restore=Återställ…
addvaultwizard.existing.chooseBtn=Välj…
addvaultwizard.existing.filePickerTitle=Välj valvfil
addvaultwizard.existing.filePickerMimeDesc=Cryptomator valv
@@ -127,6 +128,7 @@ unlock.unlockBtn=Lås upp
## Select
unlock.chooseMasterkey.message=Filen med huvudnyckeln hittades inte
unlock.chooseMasterkey.description=Kunde inte hitta Masterkey-filen för detta valv på förväntad plats. Välj filen manuellt.
+unlock.chooseMasterkey.restoreInstead=Återställ huvudnyckeln istället
unlock.chooseMasterkey.filePickerTitle=Välj Masterkey-fil
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator huvudnyckel
## Success
@@ -394,8 +396,9 @@ main.vaultlist.contextMenu.unlockNow=Lås upp nu
main.vaultlist.contextMenu.vaultoptions=Visa inställningar för valv
main.vaultlist.contextMenu.reveal=Visa enhet
main.vaultlist.contextMenu.share=Dela…
-main.vaultlist.addVaultBtn.menuItemNew=Skapa nytt valv...
-main.vaultlist.addVaultBtn.menuItemExisting=Öppna befintligt valv...
+main.vaultlist.addVaultBtn.menuItemNew=Skapa nytt valv…
+main.vaultlist.addVaultBtn.menuItemExisting=Öppna befintligt valv…
+main.vaultlist.addVaultBtn.menuItemRecover=Återställ befintligt valv…
main.vaultlist.showEventsButton.tooltip=Öppna händelsevy
##Notificaition
main.notification.updateAvailable=Uppdatering tillgänglig.
@@ -433,6 +436,9 @@ main.vaultDetail.missing.info=Cryptomator kunde inte hitta någt valv i denna s
main.vaultDetail.missing.recheck=Kontrollera igen
main.vaultDetail.missing.remove=Ta bort från listan…
main.vaultDetail.missing.changeLocation=Ändra valvets plats…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Valvkonfigurationen saknas.
+main.vaultDetail.missingVaultConfig.restore=Återställ valvkonfiguration
### Needs Migration
main.vaultDetail.migrateButton=Uppgradera valv
main.vaultDetail.migratePrompt=Ditt valv behöver uppgraderas till ett nytt format innan du kan använda det
@@ -497,6 +503,7 @@ vaultOptions.hub.convertBtn=Konvertera till Lösenordsbaserat Valv
recoveryKey.display.title=Visa återställningsnyckel
recoveryKey.create.message=Lösenord krävs
recoveryKey.create.description=Ange ditt lösenord för att visa återställningsnyckeln för "%s":
+recoveryKey.recover.description=Ange lösenordet för "%s" för att återställa valvkonfigurationen.
recoveryKey.display.description=Använd denna återställningsnyckel för att återställa åtkomst till "%s":
recoveryKey.display.StorageHints=Spara den på en säker plats, t.ex:\n • I en lösenordshanterare\n • På ett USB-minne (förvara säkert) \n • Skriv ut på ett papper (förvara säkert)
## Reset Password
@@ -509,9 +516,41 @@ recoveryKey.recover.invalidKey=Denna återställningsnyckel är ogiltig
recoveryKey.printout.heading=Cryptomator återställningsnyckel\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Återställ
+recoveryKey.recover.recoverBtn=Återställ
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Lösenord återställt
recoveryKey.recover.resetSuccess.description=Du kan låsa upp valvet med det nya lösenordet.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Nu kan du låsa upp valvet med lösenordet.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Valvet tillagt
+recover.existing.message=Valvet har lagts till
+recover.existing.description=Ditt valv "%s" har lagts till i valvlistan. Ingen återhämtningsprocess var nödvändig.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Valvet finns redan
+recover.alreadyExists.message=Detta valv har redan lagts till
+recover.alreadyExists.description=Ditt valv "%s" finns redan i din valvlista och lades därför inte till igen.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Ogiltigt val
+recover.invalidSelection.message=Ditt val är inte ett valv
+recover.invalidSelection.description=Den valda mappen måste vara ett giltigt Cryptomatorvalv.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hubb valv
+contactHubVaultOwner.message=Detta valv skapades med Cryptomator Hub
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Konvertera valv
diff --git a/src/main/resources/i18n/strings_sw.properties b/src/main/resources/i18n/strings_sw.properties
index 508d4c141..b0d94dc36 100644
--- a/src/main/resources/i18n/strings_sw.properties
+++ b/src/main/resources/i18n/strings_sw.properties
@@ -365,6 +365,7 @@ main.vaultDetail.missing.info=Cryptomator haikuweza kupata kuba katika njia hii.
main.vaultDetail.missing.recheck=Kagua upya
main.vaultDetail.missing.remove=Ondoa kutoka kwenye Orodha ya Kuba…
main.vaultDetail.missing.changeLocation=Badilisha Mahali pa Kuba…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Pandisha daraja Kuba
main.vaultDetail.migratePrompt=Kuba yako inahitaji kuboreshwa hadi umbizo jipya, kabla ya kuipata
@@ -435,6 +436,25 @@ recoveryKey.recover.resetBtn=Weka upya
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Kuweka upya nenosiri kumefaulu
recoveryKey.recover.resetSuccess.description=Unaweza kufungua chumba chako kwa kutumia neno la siri jipya.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_ta.properties b/src/main/resources/i18n/strings_ta.properties
index 86df70c40..204fa6b6b 100644
--- a/src/main/resources/i18n/strings_ta.properties
+++ b/src/main/resources/i18n/strings_ta.properties
@@ -243,6 +243,7 @@ main.vaultDetail.unlockNowBtn=இப்போது திறக்கவும
main.vaultDetail.revealBtn=இயக்ககத்தை வெளிப்படுத்து
main.vaultDetail.lockBtn=பூட்டு
### Missing
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=பெட்டகத்தை மேம்படுத்து
### Error
@@ -280,6 +281,25 @@ vaultOptions.masterkey.changePasswordBtn=கடவுச்சொல்லை
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_te.properties b/src/main/resources/i18n/strings_te.properties
index 046c8ed75..d75875603 100644
--- a/src/main/resources/i18n/strings_te.properties
+++ b/src/main/resources/i18n/strings_te.properties
@@ -91,6 +91,7 @@ preferences.interface.theme.light=కాంతి
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -109,6 +110,25 @@ preferences.interface.theme.light=కాంతి
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_th.properties b/src/main/resources/i18n/strings_th.properties
index d8c82a09d..f29da2a50 100644
--- a/src/main/resources/i18n/strings_th.properties
+++ b/src/main/resources/i18n/strings_th.properties
@@ -360,6 +360,7 @@ main.vaultDetail.stats=สถิติของ Vault
main.vaultDetail.missing.recheck=ตรวจสอบอีกครั้ง
main.vaultDetail.missing.remove=ลบออกจากรายชื่อ Vault…
main.vaultDetail.missing.changeLocation=เปลี่ยนที่อยู่ vault…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=อัปเกรด Vault
### Error
@@ -412,6 +413,26 @@ recoveryKey.recover.title=ตั้งรหัสผ่านใหม่
recoveryKey.recover.resetBtn=รีเซ็ต
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=รีเซ็ตรหัสผ่านสำเร็จ
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Vault
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.convert.convertBtn.before=แปลง
diff --git a/src/main/resources/i18n/strings_tr.properties b/src/main/resources/i18n/strings_tr.properties
index 69d097492..3e5aaadd3 100644
--- a/src/main/resources/i18n/strings_tr.properties
+++ b/src/main/resources/i18n/strings_tr.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Kilidi Şimdi Aç
main.vaultlist.contextMenu.vaultoptions=Kasa Ayarlarını Göster
main.vaultlist.contextMenu.reveal=Sürücüyü Göster
main.vaultlist.contextMenu.share=Paylaş…
-main.vaultlist.addVaultBtn.menuItemNew=Yeni Kasa Oluştur...
-main.vaultlist.addVaultBtn.menuItemExisting=Var Olan Kasayı Aç...
##Notificaition
main.notification.updateAvailable=Güncelleme mevcut.
main.notification.support=Cryptomator'a destek olun.
@@ -429,6 +427,7 @@ main.vaultDetail.missing.info=Cryptomator bu yolda bir kasa bulamadı.
main.vaultDetail.missing.recheck=Yeniden denetle
main.vaultDetail.missing.remove=Kasa Listesinden Sil…
main.vaultDetail.missing.changeLocation=Kasa Konumunu Değiştir…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Kasayı Yükselt
main.vaultDetail.migratePrompt=Kasaya erişmeden önce kasanızın yeni bir formata yükseltilmesi gerekiyor
@@ -508,6 +507,26 @@ recoveryKey.recover.resetBtn=Sıfırla
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Parola sıfırlama başarılı
recoveryKey.recover.resetSuccess.description=Yeni parola ile kasanızın kilidini açabilirsiniz.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub Kasası
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Kasayı Dönüştür
diff --git a/src/main/resources/i18n/strings_ug.properties b/src/main/resources/i18n/strings_ug.properties
index 50624bf22..0200d795b 100644
--- a/src/main/resources/i18n/strings_ug.properties
+++ b/src/main/resources/i18n/strings_ug.properties
@@ -415,6 +415,7 @@ main.vaultDetail.missing.info=Cryptomator بۇ يولدا قويۇلما تېپ
main.vaultDetail.missing.recheck=قايتا تەكشۈرۈش
main.vaultDetail.missing.remove=قويۇلما تىزىمىدىن ئۆچۈرۈش…
main.vaultDetail.missing.changeLocation=قويۇلما ئورنىنى ئۆزگەرتىش…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=ئامبار يېڭىلاش
main.vaultDetail.migratePrompt=بۇ ئامبارنى ئىچىشتىن بۇرۇن يېڭى فورماتقا يېڭىلىنىشى كېرەك
@@ -494,6 +495,25 @@ recoveryKey.recover.resetBtn=قايتا تەڭشەش
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=پارول قايتا بېكىتىلدى
recoveryKey.recover.resetSuccess.description=يېڭى پارول بىلەن ئامبانى ئاچالايسىز.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=ئامبار ئۆزگەرتىش
diff --git a/src/main/resources/i18n/strings_uk.properties b/src/main/resources/i18n/strings_uk.properties
index 2b120b967..e4905fef3 100644
--- a/src/main/resources/i18n/strings_uk.properties
+++ b/src/main/resources/i18n/strings_uk.properties
@@ -97,6 +97,7 @@ addvault.new.readme.accessLocation.4=Цей файл можна видалити
## Existing
addvaultwizard.existing.title=Додати наявне сховище
addvaultwizard.existing.instruction=Оберіть файл «vault.cryptomator» свого наявного сховища. Якщо існує лише файл з назвою «masterkey.cryptomator», оберіть його.
+addvaultwizard.existing.restore=Відновити…
addvaultwizard.existing.chooseBtn=Обрати…
addvaultwizard.existing.filePickerTitle=Виберіть файл сховища
addvaultwizard.existing.filePickerMimeDesc=Сховище Cryptomator
@@ -126,14 +127,15 @@ unlock.passwordPrompt=Введіть пароль для «%s»:
unlock.savePassword=Запам'ятати пароль
unlock.unlockBtn=Розблокувати
## Select
-unlock.chooseMasterkey.message=Файл майстер-ключа не знайдено
-unlock.chooseMasterkey.description=Cryptomator не зміг знайти файл майстер-ключа для сховища «%s». Будь ласка, виберіть файл ключа вручну.
-unlock.chooseMasterkey.filePickerTitle=Виберіть файл майстер-ключа
+unlock.chooseMasterkey.message=Файл masterkey не знайдено
+unlock.chooseMasterkey.description=Cryptomator не зміг знайти файл masterkey для сховища «%s». Будь ласка, оберіть файл ключа вручну.
+unlock.chooseMasterkey.restoreInstead=Натомість відновити файл masterkey
+unlock.chooseMasterkey.filePickerTitle=Виберіть файл Masterkey
unlock.chooseMasterkey.filePickerMimeDesc=Майстер-ключ Cryptomator
## Success
unlock.success.message=Успішно розблоковано
unlock.success.description=Вміст сховища «%s» тепер доступний через точку монтування.
-unlock.success.rememberChoice=Запам'ятайте мій вибір та більше не запитуйте
+unlock.success.rememberChoice=Запам’ятати мій вибір та більше не запитувати
unlock.success.revealBtn=Відкрити диск
## Failure
unlock.error.customPath.message=Не вдалося змонтувати сховище за вказаним шляхом
@@ -395,8 +397,9 @@ main.vaultlist.contextMenu.unlockNow=Розблокувати
main.vaultlist.contextMenu.vaultoptions=Показати параметри сховища
main.vaultlist.contextMenu.reveal=Відкрити диск
main.vaultlist.contextMenu.share=Поділитися…
-main.vaultlist.addVaultBtn.menuItemNew=Створити нове сховище...
-main.vaultlist.addVaultBtn.menuItemExisting=Відкрити наявне сховище...
+main.vaultlist.addVaultBtn.menuItemNew=Створити нове сховище…
+main.vaultlist.addVaultBtn.menuItemExisting=Відкрити наявне сховище…
+main.vaultlist.addVaultBtn.menuItemRecover=Відновити наявне сховище…
main.vaultlist.showEventsButton.tooltip=Відкрити журнал подій
##Notificaition
main.notification.updateAvailable=Доступне оновлення.
@@ -434,6 +437,9 @@ main.vaultDetail.missing.info=Cryptomator не зміг знайти схови
main.vaultDetail.missing.recheck=Перевірити знову
main.vaultDetail.missing.remove=Вилучити зі списку сховищ…
main.vaultDetail.missing.changeLocation=Змінити розташування сховища…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=Відсутня конфігурація сховища.
+main.vaultDetail.missingVaultConfig.restore=Відновити конфігурацію сховища
### Needs Migration
main.vaultDetail.migrateButton=Покращити сховище
main.vaultDetail.migratePrompt=Ваше сховище потрібно оновити до нового формату, перш ніж ви зможете отримати до нього доступ
@@ -498,6 +504,7 @@ vaultOptions.hub.convertBtn=Перетворити на сховище, захи
recoveryKey.display.title=Показати ключ відновлення
recoveryKey.create.message=Потрібен пароль
recoveryKey.create.description=Введіть пароль для «%s», щоб показати його ключ відновлення.
+recoveryKey.recover.description=Введіть пароль для «%s», щоб відновити конфігурацію сховища.
recoveryKey.display.description=Зазначений ключ відновлення можна використовувати для відновлення доступу до «%s»:
recoveryKey.display.StorageHints=Зберігайте його в дуже надійному місці, наприклад:\n • Збережіть його за допомогою менеджера паролів\n • Збережіть його на USB-накопичувачі\n • Роздрукуйте його на папері
## Reset Password
@@ -510,9 +517,57 @@ recoveryKey.recover.invalidKey=Невірний ключ відновлення
recoveryKey.printout.heading=Ключ відновлення Cryptomator\n«%s»\n
### Reset Password
recoveryKey.recover.resetBtn=Скинути
+recoveryKey.recover.recoverBtn=Відновити
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Пароль успішно скинуто
recoveryKey.recover.resetSuccess.description=Ви можете розблокувати своє сховище за допомогою нового пароля.
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=Тепер ви можете розблокувати сховище за допомогою свого пароля.
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=Сховище додано
+recover.existing.message=Сховище успішно додано
+recover.existing.description=Ваше сховище «%s» додано до списку. Процес відновлення не знадобився.
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=Сховище вже існує
+recover.alreadyExists.message=Це сховище вже додано
+recover.alreadyExists.description=Ваше сховище «%s» вже є у списку, тому його не було додано знову.
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=Неприпустимий вибір
+recover.invalidSelection.message=Обраний об’єкт не є сховищем
+recover.invalidSelection.description=Обрана папка має бути дійсним сховищем Cryptomator.
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Сховище Hub
+contactHubVaultOwner.message=Це сховище було створено за допомогою Cryptomator Hub
+contactHubVaultOwner.description=Будь ласка, зверніться до власника сховища, щоб відновити відсутній файл. Він може завантажити шаблон сховища з Cryptomator Hub.
+
+##Dialog Title
+recover.recoverVaultConfig.title=Відновлення конфігурації сховища
+recover.recoverMasterkey.title=Відновлення masterkey
+
+## OnBoarding
+recover.onBoarding.chooseMethod=Оберіть спосіб відновлення:
+recover.onBoarding.useRecoveryKey=Використати ключ відновлення
+recover.onBoarding.usePassword=Використати пароль
+recover.onBoarding.intro=Обов'язково перевірте наступне:
+recover.onBoarding.pleaseConfirm=Перш ніж продовжити, переконайтеся, що:
+recover.onBoarding.otherwisePleaseConfirm=В іншому випадку, переконайтеся, що:
+recover.onBoarding.allMissing.intro=Якщо цим сховищем керує Cryptomator Hub, його власник повинен відновити його для вас.
+recover.onBoarding.intro.ensure=Усі файли повністю синхронізовано.
+recover.onBoarding.affirmation=Я прочитав(ла) і зрозумів(ла) ці вимоги
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=У вас є ключ відновлення, і ви знаєте, чи використовувалися експертні налаштування.
+recover.onBoarding.intro.password=У вас є пароль до сховища, і ви знаєте, чи використовувалися експертні налаштування.
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=У вас є ключ відновлення сховища.
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=Це значення має збігатися з тим, що використовувалося до відновлення, для забезпечення сумісності з попередньо зашифрованими даними.
# Convert Vault
convertVault.title=Перетворити сховище
diff --git a/src/main/resources/i18n/strings_ur.properties b/src/main/resources/i18n/strings_ur.properties
index aa86df2bd..8c48fa5b9 100644
--- a/src/main/resources/i18n/strings_ur.properties
+++ b/src/main/resources/i18n/strings_ur.properties
@@ -87,6 +87,7 @@
### Locked
### Unlocked
### Missing
+### Missing Vault Config
### Needs Migration
### Error
@@ -105,6 +106,25 @@
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
diff --git a/src/main/resources/i18n/strings_vi.properties b/src/main/resources/i18n/strings_vi.properties
index f0806b21a..1456a5c74 100644
--- a/src/main/resources/i18n/strings_vi.properties
+++ b/src/main/resources/i18n/strings_vi.properties
@@ -394,8 +394,6 @@ main.vaultlist.contextMenu.unlockNow=Mở khóa bây giờ
main.vaultlist.contextMenu.vaultoptions=Hiện tùy chọn vault
main.vaultlist.contextMenu.reveal=Hiển thị Ổ đĩa
main.vaultlist.contextMenu.share=Chia sẻ…
-main.vaultlist.addVaultBtn.menuItemNew=Tạo Vault Mới...
-main.vaultlist.addVaultBtn.menuItemExisting=Mở Vault Hiện Có...
main.vaultlist.showEventsButton.tooltip=Mở xem sự kiện
##Notificaition
main.notification.updateAvailable=Có bản cập nhật mới.
@@ -433,6 +431,7 @@ main.vaultDetail.missing.info=Cryptomator không thể tìm thấy vault tại
main.vaultDetail.missing.recheck=Kiểm tra lại
main.vaultDetail.missing.remove=Xóa khỏi Danh sách Vault…
main.vaultDetail.missing.changeLocation=Thay đổi vị trí Vault…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=Nâng cấp Vault
main.vaultDetail.migratePrompt=Vault của bạn cần được nâng cấp lên một định dạng mới, trước khi bạn có thể truy cập nó
@@ -512,6 +511,25 @@ recoveryKey.recover.resetBtn=Đặt lại
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Đặt lại mật khẩu thành công
recoveryKey.recover.resetSuccess.description=Bạn có thể mở khóa vault với mật khẩu mới.
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=Chuyển đổi Vault
diff --git a/src/main/resources/i18n/strings_zh.properties b/src/main/resources/i18n/strings_zh.properties
index caa74221c..95bab8e84 100644
--- a/src/main/resources/i18n/strings_zh.properties
+++ b/src/main/resources/i18n/strings_zh.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=您可以随时删除此文件。
## Existing
addvaultwizard.existing.title=添加现有保险库
addvaultwizard.existing.instruction=请选择现有保险库中的“vault.cryptomator”文件。如果只有一个名为“masterkey.cryptomator”的文件,则改为选择该文件。
+addvaultwizard.existing.restore=还原…
addvaultwizard.existing.chooseBtn=选择...
addvaultwizard.existing.filePickerTitle=请选择保险库对应文件
addvaultwizard.existing.filePickerMimeDesc=Cryptomator 保险库
@@ -127,6 +128,7 @@ unlock.unlockBtn=解锁
## Select
unlock.chooseMasterkey.message=未找到 Masterkey 文件
unlock.chooseMasterkey.description=在指定路径找不到该保险库的 masterkey 文件,请手动选择密钥文件
+unlock.chooseMasterkey.restoreInstead=改为还原 Masterkey 文件
unlock.chooseMasterkey.filePickerTitle=选择 Masterkey 文件
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator 主密钥
## Success
@@ -394,8 +396,10 @@ main.vaultlist.contextMenu.unlockNow=立即解锁
main.vaultlist.contextMenu.vaultoptions=显示保险库选项
main.vaultlist.contextMenu.reveal=显示驱动器
main.vaultlist.contextMenu.share=共享…
-main.vaultlist.addVaultBtn.menuItemNew=新建保险库...
-main.vaultlist.addVaultBtn.menuItemExisting=打开现有的保险库...
+main.vaultlist.addVaultBtn.menuItemNew=新建保险库…
+main.vaultlist.addVaultBtn.menuItemExisting=打开现有的保险库…
+main.vaultlist.addVaultBtn.menuItemRecover=恢复现有保险库…
+main.vaultlist.showEventsButton.tooltip=打开事件视图
##Notificaition
main.notification.updateAvailable=发现新版本
main.notification.support=支持 Cryptomator
@@ -424,11 +428,17 @@ main.vaultDetail.stats=保险库统计
main.vaultDetail.locateEncryptedFileBtn=找出加密后文件
main.vaultDetail.locateEncryptedFileBtn.tooltip=选择保险库中的一个文件来找出已加密文件的位置
main.vaultDetail.encryptedPathsCopied=路径已复制到剪贴板
+main.vaultDetail.locateEncrypted.filePickerTitle=选择保险库内的文件
+main.vaultDetail.decryptName.buttonLabel=解密文件名
+main.vaultDetail.decryptName.tooltip=选择一个加密的保险库文件来解密其名称
### Missing
main.vaultDetail.missing.info=Cryptomator在此路径找不到保险库
main.vaultDetail.missing.recheck=重新检查
main.vaultDetail.missing.remove=从保险库列表中移除...
main.vaultDetail.missing.changeLocation=更改保险库位置…
+### Missing Vault Config
+main.vaultDetail.missingVaultConfig.info=保险库配置缺失
+main.vaultDetail.missingVaultConfig.restore=还原保险库配置
### Needs Migration
main.vaultDetail.migrateButton=升级保险库
main.vaultDetail.migratePrompt=您的保险库需要升级到新格式后才能访问
@@ -493,6 +503,7 @@ vaultOptions.hub.convertBtn=转换为基于密码的保险库
recoveryKey.display.title=显示恢复密钥
recoveryKey.create.message=密码是必填的
recoveryKey.create.description=输入您的密码以显示"%s"的恢复密钥:
+recoveryKey.recover.description=输入“%s”的密码以恢复保险库配置
recoveryKey.display.description=下面的恢复密钥可用于恢复对"%s"的访问:
recoveryKey.display.StorageHints=将它保存到非常安全的地方,例如:\n • 使用密码管理器来保存\n • 将其保存在U盘上\n • 在纸上打印
## Reset Password
@@ -505,9 +516,57 @@ recoveryKey.recover.invalidKey=此恢复密钥无效
recoveryKey.printout.heading=Cryptomator 恢复密钥\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=重置
+recoveryKey.recover.recoverBtn=恢复
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=成功重置密码
recoveryKey.recover.resetSuccess.description=现在可通过新密码解锁您的保险库了
+### Recovery Key Vault Config Reset Success
+recoveryKey.recover.resetMasterkeyFileSuccess.description=您现在可以通过密码解锁保险库
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+recover.existing.title=保险库已添加
+recover.existing.message=已成功添加保险库
+recover.existing.description=您的保险库“%s”已添加至保险库列表,无需进行恢复过程
+
+##Vault Already Exists - Dialog
+recover.alreadyExists.title=保险库已存在
+recover.alreadyExists.message=此保险库已被添加
+recover.alreadyExists.description=保险库“%s”已存在于您的保险库列表中,因此不会再次添加
+
+##Invalid Selection - Dialog
+recover.invalidSelection.title=无效选择
+recover.invalidSelection.message=请选择保险库
+recover.invalidSelection.description=所选文件夹必须是一个有效的 Cryptomator 保险库
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub 保险库
+contactHubVaultOwner.message=此保险库由 Cryptomator Hub 创建
+contactHubVaultOwner.description=请联系保险库所有者以恢复丢失的文件,他们可以从 Cryptomator Hub 下载保险库模板
+
+##Dialog Title
+recover.recoverVaultConfig.title=恢复保险库配置
+recover.recoverMasterkey.title=恢复 Masterkey
+
+## OnBoarding
+recover.onBoarding.chooseMethod=选择恢复方式:
+recover.onBoarding.useRecoveryKey=使用恢复密钥
+recover.onBoarding.usePassword=使用密码
+recover.onBoarding.intro=请务必检查以下内容:
+recover.onBoarding.pleaseConfirm=在继续操作之前,请确认:
+recover.onBoarding.otherwisePleaseConfirm=否则,请确认:
+recover.onBoarding.allMissing.intro=如果此保险库由 Cryptomator Hub 管理,则必须由保险库所有者为您恢复它
+recover.onBoarding.intro.ensure=所有文件已完全同步
+recover.onBoarding.affirmation=我已经阅读并理解了这些要求
+
+###Vault Config Missing
+recover.onBoarding.intro.recoveryKey=您拥有恢复密钥,并且知道是否使用了专家设置
+recover.onBoarding.intro.password=您拥有保险库密码,并且知道是否使用了专家设置
+###Masterkey Missing
+recover.onBoarding.intro.masterkey.recoveryKey=您拥有保险库恢复密钥
+
+## Expert Settings
+recover.expertSettings.shorteningThreshold.title=该值必须与恢复前使用的值一致,以确保与先前加密的数据兼容
# Convert Vault
convertVault.title=转换保险库
@@ -580,7 +639,40 @@ shareVault.hub.instruction.2=2:在 Cryptomator Hub 内授予团队成员访问
shareVault.hub.openHub=打开 Cryptomator Hub
# Decrypt File Names
+decryptNames.title=解密文件名
+decryptNames.filePicker.title=选择加密文件
+decryptNames.filePicker.extensionDescription=Cryptomator 加密文件
+decryptNames.copyTable.tooltip=复制表格
+decryptNames.clearTable.tooltip=清除表格
+decryptNames.copyHint=用%s复制单元格内容
+decryptNames.dropZone.message=拖放文件或点击选择
+decryptNames.dropZone.error.vaultInternalFiles=已选择名称不可解密的保险库内部文件
+decryptNames.dropZone.error.foreignFiles=文件不属于保险库“%s”
+decryptNames.dropZone.error.noDirIdBackup=所选文件的目录不包含 dirId.c9r 文件
+decryptNames.dropZone.error.generic=解密文件名失败
# Event View
+eventView.title=事件
+eventView.filter.allVaults=全部
+eventView.clearListButton.tooltip=清除列表
## event list entries
+eventView.entry.vaultLocked.description=解锁“%s”查看详情
+eventView.entry.conflictResolved.message=已解决冲突
+eventView.entry.conflictResolved.showDecrypted=显示解密文件
+eventView.entry.conflictResolved.copyDecrypted=复制解密路径
+eventView.entry.conflict.message=冲突解决失败
+eventView.entry.conflict.showDecrypted=显示解密后的原始文件
+eventView.entry.conflict.copyDecrypted=复制解密后的原始路径
+eventView.entry.conflict.showEncrypted=显示冲突的加密文件
+eventView.entry.conflict.copyEncrypted=复制冲突的加密路径
+eventView.entry.decryptionFailed.message=解密失败
+eventView.entry.decryptionFailed.showEncrypted=显示加密文件
+eventView.entry.decryptionFailed.copyEncrypted=复制加密路径
+eventView.entry.brokenDirFile.message=目录链接已损坏
+eventView.entry.brokenDirFile.showEncrypted=显示损坏的加密链接
+eventView.entry.brokenDirFile.copyEncrypted=复制损坏链接的路径
+eventView.entry.brokenFileNode.message=损坏的文件系统节点
+eventView.entry.brokenFileNode.showEncrypted=显示损坏的加密节点
+eventView.entry.brokenFileNode.copyEncrypted=复制损坏的加密节点的路径
+eventView.entry.brokenFileNode.copyDecrypted=复制解密路径
diff --git a/src/main/resources/i18n/strings_zh_HK.properties b/src/main/resources/i18n/strings_zh_HK.properties
index 984fbf1f6..5f4ef09a8 100644
--- a/src/main/resources/i18n/strings_zh_HK.properties
+++ b/src/main/resources/i18n/strings_zh_HK.properties
@@ -392,8 +392,6 @@ main.vaultlist.contextMenu.unlockNow=立即解鎖
main.vaultlist.contextMenu.vaultoptions=顯示加密庫選項
main.vaultlist.contextMenu.reveal=展示磁碟
main.vaultlist.contextMenu.share=分享…
-main.vaultlist.addVaultBtn.menuItemNew=新建加密檔案庫...
-main.vaultlist.addVaultBtn.menuItemExisting=開啟現有的加密檔案庫...
##Notificaition
main.notification.updateAvailable=有可用更新
main.notification.support=贊助Cryptomator.
@@ -427,6 +425,7 @@ main.vaultDetail.missing.info=Cryptomator 無法在指定位置找到加密庫
main.vaultDetail.missing.recheck=重新檢查
main.vaultDetail.missing.remove=從加密庫列表中移除…
main.vaultDetail.missing.changeLocation=升級加密庫
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=升級加密庫
main.vaultDetail.migratePrompt=你必須先更新加密庫才能存取內容
@@ -501,6 +500,25 @@ recoveryKey.recover.resetBtn=重設
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=密碼重設成功
recoveryKey.recover.resetSuccess.description=您現在可以用新密碼解鎖您的加密庫
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+
+##Dialog Title
+
+## OnBoarding
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=轉換加密檔案庫
diff --git a/src/main/resources/i18n/strings_zh_TW.properties b/src/main/resources/i18n/strings_zh_TW.properties
index 9d03cfa49..8783f6fcf 100644
--- a/src/main/resources/i18n/strings_zh_TW.properties
+++ b/src/main/resources/i18n/strings_zh_TW.properties
@@ -96,6 +96,7 @@ addvault.new.readme.accessLocation.4=您可以放心移除這個檔案。
## Existing
addvaultwizard.existing.title=開啟現有加密檔案庫
addvaultwizard.existing.instruction=請選擇現有加密檔案庫中名為「vault.cryptomator」的檔案。如果只有一個名為「masterkey.cryptomator」的檔案,則選擇該檔案。
+addvaultwizard.existing.restore=復原…
addvaultwizard.existing.chooseBtn=選取…
addvaultwizard.existing.filePickerTitle=選取加密檔案庫的檔案
addvaultwizard.existing.filePickerMimeDesc=Cryptomator 加密檔案庫
@@ -394,8 +395,6 @@ main.vaultlist.contextMenu.unlockNow=立即解鎖
main.vaultlist.contextMenu.vaultoptions=顯示加密檔案庫選項
main.vaultlist.contextMenu.reveal=顯示磁碟
main.vaultlist.contextMenu.share=分享…
-main.vaultlist.addVaultBtn.menuItemNew=新建加密檔案庫...
-main.vaultlist.addVaultBtn.menuItemExisting=開啟現有的加密檔案庫...
main.vaultlist.showEventsButton.tooltip=打開事件檢視
##Notificaition
main.notification.updateAvailable=有可用更新
@@ -433,6 +432,7 @@ main.vaultDetail.missing.info=Cryptomator 無法在指定位置找到加密檔
main.vaultDetail.missing.recheck=重新檢查
main.vaultDetail.missing.remove=從加密檔案庫列表中移除…
main.vaultDetail.missing.changeLocation=更改加密檔案庫位置…
+### Missing Vault Config
### Needs Migration
main.vaultDetail.migrateButton=升級加密檔案庫
main.vaultDetail.migratePrompt=您必須先更新加密檔案庫才能存取內容
@@ -512,6 +512,28 @@ recoveryKey.recover.resetBtn=重設
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=密碼重設完成
recoveryKey.recover.resetSuccess.description=您可以用新設的密碼解鎖檔案庫
+### Recovery Key Vault Config Reset Success
+
+# Recover Vault Config File and/or Masterkey
+##Add Existing Vault without recovery - Dialog
+
+##Vault Already Exists - Dialog
+
+##Invalid Selection - Dialog
+
+## Contact Hub Vault Owner - Dialog
+contactHubVaultOwner.title=Hub 加密檔案庫
+
+##Dialog Title
+
+## OnBoarding
+recover.onBoarding.useRecoveryKey=使用恢復金鑰
+recover.onBoarding.usePassword=使用密碼
+
+###Vault Config Missing
+###Masterkey Missing
+
+## Expert Settings
# Convert Vault
convertVault.title=轉換加密檔案庫