mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-14 16:51:28 +00:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ca1ff1a2d | ||
|
|
164a350e7e | ||
|
|
b48ebd524b | ||
|
|
7ba9d4de4f | ||
|
|
807e718d13 | ||
|
|
8ed1878035 | ||
|
|
4e3b2e0be0 | ||
|
|
c2819963d2 | ||
|
|
702ae72063 | ||
|
|
b296dc775c | ||
|
|
e5e0d4076a | ||
|
|
da0eeb2e45 | ||
|
|
ff49094f35 | ||
|
|
be1c5da54e | ||
|
|
40abf582c5 | ||
|
|
a8377be691 | ||
|
|
81c12f50fe | ||
|
|
e2eac0e398 | ||
|
|
9d573c497e | ||
|
|
81087a9568 | ||
|
|
2806525397 | ||
|
|
0c0060262a | ||
|
|
9af4ffe83b | ||
|
|
c6f963793d | ||
|
|
8c34fc76c5 | ||
|
|
785cf7a9a6 | ||
|
|
c63837c4ce | ||
|
|
b1a3ef9023 | ||
|
|
32436f779f | ||
|
|
ccc6f605ba | ||
|
|
f338d2447b | ||
|
|
179240b325 | ||
|
|
32a65bddce | ||
|
|
710cdf800d | ||
|
|
1d6edb8373 | ||
|
|
a3d30612ec | ||
|
|
6acda9b13c | ||
|
|
28cb812dab | ||
|
|
68ea4af0ad | ||
|
|
0af0a9e440 | ||
|
|
0989c735c0 | ||
|
|
a3492b9ea3 | ||
|
|
e345e6415f | ||
|
|
5b6d09308b | ||
|
|
49bda58993 | ||
|
|
32d7189a12 | ||
|
|
1253b7db2b | ||
|
|
067a7ad3ee | ||
|
|
a9ec76a344 | ||
|
|
085f762a35 | ||
|
|
7dd1c3576f | ||
|
|
d23bd2865a | ||
|
|
4429d57b5e | ||
|
|
2ff71ed7b0 | ||
|
|
82de8b6994 | ||
|
|
d4cba2fd6e | ||
|
|
ff80f634d2 | ||
|
|
6386dd3d50 | ||
|
|
a3f05db189 | ||
|
|
151ef6c7b2 | ||
|
|
72fd38baf1 | ||
|
|
532ffb1202 | ||
|
|
2a704d5eb4 | ||
|
|
e8f8466d9a | ||
|
|
9297562c99 | ||
|
|
7d62fc78de | ||
|
|
ba627d0d60 | ||
|
|
8e7e7de358 | ||
|
|
10c60d7492 | ||
|
|
aa03bd119a |
29
.github/release.yml
vendored
Normal file
29
.github/release.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# .github/release.yml
|
||||
# see https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
|
||||
|
||||
changelog:
|
||||
exclude:
|
||||
authors:
|
||||
- cryptobot
|
||||
- dependabot
|
||||
- github-actions
|
||||
categories:
|
||||
- title: What's New 🎉
|
||||
labels:
|
||||
- type:feature-request
|
||||
- type:enhancement
|
||||
- title: Bugfixes 🐛
|
||||
labels:
|
||||
- type:security-issue
|
||||
- type:bug
|
||||
- type:minor-bug
|
||||
- title: Other Changes 📎
|
||||
labels:
|
||||
- "*"
|
||||
exclude:
|
||||
labels:
|
||||
- type:feature-request
|
||||
- type:enhancement
|
||||
- type:security-issue
|
||||
- type:bug
|
||||
- type:minor-bug
|
||||
2
.github/workflows/appimage.yml
vendored
2
.github/workflows/appimage.yml
vendored
@@ -10,7 +10,7 @@ on:
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
|
||||
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
types: [labeled]
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -53,4 +53,9 @@ jobs:
|
||||
body: |-
|
||||
:construction: Work in Progress
|
||||
|
||||
⏳ Please be patient, the builds are still [running](https://github.com/cryptomator/cryptomator/actions). New versions of Cryptomator can be found here in a few moments. ⏳
|
||||
|
||||
As usual, the GPG signatures can be checked using [our public key `5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a).
|
||||
|
||||
---
|
||||
<!-- Don't forget to include the 💾 SHA-256 checksums of release artifacts: -->
|
||||
8
.github/workflows/debian.yml
vendored
8
.github/workflows/debian.yml
vendored
@@ -19,9 +19,9 @@ on:
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_linux-aarch64_bin-jmods.zip'
|
||||
JAVA_VERSION: 20
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_linux-aarch64_bin-jmods.zip'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
run: |
|
||||
sudo add-apt-repository ppa:coffeelibs/openjdk
|
||||
sudo apt-get update
|
||||
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-19 libgtk2.0-0
|
||||
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.JAVA_VERSION }} libgtk2.0-0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
|
||||
2
.github/workflows/get-version.yml
vendored
2
.github/workflows/get-version.yml
vendored
@@ -22,7 +22,7 @@ on:
|
||||
value: ${{ jobs.determine-version.outputs.type }}
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'temurin'
|
||||
JAVA_CACHE: 'maven'
|
||||
|
||||
|
||||
2
.github/workflows/mac-dmg.yml
vendored
2
.github/workflows/mac-dmg.yml
vendored
@@ -10,7 +10,7 @@ on:
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
|
||||
2
.github/workflows/pullrequest.yml
vendored
2
.github/workflows/pullrequest.yml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
||||
2
.github/workflows/release-check.yml
vendored
2
.github/workflows/release-check.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- 'hotfix/**'
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
||||
8
.github/workflows/win-exe.yml
vendored
8
.github/workflows/win-exe.yml
vendored
@@ -14,11 +14,11 @@ on:
|
||||
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'temurin'
|
||||
JAVA_CACHE: 'maven'
|
||||
JFX_JMODS_URL: 'https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_windows-x64_bin-jmods.zip'
|
||||
JFX_JMODS_HASH: 'B7CF2CAD2468842B3B78D99F6C0555771499A36FA1F1EE3DD1B9A4597F1FAB86'
|
||||
JFX_JMODS_URL: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_windows-x64_bin-jmods.zip'
|
||||
JFX_JMODS_HASH: 'D00767334C43B8832B5CF10267D34CA8F563D187C4655B73EB6020DD79C054B5'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
run: |
|
||||
curl --output jfxjmods.zip -L "${{ env.JFX_JMODS_URL }}"
|
||||
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.equals("${{ env.JFX_JMODS_HASH }}")) {
|
||||
exit 1;
|
||||
throw "Wrong checksum of JMOD archive downloaded from ${{ env.JFX_JMODS_URL }}.";
|
||||
}
|
||||
Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
|
||||
Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
|
||||
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -8,7 +8,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_20_PREVIEW" project-jdk-name="20" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -66,6 +66,9 @@
|
||||
</content_rating>
|
||||
|
||||
<releases>
|
||||
<release date="2023-07-24" version="1.9.2"/>
|
||||
<release date="2023-06-07" version="1.9.1"/>
|
||||
<release date="2023-05-30" version="1.9.0"/>
|
||||
<release date="2023-04-25" version="1.8.0"/>
|
||||
<release date="2023-04-07" version="1.7.5"/>
|
||||
<release date="2023-04-05" version="1.7.4"/>
|
||||
|
||||
2
dist/linux/debian/control
vendored
2
dist/linux/debian/control
vendored
@@ -2,7 +2,7 @@ Source: cryptomator
|
||||
Maintainer: Cryptobot <releases@cryptomator.org>
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>=10), coffeelibs-jdk-19, libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
|
||||
Build-Depends: debhelper (>=10), coffeelibs-jdk-20, libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
|
||||
Standards-Version: 4.5.0
|
||||
Homepage: https://cryptomator.org
|
||||
Vcs-Git: https://github.com/cryptomator/cryptomator.git
|
||||
|
||||
2
dist/linux/debian/rules
vendored
2
dist/linux/debian/rules
vendored
@@ -4,7 +4,7 @@
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
JAVA_HOME = /usr/lib/jvm/java-19-coffeelibs
|
||||
JAVA_HOME = /usr/lib/jvm/java-20-coffeelibs
|
||||
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
||||
ifeq ($(DEB_BUILD_ARCH),amd64)
|
||||
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
|
||||
|
||||
22
dist/win/resources/main.wxs
vendored
22
dist/win/resources/main.wxs
vendored
@@ -70,6 +70,9 @@
|
||||
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
||||
<?endif?>
|
||||
|
||||
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
|
||||
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
|
||||
|
||||
<?ifndef SkipCryptomatorLegacyCheck ?>
|
||||
<!-- Block installation if innosetup entry of Cryptomator is found -->
|
||||
<Property Id="OLDEXEINSTALLER">
|
||||
@@ -129,11 +132,17 @@
|
||||
<CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
|
||||
<?endif?>
|
||||
|
||||
<Property Id="WixQuietExec64CmdTimeout" Value="20" />
|
||||
<!-- Note for custom actions: Immediate CAs run BEFORE the files are installed, hence if you depend on installed files, the CAs must be deferred.-->
|
||||
<!-- WebDAV patches -->
|
||||
<CustomAction Id="PatchWebDAV" Impersonate="no" ExeCommand="[INSTALLDIR]patchWebDAV.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
|
||||
<SetProperty Id="PatchWebDAV" Value=""[INSTALLDIR]patchWebDAV.bat""
|
||||
Sequence="execute" Before="PatchWebDAV" />
|
||||
<CustomAction Id="PatchWebDAV" BinaryKey="WixCA" DllEntry="WixQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
|
||||
|
||||
<!-- Special Settings migration for 1.7.0,. Should be removed eventually, for more info, see ../contrib/version170-migrate-settings.ps1-->
|
||||
<CustomAction Id="V170MigrateSettings" Impersonate="no" ExeCommand="[INSTALLDIR]version170-migrate-settings.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
|
||||
<SetProperty Id="V170MigrateSettings" Value=""[INSTALLDIR]version170-migrate-settings.bat""
|
||||
Sequence="execute" Before="V170MigrateSettings" />
|
||||
<CustomAction Id="V170MigrateSettings" BinaryKey="WixCA" DllEntry="WixQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
|
||||
|
||||
<!-- Running App detection and exit -->
|
||||
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
||||
@@ -172,11 +181,12 @@
|
||||
<?endif?>
|
||||
|
||||
<?ifndef JpAllowUpgrades ?>
|
||||
<Custom Action="JpDisallowUpgrade" After="FindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
|
||||
<Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
|
||||
<?endif?>
|
||||
<?ifndef JpAllowDowngrades ?>
|
||||
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
||||
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
||||
<?endif?>
|
||||
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||
|
||||
<!-- Check and fail if Cryptomator is running -->
|
||||
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
|
||||
@@ -188,6 +198,10 @@
|
||||
<Custom Action="V170MigrateSettings" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<InstallUISequence>
|
||||
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||
</InstallUISequence>
|
||||
|
||||
<WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
|
||||
<WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
|
||||
</Product>
|
||||
|
||||
33
pom.xml
33
pom.xml
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptomator</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.9.2</version>
|
||||
<name>Cryptomator Desktop App</name>
|
||||
|
||||
<organization>
|
||||
@@ -26,45 +26,45 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.jdk.version>19</project.jdk.version>
|
||||
<project.jdk.version>20</project.jdk.version>
|
||||
|
||||
<!-- Group IDs of jars that need to stay on the class path for now -->
|
||||
<!-- Once hypfvieh, swiesend, purejava and integrations-linux have module-info, remove them-->
|
||||
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>2.6.2</cryptomator.cryptofs.version>
|
||||
<cryptomator.cryptofs.version>2.6.5</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.2.0</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.2.0</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.2.0</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.2.0</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>2.0.5</cryptomator.fuse.version>
|
||||
<cryptomator.integrations.linux.version>1.2.1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>3.0.0</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>2.0.0</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>2.0.2</cryptomator.webdav.version>
|
||||
<cryptomator.webdav.version>2.0.3</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<dagger.version>2.45</dagger.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
<guava.version>32.0.0-jre</guava.version>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<javafx.version>19.0.2.1</javafx.version>
|
||||
<jwt.version>4.3.0</jwt.version>
|
||||
<javafx.version>20.0.1</javafx.version>
|
||||
<jwt.version>4.4.0</jwt.version>
|
||||
<nimbus-jose.version>9.31</nimbus-jose.version>
|
||||
<logback.version>1.4.5</logback.version>
|
||||
<slf4j.version>2.0.6</slf4j.version>
|
||||
<logback.version>1.4.7</logback.version>
|
||||
<slf4j.version>2.0.7</slf4j.version>
|
||||
<tinyoauth2.version>0.5.1</tinyoauth2.version>
|
||||
<zxcvbn.version>1.7.0</zxcvbn.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.9.2</junit.jupiter.version>
|
||||
<mockito.version>5.1.1</mockito.version>
|
||||
<junit.jupiter.version>5.9.3</junit.jupiter.version>
|
||||
<mockito.version>5.3.1</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
|
||||
<!-- build-time dependencies -->
|
||||
<jetbrains.annotations.version>23.0.0</jetbrains.annotations.version>
|
||||
<dependency-check.version>8.1.0</dependency-check.version>
|
||||
<jacoco.version>0.8.8</jacoco.version>
|
||||
<dependency-check.version>8.1.2</dependency-check.version>
|
||||
<jacoco.version>0.8.9</jacoco.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -332,6 +332,9 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>--enable-preview</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import ch.qos.logback.classic.spi.Configurator;
|
||||
import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.GoogleDriveLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.ICloudMacLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.ICloudWindowsLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.MegaLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
|
||||
import org.cryptomator.integrations.tray.TrayMenuController;
|
||||
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
||||
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
||||
@@ -37,6 +49,15 @@ open module org.cryptomator.desktop {
|
||||
/* TODO: filename-based modules: */
|
||||
requires static javax.inject; /* ugly dagger/guava crap */
|
||||
|
||||
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||
|
||||
provides TrayMenuController with AwtTrayMenuController;
|
||||
provides Configurator with LogbackConfiguratorFactory;
|
||||
provides LocationPresetsProvider with DropboxMacLocationPresetsProvider, //
|
||||
DropboxWindowsLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
|
||||
ICloudMacLocationPresetsProvider, ICloudWindowsLocationPresetsProvider, //
|
||||
GoogleDriveLocationPresetsProvider, //
|
||||
PCloudLocationPresetsProvider, MegaLocationPresetsProvider, //
|
||||
OneDriveLinuxLocationPresetsProvider, OneDriveWindowsLocationPresetsProvider, //
|
||||
OneDriveMacLocationPresetsProvider;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Enum of common cloud providers and their default local storage location path.
|
||||
*/
|
||||
public enum LocationPreset {
|
||||
|
||||
DROPBOX("Dropbox", "~/Dropbox"),
|
||||
ICLOUDDRIVE("iCloud Drive", "~/Library/Mobile Documents/com~apple~CloudDocs", "~/iCloudDrive"),
|
||||
GDRIVE("Google Drive", "~/Google Drive/My Drive", "~/Google Drive"),
|
||||
MEGA("MEGA", "~/MEGA"),
|
||||
ONEDRIVE("OneDrive", "~/OneDrive"),
|
||||
PCLOUD("pCloud", "~/pCloudDrive"),
|
||||
|
||||
LOCAL("local");
|
||||
|
||||
private final String name;
|
||||
private final List<Path> candidates;
|
||||
|
||||
LocationPreset(String name, String... candidates) {
|
||||
this.name = name;
|
||||
this.candidates = Arrays.stream(candidates).map(UserHome::resolve).map(Path::of).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for this LocationPreset if any of the associated paths exist.
|
||||
*
|
||||
* @return the first existing path or null, if none exists.
|
||||
*/
|
||||
public Path existingPath() {
|
||||
return candidates.stream().filter(Files::isDirectory).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDisplayName();
|
||||
}
|
||||
|
||||
//this contruct is needed, since static members are initialized after every enum member is initialized
|
||||
//TODO: refactor this to normal class and use this also in different parts of the project
|
||||
private static class UserHome {
|
||||
|
||||
private static final String USER_HOME = System.getProperty("user.home");
|
||||
|
||||
private static String resolve(String path) {
|
||||
if (path.startsWith("~/")) {
|
||||
return UserHome.USER_HOME + path.substring(1);
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
|
||||
|
||||
@OperatingSystem(LINUX)
|
||||
public final class DropboxLinuxLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path USER_HOME = LocationPresetsProvider.resolveLocation("~/.").toAbsolutePath();
|
||||
private static final Predicate<String> PATTERN = Pattern.compile("Dropbox \\(.+\\)").asMatchPredicate();
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
try (var dirStream = Files.list(USER_HOME)) {
|
||||
var presets = dirStream.filter(p -> Files.isDirectory(p) && PATTERN.test(p.getFileName().toString())) //
|
||||
.map(p -> new LocationPreset(p.getFileName().toString(), p)) //
|
||||
.toList();
|
||||
return presets.stream(); //workaround to ensure that the directory stream is always closed
|
||||
} catch (IOException | UncheckedIOException e) { //UncheckedIOException thrown by the stream of Files.list()
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
|
||||
@OperatingSystem(MAC)
|
||||
@CheckAvailability
|
||||
public final class DropboxMacLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/Dropbox");
|
||||
private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
|
||||
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION) || Files.isDirectory(FALLBACK_LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
if(Files.isDirectory(LOCATION)) {
|
||||
return Stream.of(new LocationPreset("Dropbox", LOCATION));
|
||||
} else if(Files.isDirectory(FALLBACK_LOCATION)) {
|
||||
return Stream.of(new LocationPreset("Dropbox", FALLBACK_LOCATION));
|
||||
} else {
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
|
||||
@OperatingSystem(WINDOWS)
|
||||
@CheckAvailability
|
||||
public final class DropboxWindowsLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
|
||||
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("Dropbox", LOCATION));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
|
||||
@OperatingSystem(WINDOWS)
|
||||
@OperatingSystem(MAC)
|
||||
@CheckAvailability
|
||||
public final class GoogleDriveLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION1 = LocationPresetsProvider.resolveLocation("~/GoogleDrive");
|
||||
private static final Path LOCATION2 = LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive");
|
||||
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION1) || Files.isDirectory(LOCATION2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
if(Files.isDirectory(LOCATION1)) {
|
||||
return Stream.of(new LocationPreset("Google Drive", LOCATION1));
|
||||
} else if(Files.isDirectory(LOCATION2)) {
|
||||
return Stream.of(new LocationPreset("Google Drive", LOCATION2));
|
||||
} else {
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
|
||||
@OperatingSystem(MAC)
|
||||
@CheckAvailability
|
||||
public final class ICloudMacLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/Mobile Documents/com~apple~CloudDocs");
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
|
||||
@OperatingSystem(WINDOWS)
|
||||
@CheckAvailability
|
||||
public final class ICloudWindowsLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/iCloudDrive");
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public record LocationPreset(String name, Path path) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.IntegrationsLoader;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public interface LocationPresetsProvider {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(LocationPresetsProvider.class);
|
||||
String USER_HOME = System.getProperty("user.home");
|
||||
|
||||
/**
|
||||
* Streams account-separated location presets found by this provider
|
||||
* @return Stream of LocationPresets
|
||||
*/
|
||||
Stream<LocationPreset> getLocations();
|
||||
|
||||
static Path resolveLocation(String p) {
|
||||
if (p.startsWith("~/")) {
|
||||
return Path.of(USER_HOME, p.substring(2));
|
||||
} else {
|
||||
return Path.of(p);
|
||||
}
|
||||
}
|
||||
|
||||
//copied from org.cryptomator.integrations.common.IntegrationsLoader
|
||||
//TODO: delete, once migrated to integrations-api
|
||||
static <T> Stream<T> loadAll(Class<T> clazz) {
|
||||
return ServiceLoader.load(clazz)
|
||||
.stream()
|
||||
.filter(LocationPresetsProvider::isSupportedOperatingSystem)
|
||||
.filter(LocationPresetsProvider::passesStaticAvailabilityCheck)
|
||||
.map(ServiceLoader.Provider::get)
|
||||
.peek(impl -> logServiceIsAvailable(clazz, impl.getClass()));
|
||||
}
|
||||
|
||||
|
||||
private static boolean isSupportedOperatingSystem(ServiceLoader.Provider<?> provider) {
|
||||
var annotations = provider.type().getAnnotationsByType(OperatingSystem.class);
|
||||
return annotations.length == 0 || Arrays.stream(annotations).anyMatch(OperatingSystem.Value::isCurrent);
|
||||
}
|
||||
|
||||
private static boolean passesStaticAvailabilityCheck(ServiceLoader.Provider<?> provider) {
|
||||
return passesStaticAvailabilityCheck(provider.type());
|
||||
}
|
||||
|
||||
static boolean passesStaticAvailabilityCheck(Class<?> type) {
|
||||
return passesAvailabilityCheck(type, null);
|
||||
}
|
||||
|
||||
private static void logServiceIsAvailable(Class<?> apiType, Class<?> implType) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("{}: Implementation is available: {}", apiType.getSimpleName(), implType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> boolean passesAvailabilityCheck(Class<? extends T> type, @Nullable T instance) {
|
||||
if (!type.isAnnotationPresent(CheckAvailability.class)) {
|
||||
return true; // if type is not annotated, skip tests
|
||||
}
|
||||
if (!type.getModule().isExported(type.getPackageName(), IntegrationsLoader.class.getModule())) {
|
||||
LOG.error("Can't run @CheckAvailability tests for class {}. Make sure to export {} to {}!", type.getName(), type.getPackageName(), IntegrationsLoader.class.getPackageName());
|
||||
return false;
|
||||
}
|
||||
return Arrays.stream(type.getMethods())
|
||||
.filter(m -> isAvailabilityCheck(m, instance == null))
|
||||
.allMatch(m -> passesAvailabilityCheck(m, instance));
|
||||
}
|
||||
|
||||
private static boolean passesAvailabilityCheck(Method m, @Nullable Object instance) {
|
||||
assert Boolean.TYPE.equals(m.getReturnType());
|
||||
try {
|
||||
return (boolean) m.invoke(instance);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
LOG.warn("Failed to invoke @CheckAvailability test {}#{}", m.getDeclaringClass(), m.getName(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAvailabilityCheck(Method m, boolean isStatic) {
|
||||
return m.isAnnotationPresent(CheckAvailability.class)
|
||||
&& Boolean.TYPE.equals(m.getReturnType())
|
||||
&& m.getParameterCount() == 0
|
||||
&& Modifier.isStatic(m.getModifiers()) == isStatic;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
|
||||
@OperatingSystem(WINDOWS)
|
||||
@OperatingSystem(MAC)
|
||||
@CheckAvailability
|
||||
public final class MegaLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/MEGA");
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("MEGA", LOCATION));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
|
||||
|
||||
@OperatingSystem(LINUX)
|
||||
@CheckAvailability
|
||||
public final class OneDriveLinuxLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("OneDrive", LOCATION));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
|
||||
@OperatingSystem(MAC)
|
||||
public final class OneDriveMacLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
|
||||
private static final Path PARENT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage");
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
var newLocations = getNewLocations().toList();
|
||||
if (newLocations.size() >= 1) {
|
||||
return newLocations.stream();
|
||||
} else {
|
||||
return getOldLocation();
|
||||
}
|
||||
}
|
||||
|
||||
private Stream<LocationPreset> getNewLocations() {
|
||||
try (var dirStream = Files.newDirectoryStream(PARENT_LOCATION, "OneDrive*")) {
|
||||
return StreamSupport.stream(dirStream.spliterator(), false) //
|
||||
.filter(Files::isDirectory) //
|
||||
.map(p -> new LocationPreset(String.join(" - ", p.getFileName().toString().split("-")), p));
|
||||
} catch (IOException e) {
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
|
||||
private Stream<LocationPreset> getOldLocation() {
|
||||
return Stream.of(new LocationPreset("OneDrive", FALLBACK_LOCATION)).filter(preset -> Files.isDirectory(preset.path()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
import org.jetbrains.annotations.Blocking;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
|
||||
@OperatingSystem(WINDOWS)
|
||||
public final class OneDriveWindowsLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OneDriveWindowsLocationPresetsProvider.class);
|
||||
private static final String REGSTR_TOKEN = "REG_SZ";
|
||||
private static final String REG_ONEDRIVE_ACCOUNTS = "HKEY_CURRENT_USER\\Software\\Microsoft\\OneDrive\\Accounts\\";
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
try {
|
||||
var accountRegKeys = queryRegistry(REG_ONEDRIVE_ACCOUNTS, List.of(), l -> l.startsWith(REG_ONEDRIVE_ACCOUNTS)).toList();
|
||||
var cloudLocations = new ArrayList<LocationPreset>();
|
||||
for (var accountRegKey : accountRegKeys) {
|
||||
var path = queryRegistry(accountRegKey, List.of("/v", "UserFolder"), l -> l.contains("UserFolder")).map(result -> result.substring(result.indexOf(REGSTR_TOKEN) + REGSTR_TOKEN.length()).trim()) //
|
||||
.map(Path::of) //
|
||||
.findFirst().orElseThrow();
|
||||
var name = "OneDrive"; //we assume personal oneDrive account by default
|
||||
if (!accountRegKey.endsWith("Personal")) {
|
||||
name = queryRegistry(accountRegKey, List.of("/v", "DisplayName"), l -> l.contains("DisplayName")).map(result -> result.substring(result.indexOf(REGSTR_TOKEN) + REGSTR_TOKEN.length()).trim()) //
|
||||
.map("OneDrive - "::concat) //
|
||||
.findFirst().orElseThrow();
|
||||
}
|
||||
cloudLocations.add(new LocationPreset(name, path));
|
||||
}
|
||||
return cloudLocations.stream();
|
||||
} catch (IOException | CommandFailedException | TimeoutException e) {
|
||||
LOG.error("Unable to determine OneDrive location", e);
|
||||
return Stream.of();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.error("Determination of OneDrive location interrupted", e);
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
|
||||
private Stream<String> queryRegistry(String keyname, List<String> moreArgs, Predicate<String> outputFilter) throws InterruptedException, CommandFailedException, TimeoutException, IOException {
|
||||
var args = new ArrayList<String>();
|
||||
args.add("reg");
|
||||
args.add("query");
|
||||
args.add(keyname);
|
||||
args.addAll(moreArgs);
|
||||
ProcessBuilder command = new ProcessBuilder(args);
|
||||
Process p = command.start();
|
||||
waitForSuccess(p, 3, "`reg query`");
|
||||
return p.inputReader(StandardCharsets.UTF_8).lines().filter(outputFilter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits {@code timeoutSeconds} seconds for {@code process} to finish with exit code {@code 0}.
|
||||
*
|
||||
* @param process The process to wait for
|
||||
* @param timeoutSeconds How long to wait (in seconds)
|
||||
* @param cmdDescription A short description of the process used to generate log and exception messages
|
||||
* @throws TimeoutException Thrown when the process doesn't finish in time
|
||||
* @throws InterruptedException Thrown when the thread is interrupted while waiting for the process to finish
|
||||
* @throws CommandFailedException Thrown when the process exit code is non-zero
|
||||
*/
|
||||
@Blocking
|
||||
private static void waitForSuccess(Process process, int timeoutSeconds, String cmdDescription) throws TimeoutException, InterruptedException, CommandFailedException {
|
||||
boolean exited = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
|
||||
if (!exited) {
|
||||
throw new TimeoutException(cmdDescription + " timed out after " + timeoutSeconds + "s");
|
||||
}
|
||||
if (process.exitValue() != 0) {
|
||||
@SuppressWarnings("resource") var stdout = process.inputReader(StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));
|
||||
@SuppressWarnings("resource") var stderr = process.errorReader(StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));
|
||||
throw new CommandFailedException(cmdDescription, process.exitValue(), stdout, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CommandFailedException extends Exception {
|
||||
|
||||
int exitCode;
|
||||
String stdout;
|
||||
String stderr;
|
||||
|
||||
private CommandFailedException(String cmdDescription, int exitCode, String stdout, String stderr) {
|
||||
super(cmdDescription + " returned with non-zero exit code " + exitCode);
|
||||
this.exitCode = exitCode;
|
||||
this.stdout = stdout;
|
||||
this.stderr = stderr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.cryptomator.common.locationpresets;
|
||||
|
||||
import org.cryptomator.integrations.common.CheckAvailability;
|
||||
import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
|
||||
@OperatingSystem(WINDOWS)
|
||||
@OperatingSystem(MAC)
|
||||
@CheckAvailability
|
||||
public final class PCloudLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/pCloudDrive");
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("pCloud", LOCATION));
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.function.Function;
|
||||
|
||||
// TODO make sealed, remove enum
|
||||
interface IpcMessage {
|
||||
//TODO can the enum be removed?
|
||||
sealed interface IpcMessage permits HandleLaunchArgsMessage, RevealRunningAppMessage {
|
||||
|
||||
enum MessageType {
|
||||
REVEAL_RUNNING_APP(RevealRunningAppMessage::decode),
|
||||
|
||||
@@ -5,10 +5,9 @@ import java.util.List;
|
||||
public interface IpcMessageListener {
|
||||
|
||||
default void handleMessage(IpcMessage message) {
|
||||
if (message instanceof RevealRunningAppMessage) {
|
||||
revealRunningApp();
|
||||
} else if (message instanceof HandleLaunchArgsMessage m) {
|
||||
handleLaunchArgs(m.args());
|
||||
switch (message) {
|
||||
case RevealRunningAppMessage m -> revealRunningApp(); // TODO: rename to _ with JEP 443
|
||||
case HandleLaunchArgsMessage m -> handleLaunchArgs(m.args());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -14,26 +16,39 @@ import java.util.Locale;
|
||||
public class SupportedLanguages {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SupportedLanguages.class);
|
||||
// these are BCP 47 language codes, not ISO. Note the "-" instead of the "_":
|
||||
public static final List<String> LANGUAGAE_TAGS = List.of("en", "ar", "be", "bn", "bs", "ca", "cs", "da", "de", "el", "es", "fil", "fa", "fr", "gl", "he", //
|
||||
"hi", "hr", "hu", "id", "it", "ja", "ko", "lv", "mk", "nb", "nl", "nn", "no", "pa", "pl", "pt", "pt-BR", "ro", "ru", "si", "sk", "sr", "sr-Latn", "sv", "sw", //
|
||||
"ta", "te", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
|
||||
// these are BCP 47 language codes, not ISO. Note the "-" instead of the "_".
|
||||
// "en" is not part of this list - it is always inserted at the top.
|
||||
public static final List<String> LANGUAGE_TAGS = List.of("ar", "be", "bn", "bs", "ca", "cs", "da", "de", "el", "es", "fr", "gl", "he", //
|
||||
"hi", "hr", "hu", "id", "it", "ja", "ko", "lv", "nb", "nl", "nn", "pa", "pl", "pt", "pt-BR", "ro", "ru", "sk", "sr", "sr-Latn", "sv", "sw", //
|
||||
"ta", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
|
||||
public static final String ENGLISH = "en";
|
||||
|
||||
@Nullable
|
||||
private final String preferredLanguage;
|
||||
private final List<String> sortedLanguageTags;
|
||||
|
||||
private final Locale preferredLocale;
|
||||
|
||||
@Inject
|
||||
public SupportedLanguages(Settings settings) {
|
||||
this.preferredLanguage = settings.languageProperty().get();
|
||||
var preferredLanguage = settings.languageProperty().get();
|
||||
preferredLocale = preferredLanguage == null ? Locale.getDefault() : Locale.forLanguageTag(preferredLanguage);
|
||||
var collator = Collator.getInstance(preferredLocale);
|
||||
collator.setStrength(Collator.PRIMARY);
|
||||
var sorted = new ArrayList<String>();
|
||||
sorted.add(0, Settings.DEFAULT_LANGUAGE);
|
||||
sorted.add(1, ENGLISH);
|
||||
LANGUAGE_TAGS.stream() //
|
||||
.sorted((a, b) -> collator.compare(Locale.forLanguageTag(a).getDisplayName(), Locale.forLanguageTag(b).getDisplayName())) //
|
||||
.forEach(sorted::add);
|
||||
sortedLanguageTags = Collections.unmodifiableList(sorted);
|
||||
}
|
||||
|
||||
public void applyPreferred() {
|
||||
if (preferredLanguage == null) {
|
||||
LOG.debug("Using system locale");
|
||||
return;
|
||||
}
|
||||
var preferredLocale = Locale.forLanguageTag(preferredLanguage);
|
||||
LOG.debug("Applying preferred locale {}", preferredLocale.getDisplayName(Locale.ENGLISH));
|
||||
LOG.debug("Using locale {}", preferredLocale);
|
||||
Locale.setDefault(preferredLocale);
|
||||
}
|
||||
|
||||
public List<String> getLanguageTags() {
|
||||
return sortedLanguageTags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.cryptomator.ui.addvaultwizard;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.ObservableUtil;
|
||||
import org.cryptomator.common.locationpresets.LocationPreset;
|
||||
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
@@ -10,22 +13,19 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.beans.binding.Bindings;
|
||||
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.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.Toggle;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.File;
|
||||
@@ -34,6 +34,9 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@AddVaultWizardScoped
|
||||
@@ -46,70 +49,72 @@ public class CreateNewVaultLocationController implements FxController {
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> chooseNameScene;
|
||||
private final Lazy<Scene> choosePasswordScene;
|
||||
private final ObservedLocationPresets locationPresets;
|
||||
private final List<RadioButton> locationPresetBtns;
|
||||
private final ObjectProperty<Path> vaultPath;
|
||||
private final StringProperty vaultName;
|
||||
private final ResourceBundle resourceBundle;
|
||||
private final BooleanBinding validVaultPath;
|
||||
private final ObservableValue<VaultPathStatus> vaultPathStatus;
|
||||
private final ObservableValue<Boolean> validVaultPath;
|
||||
private final BooleanProperty usePresetPath;
|
||||
private final StringProperty statusText;
|
||||
private final ObjectProperty<Node> statusGraphic;
|
||||
|
||||
private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH;
|
||||
|
||||
//FXML
|
||||
public ToggleGroup predefinedLocationToggler;
|
||||
public RadioButton iclouddriveRadioButton;
|
||||
public RadioButton dropboxRadioButton;
|
||||
public RadioButton gdriveRadioButton;
|
||||
public RadioButton onedriveRadioButton;
|
||||
public RadioButton megaRadioButton;
|
||||
public RadioButton pcloudRadioButton;
|
||||
public ToggleGroup locationPresetsToggler;
|
||||
public VBox radioButtonVBox;
|
||||
public RadioButton customRadioButton;
|
||||
public Label vaultPathStatus;
|
||||
public Label locationStatusLabel;
|
||||
public FontAwesome5IconView goodLocation;
|
||||
public FontAwesome5IconView badLocation;
|
||||
|
||||
@Inject
|
||||
CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy<Scene> chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy<Scene> choosePasswordScene, ObservedLocationPresets locationPresets, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
|
||||
CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy<Scene> chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy<Scene> choosePasswordScene, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
|
||||
this.window = window;
|
||||
this.chooseNameScene = chooseNameScene;
|
||||
this.choosePasswordScene = choosePasswordScene;
|
||||
this.locationPresets = locationPresets;
|
||||
this.vaultPath = vaultPath;
|
||||
this.vaultName = vaultName;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.validVaultPath = Bindings.createBooleanBinding(this::validateVaultPathAndSetStatus, this.vaultPath);
|
||||
this.vaultPathStatus = ObservableUtil.mapWithDefault(vaultPath, this::validatePath, new VaultPathStatus(false, "error.message"));
|
||||
this.validVaultPath = ObservableUtil.mapWithDefault(vaultPathStatus, VaultPathStatus::valid, false);
|
||||
this.vaultPathStatus.addListener(this::updateStatusLabel);
|
||||
this.usePresetPath = new SimpleBooleanProperty();
|
||||
this.statusText = new SimpleStringProperty();
|
||||
this.statusGraphic = new SimpleObjectProperty<>();
|
||||
this.locationPresetBtns = LocationPresetsProvider.loadAll(LocationPresetsProvider.class) //
|
||||
.flatMap(LocationPresetsProvider::getLocations) //
|
||||
.sorted(Comparator.comparing(LocationPreset::name)) //
|
||||
.map(preset -> { //
|
||||
var btn = new RadioButton(preset.name());
|
||||
btn.setUserData(preset.path());
|
||||
return btn;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private boolean validateVaultPathAndSetStatus() {
|
||||
final Path p = vaultPath.get();
|
||||
if (p == null) {
|
||||
statusText.set("Error: Path is NULL.");
|
||||
statusGraphic.set(badLocation);
|
||||
return false;
|
||||
} else if (!Files.exists(p.getParent())) {
|
||||
statusText.set(resourceBundle.getString("addvaultwizard.new.locationDoesNotExist"));
|
||||
statusGraphic.set(badLocation);
|
||||
return false;
|
||||
private VaultPathStatus validatePath(Path p) throws NullPointerException {
|
||||
if (!Files.exists(p.getParent())) {
|
||||
return new VaultPathStatus(false, "addvaultwizard.new.locationDoesNotExist");
|
||||
} else if (!isActuallyWritable(p.getParent())) {
|
||||
statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsNotWritable"));
|
||||
statusGraphic.set(badLocation);
|
||||
return false;
|
||||
return new VaultPathStatus(false, "addvaultwizard.new.locationIsNotWritable");
|
||||
} else if (!Files.notExists(p)) {
|
||||
statusText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
|
||||
statusGraphic.set(badLocation);
|
||||
return false;
|
||||
return new VaultPathStatus(false, "addvaultwizard.new.fileAlreadyExists");
|
||||
} else {
|
||||
statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsOk"));
|
||||
statusGraphic.set(goodLocation);
|
||||
return true;
|
||||
return new VaultPathStatus(true, "addvaultwizard.new.locationIsOk");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStatusLabel(ObservableValue<? extends VaultPathStatus> observable, VaultPathStatus oldValue, VaultPathStatus newValue) {
|
||||
if (newValue.valid()) {
|
||||
locationStatusLabel.setGraphic(goodLocation);
|
||||
locationStatusLabel.getStyleClass().remove("label-red");
|
||||
locationStatusLabel.getStyleClass().add("label-muted");
|
||||
} else {
|
||||
locationStatusLabel.setGraphic(badLocation);
|
||||
locationStatusLabel.getStyleClass().remove("label-muted");
|
||||
locationStatusLabel.getStyleClass().add("label-red");
|
||||
}
|
||||
this.locationStatusLabel.setText(resourceBundle.getString(newValue.localizationKey()));
|
||||
}
|
||||
|
||||
|
||||
private boolean isActuallyWritable(Path p) {
|
||||
Path tmpFile = p.resolve(TEMP_FILE_FORMAT);
|
||||
try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
|
||||
@@ -127,26 +132,15 @@ public class CreateNewVaultLocationController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
|
||||
usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
|
||||
radioButtonVBox.getChildren().addAll(1, locationPresetBtns); //first item is the list header
|
||||
locationPresetsToggler.getToggles().addAll(locationPresetBtns);
|
||||
locationPresetsToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
|
||||
usePresetPath.bind(locationPresetsToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
|
||||
}
|
||||
|
||||
private void togglePredefinedLocation(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
|
||||
if (iclouddriveRadioButton.equals(newValue)) {
|
||||
vaultPath.set(locationPresets.getIclouddriveLocation().resolve(vaultName.get()));
|
||||
} else if (dropboxRadioButton.equals(newValue)) {
|
||||
vaultPath.set(locationPresets.getDropboxLocation().resolve(vaultName.get()));
|
||||
} else if (gdriveRadioButton.equals(newValue)) {
|
||||
vaultPath.set(locationPresets.getGdriveLocation().resolve(vaultName.get()));
|
||||
} else if (onedriveRadioButton.equals(newValue)) {
|
||||
vaultPath.set(locationPresets.getOnedriveLocation().resolve(vaultName.get()));
|
||||
} else if (megaRadioButton.equals(newValue)) {
|
||||
vaultPath.set(locationPresets.getMegaLocation().resolve(vaultName.get()));
|
||||
} else if (pcloudRadioButton.equals(newValue)) {
|
||||
vaultPath.set(locationPresets.getPcloudLocation().resolve(vaultName.get()));
|
||||
} else if (customRadioButton.equals(newValue)) {
|
||||
vaultPath.set(customVaultPath.resolve(vaultName.get()));
|
||||
}
|
||||
var storagePath = Optional.ofNullable((Path) newValue.getUserData()).orElse(customVaultPath);
|
||||
vaultPath.set(storagePath.resolve(vaultName.get()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -156,10 +150,8 @@ public class CreateNewVaultLocationController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void next() {
|
||||
if (validateVaultPathAndSetStatus()) {
|
||||
if (validVaultPath.getValue()) {
|
||||
window.setScene(choosePasswordScene.get());
|
||||
} else {
|
||||
validVaultPath.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +171,12 @@ public class CreateNewVaultLocationController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal classes */
|
||||
|
||||
private record VaultPathStatus(boolean valid, String localizationKey) {
|
||||
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public Path getVaultPath() {
|
||||
@@ -189,47 +187,28 @@ public class CreateNewVaultLocationController implements FxController {
|
||||
return vaultPath;
|
||||
}
|
||||
|
||||
public BooleanBinding validVaultPathProperty() {
|
||||
public ObservableValue<Boolean> validVaultPathProperty() {
|
||||
return validVaultPath;
|
||||
}
|
||||
|
||||
public Boolean getValidVaultPath() {
|
||||
return validVaultPath.get();
|
||||
}
|
||||
|
||||
public ObservedLocationPresets getObservedLocationPresets() {
|
||||
return locationPresets;
|
||||
public boolean isValidVaultPath() {
|
||||
return validVaultPath.getValue();
|
||||
}
|
||||
|
||||
public BooleanProperty usePresetPathProperty() {
|
||||
return usePresetPath;
|
||||
}
|
||||
|
||||
public boolean getUsePresetPath() {
|
||||
public boolean isUsePresetPath() {
|
||||
return usePresetPath.get();
|
||||
}
|
||||
|
||||
public BooleanBinding anyRadioButtonSelectedProperty() {
|
||||
return predefinedLocationToggler.selectedToggleProperty().isNotNull();
|
||||
return locationPresetsToggler.selectedToggleProperty().isNotNull();
|
||||
}
|
||||
|
||||
public boolean isAnyRadioButtonSelected() {
|
||||
return anyRadioButtonSelectedProperty().get();
|
||||
}
|
||||
|
||||
public StringProperty statusTextProperty() {
|
||||
return statusText;
|
||||
}
|
||||
|
||||
public String getStatusText() {
|
||||
return statusText.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<Node> statusGraphicProperty() {
|
||||
return statusGraphic;
|
||||
}
|
||||
|
||||
public Node getStatusGraphic() {
|
||||
return statusGraphic.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
package org.cryptomator.ui.addvaultwizard;
|
||||
|
||||
import org.cryptomator.common.LocationPreset;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@AddVaultWizardScoped
|
||||
public class ObservedLocationPresets {
|
||||
|
||||
private final ReadOnlyObjectProperty<Path> iclouddriveLocation;
|
||||
private final ReadOnlyObjectProperty<Path> dropboxLocation;
|
||||
private final ReadOnlyObjectProperty<Path> gdriveLocation;
|
||||
private final ReadOnlyObjectProperty<Path> onedriveLocation;
|
||||
private final ReadOnlyObjectProperty<Path> megaLocation;
|
||||
private final ReadOnlyObjectProperty<Path> pcloudLocation;
|
||||
private final BooleanBinding foundIclouddrive;
|
||||
private final BooleanBinding foundDropbox;
|
||||
private final BooleanBinding foundGdrive;
|
||||
private final BooleanBinding foundOnedrive;
|
||||
private final BooleanBinding foundMega;
|
||||
private final BooleanBinding foundPcloud;
|
||||
|
||||
@Inject
|
||||
public ObservedLocationPresets() {
|
||||
this.iclouddriveLocation = new SimpleObjectProperty<>(LocationPreset.ICLOUDDRIVE.existingPath());
|
||||
this.dropboxLocation = new SimpleObjectProperty<>(LocationPreset.DROPBOX.existingPath());
|
||||
this.gdriveLocation = new SimpleObjectProperty<>(LocationPreset.GDRIVE.existingPath());
|
||||
this.onedriveLocation = new SimpleObjectProperty<>(LocationPreset.ONEDRIVE.existingPath());
|
||||
this.megaLocation = new SimpleObjectProperty<>(LocationPreset.MEGA.existingPath());
|
||||
this.pcloudLocation = new SimpleObjectProperty<>(LocationPreset.PCLOUD.existingPath());
|
||||
this.foundIclouddrive = iclouddriveLocation.isNotNull();
|
||||
this.foundDropbox = dropboxLocation.isNotNull();
|
||||
this.foundGdrive = gdriveLocation.isNotNull();
|
||||
this.foundOnedrive = onedriveLocation.isNotNull();
|
||||
this.foundMega = megaLocation.isNotNull();
|
||||
this.foundPcloud = pcloudLocation.isNotNull();
|
||||
}
|
||||
|
||||
/* Observables */
|
||||
|
||||
public ReadOnlyObjectProperty<Path> iclouddriveLocationProperty() {
|
||||
return iclouddriveLocation;
|
||||
}
|
||||
|
||||
public Path getIclouddriveLocation() {
|
||||
return iclouddriveLocation.get();
|
||||
}
|
||||
|
||||
public BooleanBinding foundIclouddriveProperty() {
|
||||
return foundIclouddrive;
|
||||
}
|
||||
|
||||
public boolean isFoundIclouddrive() {
|
||||
return foundIclouddrive.get();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Path> dropboxLocationProperty() {
|
||||
return dropboxLocation;
|
||||
}
|
||||
|
||||
public Path getDropboxLocation() {
|
||||
return dropboxLocation.get();
|
||||
}
|
||||
|
||||
public BooleanBinding foundDropboxProperty() {
|
||||
return foundDropbox;
|
||||
}
|
||||
|
||||
public boolean isFoundDropbox() {
|
||||
return foundDropbox.get();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Path> gdriveLocationProperty() {
|
||||
return gdriveLocation;
|
||||
}
|
||||
|
||||
public Path getGdriveLocation() {
|
||||
return gdriveLocation.get();
|
||||
}
|
||||
|
||||
public BooleanBinding foundGdriveProperty() {
|
||||
return foundGdrive;
|
||||
}
|
||||
|
||||
public boolean isFoundGdrive() {
|
||||
return foundGdrive.get();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Path> onedriveLocationProperty() {
|
||||
return onedriveLocation;
|
||||
}
|
||||
|
||||
public Path getOnedriveLocation() {
|
||||
return onedriveLocation.get();
|
||||
}
|
||||
|
||||
public BooleanBinding foundOnedriveProperty() {
|
||||
return foundOnedrive;
|
||||
}
|
||||
|
||||
public boolean isFoundOnedrive() {
|
||||
return foundOnedrive.get();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Path> megaLocationProperty() {
|
||||
return megaLocation;
|
||||
}
|
||||
|
||||
public Path getMegaLocation() {
|
||||
return megaLocation.get();
|
||||
}
|
||||
|
||||
public BooleanBinding foundMegaProperty() {
|
||||
return foundMega;
|
||||
}
|
||||
|
||||
public boolean isFoundMega() {
|
||||
return foundMega.get();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<Path> pcloudLocationProperty() {
|
||||
return pcloudLocation;
|
||||
}
|
||||
|
||||
public Path getPcloudLocation() {
|
||||
return pcloudLocation.get();
|
||||
}
|
||||
|
||||
public BooleanBinding foundPcloudProperty() {
|
||||
return foundPcloud;
|
||||
}
|
||||
|
||||
public boolean isFoundPcloud() {
|
||||
return foundPcloud.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +1,85 @@
|
||||
package org.cryptomator.ui.fxapp;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.collections.ObservableList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class AutoUnlocker {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AutoUnlocker.class);
|
||||
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final FxApplicationWindows appWindows;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private ScheduledFuture<?> unlockMissingFuture;
|
||||
private ScheduledFuture<?> timeoutFuture;
|
||||
|
||||
@Inject
|
||||
public AutoUnlocker(ObservableList<Vault> vaults, FxApplicationWindows appWindows) {
|
||||
public AutoUnlocker(ObservableList<Vault> vaults, FxApplicationWindows appWindows, ScheduledExecutorService scheduler) {
|
||||
this.vaults = vaults;
|
||||
this.appWindows = appWindows;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
vaults.stream().filter(Vault::isLocked) //
|
||||
.filter(v -> v.getVaultSettings().unlockAfterStartup().get()) //
|
||||
.<CompletionStage<Void>>reduce(CompletableFuture.completedFuture(null), //
|
||||
(unlockFlow, v) -> unlockFlow.handle((voit, ex) -> appWindows.startUnlockWorkflow(v, null)).thenCompose(stage -> stage), //we don't care here about the exception, logged elsewhere
|
||||
(unlockChain1, unlockChain2) -> unlockChain1.handle((voit, ex) -> unlockChain2).thenCompose(stage -> stage));
|
||||
public void tryUnlockForTimespan(int timespan, TimeUnit timeUnit) {
|
||||
// Unlock all available auto unlock vaults
|
||||
Predicate<Vault> shouldAutoUnlock = v -> v.getVaultSettings().unlockAfterStartup().get();
|
||||
unlockSequentially(vaults.stream().filter(shouldAutoUnlock)).thenRun(() -> startUnlockMissing(timespan, timeUnit));
|
||||
}
|
||||
|
||||
private CompletionStage<Void> unlockSequentially(Stream<Vault> vaultStream) {
|
||||
// this is an attempt to run all the unlock workflows sequentially, i.e. start the next workflow only after completing/failing the previous workflow.
|
||||
return vaultStream.filter(Vault::isLocked).reduce(CompletableFuture.completedFuture(null),
|
||||
(prevUnlock, nextVault) -> prevUnlock.thenCompose(unused -> appWindows.startUnlockWorkflow(nextVault, null)),
|
||||
(prevUnlock, nextUnlock) -> nextUnlock.exceptionally(e -> null) // we don't care here about the exception, logged elsewhere
|
||||
);
|
||||
}
|
||||
|
||||
private void startUnlockMissing(int timespan, TimeUnit timeUnit) {
|
||||
// Start a temporary service if there are missing auto unlock vaults
|
||||
if (getMissingAutoUnlockVaults().findAny().isPresent()) {
|
||||
LOG.info("Found MISSING vaults, starting periodic check");
|
||||
unlockMissingFuture = scheduler.scheduleWithFixedDelay(this::unlockMissing, 0, 1, TimeUnit.SECONDS);
|
||||
timeoutFuture = scheduler.schedule(this::timeout, timespan, timeUnit);
|
||||
}
|
||||
}
|
||||
|
||||
private void unlockMissing() {
|
||||
List<Vault> missingAutoUnlockVaults = getMissingAutoUnlockVaults().toList();
|
||||
missingAutoUnlockVaults.forEach(VaultListManager::redetermineVaultState);
|
||||
unlockSequentially(missingAutoUnlockVaults.stream()).thenRun(this::stopUnlockMissing);
|
||||
}
|
||||
|
||||
private void stopUnlockMissing() {
|
||||
// Stop checking if there are no more missing vaults
|
||||
if (getMissingAutoUnlockVaults().findAny().isEmpty()) {
|
||||
LOG.info("No more MISSING vaults, stopping periodic check");
|
||||
unlockMissingFuture.cancel(false);
|
||||
timeoutFuture.cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void timeout() {
|
||||
LOG.info("MISSING vaults periodic check timed out");
|
||||
unlockMissingFuture.cancel(false);
|
||||
}
|
||||
|
||||
private Stream<Vault> getMissingAutoUnlockVaults() {
|
||||
return vaults.stream()
|
||||
.filter(Vault::isMissing)
|
||||
.filter(v -> v.getVaultSettings().unlockAfterStartup().get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class FxApplication {
|
||||
@@ -68,7 +69,6 @@ public class FxApplication {
|
||||
});
|
||||
|
||||
launchEventHandler.startHandlingLaunchEvents();
|
||||
autoUnlocker.unlock();
|
||||
autoUnlocker.tryUnlockForTimespan(2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
import org.cryptomator.ui.quit.QuitComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockWorkflow;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -114,7 +115,7 @@ public class FxApplicationWindows {
|
||||
LOG.debug("Start unlock workflow for {}", vault.getDisplayName());
|
||||
return unlockWorkflowFactory.create(vault, owner).unlockWorkflow();
|
||||
}, Platform::runLater) //
|
||||
.thenCompose(unlockWorkflow -> CompletableFuture.runAsync(unlockWorkflow, executor)) //
|
||||
.thenAcceptAsync(UnlockWorkflow::run, executor)
|
||||
.exceptionally(e -> {
|
||||
showErrorWindow(e, owner == null ? primaryStage : owner, null);
|
||||
return null;
|
||||
|
||||
@@ -102,14 +102,16 @@ public class StartController implements FxController {
|
||||
}
|
||||
|
||||
private void loadingKeyFailed(Throwable e) {
|
||||
if (e instanceof UnlockCancelledException) {
|
||||
// ok
|
||||
} else if (e instanceof VaultKeyInvalidException) {
|
||||
LOG.error("Invalid key"); //TODO: specific error screen
|
||||
appWindows.showErrorWindow(e, window, null);
|
||||
} else {
|
||||
LOG.error("Failed to load key.", e);
|
||||
appWindows.showErrorWindow(e, window, null);
|
||||
switch (e) {
|
||||
case UnlockCancelledException uce -> {} //ok
|
||||
case VaultKeyInvalidException vkie -> {
|
||||
LOG.error("Invalid key"); //TODO: specific error screen
|
||||
appWindows.showErrorWindow(e, window, null);
|
||||
}
|
||||
default -> {
|
||||
LOG.error("Failed to load key.", e);
|
||||
appWindows.showErrorWindow(e, window, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.cryptomator.common.LicenseHolder;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
@@ -35,6 +34,7 @@ public class InterfacePreferencesController implements FxController {
|
||||
private final ObjectProperty<SelectedPreferencesTab> selectedTabProperty;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final ResourceBundle resourceBundle;
|
||||
private final SupportedLanguages supportedLanguages;
|
||||
public ChoiceBox<UiTheme> themeChoiceBox;
|
||||
public CheckBox showMinimizeButtonCheckbox;
|
||||
public CheckBox showTrayIconCheckbox;
|
||||
@@ -44,13 +44,14 @@ public class InterfacePreferencesController implements FxController {
|
||||
public RadioButton nodeOrientationRtl;
|
||||
|
||||
@Inject
|
||||
InterfacePreferencesController(Settings settings, TrayMenuComponent trayMenu, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ResourceBundle resourceBundle) {
|
||||
InterfacePreferencesController(Settings settings, SupportedLanguages supportedLanguages, TrayMenuComponent trayMenu, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ResourceBundle resourceBundle) {
|
||||
this.settings = settings;
|
||||
this.trayMenuInitialized = trayMenu.isInitialized();
|
||||
this.trayMenuSupported = trayMenu.isSupported();
|
||||
this.selectedTabProperty = selectedTabProperty;
|
||||
this.licenseHolder = licenseHolder;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.supportedLanguages = supportedLanguages;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -66,8 +67,7 @@ public class InterfacePreferencesController implements FxController {
|
||||
|
||||
showTrayIconCheckbox.selectedProperty().bindBidirectional(settings.showTrayIcon());
|
||||
|
||||
preferredLanguageChoiceBox.getItems().add(null);
|
||||
preferredLanguageChoiceBox.getItems().addAll(SupportedLanguages.LANGUAGAE_TAGS);
|
||||
preferredLanguageChoiceBox.getItems().addAll(supportedLanguages.getLanguageTags());
|
||||
preferredLanguageChoiceBox.valueProperty().bindBidirectional(settings.languageProperty());
|
||||
preferredLanguageChoiceBox.setConverter(new LanguageTagConverter(resourceBundle));
|
||||
|
||||
@@ -141,9 +141,7 @@ public class InterfacePreferencesController implements FxController {
|
||||
return resourceBundle.getString("preferences.interface.language.auto");
|
||||
} else {
|
||||
var locale = Locale.forLanguageTag(tag);
|
||||
var lang = locale.getDisplayLanguage(locale);
|
||||
var region = locale.getDisplayCountry(locale);
|
||||
return lang + (Strings.isNullOrEmpty(region) ? "" : " (" + region + ")");
|
||||
return locale.getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,18 +84,19 @@ public class AwtTrayMenuController implements TrayMenuController {
|
||||
|
||||
private void addChildren(Menu menu, List<TrayMenuItem> items) {
|
||||
for (var item : items) {
|
||||
// TODO: use Pattern Matching for switch, once available
|
||||
if (item instanceof ActionItem a) {
|
||||
var menuItem = new MenuItem(a.title());
|
||||
menuItem.addActionListener(evt -> a.action().run());
|
||||
menuItem.setEnabled(a.enabled());
|
||||
menu.add(menuItem);
|
||||
} else if (item instanceof SeparatorItem) {
|
||||
menu.addSeparator();
|
||||
} else if (item instanceof SubMenuItem s) {
|
||||
var submenu = new Menu(s.title());
|
||||
addChildren(submenu, s.items());
|
||||
menu.add(submenu);
|
||||
switch (item) {
|
||||
case ActionItem a -> {
|
||||
var menuItem = new MenuItem(a.title());
|
||||
menuItem.addActionListener(evt -> a.action().run());
|
||||
menuItem.setEnabled(a.enabled());
|
||||
menu.add(menuItem);
|
||||
}
|
||||
case SeparatorItem s -> menu.addSeparator(); // TODO: rename to _ with JEP 443
|
||||
case SubMenuItem s -> {
|
||||
var submenu = new Menu(s.title());
|
||||
addChildren(submenu, s.items());
|
||||
menu.add(submenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,11 @@ public class UnlockInvalidMountPointController implements FxController {
|
||||
@FXML
|
||||
public void initialize() {
|
||||
var e = unlockException.get();
|
||||
String translationKey = "unlock.error.customPath.description.generic";
|
||||
if (e instanceof MountPointNotSupportedException) {
|
||||
translationKey = "unlock.error.customPath.description.notSupported";
|
||||
} else if (e instanceof MountPointNotExistsException) {
|
||||
translationKey = "unlock.error.customPath.description.notExists";
|
||||
}
|
||||
var translationKey = switch (e) {
|
||||
case MountPointNotSupportedException x -> "unlock.error.customPath.description.notSupported";
|
||||
case MountPointNotExistsException x -> "unlock.error.customPath.description.notExists";
|
||||
default -> "unlock.error.customPath.description.generic";
|
||||
};
|
||||
dialogDescription.setFormat(resourceBundle.getString(translationKey));
|
||||
dialogDescription.setArg1(e.getMessage());
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
spacing="12"
|
||||
alignment="CENTER_LEFT">
|
||||
<fx:define>
|
||||
<ToggleGroup fx:id="predefinedLocationToggler"/>
|
||||
<ToggleGroup fx:id="locationPresetsToggler"/>
|
||||
<FontAwesome5IconView fx:id="badLocation" styleClass="glyph-icon-red" glyph="TIMES" />
|
||||
<FontAwesome5IconView fx:id="goodLocation" styleClass="glyph-icon-primary" glyph="CHECK" />
|
||||
</fx:define>
|
||||
@@ -29,16 +29,11 @@
|
||||
<children>
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<VBox spacing="6">
|
||||
<VBox fx:id="radioButtonVBox" spacing="6">
|
||||
<Label wrapText="true" text="%addvaultwizard.new.locationInstruction"/>
|
||||
<RadioButton fx:id="iclouddriveRadioButton" toggleGroup="${predefinedLocationToggler}" text="iCloud Drive" visible="${controller.observedLocationPresets.foundIclouddrive}" managed="${controller.observedLocationPresets.foundIclouddrive}"/>
|
||||
<RadioButton fx:id="dropboxRadioButton" toggleGroup="${predefinedLocationToggler}" text="Dropbox" visible="${controller.observedLocationPresets.foundDropbox}" managed="${controller.observedLocationPresets.foundDropbox}"/>
|
||||
<RadioButton fx:id="gdriveRadioButton" toggleGroup="${predefinedLocationToggler}" text="Google Drive" visible="${controller.observedLocationPresets.foundGdrive}" managed="${controller.observedLocationPresets.foundGdrive}"/>
|
||||
<RadioButton fx:id="onedriveRadioButton" toggleGroup="${predefinedLocationToggler}" text="OneDrive" visible="${controller.observedLocationPresets.foundOnedrive}" managed="${controller.observedLocationPresets.foundOnedrive}"/>
|
||||
<RadioButton fx:id="megaRadioButton" toggleGroup="${predefinedLocationToggler}" text="MEGA" visible="${controller.observedLocationPresets.foundMega}" managed="${controller.observedLocationPresets.foundMega}"/>
|
||||
<RadioButton fx:id="pcloudRadioButton" toggleGroup="${predefinedLocationToggler}" text="pCloud" visible="${controller.observedLocationPresets.foundPcloud}" managed="${controller.observedLocationPresets.foundPcloud}"/>
|
||||
<!-- PLACEHOLDER, more radio buttons are added programmatically via controller -->
|
||||
<HBox spacing="12" alignment="CENTER_LEFT">
|
||||
<RadioButton fx:id="customRadioButton" toggleGroup="${predefinedLocationToggler}" text="%addvaultwizard.new.directoryPickerLabel"/>
|
||||
<RadioButton fx:id="customRadioButton" toggleGroup="${locationPresetsToggler}" text="%addvaultwizard.new.directoryPickerLabel"/>
|
||||
<Button contentDisplay="LEFT" text="%addvaultwizard.new.directoryPickerButton" onAction="#chooseCustomVaultPath" disable="${controller.usePresetPath}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="FOLDER_OPEN"/>
|
||||
@@ -51,8 +46,8 @@
|
||||
|
||||
<VBox spacing="6">
|
||||
<Label text="%addvaultwizard.new.locationLabel" labelFor="$locationTextField"/>
|
||||
<TextField promptText="%addvaultwizard.new.locationPrompt" text="${controller.vaultPath}" editable="false" disable="${!controller.anyRadioButtonSelected}" HBox.hgrow="ALWAYS"/>
|
||||
<Label fx:id="vaultPathStatus" styleClass="label-muted" alignment="CENTER_RIGHT" wrapText="true" visible="${controller.anyRadioButtonSelected}" maxWidth="Infinity" graphicTextGap="6" text="${controller.statusText}" graphic="${controller.statusGraphic}" />
|
||||
<TextField fx:id="locationTextField" promptText="%addvaultwizard.new.locationPrompt" text="${controller.vaultPath}" editable="false" disable="${!controller.anyRadioButtonSelected}" HBox.hgrow="ALWAYS"/>
|
||||
<Label fx:id="locationStatusLabel" alignment="CENTER_RIGHT" wrapText="true" visible="${controller.anyRadioButtonSelected}" maxWidth="Infinity" graphicTextGap="6" />
|
||||
</VBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
233
src/main/resources/i18n/strings_bg.properties
Normal file
233
src/main/resources/i18n/strings_bg.properties
Normal file
@@ -0,0 +1,233 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=Прилагане
|
||||
generic.button.back=Назад
|
||||
generic.button.cancel=Отказ
|
||||
generic.button.change=Променяне
|
||||
generic.button.choose=Избиране…
|
||||
generic.button.close=Затваряне
|
||||
generic.button.copy=Копиране
|
||||
generic.button.copied=Копирано!
|
||||
generic.button.done=Готово
|
||||
generic.button.next=Напред
|
||||
generic.button.print=Отпечатване
|
||||
|
||||
# Error
|
||||
error.message=Възникна грешка
|
||||
error.description=Това е неочаквано за Криптоматор. Можете да потърсите съществуващи ревения за тази грешка. Или ако все още не е докладвана се чувствайте свободни да го направите.
|
||||
error.hyperlink.lookup=Търсене на грешката
|
||||
error.hyperlink.report=Докладване на грешката
|
||||
error.technicalDetails=Подробности:
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Хранилище
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Показване
|
||||
traymenu.showPreferencesWindow=Настройки
|
||||
traymenu.lockAllVaults=Заключване на всички
|
||||
traymenu.quitApplication=Изход
|
||||
traymenu.vault.unlock=Отключване
|
||||
traymenu.vault.lock=Заключване
|
||||
traymenu.vault.reveal=Разкриване
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=Добавяне на хранилище
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Ново хранилище
|
||||
addvaultwizard.welcome.existingButton=Отваряне на хранилище
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Изберете име на хранилището
|
||||
addvaultwizard.new.namePrompt=Наименование
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Къде Криптоматор ще държи шифрованите файлове на хранилището?
|
||||
addvaultwizard.new.locationLabel=Местоположение на хранилището
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=Потребителско местоположение
|
||||
addvaultwizard.new.directoryPickerButton=Избиране…
|
||||
addvaultwizard.new.directoryPickerTitle=Избор на папка
|
||||
addvaultwizard.new.fileAlreadyExists=Файл или папка с името на хранилището вече съществува
|
||||
addvaultwizard.new.locationDoesNotExist=Папка на посоченото място не съществува или не може да бъде достъпена
|
||||
addvaultwizard.new.locationIsNotWritable=Липсват права за писане на посоченото място
|
||||
addvaultwizard.new.locationIsOk=Мястото е подходящо за хранилище
|
||||
addvaultwizard.new.invalidName=Неприемливо име на хранилище
|
||||
addvaultwizard.new.validName=Приемливо име на хранилище
|
||||
addvaultwizard.new.validCharacters.message=Името на хранилището може да съдържа следните знаци:
|
||||
addvaultwizard.new.validCharacters.chars=Букви (напр. a, ж или 수)
|
||||
addvaultwizard.new.validCharacters.numbers=Числа
|
||||
addvaultwizard.new.validCharacters.dashes=Тире (%s) или долна черта (%s)
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Създаване
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Без парола няма да имате достъп до данните си. Желаете ли да бъде създаден ключ за възстановяване, в случай че загубите паролата си?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Да, нека имам за всеки случай
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Не, няма да загубя паролата си
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.1=⚠️ ФАЙЛОВЕ НА ХРАНИЛИЩЕ ⚠️
|
||||
addvault.new.readme.storageLocation.2=Това е местоположението на хранилището.
|
||||
addvault.new.readme.storageLocation.3=НЕДЕЙТЕ
|
||||
addvault.new.readme.storageLocation.4=• да променяте файловете в тази папка или
|
||||
addvault.new.readme.storageLocation.5=• да добавяте файлове, които да бъдат шифровани в папката.
|
||||
addvault.new.readme.storageLocation.6=Ако искате някакви файлове да бъдат шифровани или да прегледате хранилището, направете следното:
|
||||
addvault.new.readme.storageLocation.7=1. Добавете това хранилище към Криптоматор.
|
||||
addvault.new.readme.storageLocation.8=2. Отключете хранилището в Криптоматор.
|
||||
addvault.new.readme.storageLocation.9=3. Отворете местоположението на съдържанието чрез бутона „Разкриване“.
|
||||
addvault.new.readme.storageLocation.10=Ако имате нужда от помощ, посетете документацията: %s
|
||||
addvault.new.readme.accessLocation.1=🔐️ ШИФРОВАН ДЯЛ 🔐️
|
||||
addvault.new.readme.accessLocation.2=Това е местоположението на съдържанието на хранилището.
|
||||
addvault.new.readme.accessLocation.3=Файловете, в този дял са шифроване от Криптоматор. Можете да работите с тях както с всеки друг диск или папка. Това е само разшифрован вариант на съдуржанието. Файловете остават шифровани на твърдия диск през цялото време.
|
||||
addvault.new.readme.accessLocation.4=При желание можете да премахнете този файл.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Изберете файла „vault.cryptomator“ от съществуващото хранилище. Но ако съществува файл „masterkey.cryptomator“, изберете него.
|
||||
addvaultwizard.existing.chooseBtn=Избиране…
|
||||
addvaultwizard.existing.filePickerTitle=Избор на файл на хранилището
|
||||
addvaultwizard.existing.filePickerMimeDesc=Хранилище на Криптоматор
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Хранилището „%s“ е добавено.\nЗа да го достъпите или да добавите съдържание в него трябва да го отключите. Можете да го направите сега или по всяко друго време.
|
||||
addvaultwizard.success.unlockNow=Отключване сега
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Премахване на „%s“
|
||||
removeVault.message=Премахване на хранилище?
|
||||
removeVault.description=По този начин Криптоматор ще забрави за това хранилище. Можете да го добавите отново. Шифрованите файлове няма да бъдат премахнати от твърдия диск.
|
||||
removeVault.confirmBtn=Премахване
|
||||
|
||||
# Change Password
|
||||
changepassword.title=Промяна на парола
|
||||
changepassword.enterOldPassword=Въведете текущата парола за %s
|
||||
changepassword.finalConfirmation=Разбирам, че ще загубя достъпа до данните си ако забравя паролата
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=Забравяне на парола
|
||||
forgetPassword.message=Забравяне на запазена парола?
|
||||
forgetPassword.description=По този начин запазената парола за хранилището ще бъде премахната от ключодържателя на системата.
|
||||
forgetPassword.confirmBtn=Забравяне на парола
|
||||
|
||||
# Unlock
|
||||
unlock.title=Отключване на „%s“
|
||||
unlock.passwordPrompt=Въведете паролата за „%s“:
|
||||
unlock.savePassword=Запомняне на паролата
|
||||
unlock.unlockBtn=Отключване
|
||||
## Select
|
||||
unlock.chooseMasterkey.message=Файлът на главния ключ не е намерен
|
||||
unlock.chooseMasterkey.description=Криптоматор не може да намери файлът на главния ключ на хранилището „%s“. Изберете ръчно файла.
|
||||
unlock.chooseMasterkey.filePickerTitle=Изберете файл на главен ключ
|
||||
unlock.chooseMasterkey.filePickerMimeDesc=Гкавен ключ на Криптоматор
|
||||
## Success
|
||||
unlock.success.message=Отключено е успешно
|
||||
unlock.success.description=Съдържанието на хранилището „%s“ е достъпно в точката му на монтиране.
|
||||
unlock.success.revealBtn=Разкриване на диска
|
||||
## Failure
|
||||
## Hub
|
||||
hub.noKeychain.openBtn=Към настройките
|
||||
### Waiting
|
||||
### Receive Key
|
||||
### Register Device
|
||||
### Registration Success
|
||||
### Registration Failed
|
||||
### Unauthorized
|
||||
### License Exceeded
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
## Failure
|
||||
|
||||
# Migration
|
||||
## Start
|
||||
## Run
|
||||
## Success
|
||||
migration.success.unlockNow=Отключване сега
|
||||
## Missing file system capabilities
|
||||
## Impossible
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
health.title=Проверка на състоянието на „%s“
|
||||
health.intro.header=Проверка на състоянието
|
||||
health.intro.text=Проверката на състоянието е набор от проверки и евентуално поправки за проблеми във вътрешната структура на хранилището. Имайте предвид, че:
|
||||
## Start Failure
|
||||
## Check Selection
|
||||
## Detail view
|
||||
health.check.detail.listFilters.label=Филтър
|
||||
health.check.detail.fixAllSpecificBtn=Поправка всички от вида
|
||||
health.check.exportBtn=Отчет
|
||||
## Result view
|
||||
health.result.severityFilter.all=Сериозност - Всички
|
||||
health.result.severityFilter.good=Добре
|
||||
health.result.severityFilter.info=Информация
|
||||
health.result.severityFilter.warn=Предупреждение
|
||||
health.result.severityFilter.crit=Криточно
|
||||
## Fix Application
|
||||
|
||||
# Preferences
|
||||
preferences.title=Настройки
|
||||
## General
|
||||
## Interface
|
||||
preferences.interface.theme=Оформление
|
||||
## Volume
|
||||
## Updates
|
||||
## Contribution
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
# Vault Statistics
|
||||
## Read
|
||||
## Write
|
||||
|
||||
## Accesses
|
||||
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Затваряне
|
||||
main.preferencesBtn.tooltip=Настройки
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.lock=Заключване
|
||||
main.vaultlist.contextMenu.unlock=Отключване…
|
||||
main.vaultlist.contextMenu.unlockNow=Отключване сега
|
||||
main.vaultlist.contextMenu.vaultoptions=Настройки на хранилището
|
||||
main.vaultlist.contextMenu.reveal=Разкриване на диска
|
||||
main.vaultlist.addVaultBtn=Добавяне на хранилище
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
main.vaultDetail.unlockBtn=Отключване…
|
||||
main.vaultDetail.unlockNowBtn=Отключване сега
|
||||
### Unlocked
|
||||
main.vaultDetail.unlockedStatus=ОТКЛЮЧЕНО
|
||||
main.vaultDetail.revealBtn=Разкриване на диска
|
||||
main.vaultDetail.lockBtn=Заключване
|
||||
### Missing
|
||||
### Needs Migration
|
||||
### Error
|
||||
|
||||
# Wrong File Alert
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general.vaultName=Наименование
|
||||
vaultOptions.general.actionAfterUnlock.reveal=Разкриване на диска
|
||||
vaultOptions.general.actionAfterUnlock.ask=Запитване
|
||||
|
||||
## Mount
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Избиране…
|
||||
## Master Key
|
||||
vaultOptions.masterkey.changePasswordBtn=Промяна на парола
|
||||
## Hub
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
### Reset Password
|
||||
### Recovery Key Password Reset Success
|
||||
|
||||
# Convert Vault
|
||||
|
||||
# New Password
|
||||
|
||||
# Quit
|
||||
|
||||
# Forced Quit
|
||||
@@ -172,8 +172,8 @@ migration.title=Tresor upgraden
|
||||
## Start
|
||||
migration.start.header=Tresor upgraden
|
||||
migration.start.text=Um deinen Tresor "%s" in dieser neuen Version von Cryptomator zu öffnen, muss der Tresor auf ein neueres Format aktualisiert werden. Bevor du dies tust, solltest du Folgendes wissen:
|
||||
migration.start.remarkUndone=Dieser Vorgang kann nicht rückgängig gemacht werden.
|
||||
migration.start.remarkVersions=Ältere Versionen von Cryptomator können den aktualisierten Tresor nicht öffnen.
|
||||
migration.start.remarkUndone=Diese Aktualisierung kann nicht rückgängig gemacht werden.
|
||||
migration.start.remarkVersions=Ältere Versionen von Cryptomator werden den aktualisierten Tresor nicht öffnen können.
|
||||
migration.start.remarkCanRun=Du musst sicherstellen, dass jedes Gerät, von dem aus du auf den Tresor zugreifst, diese Version von Cryptomator ausführen kann.
|
||||
migration.start.remarkSynced=Du musst sicherstellen, dass dein Tresor auf diesem Gerät und auf deinen anderen Geräten vollständig synchronisiert ist, bevor du ihn aktualisierst.
|
||||
migration.start.confirm=Ich habe die oben genannten Informationen gelesen und verstanden
|
||||
@@ -225,7 +225,7 @@ health.check.detail.checkFinishedAndFound=Die Prüfung wurde abgeschlossen. Bitt
|
||||
health.check.detail.checkFailed=Die Prüfung wurde wegen eines Fehlers abgebrochen.
|
||||
health.check.detail.checkCancelled=Die Prüfung wurde abgebrochen.
|
||||
health.check.detail.listFilters.label=Filter
|
||||
health.check.detail.fixAllSpecificBtn=Alle dieses Typs reparieren
|
||||
health.check.detail.fixAllSpecificBtn=Behebe alle vom Typ
|
||||
health.check.exportBtn=Bericht exportieren
|
||||
## Result view
|
||||
health.result.severityFilter.all=Schweregrad - Alle
|
||||
@@ -464,7 +464,7 @@ convertVault.title=Tresor konvertieren
|
||||
convertVault.convert.convertBtn.before=Konvertieren
|
||||
convertVault.convert.convertBtn.processing=Konvertierung läuft…
|
||||
convertVault.success.message=Konvertierung erfolgreich
|
||||
convertVault.hubToPassword.success.description=Du kannst nun den Tresor mit dem gewählten Passwort entsperren, ohne auf den Hub zuzugreifen.
|
||||
convertVault.hubToPassword.success.description=Du kannst nun den Tresor mit dem gewählten Passwort entsperren, ohne Hub Zugriff zu benötigen.
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Gib ein neues Passwort ein
|
||||
|
||||
258
src/main/resources/i18n/strings_fi.properties
Normal file
258
src/main/resources/i18n/strings_fi.properties
Normal file
@@ -0,0 +1,258 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=Vahvista
|
||||
generic.button.back=Takaisin
|
||||
generic.button.cancel=Peruuta
|
||||
generic.button.change=Muuta
|
||||
generic.button.choose=Valitse…
|
||||
generic.button.close=Sulje
|
||||
generic.button.copy=Kopioi
|
||||
generic.button.copied=Kopioitu!
|
||||
generic.button.done=Valmis
|
||||
generic.button.next=Seuraava
|
||||
generic.button.print=Tulosta
|
||||
|
||||
# Error
|
||||
error.message=Tapahtui virhe
|
||||
error.description=Cryptomator ei odottanut tämän tapahtuvan. Voit etsiä olemassa olevia ratkaisuja tähän virheeseen. Tai jos sitä ei ole vielä raportoitu, voit tehdä niin.
|
||||
error.hyperlink.lookup=Etsi tämä virhe
|
||||
error.hyperlink.report=Ilmoita ongelmasta
|
||||
error.technicalDetails=Tiedot:
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Vault
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Näytä
|
||||
traymenu.showPreferencesWindow=Asetukset
|
||||
traymenu.lockAllVaults=Lukitse Kaikki
|
||||
traymenu.quitApplication=Sulje
|
||||
traymenu.vault.unlock=Avaa
|
||||
traymenu.vault.lock=Lukitse
|
||||
traymenu.vault.reveal=Paljasta
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=Lisää Vault
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Luo Uusi Vault
|
||||
addvaultwizard.welcome.existingButton=Avaa Olemassaoleva Vault
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Anna uusi nimi Vaultille
|
||||
addvaultwizard.new.namePrompt=Vault Nimi
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Missä pitäisi Cryptomator tallentaa salattuja tiedostoja Vault?
|
||||
addvaultwizard.new.locationLabel=Tallennustilan sijainti
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=Oma sijainti
|
||||
addvaultwizard.new.directoryPickerButton=Valitse…
|
||||
addvaultwizard.new.directoryPickerTitle=Valitse Hakemisto
|
||||
addvaultwizard.new.fileAlreadyExists=Varoitus: samanniminen tiedosto tai Vault on jo olemassa!
|
||||
addvaultwizard.new.locationDoesNotExist=Määritetyn polun hakemistoa ei ole olemassa tai sitä ei voi käyttää
|
||||
addvaultwizard.new.locationIsNotWritable=Ei kirjoitusoikeuksia määritetyllä polulla
|
||||
addvaultwizard.new.locationIsOk=Sopiva sijainti Vaultille
|
||||
addvaultwizard.new.invalidName=Virheellinen vault nimi
|
||||
addvaultwizard.new.validName=Kelvollinen vault nimi
|
||||
addvaultwizard.new.validCharacters.message=Vaultin nimi voi sisältää seuraavat merkit:
|
||||
addvaultwizard.new.validCharacters.chars=Sanamerkit (e.g. a, ж or 수)
|
||||
addvaultwizard.new.validCharacters.numbers=Numerot
|
||||
addvaultwizard.new.validCharacters.dashes=Hyphen (%s) tai alaviiva (%s)
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Luo Uusi Vault
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Et voi käyttää tietojasi ilman salasanaasi. Haluatko palautusavaimen siltä varalta, että menetät salasanasi?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Kyllä kiitos, parempi olla varma kuin katua
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Ei kiitos, en menetä salasanani
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=IMPORTANT.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ VAULT TIEDOSTOT⚠️
|
||||
addvault.new.readme.storageLocation.2=Tämä on vaultin tallennuspaikka.
|
||||
addvault.new.readme.storageLocation.3=ÄLÄ
|
||||
addvault.new.readme.storageLocation.4=• muuttaa mitä tahansa tiedostoja tämän hakemiston tai
|
||||
addvault.new.readme.storageLocation.5=• liitä kaikki tiedostot salaukseen tähän kansioon.
|
||||
addvault.new.readme.storageLocation.6=Jos haluat salata tiedostoja ja tarkastella Vaultin sisältöä, tee seuraavat toimet:
|
||||
addvault.new.readme.storageLocation.7=1. Lisää tämä Vault Cryptomatoriin.
|
||||
addvault.new.readme.storageLocation.8=2. Avaa Vault Cryptomatorissa.
|
||||
addvault.new.readme.storageLocation.9=3. Avaa tallennuskansiosi klikkaamalla "Näytä" -painiketta.
|
||||
addvault.new.readme.storageLocation.10=Mikäli tarvitset apua, konsultoi Cryptomatorin dokumentaatiota: %s
|
||||
addvault.new.readme.accessLocation.fileName=TERVETULOA.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ SALATTU VOLYYMI 🔐️
|
||||
addvault.new.readme.accessLocation.2=Tämä on salatun holvisi tallennuskansio.
|
||||
addvault.new.readme.accessLocation.3=Cryptomator salaa kaikki tänne siirtämäsi tiedostot. Voit työskennellä tässä kansiossa aivan samalla tavalla kuin muutenkin. Tämä on ainoastaan näkymä jossa salaus on purettu. Todellisuudessa kaikki tiedostot pysyvät salattuina aina.
|
||||
addvault.new.readme.accessLocation.4=Voit halutessasi poistaa tämän tiedoston. Poistaminen ei vaikuta Cryptomatorin toimintaan.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Valitse olemassa olevan Cryptomator holvin "vault.cryptomator" -tiedosto. Mikäli "vault.cryptomator" -tiedostoa ei ole, valitse "masterkey.cryptomator" -tiedosto.
|
||||
addvaultwizard.existing.chooseBtn=Valitse…
|
||||
addvaultwizard.existing.filePickerTitle=Valitse Holvi -tiedosto
|
||||
addvaultwizard.existing.filePickerMimeDesc=Cryptomator Holvi
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Holvi "%s" on lisätty.\nSinun täytyy avata kyseinen holvi tarkastellaksesi sen sisältöä. Vaihtoehtoisesti voit avata sen myöhemmin koska tahansa.
|
||||
addvaultwizard.success.unlockNow=Avaa Nyt
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Poista "%s"
|
||||
removeVault.message=Poistetaanko holvi?
|
||||
removeVault.description=Tämä toiminto ainoastaan poistaa valitun holvin Cryptomatorin näkymästä. Salattuja tiedostoja tai holvia itsessään ei poisteta.
|
||||
removeVault.confirmBtn=Poista Holvi
|
||||
|
||||
# Change Password
|
||||
changepassword.title=Vaihda salasana
|
||||
changepassword.enterOldPassword=Syötä "%s": n nykyinen salasana
|
||||
changepassword.finalConfirmation=Ymmärrän, että tiedostojani ei voi palauttaa, mikäli unohdan salasanani.
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=Unohda Salasana
|
||||
forgetPassword.message=Unohda tallennetut salasanat?
|
||||
forgetPassword.description=Tämä poistaa valitun holvin tallennetun salasanan järjestelmäsi avainrenkaasta.
|
||||
forgetPassword.confirmBtn=Unohda Salasana
|
||||
|
||||
# Unlock
|
||||
unlock.title=Avaa "%s"
|
||||
unlock.passwordPrompt=Syötä salasana "%s":lle
|
||||
unlock.savePassword=Muista salasana
|
||||
unlock.unlockBtn=Avaa
|
||||
## Select
|
||||
unlock.chooseMasterkey.message=Masterkey -tiedostoa ei löydy
|
||||
unlock.chooseMasterkey.description=Cryptomator ei paikantanut masterkey -tiedostoa holville "%s". Ole hyvä ja valitse tiedosto manuaalisesti.
|
||||
unlock.chooseMasterkey.filePickerTitle=Valitse Masterkey -tiedosto
|
||||
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
|
||||
## Success
|
||||
unlock.success.message=Lukituksen purku onnistui
|
||||
unlock.success.description="%s" holvin sisältö on nyt saatavilla sen hallinnointikohteessa.
|
||||
unlock.success.rememberChoice=Muista valintani. Älä kysy uudelleen.
|
||||
unlock.success.revealBtn=Paljasta Asema
|
||||
## Failure
|
||||
unlock.error.customPath.message=Holvia ei pystytty yhdistämään valittuun polkuun
|
||||
unlock.error.customPath.description.notSupported=Mikäli haluat jatkaa mukautetun polun käyttöä, ole hyvä ja mene Asetuksiin ja valitse volyymityyppi mikä tukee sitä. Muussa tapauksessa avaa holvin asetukset ja valitse tuettu mukautettu polku.
|
||||
unlock.error.customPath.description.notExists=Valitsemaasi mukautettua polkua ei ole olemassa. Voit joko luoda uuden polun tai muuttaa polkua holvisi asetuksissa.
|
||||
unlock.error.customPath.description.generic=Olet valinnut mukautetun polun holvillesi, mutta sen kanssa ilmeni ongelma: %s
|
||||
## Hub
|
||||
hub.noKeychain.message=Laitteen avainta ei löytynyt
|
||||
hub.noKeychain.description=Hub-holvien purkamiseksi tarvitaan laiteavain joka on suojattu avainrenkaalla. Jatkaaksesi, kytke “%s” päälle ja valitse avainrengas asetuksista.
|
||||
hub.noKeychain.openBtn=Avaa asetukset
|
||||
### Waiting
|
||||
hub.auth.message=Odotetaan todennusta…
|
||||
hub.auth.description=Pitäisi ohjata sinut automaattisesti uudelleen kirjautumissivulle.
|
||||
hub.auth.loginLink=Uudelleenohjaus epäonnistui? Avaa tästä manuaalisesti.
|
||||
### Receive Key
|
||||
hub.receive.message=Odotetaan vastausta…
|
||||
hub.receive.description=Cryptomator yhdistää Hub:iin. Ole hyvä ja odota.
|
||||
### Register Device
|
||||
hub.register.message=Laitteen nimi vaaditaan
|
||||
hub.register.description=Et ole ilmeisesti ennen yhdistänyt Hub:iin tältä laitteelta. Jotta pääsyoikeus voidaan todentaa, sinun täytyy nimetä tämä laite.
|
||||
hub.register.nameLabel=Laitteen Nimi
|
||||
hub.register.occupiedMsg=Tämä nimi on jo käytössä
|
||||
hub.register.registerBtn=Vahvista
|
||||
### Registration Success
|
||||
hub.registerSuccess.message=Laite nimetty onnistuneesti
|
||||
hub.registerSuccess.description=Käyttääksesi holvia, holvin omistajan on valtuutettava laitteesi.
|
||||
### Registration Failed
|
||||
hub.registerFailed.message=Laitteen nimeäminen epäonnistui
|
||||
hub.registerFailed.description=Nimeämisprosessissa tapahtui virhe. Löydät lisää tietoja lokitiedostoista.
|
||||
### Unauthorized
|
||||
hub.unauthorized.message=Pääsy estetty
|
||||
hub.unauthorized.description=Laitteellasi ei ole pääsyvaltuutusta tähän holviin. Pyydä holvin omistajaa lisäämän valtuutus laitteellesi.
|
||||
### License Exceeded
|
||||
hub.invalidLicense.message=Hub-lisenssi ei ole voimassa
|
||||
hub.invalidLicense.description=Cryptomator Hub:illasi ei ole voimassa olevaa lisenssiä. Ole hyvä ja ilmoita Hubin järjestelmänvalvojalle lisenssin päivittämiseksi tai sen uusimiseksi.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
lock.forced.message=Lukitus epäonnistui
|
||||
lock.forced.description="%s":n lukitus epäonnistui, koska sinulla on avoimia tiedostoja tai niihin liittyviä päivityksiä vireillä. Voit halutessasi pakottaa lukituksen, mutta tämä saattaa johtaa tallentamattomien tiedostojen katoamiseen.
|
||||
lock.forced.retryBtn=Yritä uudestaan
|
||||
lock.forced.forceBtn=Pakota Lukitus
|
||||
## Failure
|
||||
lock.fail.message=Holvin lukitseminen epäonnistui
|
||||
lock.fail.description="%s" holvia ei voitu lukita. Varmista, että avoinna olevat tiedostot tallennetaan turvalliseen paikkaan ja että tiedostot eivät ole avoinna tai käytössä. Lukitaksesi holvin, pakota Cryptomator -prosessin lopetus manuaalisesti.
|
||||
|
||||
# Migration
|
||||
migration.title=Päivitä Holvi
|
||||
## Start
|
||||
migration.start.header=Päivitä Holvi
|
||||
migration.start.text="%s" holvi tulee päivittää uuteen versioon, jotta voit avata sen Cryptomatorissa. Ennen kuin jatkat, varmista että ymmärrät seuraavan:
|
||||
migration.start.remarkUndone=Päivitystä ei voi peruuttaa.
|
||||
migration.start.remarkVersions=Cryptomatorin vanhemmat versiot eivät voi avata päivitettyä holvia.
|
||||
migration.start.remarkCanRun=Sinun tulee varmistaa, että kaikki laitteet joilla haluat käyttää tätä holvia on päivitetty Cryptomatorin uusimpaan versioon.
|
||||
migration.start.remarkSynced=Sinun tulee varmistaa, että holvisi on täysin ajantasalla tällä laitteella ja muilla laitteillasi, ennen kuin aloitat päivitysprosessin.
|
||||
migration.start.confirm=Olen lukenut ja ymmärtänyt yllä ilmoitetut ohjeet
|
||||
## Run
|
||||
## Success
|
||||
migration.success.unlockNow=Avaa Nyt
|
||||
## Missing file system capabilities
|
||||
## Impossible
|
||||
|
||||
# Health Check
|
||||
## Start
|
||||
## Start Failure
|
||||
## Check Selection
|
||||
## Detail view
|
||||
## Result view
|
||||
## Fix Application
|
||||
|
||||
# Preferences
|
||||
preferences.title=Asetukset
|
||||
## General
|
||||
## Interface
|
||||
## Volume
|
||||
## Updates
|
||||
## Contribution
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
# Vault Statistics
|
||||
## Read
|
||||
## Write
|
||||
|
||||
## Accesses
|
||||
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Sulje
|
||||
main.preferencesBtn.tooltip=Asetukset
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.lock=Lukitse
|
||||
main.vaultlist.contextMenu.unlockNow=Avaa Nyt
|
||||
main.vaultlist.contextMenu.reveal=Paljasta Asema
|
||||
main.vaultlist.addVaultBtn=Lisää Vault
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
main.vaultDetail.unlockNowBtn=Avaa Nyt
|
||||
### Unlocked
|
||||
main.vaultDetail.revealBtn=Paljasta Asema
|
||||
main.vaultDetail.lockBtn=Lukitse
|
||||
### Missing
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=Päivitä Holvi
|
||||
### Error
|
||||
|
||||
# Wrong File Alert
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general.vaultName=Vault Nimi
|
||||
vaultOptions.general.actionAfterUnlock.reveal=Paljasta Asema
|
||||
|
||||
## Mount
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Valitse…
|
||||
## Master Key
|
||||
vaultOptions.masterkey.changePasswordBtn=Vaihda salasana
|
||||
## Hub
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
### Reset Password
|
||||
### Recovery Key Password Reset Success
|
||||
|
||||
# Convert Vault
|
||||
|
||||
# New Password
|
||||
|
||||
# Quit
|
||||
|
||||
# Forced Quit
|
||||
@@ -50,26 +50,41 @@ addvaultwizard.new.directoryPickerLabel=Custom Location
|
||||
addvaultwizard.new.directoryPickerButton=Mamili…
|
||||
addvaultwizard.new.directoryPickerTitle=Pumili ng Direktoryo
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Gumawa ng bagong Vault
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.2=Ito ang lokasyon ng iyong vault na imbakan.
|
||||
addvault.new.readme.storageLocation.3=HUWAG
|
||||
addvault.new.readme.storageLocation.6=Kung gusto mo i-encrypt ang mga files at makita nang nilalaman ng vault, gawin ang nakasabi:
|
||||
addvault.new.readme.storageLocation.7=1. Idagdag ang vault na ito sa Cryptomator.
|
||||
addvault.new.readme.accessLocation.2=Ito ang lokasyon ng iyong vault.
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=Mamili…
|
||||
## Success
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Tanggalin %s
|
||||
removeVault.message=Itangal ang vault?
|
||||
removeVault.confirmBtn=Itangal ang vault
|
||||
|
||||
# Change Password
|
||||
|
||||
# Forget Password
|
||||
|
||||
# Unlock
|
||||
unlock.savePassword=Maalala ang password
|
||||
unlock.unlockBtn=I-unlock
|
||||
## Select
|
||||
unlock.chooseMasterkey.filePickerTitle=Piliin ang masterkey file
|
||||
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
|
||||
## Success
|
||||
unlock.success.rememberChoice=Paalala ang pinili ko, huwag mag tanong ulit
|
||||
## Failure
|
||||
## Hub
|
||||
### Waiting
|
||||
### Receive Key
|
||||
### Register Device
|
||||
hub.register.occupiedMsg=Ang pangalan ay nagamit na
|
||||
hub.register.registerBtn=Kumpirmahin
|
||||
### Registration Success
|
||||
### Registration Failed
|
||||
### Unauthorized
|
||||
|
||||
@@ -56,6 +56,9 @@ addvaultwizard.new.locationIsOk=Megfelelő hely a trezornak
|
||||
addvaultwizard.new.invalidName=Érvénytelen vault név
|
||||
addvaultwizard.new.validName=Érvényes vault név
|
||||
addvaultwizard.new.validCharacters.message=A vault neve a következő karaktereket tartalmazhatja:
|
||||
addvaultwizard.new.validCharacters.chars=Szókarakterek (pl. a, ж vagy 수)
|
||||
addvaultwizard.new.validCharacters.numbers=Számok
|
||||
addvaultwizard.new.validCharacters.dashes=Kötőjel (%s) vagy alulvonás (%s)
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Új széf létrehozása
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Nem fog tudni hozzáférni az adataihoz a jelszó nélkül. Akar egy visszaállítási kulcsot arra az esetre, ha elveszíti a jelszavát?
|
||||
@@ -110,28 +113,49 @@ unlock.passwordPrompt=Írja be a jelszavát a következő széfhez "%s":
|
||||
unlock.savePassword=Jelszó megjegyzése
|
||||
unlock.unlockBtn=Feloldás
|
||||
## Select
|
||||
unlock.chooseMasterkey.message=Mesterkulcs fájl nem található
|
||||
unlock.chooseMasterkey.description=Nem található a tároló kulcsfájlja a várt helyen. Kérjük válassza ki a kulcsfájlt manuálisan.
|
||||
unlock.chooseMasterkey.filePickerTitle=Mesterkulcs fájl kiválasztása
|
||||
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Mesterkulcs
|
||||
## Success
|
||||
unlock.success.message=Sikeres feloldás
|
||||
unlock.success.description="%s" sikreresen feloldásra került! Mostmár hozzáférhet a virtuális trezorhoz.
|
||||
unlock.success.rememberChoice=Jegyezze meg a választást és ne mutassa többet
|
||||
unlock.success.revealBtn=Széf megjelenítése
|
||||
## Failure
|
||||
unlock.error.customPath.message=Nem lehet csatolni a széfet az egyéni útvonalhoz
|
||||
unlock.error.customPath.description.notSupported=Ha szeretné továbbra is az egyéni útvonalat használni, kérem, menjen a beállításokba és válasszon egy kötet típust, amely támogatja azt. Máskülönben, menjen a széf opciókhoz és válasszon egy támogatott csatoláspontot.
|
||||
unlock.error.customPath.description.notExists=Az egyéni csatolás útvonal nem létezik. Hozza létre a helyi fájlrendszerében vagy változtassa meg a széf opciókban.
|
||||
unlock.error.customPath.description.generic=Egyéni csatolási útvonalat választott ehhez a széfhez, de használatakor ez a hibaüzenet érkezett: %s
|
||||
## Hub
|
||||
hub.noKeychain.message=Nem lehet az eszközkulcshoz hozzáférni
|
||||
hub.noKeychain.description=Hogy feloldja a Hub széfeket, egy eszközkulcs szükséges, mely egy kulcslánccal van biztosítva. A folytatáshoz engedélyezze a következőt: “%s” és válasszon egy kulcsláncot a beállításokban.
|
||||
hub.noKeychain.openBtn=Beállítások megnyitása
|
||||
### Waiting
|
||||
hub.auth.message=Várakozás a hitelesítésre…
|
||||
hub.auth.description=Automatikusan átirányítjuk a bejelentkezési oldalra.
|
||||
hub.auth.loginLink=Nem sikerült az átirányítás? Kattintson ide a megnyitáshoz.
|
||||
### Receive Key
|
||||
hub.receive.message=Válasz feldolgozása…
|
||||
hub.receive.description=Cryptomator fogadja és feldolgozza a Hub válaszát. Kérem, várjon.
|
||||
### Register Device
|
||||
hub.register.message=Eszköznév szükséges
|
||||
hub.register.description=Úgy tűnik, ez az első Hub-hozzáférés erről az eszközről. A hozzáférési jogosultság azonosításához el kell neveznie ezt az eszközt.
|
||||
hub.register.nameLabel=Készülék neve
|
||||
hub.register.occupiedMsg=Ez a név már használatban van
|
||||
hub.register.registerBtn=Megerősítés
|
||||
### Registration Success
|
||||
hub.registerSuccess.message=Eszköz elnevezve
|
||||
hub.registerSuccess.description=A széf hozzáféréséhez a széf tulajdonosának hitelesítenie kell az eszközét.
|
||||
### Registration Failed
|
||||
hub.registerFailed.message=Az eszköz elnevezése sikertelen volt
|
||||
hub.registerFailed.description=Hiba állt fel az elnevezési folyamatban. További részletekért tekintse meg az alkalmazásnaplót.
|
||||
### Unauthorized
|
||||
hub.unauthorized.message=Hozzáférés megtagadva
|
||||
hub.unauthorized.description=Eszköze még nem kapott engedélyt ehhez a széfhez. Kérje a széf tulajdonosát, hogy engedélyezze a hozzáférést.
|
||||
### License Exceeded
|
||||
hub.invalidLicense.message=Érvénytelen Hub licenc
|
||||
hub.invalidLicense.description=Az Ön Cryptomator Hub példánya érvénytelen licenccel rendelkezik. Kérem, értesítsen egy Hub rendszergazdát hogy frissítse vagy újítsa meg a licencet.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -147,7 +171,11 @@ lock.fail.description=A "%s" tárolót nem lehetett zárolni. Győződjön meg a
|
||||
migration.title=Széf frissítése
|
||||
## Start
|
||||
migration.start.header=Széf frissítése
|
||||
migration.start.text=Hogy megnyissa a "%s" nevű széfét a Cryptomator ezen új verziójában, a széfet frissíteni kell egy újabb formátumra. Mielőtt ezt megteszi, az alábbiakat érdemes figyelembe vennie:
|
||||
migration.start.remarkUndone=Ezt a módosítást nem lehet visszafordítani.
|
||||
migration.start.remarkVersions=A Cryptomator régebbi verziói nem fogják tudni megnyitni a frissített széfet.
|
||||
migration.start.remarkCanRun=Meg kell győződnie arról, hogy minden eszköz, amelyről eléri ezt a széfet képes futtatni a Cryptomator ezen verzióját.
|
||||
migration.start.remarkSynced=Meg kell győződnie arról, hogy a széfe teljesen szinkronizálva van ezen és az összes többi eszközön a frissítés előtt.
|
||||
migration.start.confirm=Elolvastam és megértettem a fenti információkat
|
||||
## Run
|
||||
migration.run.enterPassword=Írja be a jelszót a következőhöz Enter the password for "%s"
|
||||
@@ -205,10 +233,16 @@ health.result.severityFilter.good=Rendben
|
||||
health.result.severityFilter.info=Infó
|
||||
health.result.severityFilter.warn=Figyelmeztetés
|
||||
health.result.severityFilter.crit=Kritikus
|
||||
health.result.severityTip.good=Súlyosság: Jó\nNormális séf struktúra.
|
||||
health.result.severityTip.info=Súlyosság: Info\nA széf struktúrája ép, javítás ajánlott.
|
||||
health.result.severityTip.warn=Súlyosság: Figyelmeztetés\nA széf struktúrája sérült, javítás erősen ajánlott.
|
||||
health.result.severityTip.crit=Súlyosság: Kritikus\nA széf struktúrája sérült, adatvesztés áll fönt.
|
||||
health.result.fixStateFilter.all=Javítás státusz - Mind
|
||||
health.result.fixStateFilter.fixable=Javítható
|
||||
health.result.fixStateFilter.notFixable=Nem javítható
|
||||
health.result.fixStateFilter.fixing=Javítás alatt…
|
||||
health.result.fixStateFilter.fixed=Kijavított
|
||||
health.result.fixStateFilter.fixFailed=Sikertelen javítás
|
||||
## Fix Application
|
||||
health.fix.fixBtn=Javítás
|
||||
health.fix.successTip=Javítás sikeres
|
||||
@@ -219,6 +253,7 @@ preferences.title=Beállítások
|
||||
## General
|
||||
preferences.general=Általános
|
||||
preferences.general.startHidden=Az ablak elrejtése a Cryptomator indítása után
|
||||
preferences.general.autoCloseVaults=A széfek automatikus lezárása az alkalmazás bezárásakor
|
||||
preferences.general.debugLogging=Hibakeresési naplózás engedélyezése
|
||||
preferences.general.debugDirectory=Naplófájlok megjelenítése
|
||||
preferences.general.autoStart=Cryptomator indítása a rendszerrel együtt
|
||||
@@ -239,7 +274,17 @@ preferences.interface.showMinimizeButton=Kicsinyítés ikon megjelenítése
|
||||
preferences.interface.showTrayIcon=Tálca ikon megjelenítése (újraindítás szükséges)
|
||||
## Volume
|
||||
preferences.volume=Virtuális meghajtó
|
||||
preferences.volume.type=Kötet Típusa
|
||||
preferences.volume.type.automatic=Automatikus
|
||||
preferences.volume.docsTooltip=További információért a kötet típusokról kattintson ide, hogy megnyissa a dokumentációt.
|
||||
preferences.volume.fuseRestartRequired=A változtatások alkalmazásához újra kell indítania a Cryptomatort.
|
||||
preferences.volume.tcp.port=TCP Port
|
||||
preferences.volume.supportedFeatures=A kiválaszott kötet típus az alábbi funkciókat támogatja:
|
||||
preferences.volume.feature.mountAuto=Automatikus csatlakozási pont választás
|
||||
preferences.volume.feature.mountToDir=Egyéni mappa csatlakozási pontként
|
||||
preferences.volume.feature.mountToDriveLetter=Meghajtó betűjel csatolási pontként
|
||||
preferences.volume.feature.mountFlags=Egyéni csatolási opciók
|
||||
preferences.volume.feature.readOnly=Csak olvasható csatolás
|
||||
## Updates
|
||||
preferences.updates=Frissítések
|
||||
preferences.updates.currentVersion=Jelenlegi verzió: %s
|
||||
@@ -262,26 +307,34 @@ stats.title=Statisztika ehhez %s
|
||||
stats.cacheHitRate=Gyorsítótár találati arány
|
||||
## Read
|
||||
stats.read.throughput.idle=Olvasás: tétlen
|
||||
stats.read.throughput.kibs=Olvasás: %.2f KiB/s
|
||||
stats.read.throughput.mibs=Olvasás: %.2f MiB/s
|
||||
stats.read.total.data.none=Olvasott adat: -
|
||||
stats.read.total.data.kib=Adat beolvasva: %.1f KiB
|
||||
stats.read.total.data.mib=Olvasott adat: %.1f MiB
|
||||
stats.read.total.data.gib=Olvasott adat: %.1f GiB
|
||||
stats.decr.total.data.none=Dekódolt adat: -
|
||||
stats.decr.total.data.kib=Adat visszafejtve: %.1f KiB
|
||||
stats.decr.total.data.mib=Dekódolt adat: %.1f MiB
|
||||
stats.decr.total.data.gib=Dekódolt adat: %.1f GiB
|
||||
stats.read.accessCount=Összes olvasás: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Írás: tétlen
|
||||
stats.write.throughput.kibs=Írás: %.2f KiB/s
|
||||
stats.write.throughput.mibs=Írás: %.2f MiB/s
|
||||
stats.write.total.data.none=Írva: -
|
||||
stats.write.total.data.kib=Írt adatok: %.1f KiB
|
||||
stats.write.total.data.mib=Írott adat: %.1f MiB
|
||||
stats.write.total.data.gib=Írott adat: %.1f GiB
|
||||
stats.encr.total.data.none=Titkosított adat: -
|
||||
stats.encr.total.data.kib=Titkosított adatok: %.1f KiB
|
||||
stats.encr.total.data.mib=Titkosított adat: %.1f MiB
|
||||
stats.encr.total.data.gib=Titkosított adat: %.1f GiB
|
||||
stats.write.accessCount=Összes írás: %d
|
||||
|
||||
## Accesses
|
||||
stats.access.current=Hozzáférések: %d
|
||||
stats.access.total=Összes hozzáférés: %d
|
||||
|
||||
|
||||
# Main Window
|
||||
@@ -312,12 +365,18 @@ main.vaultDetail.passwordSavedInKeychain=Jelszó mentve
|
||||
main.vaultDetail.unlockedStatus=FELOLDVA
|
||||
main.vaultDetail.accessLocation=A széf tartalma itt érhető el:
|
||||
main.vaultDetail.revealBtn=Széf megjelenítése
|
||||
main.vaultDetail.copyUri=URI másolása
|
||||
main.vaultDetail.lockBtn=Zárolás
|
||||
main.vaultDetail.bytesPerSecondRead=Olvasás:
|
||||
main.vaultDetail.bytesPerSecondWritten=Írás:
|
||||
main.vaultDetail.throughput.idle=tétlen
|
||||
main.vaultDetail.throughput.kbps=%.1f KiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
main.vaultDetail.stats=Széf statisztika
|
||||
main.vaultDetail.locateEncryptedFileBtn=Titkosított fájl megkeresése
|
||||
main.vaultDetail.locateEncryptedFileBtn.tooltip=Válasszon a széfből egy fájlt a titkosított megfelelőjének megkereséséhez
|
||||
main.vaultDetail.encryptedPathsCopied=Az útvonal a vágólapra került!
|
||||
main.vaultDetail.filePickerTitle=Fájl választása a széfben
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=A Cryptomator nem talált széfet ezen az útvonalon.
|
||||
main.vaultDetail.missing.recheck=Ellenőrizze újra
|
||||
@@ -356,36 +415,56 @@ vaultOptions.general.startHealthCheckBtn=Épség-ellenőrzés indítása
|
||||
|
||||
## Mount
|
||||
vaultOptions.mount=Felcsatolás
|
||||
vaultOptions.mount.info=Az opciók a kiválasztott kötet típustól függőek.
|
||||
vaultOptions.mount.linkToPreferences=Virtuális meghajtó opciók megnyitása
|
||||
vaultOptions.mount.readonly=Csak-olvasható
|
||||
vaultOptions.mount.customMountFlags=Egyedi csatolási paraméterek
|
||||
vaultOptions.mount.winDriveLetterOccupied=foglalt
|
||||
vaultOptions.mount.mountPoint=Csatolási pont
|
||||
vaultOptions.mount.mountPoint.auto=Válasszon egy megfelelő helyet automatikusan
|
||||
vaultOptions.mount.mountPoint.driveLetter=Használja a kiválasztott meghajtó betűjelét
|
||||
vaultOptions.mount.mountPoint.custom=Egyéni könyvtár használata
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Kiválaszt…
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Válasszon könyvtárat
|
||||
## Master Key
|
||||
vaultOptions.masterkey=Jelszó
|
||||
vaultOptions.masterkey.changePasswordBtn=Jelszó megváltoztatása
|
||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Mentett jelszó törlése
|
||||
vaultOptions.masterkey.recoveryKeyExplanation=A helyreállítási kulcs az egyetlen módja annak, hogy visszaállítsa a széfhez való hozzáférést, ha elveíti a jelszavát.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Visszaállítási kulcs megjelenítése
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Jelszó visszaállítása
|
||||
## Hub
|
||||
vaultOptions.hub=Helyreállítás
|
||||
vaultOptions.hub.convertInfo=Ezen visszaállítási kulcs segítségével átváltoztathatja ezt a Hub széfet egy jelszó-alapú széffé vészhelyzet esetén.
|
||||
vaultOptions.hub.convertBtn=Jelszó-alapú széffé alakítás
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
recoveryKey.display.title=Visszaállítási kulcs mutatása
|
||||
recoveryKey.create.message=Jelszó szükséges
|
||||
recoveryKey.create.description=Írja be a jelszavát a "%s" visszaállítási kulcsának megjelenítéséhez:
|
||||
recoveryKey.display.description=A következő helyreállítási kulcs használható a "%s" hozzáférésének visszaállítására:
|
||||
recoveryKey.display.StorageHints=Tartsa nagyon biztonságos helyen. pl.:\n •Tárolja egy jelszókezelővel\n •Mentse el egy USB meghajtóra\n •Nyomtassa egy papírra
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
recoveryKey.recover.title=Jelszó visszaállítása
|
||||
recoveryKey.recover.prompt=Írja be a visszaállítási kulcsot a következőhöz "%s":
|
||||
recoveryKey.recover.correctKey=Ez a visszaállítási kulcs érvényes
|
||||
recoveryKey.recover.wrongKey=Ez a visszaállítási kulcs egy másik széfhez tartozik
|
||||
recoveryKey.recover.invalidKey=Ez a visszaállítási kulcs nem érvényes
|
||||
recoveryKey.printout.heading=Cryptomator visszaállítási kulcs\n"%s"\n
|
||||
### Reset Password
|
||||
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.
|
||||
|
||||
# Convert Vault
|
||||
convertVault.title=Széf átalakítása
|
||||
convertVault.convert.convertBtn.before=Átalakítás
|
||||
convertVault.convert.convertBtn.processing=Átalakítás…
|
||||
convertVault.success.message=Sikeres átalakítás
|
||||
convertVault.hubToPassword.success.description=Feloldhatja a széfet a kiválasztott jelszóval Hub hozzáférés nélkül.
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Adjon meg egy új jelszót
|
||||
@@ -400,6 +479,12 @@ passwordStrength.messageLabel.3=Erős
|
||||
passwordStrength.messageLabel.4=Nagyon erős
|
||||
|
||||
# Quit
|
||||
quit.title=Alkalmazás bezárása
|
||||
quit.message=Vannak feloldott széfek
|
||||
quit.description=Kérem, erősítse meg a kilépési szándékát. A Cryptomator lezárja az összes feloldott széfet az adatvesztés elkerülése érdekében.
|
||||
quit.lockAndQuitBtn=Zárolás és kilépés
|
||||
|
||||
# Forced Quit
|
||||
# Forced Quit
|
||||
quit.forced.message=Egyes széfeket nem lehetett lezárni
|
||||
quit.forced.description=A széfek zárolását függőbben lévő műveletek vagy megnyitott fájlok blokkolták. Kényszerítheti a maradék széfek zárolását, de az I/O megszakítása nem mentett adatok elvesztéséhez vezethet.
|
||||
quit.forced.forceAndQuitBtn=Kényszerítés és Kilépés
|
||||
@@ -434,6 +434,7 @@ vaultOptions.masterkey.recoveryKeyExplanation=回復キーはパスワードを
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=回復キーを表示
|
||||
vaultOptions.masterkey.recoverPasswordBtn=パスワードをリセット
|
||||
## Hub
|
||||
vaultOptions.hub=回復
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
@@ -456,6 +457,10 @@ recoveryKey.recover.resetSuccess.message=パスワードをリセットしまし
|
||||
recoveryKey.recover.resetSuccess.description=新しいパスワードで金庫の施錠ができます。
|
||||
|
||||
# Convert Vault
|
||||
convertVault.title=金庫を変換
|
||||
convertVault.convert.convertBtn.before=変換
|
||||
convertVault.convert.convertBtn.processing=変換中…
|
||||
convertVault.success.message=変換完了
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=新しいパスワードを入力してください
|
||||
|
||||
@@ -168,6 +168,7 @@ lock.fail.description=O cofre "%s" não pode ser bloqueado. Certifique-se de que
|
||||
migration.title=Atualizar Cofre
|
||||
## Start
|
||||
migration.start.header=Atualizar Cofre
|
||||
migration.start.remarkUndone=Esta atualização não pode ser revertida.
|
||||
migration.start.confirm=Li e entendi as informações acima
|
||||
## Run
|
||||
migration.run.enterPassword=Introduza a palavra-passe de "%s"
|
||||
@@ -222,8 +223,11 @@ health.result.severityFilter.good=Ótimo
|
||||
health.result.severityFilter.info=Informações
|
||||
health.result.severityFilter.warn=Atenção
|
||||
health.result.severityFilter.crit=Crítico
|
||||
health.result.fixStateFilter.fixed=Corrigido
|
||||
health.result.fixStateFilter.fixFailed=Falha na correção
|
||||
## Fix Application
|
||||
health.fix.fixBtn=Corrigir
|
||||
health.fix.successTip=Correção bem-sucedida
|
||||
|
||||
# Preferences
|
||||
preferences.title=Preferências
|
||||
@@ -231,6 +235,7 @@ preferences.title=Preferências
|
||||
preferences.general=Geral
|
||||
preferences.general.startHidden=Ocultar janela ao iniciar o Cryptomator
|
||||
preferences.general.autoCloseVaults=Bloquear cofres abertos automaticamente ao sair da aplicação
|
||||
preferences.general.keychainBackend=Guardar palavras-passe com
|
||||
## Interface
|
||||
preferences.interface=Interface
|
||||
preferences.interface.theme=Aspecto e Ambiente
|
||||
@@ -246,7 +251,9 @@ preferences.interface.interfaceOrientation.rtl=Da direita para a esquerda
|
||||
preferences.interface.showMinimizeButton=Mostrar botão de minimização
|
||||
## Volume
|
||||
preferences.volume=Unidade Virtual
|
||||
preferences.volume.type=Tipo de Volume
|
||||
preferences.volume.type.automatic=Automático
|
||||
preferences.volume.feature.readOnly=Volume apenas-leitura
|
||||
## Updates
|
||||
preferences.updates=Atualizações
|
||||
preferences.updates.currentVersion=Versão atual: %s
|
||||
@@ -255,6 +262,10 @@ preferences.updates.checkNowBtn=Verificar Agora
|
||||
preferences.updates.updateAvailable=Atualização para a versão %s disponível.
|
||||
## Contribution
|
||||
preferences.contribute=Apoie-nos
|
||||
preferences.contribute.registeredFor=Certificado de apoiador registado para %s
|
||||
preferences.contribute.noCertificate=Apoie o Cryptomator e receba um certificado de apoiador. É como uma chave de licença, mas para pessoas incríveis a usar um software gratuito. ;-)
|
||||
preferences.contribute.getCertificate=Não o tem? Saiba como pode obtê-lo.
|
||||
preferences.contribute.promptText=Insira o código do certificado de apoiador aqui
|
||||
#<-- Add entries for donations and code/translation/documentation contribution -->
|
||||
|
||||
## About
|
||||
|
||||
@@ -154,6 +154,8 @@ hub.registerFailed.description=Ocorreu um erro no processo de nomeação do disp
|
||||
hub.unauthorized.message=Acesso negado
|
||||
hub.unauthorized.description=Seu dispositivo ainda não foi autorizado a acessar este cofre. Peça ao proprietário ou a um administrador deste cofre para autorizá-lo.
|
||||
### License Exceeded
|
||||
hub.invalidLicense.message=Licença Invalida
|
||||
hub.invalidLicense.description=Sua instância do Cryptomator Hub possui uma licença inválida. Por favor, informe um administrador do Hub para atualizar ou renovar a licença.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -272,7 +274,10 @@ preferences.interface.showMinimizeButton=Mostrar botão minimizar
|
||||
preferences.interface.showTrayIcon=Mostrar ícone na barra do sistema (requer reinicialização)
|
||||
## Volume
|
||||
preferences.volume=Volume Virtual
|
||||
preferences.volume.type=Tipo de Volume
|
||||
preferences.volume.type.automatic=Automático
|
||||
preferences.volume.docsTooltip=Abra a documentação para saber mais sobre os diferentes tipos de volumes.
|
||||
preferences.volume.fuseRestartRequired=Para aplicar as mudanças, o Cryptomator precisa ser reiniciado.
|
||||
preferences.volume.tcp.port=Porta TCP
|
||||
preferences.volume.supportedFeatures=O tipo de volume escolhido suporta os seguintes recursos:
|
||||
preferences.volume.feature.mountAuto=Seleção automática de ponto de montagem
|
||||
@@ -302,21 +307,27 @@ stats.title=Estatísticas para %s
|
||||
stats.cacheHitRate=Taxa de Utilização do Cache
|
||||
## Read
|
||||
stats.read.throughput.idle=Leitura: ociosa
|
||||
stats.read.throughput.kibs=Leitura: %.2f MiB/s
|
||||
stats.read.throughput.mibs=Leitura: %.2f MiB/s
|
||||
stats.read.total.data.none=Dados lidos: -
|
||||
stats.read.total.data.kib=Dados lidos: %.1f GiB
|
||||
stats.read.total.data.mib=Dados lidos: %.1f MiB
|
||||
stats.read.total.data.gib=Dados lidos: %.1f GiB
|
||||
stats.decr.total.data.none=Dados descriptografados: -
|
||||
stats.decr.total.data.kib=Dados descriptografados: %.1f GiB
|
||||
stats.decr.total.data.mib=Dados descriptografados: %.1f MiB
|
||||
stats.decr.total.data.gib=Dados descriptografados: %.1f GiB
|
||||
stats.read.accessCount=Total de leituras: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Escrita: ociosa
|
||||
stats.write.throughput.kibs=Escrita: %.2f MiB/s
|
||||
stats.write.throughput.mibs=Escrita: %.2f MiB/s
|
||||
stats.write.total.data.none=Dados gravados: -
|
||||
stats.write.total.data.kib=Dados gravados: %.1f kiB
|
||||
stats.write.total.data.mib=Dados gravados: %.1f MiB
|
||||
stats.write.total.data.gib=Dados gravados: %.1f GiB
|
||||
stats.encr.total.data.none=Dados criptografados: -
|
||||
stats.encr.total.data.kib=Dados encriptados: %.1f KiB
|
||||
stats.encr.total.data.mib=Dados criptografados: %.1f MiB
|
||||
stats.encr.total.data.gib=Dados criptografados: %.1f GiB
|
||||
stats.write.accessCount=Total gravado: %d
|
||||
@@ -359,6 +370,7 @@ main.vaultDetail.lockBtn=Bloquear
|
||||
main.vaultDetail.bytesPerSecondRead=Leitura:
|
||||
main.vaultDetail.bytesPerSecondWritten=Escrita:
|
||||
main.vaultDetail.throughput.idle=ocioso
|
||||
main.vaultDetail.throughput.kbps=%.1f KiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
main.vaultDetail.stats=Estatísticas do Cofre
|
||||
main.vaultDetail.locateEncryptedFileBtn=Localizar Arquivo Criptografado
|
||||
@@ -422,6 +434,9 @@ vaultOptions.masterkey.recoveryKeyExplanation=Se você perder a sua senha, a ún
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Exibir chave de recuperação
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Redefinir Senha
|
||||
## Hub
|
||||
vaultOptions.hub=Recuperação
|
||||
vaultOptions.hub.convertInfo=Você pode usar a chave de recuperação para converter este cofre do Hub em um cofre protegido por senha de emergência.
|
||||
vaultOptions.hub.convertBtn=Converter para Cofre protegido por senha
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
@@ -433,7 +448,10 @@ recoveryKey.display.StorageHints=Mantenha-a em um lugar bem seguro, por exemplo:
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
recoveryKey.recover.title=Redefinir Senha
|
||||
recoveryKey.recover.prompt=Digite a chave de recuperação para "%s":
|
||||
recoveryKey.recover.correctKey=Esta é uma chave de recuperação válida
|
||||
recoveryKey.recover.wrongKey=Esta chave de recuperação pertence a um outro cofre
|
||||
recoveryKey.recover.invalidKey=Esta chave de recuperação não é válida
|
||||
recoveryKey.printout.heading=Chave de Recuperação do Cryptomator\n"%s"\n
|
||||
### Reset Password
|
||||
recoveryKey.recover.resetBtn=Redefinir
|
||||
@@ -442,6 +460,11 @@ recoveryKey.recover.resetSuccess.message=Senha redefinida com sucesso
|
||||
recoveryKey.recover.resetSuccess.description=Você pode desbloquear o seu cofre com a nova senha.
|
||||
|
||||
# Convert Vault
|
||||
convertVault.title=Converter Cofre
|
||||
convertVault.convert.convertBtn.before=Converter
|
||||
convertVault.convert.convertBtn.processing=Convertendo...
|
||||
convertVault.success.message=Conversão bem sucedida
|
||||
convertVault.hubToPassword.success.description=Agora você pode desbloquear o cofre com a senha escolhida sem exigir acesso ao Hub.
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Digite a nova senha
|
||||
|
||||
@@ -432,6 +432,7 @@ vaultOptions.masterkey.recoveryKeyExplanation=Kľúč pre obnovu je Vašou jedin
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Ukázať klúč obnovy
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Resetovanie hesla
|
||||
## Hub
|
||||
vaultOptions.hub=Obnova
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
@@ -454,6 +455,10 @@ recoveryKey.recover.resetSuccess.message=Heslo úspešne zresetované
|
||||
recoveryKey.recover.resetSuccess.description=Môžte odomknúť trezor s novým heslom.
|
||||
|
||||
# Convert Vault
|
||||
convertVault.title=Konvertovať trezor
|
||||
convertVault.convert.convertBtn.before=Konvertovať
|
||||
convertVault.convert.convertBtn.processing=Konvertujem…
|
||||
convertVault.success.message=Konverzia úspešná
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Zadajte nové heslo
|
||||
|
||||
@@ -434,6 +434,9 @@ vaultOptions.masterkey.recoveryKeyExplanation=Bir kurtarma anahtarı şifrenizi
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Kurtarma Anahtarını Göster
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Şifreyi Sıfırla
|
||||
## Hub
|
||||
vaultOptions.hub=Kurtarma
|
||||
vaultOptions.hub.convertInfo=Acil bir durumda bu Hub kasasını parola tabanlı bir kasaya dönüştürmek için kurtarma anahtarını kullanabilirsiniz.
|
||||
vaultOptions.hub.convertBtn=Parola Tabanlı Kasaya Dönüştür
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
@@ -445,6 +448,7 @@ recoveryKey.display.StorageHints=Bunu çok güvenli bir yerde saklayın, örneğ
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
recoveryKey.recover.title=Şifreyi Sıfırla
|
||||
recoveryKey.recover.prompt="%s" için kurtarma anahtarını girin:
|
||||
recoveryKey.recover.correctKey=Bu geçerli bir kurtarma anahtarı
|
||||
recoveryKey.recover.wrongKey=Bu kurtarma anahtarı farklı bir kasaya ait
|
||||
recoveryKey.recover.invalidKey=Bu kurtarma anahtarı geçerli değil
|
||||
@@ -456,6 +460,11 @@ recoveryKey.recover.resetSuccess.message=Şifre sıfırlama başarılı
|
||||
recoveryKey.recover.resetSuccess.description=Yeni şifre ile kasanızın kilidini açabilirsiniz.
|
||||
|
||||
# Convert Vault
|
||||
convertVault.title=Kasayı Dönüştür
|
||||
convertVault.convert.convertBtn.before=Dönüştür
|
||||
convertVault.convert.convertBtn.processing=Dönüştürülüyor…
|
||||
convertVault.success.message=Dönüştürme başarılı
|
||||
convertVault.hubToPassword.success.description=Artık Hub erişimi gerektirmeden seçilen parola ile kasanın kilidini açabilirsiniz.
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Yeni bir şifre girin
|
||||
|
||||
@@ -79,17 +79,21 @@ addvault.new.readme.storageLocation.10=Якщо вам потрібна допо
|
||||
addvault.new.readme.accessLocation.fileName=ПРИВІТ.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ ЗАШИФРОВАНИЙ ТОМ 🔐️
|
||||
addvault.new.readme.accessLocation.2=Це місце розташування вашого vault.
|
||||
addvault.new.readme.accessLocation.3=Будь-які файли, додані до цього тому, будуть зашифровані за допомогою Cryptomator. Ви можете працювати із ним як із будь-якою іншою директорією або накопичувачем. Це лише розшифрований вигляд його вмісту, ваші файли завжди знаходяться в зашифрованому вигляді на диску.
|
||||
addvault.new.readme.accessLocation.4=Якщо хочете, то можете видалити цей файл.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Виберіть файл "vault.cryptomator" у вашому існуючому сховищі. Якщо існує лише файл з назвою "masterkey.cryptomator", виберіть його.
|
||||
addvaultwizard.existing.chooseBtn=Обрати…
|
||||
addvaultwizard.existing.filePickerTitle=Виберіть Vault Файл
|
||||
addvaultwizard.existing.filePickerMimeDesc=Cryptomator Vault
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Додано сховище "%s".\nДля доступу або додавання вмісту це сховище необхідно розблокувати. Також його можна розблокувати й пізніше.
|
||||
addvaultwizard.success.unlockNow=Розблокувати
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Видалити "%s"
|
||||
removeVault.message=Видалити vault?
|
||||
removeVault.description=Це лише змусить Cryptomator забути про це сховище. Його можна буде додати пізніше. Зашифровані файли на жорсткому диску не будуть видалені.
|
||||
removeVault.confirmBtn=Видалити сховище
|
||||
|
||||
# Change Password
|
||||
@@ -119,6 +123,10 @@ unlock.success.description=Вміст vault "%s" тепер доступний
|
||||
unlock.success.rememberChoice=Запам'ятайте мій вибір та більше не запитуйте
|
||||
unlock.success.revealBtn=Розкрити Диск
|
||||
## Failure
|
||||
unlock.error.customPath.message=Не вдалося змонтувати сховище за вказаним шляхом
|
||||
unlock.error.customPath.description.notSupported=Якщо ви хочете надалі використовувати власний шлях, будь ласка, перейдіть до налаштувань та виберіть тип тому, що його підтримує. В іншому випадку перейдіть до параметрів сховища та оберіть точку монтування, що підтримується.
|
||||
unlock.error.customPath.description.notExists=Вказаний шлях підключення не існує. Створіть його в локальній файловій системі або змініть його в параметрах сховища.
|
||||
unlock.error.customPath.description.generic=Ви створили власний шлях підключення для цього сховища, але скористатися ним не вдалося. Повідомлення про помилку: %s
|
||||
## Hub
|
||||
hub.noKeychain.message=Не вдалося отримати доступ до ключа пристрою
|
||||
hub.noKeychain.description=Щоб розблокувати Hub vaults, необхідний ключ пристрою, який захищено за допомогою ланцюга ключів. Щоб продовжити, увімкніть “%s” та виберіть ланцюг ключів у налаштуваннях.
|
||||
@@ -146,6 +154,8 @@ hub.registerFailed.description=Виникла помилка у процесі
|
||||
hub.unauthorized.message=У доступі відмовлено
|
||||
hub.unauthorized.description=Ваш пристрій ще не має прав доступу до цього vault. Попросіть власника vault надати їх.
|
||||
### License Exceeded
|
||||
hub.invalidLicense.message=Недійсна ліцензія Hub
|
||||
hub.invalidLicense.description=У вашого Cryptomator Hub недійсна ліцензія. Будь ласка, повідомте адміністратору Hub, що потрібно оновити або продовжити ліцензію.
|
||||
|
||||
# Lock
|
||||
## Force
|
||||
@@ -324,16 +334,25 @@ vaultOptions.masterkey.recoveryKeyExplanation=У разі втрати паро
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Показати Ключ Відновлення
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Скинути Пароль
|
||||
## Hub
|
||||
vaultOptions.hub=Відновлення
|
||||
vaultOptions.hub.convertInfo=Ключ відновлення використовується для перетворення цього Hub-сховища на сховище з паролем у надзвичайній ситуації.
|
||||
vaultOptions.hub.convertBtn=Перетворити на сховище з паролем
|
||||
|
||||
# Recovery Key
|
||||
## Display Recovery Key
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
recoveryKey.recover.title=Скинути Пароль
|
||||
recoveryKey.recover.prompt=Введіть ключ відновлення для "%s:
|
||||
### Reset Password
|
||||
### Recovery Key Password Reset Success
|
||||
|
||||
# Convert Vault
|
||||
convertVault.title=Перетворити сховище
|
||||
convertVault.convert.convertBtn.before=Перетворити
|
||||
convertVault.convert.convertBtn.processing=Перетворення…
|
||||
convertVault.success.message=Перетворення виконано успішно
|
||||
convertVault.hubToPassword.success.description=Тепер ви можете розблокувати сховище за допомогою обраного пароля без необхідності доступу до Hub.
|
||||
|
||||
# New Password
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public class SupportedLanguagesTest {
|
||||
}
|
||||
|
||||
public static Stream<String> languageTags() {
|
||||
return SupportedLanguages.LANGUAGAE_TAGS.stream() //
|
||||
return SupportedLanguages.LANGUAGE_TAGS.stream() //
|
||||
.filter(tag -> !"en".equals(tag)); // english uses the default bundle
|
||||
}
|
||||
}
|
||||
@@ -57,11 +57,10 @@
|
||||
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppress false positive, because com.google.common.io.Files.getTempDir() is not used
|
||||
Cryptomator not affected of cve in jackson-databind-2.14.2.jar
|
||||
]]></notes>
|
||||
<packageUrl regex="true">^pkg:maven/com\.google\.guava/guava@.*$</packageUrl>
|
||||
<vulnerabilityName>CVE-2020-8908</vulnerabilityName>
|
||||
<cve>CVE-2020-8908</cve>
|
||||
<packageUrl regex="true">^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$</packageUrl>
|
||||
<cve>CVE-2023-35116</cve>
|
||||
</suppress>
|
||||
|
||||
</suppressions>
|
||||
Reference in New Issue
Block a user