Compare commits

...

28 Commits
1.2.0 ... 1.2.3

Author SHA1 Message Date
Tobias Hagemann
cef3a5fc77 Merge branch 'release/1.2.3'
# Conflicts:
#	main/ant-kit/pom.xml
#	main/commons-test/pom.xml
#	main/commons/pom.xml
#	main/filesystem-api/pom.xml
#	main/filesystem-charsets/pom.xml
#	main/filesystem-crypto-integration-tests/pom.xml
#	main/filesystem-crypto/pom.xml
#	main/filesystem-inmemory/pom.xml
#	main/filesystem-invariants-tests/pom.xml
#	main/filesystem-nameshortening/pom.xml
#	main/filesystem-nio/pom.xml
#	main/filesystem-stats/pom.xml
#	main/frontend-api/pom.xml
#	main/frontend-webdav/pom.xml
#	main/jacoco-report/pom.xml
#	main/keychain/pom.xml
#	main/pom.xml
#	main/uber-jar/pom.xml
#	main/ui/pom.xml
2016-11-29 23:03:26 +01:00
Tobias Hagemann
9956f43fd9 updated to version 1.2.3 2016-11-29 22:24:26 +01:00
Tobias Hagemann
2b84593bde updated localization 2016-11-29 22:16:46 +01:00
Markus Kreusch
4e728fd387 Merge branch 'feature/issue-363' into develop 2016-11-29 15:21:48 +01:00
Tobias Hagemann
438ade1106 fixes #382 2016-11-27 14:28:44 +01:00
Sebastian Stenzel
fe54f4ec66 Update README.md
As suggested by @tallesh in #135
2016-11-27 10:14:34 +01:00
Markus Kreusch
fe86b4c593 Implemented #363 2016-11-14 22:26:55 +01:00
Markus Kreusch
a583afeb60 Merge branch 'feature/issue-393' into develop 2016-11-14 15:08:31 +01:00
Sebastian Stenzel
a585d3cf16 cherry picked from bac1d6f [ci skip] 2016-11-12 17:04:58 +01:00
Sebastian Stenzel
3db757193e Merge branch 'hotfix/1.2.2' 2016-11-12 17:02:04 +01:00
Sebastian Stenzel
bac1d6fd83 Updated siv-mode to 1.2.0 to be consistent with CryptoLib 2016-11-12 16:41:26 +01:00
Sebastian Stenzel
39ee8a9cde coverity issue 151831 2016-11-11 17:11:21 +01:00
Markus Kreusch
1263b3af81 fixed 'a' really bad thing in the last commit 2016-11-11 09:56:45 +01:00
Markus Kreusch
dafa29d8a3 Implemented #393 2016-11-10 22:58:45 +01:00
Sebastian Stenzel
2bc6fe89ad Merge branch 'release/1.2.1' 2016-11-10 15:23:11 +01:00
Sebastian Stenzel
8439216233 Updated version to 1.2.1 2016-11-10 15:13:28 +01:00
Sebastian Stenzel
aab616d184 Updated CryptoLib, hopefully fixes #373 2016-11-10 15:11:04 +01:00
Sebastian Stenzel
70c3a38c49 invoking UI methods on UI thread, might solve #351 2016-11-10 14:07:37 +01:00
Sebastian Stenzel
c64294ac3e Added chinese localizations, updated dutch localization 2016-11-10 13:41:09 +01:00
Markus Kreusch
82330db871 Additional logging for vault version upgrade 2016-11-09 15:54:10 +01:00
Sebastian Stenzel
c54a721f9a Merge pull request #385 from IAMtheIAM/patch-1
Update README.md
2016-11-06 21:59:16 +01:00
Sebastian Stenzel
355bbb5459 Merge branch 'develop' into patch-1 2016-11-06 21:53:28 +01:00
IAMtheIAM
63daa0f121 Update README.md
Update Readme with accurate info regarding v1.2.0
2016-11-06 03:56:56 -07:00
IAMtheIAM
50885d5c7c Update README.md 2016-11-05 16:51:16 -07:00
IAMtheIAM
4d68818ec5 Update README.md
Update features
2016-11-05 14:00:32 -07:00
IAMtheIAM
6fb20dd509 Update README.md
Added info about obfuscating file size and folder structure (two very important features that should be known!)
2016-11-05 13:54:39 -07:00
Sebastian Stenzel
2bb87dfa96 Merge branch 'release/1.2.0' into develop
# Conflicts:
#	main/ant-kit/pom.xml
#	main/commons-test/pom.xml
#	main/commons/pom.xml
#	main/filesystem-api/pom.xml
#	main/filesystem-charsets/pom.xml
#	main/filesystem-crypto-integration-tests/pom.xml
#	main/filesystem-crypto/pom.xml
#	main/filesystem-inmemory/pom.xml
#	main/filesystem-invariants-tests/pom.xml
#	main/filesystem-nameshortening/pom.xml
#	main/filesystem-nio/pom.xml
#	main/filesystem-stats/pom.xml
#	main/frontend-api/pom.xml
#	main/frontend-webdav/pom.xml
#	main/jacoco-report/pom.xml
#	main/keychain/pom.xml
#	main/pom.xml
#	main/uber-jar/pom.xml
#	main/ui/pom.xml
2016-09-19 15:12:24 +02:00
Sebastian Stenzel
2fa04d7b7c increased version to 1.3.0-SNAPSHOT
[ci skip]
2016-09-15 13:35:22 +02:00
65 changed files with 896 additions and 267 deletions

View File

@@ -19,7 +19,8 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
- Client-side: No accounts, no data shared with any online service
- Totally transparent: Just work on the virtual drive as if it were a USB flash drive
- AES encryption with 256-bit key length
- Filenames get encrypted, too
- File names get encrypted
- Folder structure gets obfuscated
- Use as many vaults in your Dropbox as you want, each having individual passwords
### Privacy
@@ -52,9 +53,11 @@ For more information on the security details visit [cryptomator.org](https://cry
```
cd main
mvn clean install
mvn clean install -Prelease
```
An executable jar file will be created inside `main/uber-jar/target`.
## Contributing to Cryptomator
Please read our [contribution guide](https://github.com/cryptomator/cryptomator/blob/master/CONTRIBUTING.md), if you would like to report a bug, ask a question or help us with coding.

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>ant-kit</artifactId>
<packaging>pom</packaging>

View File

@@ -10,7 +10,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>commons-test</artifactId>
<name>Cryptomator common test dependencies</name>

View File

@@ -10,7 +10,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>commons</artifactId>
<name>Cryptomator common</name>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-api</artifactId>
<name>Cryptomator filesystem: API</name>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-charsets</artifactId>
<name>Cryptomator filesystem: Charset compatibility layer</name>

View File

@@ -40,9 +40,9 @@ class NormalizedNameFolder extends DelegatingFolder<NormalizedNameFolder, Normal
NormalizedNameFile nfcFile = super.file(nfcName);
NormalizedNameFile nfdFile = super.file(nfdName);
if (!nfcName.equals(nfdName) && nfcFile.exists() && nfdFile.exists()) {
LOG.warn("Ambiguous file names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
LOG.debug("Ambiguous file names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
} else if (!nfcName.equals(nfdName) && !nfcFile.exists() && nfdFile.exists()) {
LOG.info("Moving file from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
LOG.debug("Moving file from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
nfdFile.moveTo(nfcFile);
}
return nfcFile;
@@ -60,9 +60,9 @@ class NormalizedNameFolder extends DelegatingFolder<NormalizedNameFolder, Normal
NormalizedNameFolder nfcFolder = super.folder(nfcName);
NormalizedNameFolder nfdFolder = super.folder(nfdName);
if (!nfcName.equals(nfdName) && nfcFolder.exists() && nfdFolder.exists()) {
LOG.warn("Ambiguous folder names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
LOG.debug("Ambiguous folder names \"" + nfcName + "\" (NFC) vs. \"" + nfdName + "\" (NFD). Both files exist. Using \"" + nfcName + "\" (NFC).");
} else if (!nfcName.equals(nfdName) && !nfcFolder.exists() && nfdFolder.exists()) {
LOG.info("Moving folder from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
LOG.debug("Moving folder from \"" + nfcName + "\" (NFD) to \"" + nfdName + "\" (NFC).");
nfdFolder.moveTo(nfcFolder);
}
return nfcFolder;

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-crypto-integration-tests</artifactId>
<name>Cryptomator filesystem: Encryption layer tests</name>

View File

@@ -12,14 +12,14 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-crypto</artifactId>
<name>Cryptomator filesystem: Encryption layer</name>
<properties>
<bouncycastle.version>1.51</bouncycastle.version>
<sivmode.version>1.0.8</sivmode.version>
<sivmode.version>1.2.0</sivmode.version>
</properties>
<dependencies>

View File

@@ -14,7 +14,6 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Pattern;
import javax.crypto.AEADBadTagException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
@@ -23,6 +22,7 @@ import org.apache.commons.codec.binary.BaseNCodec;
import org.cryptomator.crypto.engine.AuthenticationFailedException;
import org.cryptomator.crypto.engine.FilenameCryptor;
import org.cryptomator.siv.SivMode;
import org.cryptomator.siv.UnauthenticCiphertextException;
class FilenameCryptorImpl implements FilenameCryptor {
@@ -71,7 +71,7 @@ class FilenameCryptorImpl implements FilenameCryptor {
try {
final byte[] cleartextBytes = AES_SIV.get().decrypt(encryptionKey, macKey, encryptedBytes, associatedData);
return new String(cleartextBytes, UTF_8);
} catch (AEADBadTagException | IllegalBlockSizeException e) {
} catch (UnauthenticCiphertextException | IllegalBlockSizeException e) {
throw new AuthenticationFailedException("Invalid ciphertext.", e);
}
}

View File

@@ -68,7 +68,7 @@ final class ConflictResolver {
String alternativeCiphertext = nameEncryptor.apply(alternativeCleartext).get();
alternativeFile = folder.file(isDirectory ? DIR_PREFIX + alternativeCiphertext : alternativeCiphertext);
} while (alternativeFile.exists());
LOG.info("Detected conflict {}:\n{}\n{}", conflictId, canonicalFile, conflictingFile);
LOG.debug("Detected conflict {}:\n{}\n{}", conflictId, canonicalFile, conflictingFile);
conflictingFile.moveTo(alternativeFile);
return alternativeFile;
}

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-inmemory</artifactId>
<name>Cryptomator filesystem: In-memory mock</name>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-invariants-tests</artifactId>
<name>Cryptomator filesystem: Invariants tests</name>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-nameshortening</artifactId>
<name>Cryptomator filesystem: Name shortening layer</name>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-nio</artifactId>
<name>Cryptomator filesystem: NIO-based physical layer</name>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>filesystem-stats</artifactId>
<name>Cryptomator filesystem: Throughput statistics</name>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>frontend-api</artifactId>
<name>Cryptomator frontend: API</name>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>frontend-webdav</artifactId>
<name>Cryptomator frontend: WebDAV frontend</name>

View File

@@ -18,6 +18,10 @@ class ContextPaths {
return format("/%s/%s", id, name);
}
public static String removeFrontendId(String path) {
return path.replaceAll("/" + FRONTEND_ID_PATTERN + "/", "/[...]/");
}
public static Optional<FrontendId> extractFrontendId(String path) {
Matcher matcher = SERVLET_PATH_WITH_FRONTEND_ID_PATTERN.matcher(path);
if (matcher.matches()) {

View File

@@ -0,0 +1,17 @@
package org.cryptomator.frontend.webdav;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.servlet.ServletContextHandler;
class FontendIdHidingServletContextHandler extends ServletContextHandler {
public FontendIdHidingServletContextHandler(HandlerContainer parent, String contextPath, int options) {
super(parent, contextPath, options);
}
@Override
public String toString() {
return ContextPaths.removeFrontendId(super.toString());
}
}

View File

@@ -8,8 +8,6 @@
*******************************************************************************/
package org.cryptomator.frontend.webdav;
import static java.lang.String.format;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
@@ -110,7 +108,7 @@ public class WebDavServer implements FrontendFactory {
@Override
public Frontend create(Folder root, FrontendId id, String name) throws FrontendCreationFailedException {
String contextPath = format("/%s/%s", id, name);
String contextPath = ContextPaths.from(id, name);
final URI uri;
try {
uri = new URI("http", null, "localhost", getPort(), contextPath, null, null);
@@ -118,10 +116,10 @@ public class WebDavServer implements FrontendFactory {
throw new IllegalStateException(e);
}
final ServletContextHandler handler = addServlet(root, uri);
LOG.info("Servlet available under " + uri);
LOG.info("Servlet available under " + ContextPaths.removeFrontendId(uri.toString()));
return new WebDavFrontend(webdavMounterProvider, handler, uri);
}
public void setValidFrontendIds(Collection<FrontendId> validFrontendIds) {
tarpit.setValidFrontendIds(validFrontendIds);
}

View File

@@ -35,9 +35,10 @@ import org.eclipse.jetty.servlet.ServletHolder;
class WebDavServletContextFactory {
private static final String WILDCARD = "/*";
@Inject
public WebDavServletContextFactory() {}
public WebDavServletContextFactory() {
}
/**
* Creates a new Jetty ServletContextHandler, that can be be added to a servletCollection as follows:
@@ -63,7 +64,7 @@ class WebDavServletContextFactory {
}
};
final String contextPath = StringUtils.removeEnd(contextRoot.getPath(), "/");
final ServletContextHandler servletContext = new ServletContextHandler(null, contextPath, ServletContextHandler.SESSIONS);
final ServletContextHandler servletContext = new FontendIdHidingServletContextHandler(null, contextPath, ServletContextHandler.SESSIONS);
final ServletHolder servletHolder = new ServletHolder(contextPath, new WebDavServlet(contextRoot, root));
servletContext.addServlet(servletHolder, WILDCARD);
servletContext.addFilter(LoopbackFilter.class, WILDCARD, EnumSet.of(DispatcherType.REQUEST));

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>jacoco-report</artifactId>
<name>Cryptomator Code Coverage Report</name>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>keychain</artifactId>
<name>System Keychain Access</name>

View File

@@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
<packaging>pom</packaging>
<name>Cryptomator</name>
@@ -27,7 +27,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- dependency versions -->
<cryptomator.cryptolib.version>1.0.2</cryptomator.cryptolib.version>
<cryptomator.cryptolib.version>1.0.7</cryptomator.cryptolib.version>
<cryptomator.jni.version>1.0.0</cryptomator.jni.version>
<log4j.version>2.1</log4j.version>
<slf4j.version>1.7.7</slf4j.version>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>uber-jar</artifactId>
<packaging>pom</packaging>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.cryptomator</groupId>
<artifactId>main</artifactId>
<version>1.2.0</version>
<version>1.2.3</version>
</parent>
<artifactId>ui</artifactId>
<name>Cryptomator GUI</name>

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.util.ApplicationVersion;
import org.cryptomator.ui.util.SingleInstanceManager;
import org.cryptomator.ui.util.SingleInstanceManager.RemoteInstance;
import org.eclipse.jetty.util.ConcurrentHashSet;
@@ -33,63 +34,62 @@ public class Cryptomator {
public static final CompletableFuture<Consumer<File>> OPEN_FILE_HANDLER = new CompletableFuture<>();
private static final Logger LOG = LoggerFactory.getLogger(Cryptomator.class);
private static final Set<Runnable> SHUTDOWN_TASKS = new ConcurrentHashSet<>();
private static final CleanShutdownPerformer CLEAN_SHUTDOWN_PERFORMER = new CleanShutdownPerformer();
public static void main(String[] args) {
String cryptomatorVersion = Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion()).orElse("SNAPSHOT");
LOG.info("Starting Cryptomator {} on {} {} ({})", cryptomatorVersion, SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
LOG.info("Starting Cryptomator {} on {} {} ({})", ApplicationVersion.orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
if (SystemUtils.IS_OS_MAC_OSX) {
/*
* On OSX we're in an awkward position. We need to register a handler in the main thread of this application. However, we can't
* even pass objects to the application, so we're forced to use a static CompletableFuture for the handler, which actually opens
* the file in the application.
*
* Code taken from https://github.com/axet/desktop/blob/master/src/main/java/com/github/axet/desktop/os/mac/AppleHandlers.java
*/
try {
final Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
final Class<?> openFilesHandlerClass = Class.forName("com.apple.eawt.OpenFilesHandler");
final Method getApplication = applicationClass.getMethod("getApplication");
final Object application = getApplication.invoke(null);
final Method setOpenFileHandler = applicationClass.getMethod("setOpenFileHandler", openFilesHandlerClass);
final ClassLoader openFilesHandlerClassLoader = openFilesHandlerClass.getClassLoader();
final OpenFilesHandlerClassHandler openFilesHandlerHandler = new OpenFilesHandlerClassHandler();
final Object openFilesHandlerObject = Proxy.newProxyInstance(openFilesHandlerClassLoader, new Class<?>[] {openFilesHandlerClass}, openFilesHandlerHandler);
setOpenFileHandler.invoke(application, openFilesHandlerObject);
} catch (ReflectiveOperationException | RuntimeException e) {
// Since we're trying to call OS-specific code, we'll just have
// to hope for the best.
LOG.error("exception adding OSX file open handler", e);
}
addOsxFileOpenHandler();
}
/*
* Perform certain things on VM termination.
*/
Runtime.getRuntime().addShutdownHook(CLEAN_SHUTDOWN_PERFORMER);
new CleanShutdownPerformer().registerShutdownHook();
/*
* Before starting the application, we check if there is already an instance running on this computer. If so, we send our command
* line arguments to that instance and quit.
*/
final Optional<RemoteInstance> remoteInstance = SingleInstanceManager.getRemoteInstance(MainApplication.APPLICATION_KEY);
if (remoteInstance.isPresent()) {
try (RemoteInstance instance = remoteInstance.get()) {
LOG.info("An instance of Cryptomator is already running at {}.", instance.getRemotePort());
for (int i = 0; i < args.length; i++) {
remoteInstance.get().sendMessage(args[i], 100);
}
} catch (Exception e) {
LOG.error("Error forwarding arguments to remote instance", e);
}
final Optional<RemoteInstance> runningInstance = SingleInstanceManager.getRemoteInstance(MainApplication.APPLICATION_KEY);
if (runningInstance.isPresent()) {
sendArgsToRunningInstance(args, runningInstance);
} else {
Application.launch(MainApplication.class, args);
}
}
private static void addOsxFileOpenHandler() {
/*
* On OSX we're in an awkward position. We need to register a handler in the main thread of this application. However, we can't
* even pass objects to the application, so we're forced to use a static CompletableFuture for the handler, which actually opens
* the file in the application.
*
* Code taken from https://github.com/axet/desktop/blob/master/src/main/java/com/github/axet/desktop/os/mac/AppleHandlers.java
*/
try {
final Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
final Class<?> openFilesHandlerClass = Class.forName("com.apple.eawt.OpenFilesHandler");
final Method getApplication = applicationClass.getMethod("getApplication");
final Object application = getApplication.invoke(null);
final Method setOpenFileHandler = applicationClass.getMethod("setOpenFileHandler", openFilesHandlerClass);
final ClassLoader openFilesHandlerClassLoader = openFilesHandlerClass.getClassLoader();
final OpenFilesHandlerClassHandler openFilesHandlerHandler = new OpenFilesHandlerClassHandler();
final Object openFilesHandlerObject = Proxy.newProxyInstance(openFilesHandlerClassLoader, new Class<?>[] {openFilesHandlerClass}, openFilesHandlerHandler);
setOpenFileHandler.invoke(application, openFilesHandlerObject);
} catch (ReflectiveOperationException | RuntimeException e) {
// Since we're trying to call OS-specific code, we'll just have
// to hope for the best.
LOG.error("exception adding OSX file open handler", e);
}
}
private static void sendArgsToRunningInstance(String[] args, final Optional<RemoteInstance> remoteInstance) {
try (RemoteInstance instance = remoteInstance.get()) {
LOG.info("An instance of Cryptomator is already running at {}.", instance.getRemotePort());
for (int i = 0; i < args.length; i++) {
remoteInstance.get().sendMessage(args[i], 100);
}
} catch (Exception e) {
LOG.error("Error forwarding arguments to remote instance", e);
}
}
public static void addShutdownTask(Runnable r) {
SHUTDOWN_TASKS.add(r);
}
@@ -111,6 +111,10 @@ public class Cryptomator {
});
SHUTDOWN_TASKS.clear();
}
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(this);
}
}
private static void handleOpenFileRequest(File file) {

View File

@@ -37,6 +37,8 @@ interface CryptomatorComponent {
ExitUtil exitUtil();
DebugMode debugMode();
Optional<MacFunctions> nativeMacFunctions();
}

View File

@@ -0,0 +1,75 @@
package org.cryptomator.ui;
import static java.util.Arrays.asList;
import static org.apache.logging.log4j.LogManager.ROOT_LOGGER_NAME;
import java.util.Collection;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.cryptomator.ui.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class DebugMode {
private static final Logger LOG = LoggerFactory.getLogger(DebugMode.class);
private static final Collection<LoggerUpgrade> LOGGER_UPGRADES = asList( //
loggerUpgrade(ROOT_LOGGER_NAME, Level.INFO), //
loggerUpgrade("org.cryptomator", Level.TRACE), //
loggerUpgrade("org.eclipse.jetty.server.Server", Level.DEBUG) //
);
private final Settings settings;
@Inject
public DebugMode(Settings settings) {
this.settings = settings;
}
public void initialize() {
if (settings.getDebugMode()) {
enable();
LOG.debug("Debug mode initialized");
}
}
private void enable() {
LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configuration config = context.getConfiguration();
LOGGER_UPGRADES.forEach(loggerUpgrade -> loggerUpgrade.execute(config));
context.updateLoggers();
}
private static LoggerUpgrade loggerUpgrade(String loggerName, Level minLevel) {
return new LoggerUpgrade(loggerName, minLevel);
}
private static class LoggerUpgrade {
private final Level level;
private final String loggerName;
public LoggerUpgrade(String loggerName, Level minLevel) {
this.loggerName = loggerName;
this.level = minLevel;
}
public void execute(Configuration config) {
LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
if (loggerConfig.getLevel().isMoreSpecificThan(level)) {
loggerConfig.setLevel(level);
}
}
}
}

View File

@@ -43,18 +43,46 @@ public class MainApplication extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
LOG.info("JavaFX application started");
final CryptomatorComponent comp;
CryptomatorComponent comp = createCryptomatorComponent(primaryStage);
MainController mainCtrl = comp.mainController();
closer = comp.deferredCloser();
comp.debugMode().initialize();
setupFXMLClassLoader();
setupStylesheets();
initializeStage(primaryStage, mainCtrl);
showWindow(primaryStage);
registerExitHandler(comp);
openFilesRequestedDuringStartup(primaryStage, mainCtrl);
registerApplicationToProcessOpenFileRequests(primaryStage, comp, mainCtrl);
}
@Override
public void stop() {
try {
comp = DaggerCryptomatorComponent.builder() //
closer.close();
} catch (ExecutionException e) {
LOG.error("Error closing ressources", e);
}
}
private CryptomatorComponent createCryptomatorComponent(Stage primaryStage) {
try {
return DaggerCryptomatorComponent.builder() //
.cryptomatorModule(new CryptomatorModule(this, primaryStage)) //
.secureRandomModule(new SecureRandomModule(SecureRandom.getInstanceStrong())) //
.build();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Every implementation of the Java platform is required to support at least one strong SecureRandom implementation.", e);
}
final MainController mainCtrl = comp.mainController();
closer = comp.deferredCloser();
}
private void setupFXMLClassLoader() {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
FXMLLoader.setDefaultClassLoader(contextClassLoader);
Platform.runLater(() -> {
@@ -66,35 +94,55 @@ public class MainApplication extends Application {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
});
}
// Set stylesheets and initialize stage:
private void setupStylesheets() {
Font.loadFont(getClass().getResourceAsStream("/css/ionicons.ttf"), 12.0);
chooseNativeStylesheet();
}
private void initializeStage(Stage primaryStage, MainController mainCtrl) {
mainCtrl.initStage(primaryStage);
primaryStage.titleProperty().bind(mainCtrl.windowTitle());
primaryStage.setResizable(false);
if (SystemUtils.IS_OS_WINDOWS) {
primaryStage.getIcons().add(new Image(MainApplication.class.getResourceAsStream("/window_icon.png")));
}
}
// show window and start observing its focus:
private void showWindow(Stage primaryStage) {
primaryStage.show();
ActiveWindowStyleSupport.startObservingFocus(primaryStage);
comp.exitUtil().initExitHandler(this::quit);
}
// open files, if requested during startup:
private void registerExitHandler(CryptomatorComponent comp) {
comp.exitUtil().initExitHandler(this::quit);
}
private void openFilesRequestedDuringStartup(Stage primaryStage, final MainController mainCtrl) {
for (String arg : getParameters().getUnnamed()) {
handleCommandLineArg(arg, primaryStage, mainCtrl);
}
if (SystemUtils.IS_OS_MAC_OSX) {
Cryptomator.OPEN_FILE_HANDLER.complete(file -> handleCommandLineArg(file.getAbsolutePath(), primaryStage, mainCtrl));
}
}
// register this application instance as primary application, that other instances can send open file requests to:
private void registerApplicationToProcessOpenFileRequests(Stage primaryStage, final CryptomatorComponent comp, final MainController mainCtrl) throws IOException {
LocalInstance cryptomatorGuiInstance = closer.closeLater(SingleInstanceManager.startLocalInstance(APPLICATION_KEY, comp.executorService()), LocalInstance::close).get().get();
cryptomatorGuiInstance.registerListener(arg -> handleCommandLineArg(arg, primaryStage, mainCtrl));
}
private void chooseNativeStylesheet() {
if (SystemUtils.IS_OS_MAC_OSX) {
setUserAgentStylesheet(getClass().getResource("/css/mac_theme.css").toString());
} else if (SystemUtils.IS_OS_LINUX) {
setUserAgentStylesheet(getClass().getResource("/css/linux_theme.css").toString());
} else if (SystemUtils.IS_OS_WINDOWS) {
setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString());
}
}
private void handleCommandLineArg(String arg, Stage primaryStage, MainController mainCtrl) {
// find correct location:
final Path path = FileSystems.getDefault().getPath(arg);
@@ -118,16 +166,6 @@ public class MainApplication extends Application {
});
}
private void chooseNativeStylesheet() {
if (SystemUtils.IS_OS_MAC_OSX) {
setUserAgentStylesheet(getClass().getResource("/css/mac_theme.css").toString());
} else if (SystemUtils.IS_OS_LINUX) {
setUserAgentStylesheet(getClass().getResource("/css/linux_theme.css").toString());
} else if (SystemUtils.IS_OS_WINDOWS) {
setUserAgentStylesheet(getClass().getResource("/css/win_theme.css").toString());
}
}
private void quit() {
Platform.runLater(() -> {
stop();
@@ -136,13 +174,4 @@ public class MainApplication extends Application {
});
}
@Override
public void stop() {
try {
closer.close();
} catch (ExecutionException e) {
LOG.error("Error closing ressources", e);
}
}
}

View File

@@ -59,6 +59,9 @@ public class SettingsController extends LocalizedFXMLViewController {
@FXML
private ChoiceBox<String> prefGvfsScheme;
@FXML
private CheckBox debugModeCheckbox;
@Override
public void initialize() {
checkForUpdatesCheckbox.setDisable(areUpdatesManagedExternally());
@@ -74,11 +77,13 @@ public class SettingsController extends LocalizedFXMLViewController {
prefGvfsScheme.getItems().add("dav");
prefGvfsScheme.getItems().add("webdav");
prefGvfsScheme.setValue(settings.getPreferredGvfsScheme());
debugModeCheckbox.setSelected(settings.getDebugMode());
EasyBind.subscribe(checkForUpdatesCheckbox.selectedProperty(), this::checkForUpdateDidChange);
EasyBind.subscribe(portField.textProperty(), this::portDidChange);
EasyBind.subscribe(useIpv6Checkbox.selectedProperty(), this::useIpv6DidChange);
EasyBind.subscribe(prefGvfsScheme.valueProperty(), this::prefGvfsSchemeDidChange);
EasyBind.subscribe(debugModeCheckbox.selectedProperty(), this::debugModeDidChange);
}
@Override
@@ -114,6 +119,11 @@ public class SettingsController extends LocalizedFXMLViewController {
settings.save();
}
private void debugModeDidChange(Boolean newValue) {
settings.setDebugMode(newValue);
settings.save();
}
private void prefGvfsSchemeDidChange(String newValue) {
settings.setPreferredGvfsScheme(newValue);
settings.save();

View File

@@ -30,6 +30,7 @@ import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.util.AsyncTaskService;
import org.cryptomator.ui.util.DialogBuilderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,7 +41,9 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Hyperlink;
@@ -276,6 +279,37 @@ public class UnlockController extends LocalizedFXMLViewController {
}
}
// ****************************************
// Save password checkbox
// ****************************************
@FXML
private void didClickSavePasswordCheckbox(ActionEvent event) {
if (!savePassword.isSelected() && hasStoredPassword()) {
Alert confirmDialog = DialogBuilderUtil.buildConfirmationDialog( //
localization.getString("unlock.savePassword.delete.confirmation.title"), //
localization.getString("unlock.savePassword.delete.confirmation.header"), //
localization.getString("unlock.savePassword.delete.confirmation.content"), //
SystemUtils.IS_OS_MAC_OSX ? ButtonType.CANCEL : ButtonType.OK);
Optional<ButtonType> choice = confirmDialog.showAndWait();
if (ButtonType.OK.equals(choice.get())) {
keychainAccess.get().deletePassphrase(vault.getId());
} else if (ButtonType.CANCEL.equals(choice.get())) {
savePassword.setSelected(true);
}
}
}
private boolean hasStoredPassword() {
char[] storedPw = keychainAccess.get().loadPassphrase(vault.getId());
boolean hasPw = (storedPw != null);
if (storedPw != null) {
Arrays.fill(storedPw, ' ');
}
return hasPw;
}
// ****************************************
// Unlock button
// ****************************************
@@ -301,7 +335,7 @@ public class UnlockController extends LocalizedFXMLViewController {
if (keychainAccess.isPresent() && savePassword.isSelected()) {
keychainAccess.get().storePassphrase(vault.getId(), password);
} else {
passwordField.swipe();
Platform.runLater(passwordField::swipe);
}
} catch (InvalidPassphraseException e) {
Platform.runLater(() -> {

View File

@@ -38,6 +38,7 @@ import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
@@ -57,15 +58,6 @@ public class UnlockedController extends LocalizedFXMLViewController {
private Optional<LockListener> listener = Optional.empty();
private Timeline ioAnimation;
@Inject
public UnlockedController(Localization localization, Provider<MacWarningsController> macWarningsControllerProvider, AsyncTaskService asyncTaskService) {
super(localization);
this.macWarningsController = macWarningsControllerProvider.get();
this.asyncTaskService = asyncTaskService;
macWarningsController.vault.bind(this.vault);
}
@FXML
private Label messageLabel;
@@ -81,11 +73,25 @@ public class UnlockedController extends LocalizedFXMLViewController {
@FXML
private ContextMenu moreOptionsMenu;
@FXML
private MenuItem revealVaultMenuItem;
@Inject
public UnlockedController(Localization localization, Provider<MacWarningsController> macWarningsControllerProvider, AsyncTaskService asyncTaskService) {
super(localization);
this.macWarningsController = macWarningsControllerProvider.get();
this.asyncTaskService = asyncTaskService;
macWarningsController.vault.bind(this.vault);
}
@Override
public void initialize() {
macWarningsController.initStage(macWarningsWindow);
ActiveWindowStyleSupport.startObservingFocus(macWarningsWindow);
revealVaultMenuItem.disableProperty().bind(EasyBind.map(vault, vault -> vault != null && !vault.isMounted()));
EasyBind.subscribe(vault, this::vaultChanged);
EasyBind.subscribe(moreOptionsMenu.showingProperty(), moreOptionsButton::setSelected);
}
@@ -109,6 +115,11 @@ public class UnlockedController extends LocalizedFXMLViewController {
}
});
if (!vault.get().isMounted()) {
// TODO Markus Kreusch #393: hyperlink auf FAQ oder sowas?
messageLabel.setText(localization.getString("unlocked.label.mountFailed"));
}
// (re)start throughput statistics:
stopIoSampling();
startIoSampling();

View File

@@ -13,7 +13,6 @@ import java.net.URL;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
@@ -29,6 +28,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.util.ApplicationVersion;
import org.cryptomator.ui.util.AsyncTaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -104,7 +104,7 @@ public class WelcomeController extends LocalizedFXMLViewController {
asyncTaskService.asyncTaskOf(() -> {
final HttpClient client = new HttpClient();
final HttpMethod method = new GetMethod("https://cryptomator.org/downloads/latestVersion.json");
client.getParams().setParameter(HttpClientParams.USER_AGENT, "Cryptomator VersionChecker/" + applicationVersion().orElse("SNAPSHOT"));
client.getParams().setParameter(HttpClientParams.USER_AGENT, "Cryptomator VersionChecker/" + ApplicationVersion.orElse("SNAPSHOT"));
client.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
client.getParams().setConnectionManagerTimeout(5000);
client.executeMethod(method);
@@ -124,10 +124,6 @@ public class WelcomeController extends LocalizedFXMLViewController {
}).run();
}
private Optional<String> applicationVersion() {
return Optional.ofNullable(getClass().getPackage().getImplementationVersion());
}
private void compareVersions(final Map<String, String> latestVersions) {
final String latestVersion;
if (SystemUtils.IS_OS_MAC_OSX) {
@@ -140,7 +136,7 @@ public class WelcomeController extends LocalizedFXMLViewController {
// no version check possible on unsupported OS
return;
}
final String currentVersion = applicationVersion().orElse(null);
final String currentVersion = ApplicationVersion.orElse(null);
LOG.debug("Current version: {}, lastest version: {}", currentVersion, latestVersion);
if (currentVersion != null && semVerComparator.compare(currentVersion, latestVersion) < 0) {
final String msg = String.format(localization.getString("welcome.newVersionMessage"), latestVersion, currentVersion);

View File

@@ -41,6 +41,7 @@ public abstract class UpgradeStrategy {
* Upgrades a vault. Might take a moment, should be run in a background thread.
*/
public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException {
LOG.info("Upgrading {} from {} to {}.", vault.path().getValue(), vaultVersionBeforeUpgrade, vaultVersionAfterUpgrade);
Cryptor cryptor = null;
try {
final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME);
@@ -49,12 +50,14 @@ public abstract class UpgradeStrategy {
// create backup, as soon as we know the password was correct:
final Path masterkeyBackupFile = vault.path().getValue().resolve(Constants.MASTERKEY_BACKUP_FILENAME);
Files.copy(masterkeyFile, masterkeyBackupFile, StandardCopyOption.REPLACE_EXISTING);
LOG.info("Backuped masterkey.");
// do stuff:
upgrade(vault, cryptor);
// write updated masterkey file:
final byte[] upgradedMasterkeyFileContents = cryptor.writeKeysToMasterkeyFile(passphrase, vaultVersionAfterUpgrade).serialize();
final Path masterkeyFileAfterUpgrade = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); // path may have changed
Files.write(masterkeyFileAfterUpgrade, upgradedMasterkeyFileContents, StandardOpenOption.TRUNCATE_EXISTING);
LOG.info("Updated masterkey.");
} catch (InvalidPassphraseException e) {
throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword"));
} catch (UnsupportedVaultFormatException e) {

View File

@@ -57,6 +57,8 @@ class UpgradeVersion4to5 extends UpgradeStrategy {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (BASE32_PATTERN.matcher(file.getFileName().toString()).find() && attrs.size() > cryptor.fileHeaderCryptor().headerSize()) {
migrate(file, attrs, cryptor);
} else {
LOG.info("Skipping irrelevant file {}.", file);
}
return FileVisitResult.CONTINUE;
}
@@ -70,18 +72,20 @@ class UpgradeVersion4to5 extends UpgradeStrategy {
}
private void migrate(Path file, BasicFileAttributes attrs, Cryptor cryptor) throws IOException {
LOG.info("Starting migration of {}...", file);
try (FileChannel ch = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
// read header:
ByteBuffer headerBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize());
ch.read(headerBuf);
headerBuf.flip();
LOG.info("\tHeader read");
FileHeader header = cryptor.fileHeaderCryptor().decryptHeader(headerBuf);
long cleartextSize = header.getFilesize();
if (cleartextSize < 0) {
LOG.info("Skipping already migrated file {}.", file);
LOG.info("\tSkipping already migrated file");
return;
} else if (cleartextSize > attrs.size()) {
LOG.warn("Skipping file {} with invalid file size {}/{}", file, cleartextSize, attrs.size());
LOG.warn("\tSkipping file with invalid file size {}/{}", cleartextSize, attrs.size());
return;
}
int headerSize = cryptor.fileHeaderCryptor().headerSize();
@@ -93,12 +97,13 @@ class UpgradeVersion4to5 extends UpgradeStrategy {
long newAdditionalCiphertextBytes = newCiphertextSize % ciphertextChunkSize;
if (newAdditionalCiphertextBytes == 0) {
// (new) last block is already correct. just truncate:
LOG.info("Migrating {} of cleartext size {}: Truncating to new ciphertext size: {}", file, cleartextSize, newEOF);
LOG.info("\tMigrating cleartext size {}: Truncating to new ciphertext size: {}", cleartextSize, newEOF);
ch.truncate(newEOF);
LOG.info("\tFile truncated");
} else {
// last block may contain padding and needs to be re-encrypted:
long lastChunkIdx = newFullChunks;
LOG.info("Migrating {} of cleartext size {}: Re-encrypting chunk {}. New ciphertext size: {}", file, cleartextSize, lastChunkIdx, newEOF);
LOG.info("\tMigrating cleartext size {}: Re-encrypting chunk {}. New ciphertext size: {}", cleartextSize, lastChunkIdx, newEOF);
long beginOfLastChunk = headerSize + lastChunkIdx * ciphertextChunkSize;
assert beginOfLastChunk < newEOF;
int lastCleartextChunkLength = (int) (cleartextSize % cleartextChunkSize);
@@ -116,15 +121,18 @@ class UpgradeVersion4to5 extends UpgradeStrategy {
ch.truncate(beginOfLastChunk);
ch.write(newLastChunkCiphertext);
} else {
LOG.error("Reached EOF at position {}/{}", beginOfLastChunk, newEOF);
LOG.error("\tReached EOF at position {}/{}", beginOfLastChunk, newEOF);
return; // must exit method before changing header!
}
LOG.info("\tReencrypted last block");
}
header.setFilesize(-1l);
ByteBuffer newHeaderBuf = cryptor.fileHeaderCryptor().encryptHeader(header);
ch.position(0);
ch.write(newHeaderBuf);
LOG.info("\tUpdated header");
}
LOG.info("Finished migration of {}.", file);
}
}

View File

@@ -50,6 +50,8 @@ import org.cryptomator.ui.util.DeferredClosable;
import org.cryptomator.ui.util.DeferredCloser;
import org.cryptomator.ui.util.FXThreads;
import org.fxmisc.easybind.EasyBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
@@ -65,6 +67,8 @@ import javafx.collections.ObservableList;
public class Vault implements CryptoFileSystemDelegate {
private static final Logger LOG = LoggerFactory.getLogger(CryptoFileSystemDelegate.class);
public static final String VAULT_FILE_EXTENSION = ".cryptomator";
private final ObjectProperty<Path> path;
@@ -72,6 +76,7 @@ public class Vault implements CryptoFileSystemDelegate {
private final CryptoFileSystemFactory cryptoFileSystemFactory;
private final DeferredCloser closer;
private final BooleanProperty unlocked = new SimpleBooleanProperty();
private final BooleanProperty mounted = new SimpleBooleanProperty();
private final ObservableList<String> namesOfResourcesWithInvalidMac = FXThreads.observableListOnMainThread(FXCollections.observableArrayList());
private final Set<String> whitelistedResourcesWithInvalidMac = new HashSet<>();
private final AtomicReference<FileSystem> nioFileSystem = new AtomicReference<>();
@@ -131,7 +136,8 @@ public class Vault implements CryptoFileSystemDelegate {
}
public synchronized void activateFrontend(FrontendFactory frontendFactory, Settings settings, CharSequence passphrase) throws FrontendCreationFailedException {
boolean success = false;
boolean launchSuccess = false;
boolean mountSuccess = false;
try {
FileSystem fs = getNioFileSystem();
FileSystem shorteningFs = shorteningFileSystemFactory.get(fs);
@@ -140,22 +146,32 @@ public class Vault implements CryptoFileSystemDelegate {
StatsFileSystem statsFs = new StatsFileSystem(normalizingFs);
statsFileSystem = Optional.of(statsFs);
Frontend frontend = frontendFactory.create(statsFs, FrontendId.from(id), stripStart(mountName, "/"));
launchSuccess = true;
filesystemFrontend = closer.closeLater(frontend);
frontend.mount(getMountParams(settings));
success = true;
} catch (UncheckedIOException | CommandFailedException e) {
mountSuccess = true;
} catch (UncheckedIOException e) {
throw new FrontendCreationFailedException(e);
} catch (CommandFailedException e) {
LOG.error("Failed to mount vault " + mountName, e);
} finally {
// unlocked is a observable property and should only be changed by the FX application thread
final boolean finalSuccess = success;
Platform.runLater(() -> unlocked.set(finalSuccess));
boolean finalLaunchSuccess = launchSuccess;
boolean finalMountSuccess = mountSuccess;
Platform.runLater(() -> {
unlocked.set(finalLaunchSuccess);
mounted.set(finalMountSuccess);
});
}
}
public synchronized void deactivateFrontend() throws Exception {
filesystemFrontend.close();
statsFileSystem = Optional.empty();
Platform.runLater(() -> unlocked.set(false));
Platform.runLater(() -> {
mounted.set(false);
unlocked.set(false);
});
}
private Map<MountParam, Optional<String>> getMountParams(Settings settings) {
@@ -239,10 +255,18 @@ public class Vault implements CryptoFileSystemDelegate {
return unlocked;
}
public BooleanProperty mountedProperty() {
return mounted;
}
public boolean isUnlocked() {
return unlocked.get();
}
public boolean isMounted() {
return mounted.get();
}
public ObservableList<String> getNamesOfResourcesWithInvalidMac() {
return namesOfResourcesWithInvalidMac;
}

View File

@@ -18,6 +18,7 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,31 +29,50 @@ public class Localization extends ResourceBundle {
private static final String LOCALIZATION_DEFAULT_FILE = "/localization/en.txt";
private static final String LOCALIZATION_FILENAME_FMT = "/localization/%s.txt";
private static final String LOCALIZATION_FILE = String.format(LOCALIZATION_FILENAME_FMT, Locale.getDefault().getLanguage());
private final ResourceBundle fallback;
private final ResourceBundle localized;
@Inject
public Localization() {
try (InputStream in = getClass().getResourceAsStream(LOCALIZATION_DEFAULT_FILE)) {
Objects.requireNonNull(in);
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
this.fallback = new PropertyResourceBundle(reader);
LOG.info("Loaded localization from bundle:{}", LOCALIZATION_FILE);
try {
this.fallback = Objects.requireNonNull(loadLocalizationFile(LOCALIZATION_DEFAULT_FILE));
LOG.debug("Loaded localization default file: {}", LOCALIZATION_DEFAULT_FILE);
String language = Locale.getDefault().getLanguage();
String region = Locale.getDefault().getCountry();
LOG.info("Detected language \"{}\" and region \"{}\"", language, region);
ResourceBundle localizationBundle = null;
if (StringUtils.isNotEmpty(language) && StringUtils.isNotEmpty(region)) {
String file = String.format(LOCALIZATION_FILENAME_FMT, language + "_" + region);
LOG.info("Attempting to load localization from: {}", file);
localizationBundle = loadLocalizationFile(file);
}
if (StringUtils.isNotEmpty(language) && localizationBundle == null) {
String file = String.format(LOCALIZATION_FILENAME_FMT, language);
LOG.info("Attempting to load localization from: {}", file);
localizationBundle = loadLocalizationFile(file);
}
if (localizationBundle == null) {
LOG.info("No localization found. Falling back to default language.");
localizationBundle = this.fallback;
}
this.localized = Objects.requireNonNull(localizationBundle);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
try (InputStream in = getClass().getResourceAsStream(LOCALIZATION_FILE)) {
// returns null if no resource for given path
private ResourceBundle loadLocalizationFile(String resourcePath) throws IOException {
try (InputStream in = getClass().getResourceAsStream(resourcePath)) {
if (in != null) {
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
this.localized = new PropertyResourceBundle(reader);
return new PropertyResourceBundle(reader);
} else {
this.localized = this.fallback;
return null;
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

View File

@@ -28,6 +28,7 @@ public class Settings implements Serializable {
public static final boolean DEFAULT_USE_IPV6 = false;
public static final Integer DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
public static final String DEFAULT_GVFS_SCHEME = "dav";
public static final boolean DEFAULT_DEBUG_MODE = false;
private final Consumer<Settings> saveCmd;
@@ -49,6 +50,9 @@ public class Settings implements Serializable {
@JsonProperty("preferredGvfsScheme")
private String preferredGvfsScheme;
@JsonProperty("debugMode")
private Boolean debugMode;
/**
* Package-private constructor; use {@link SettingsProvider}.
*/
@@ -125,4 +129,12 @@ public class Settings implements Serializable {
this.preferredGvfsScheme = preferredGvfsScheme;
}
public boolean getDebugMode() {
return debugMode == null ? DEFAULT_DEBUG_MODE : debugMode;
}
public void setDebugMode(boolean debugMode) {
this.debugMode = debugMode;
}
}

View File

@@ -0,0 +1,17 @@
package org.cryptomator.ui.util;
import java.util.Optional;
import org.cryptomator.ui.Cryptomator;
public class ApplicationVersion {
public static String orElse(String other) {
return get().orElse(other);
}
public static Optional<String> get() {
return Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion());
}
}

View File

@@ -85,7 +85,7 @@ public class SingleInstanceManager {
return true;
}
return !buf.hasRemaining();
} , timeout, 10);
}, timeout, 10);
return !buf.hasRemaining();
}
@@ -117,13 +117,14 @@ public class SingleInstanceManager {
final String applicationKey;
final ServerSocketChannel channel;
final Selector selector;
int port = 0;
final int port;
public LocalInstance(String applicationKey, ServerSocketChannel channel, Selector selector) {
public LocalInstance(String applicationKey, ServerSocketChannel channel, Selector selector, int port) {
Objects.requireNonNull(applicationKey);
this.applicationKey = applicationKey;
this.channel = channel;
this.selector = selector;
this.port = port;
}
/**
@@ -317,28 +318,27 @@ public class SingleInstanceManager {
*/
public static LocalInstance startLocalInstance(String applicationKey, ExecutorService exec) throws IOException {
final ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
boolean success = false;
try {
channel.configureBlocking(false);
channel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
final int port = ((InetSocketAddress) channel.getLocalAddress()).getPort();
Preferences.userNodeForPackage(Cryptomator.class).putInt(applicationKey, port);
LOG.debug("InstanceManager bound to port {}", port);
final int port = ((InetSocketAddress) channel.getLocalAddress()).getPort();
Preferences.userNodeForPackage(Cryptomator.class).putInt(applicationKey, port);
LOG.debug("InstanceManager bound to port {}", port);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
LocalInstance instance = new LocalInstance(applicationKey, channel, selector);
exec.submit(() -> {
try {
instance.port = ((InetSocketAddress) channel.getLocalAddress()).getPort();
} catch (IOException e) {
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
LocalInstance instance = new LocalInstance(applicationKey, channel, selector, port);
exec.submit(instance::selectionLoop);
success = true;
return instance;
} finally {
if (!success) {
channel.close();
}
instance.selectionLoop();
});
return instance;
}
}
/**
@@ -368,7 +368,7 @@ public class SingleInstanceManager {
}
}
return !buf.hasRemaining();
} , timeout, 1);
}, timeout, 1);
}
}
}

View File

@@ -46,6 +46,10 @@
<Label GridPane.rowIndex="3" GridPane.columnIndex="0" fx:id="prefGvfsSchemeLabel" text="%settings.prefGvfsScheme.label" cacheShape="true" cache="true" />
<ChoiceBox GridPane.rowIndex="3" GridPane.columnIndex="1" fx:id="prefGvfsScheme" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
<!-- Row 4 -->
<Label GridPane.rowIndex="4" GridPane.columnIndex="0" fx:id="debugModeLabel" text="%settings.debugMode.label" cacheShape="true" cache="true" />
<CheckBox GridPane.rowIndex="4" GridPane.columnIndex="1" fx:id="debugModeCheckbox" cacheShape="true" cache="true" />
</children>
</GridPane>
<Label VBox.vgrow="NEVER" text="%settings.requiresRestartLabel" alignment="CENTER" cacheShape="true" cache="true" />

View File

@@ -69,7 +69,7 @@
<!-- Row 3.1 -->
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%unlock.label.savePassword" cacheShape="true" cache="true" />
<CheckBox GridPane.rowIndex="1" GridPane.columnIndex="1" fx:id="savePassword" cacheShape="true" cache="true" />
<CheckBox GridPane.rowIndex="1" GridPane.columnIndex="1" fx:id="savePassword" onAction="#didClickSavePasswordCheckbox" cacheShape="true" cache="true" />
<!-- Row 3.2 -->
<Label GridPane.rowIndex="2" GridPane.columnIndex="0" text="%unlock.label.mountName" cacheShape="true" cache="true" />

View File

@@ -28,7 +28,7 @@
<fx:define>
<ContextMenu fx:id="moreOptionsMenu">
<items>
<MenuItem text="%unlocked.moreOptions.reveal" onAction="#didClickRevealVault">
<MenuItem fx:id="revealVaultMenuItem" text="%unlocked.moreOptions.reveal" onAction="#didClickRevealVault">
<graphic><Label text="&#xf133;" styleClass="ionicons"/></graphic>
</MenuItem>
<MenuItem text="%unlocked.moreOptions.copyUrl" onAction="#didClickCopyUrl">

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Alle Cryptomator Versionen
changePassword.button.change = Passwort ändern
changePassword.errorMessage.wrongPassword = Falsches Passwort
changePassword.errorMessage.decryptionFailed = Entschlüsselung fehlgeschlagen
changePassword.infoMessage.success = Passwort geändert
# unlocked.fxml
unlocked.button.lock = Tresor sperren
unlocked.moreOptions.reveal = Laufwerk anzeigen
@@ -88,4 +87,9 @@ settings.prefGvfsScheme.label = WebDAV Schema
upgrade.confirmation.label = Ja, die Synchronisation ist abgeschlossen
initialize.messageLabel.notEmpty = Tresor ist nicht leer
unlock.label.savePassword = Passwort speichern
unlock.errorMessage.unauthenticVersionMac = Versions-MAC konnte nicht authentifiziert werden.
unlock.errorMessage.unauthenticVersionMac = Versions-MAC konnte nicht authentifiziert werden.
unlocked.label.mountFailed = Verbinden des Laufwerks fehlgeschlagen
unlock.savePassword.delete.confirmation.title = Gespeichertes Passwort löschen
unlock.savePassword.delete.confirmation.header = Möchten Sie das gespeicherte Passwort von diesem Tresor wirklich löschen?
unlock.savePassword.delete.confirmation.content = Das gespeicherte Passwort von diesem Tresor wird sofort aus Ihrem System-Schlüsselbund gelöscht. Falls Sie das Passwort erneut speichern möchten, müssen Sie den Tresor entsperren und dabei die "Passwort speichern"-Option aktiviert haben.
settings.debugMode.label = Debug-Modus *

View File

@@ -58,6 +58,9 @@ unlock.label.advancedHeading=Advanced options
unlock.button.unlock=Unlock vault
unlock.button.advancedOptions.show=More options
unlock.button.advancedOptions.hide=Less options
unlock.savePassword.delete.confirmation.title=Delete Saved Password
unlock.savePassword.delete.confirmation.header=Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content=The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
unlock.choicebox.winDriveLetter.auto=Assign automatically
unlock.errorMessage.wrongPassword=Wrong password
unlock.errorMessage.mountingFailed=Mounting failed. See log file for details.
@@ -79,6 +82,7 @@ changePassword.errorMessage.decryptionFailed=Decryption failed
unlocked.button.lock=Lock vault
unlocked.moreOptions.reveal=Reveal drive
unlocked.moreOptions.copyUrl=Copy WebDAV URL
unlocked.label.mountFailed=Connecting drive failed
unlocked.label.revealFailed=Command failed
unlocked.label.unmountFailed=Ejecting drive failed
unlocked.label.statsEncrypted=encrypted
@@ -98,6 +102,7 @@ settings.port.label=WebDAV Port *
settings.port.prompt=0 = Choose automatically
settings.useipv6.label=Use IPv6 literal
settings.prefGvfsScheme.label=WebDAV scheme
settings.debugMode.label=Debug mode *
settings.requiresRestartLabel=* Cryptomator needs to restart
# tray icon

View File

@@ -1,6 +1,6 @@
app.name = Cryptomator
# main.fxml
main.emptyListInstructions = Click aquí para añadir una caja fuerte
main.emptyListInstructions = Clic aquí para añadir una caja fuerte
# should it be imperative?
main.directoryList.contextMenu.remove = Eliminar de la lista
main.directoryList.contextMenu.changePassword = Cambiar la contraseña
@@ -45,7 +45,6 @@ changePassword.label.downloadsPageLink = Todas las versiones de Cryptomator
changePassword.button.change = Cambiar contraseña
changePassword.errorMessage.wrongPassword = Contraseña incorrecta
changePassword.errorMessage.decryptionFailed = Decifración ha fallado
changePassword.infoMessage.success = Contraseña se ha cambiado
# unlocked.fxml
unlocked.button.lock = Encerrar caja fuerte
unlocked.moreOptions.reveal = Mostrar disco
@@ -78,15 +77,21 @@ initialize.messageLabel.passwordStrength.1 = débil
initialize.messageLabel.passwordStrength.2 = suficiente
initialize.messageLabel.passwordStrength.3 = fuerte
initialize.messageLabel.passwordStrength.4 = muy fuerte
initialize.label.doNotForget = IMPORTANTE\: Si olivdes tú contraseña no hay ninguna manera de recuperar tus datos.
initialize.label.doNotForget = IMPORTANTE\: Si olivdes tú contraseña, no hay ninguna manera de recuperar tus datos.
main.directoryList.remove.confirmation.title = Borrar caja fuerte
main.directoryList.remove.confirmation.header = ¿Quieres de verdad borrar este caja fuerte?
main.directoryList.remove.confirmation.content = La caja fuerte solo se borra de la lista. Para eliminarla permanente por favor elimina los datos de tú sistema de archivos.
upgrade.version3to4.msg = Este caja fuerte se debe migrar a un formato más reciente.\nLos nombres de las carpetas cifradas se actualizan.\nPor favor asegurarse de que la sincronización ha terminado antes de seguir.
upgrade.version3to4.err.io = Migración ha fallado por causa de una excepción I/O. Para detalles revisa el archivo de registro.
settings.prefGvfsScheme.label = WebDAV scheme
# or esequema WEBDAV but I think sistema sounds better
settings.prefGvfsScheme.label = sistema WebDAV
# upgrade.fxml
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
upgrade.confirmation.label = Sí, me he asegurado de que la sincronización ha terminado
initialize.messageLabel.notEmpty = Caja fuerte no está vacio
unlock.label.savePassword = Contraseña segura
unlock.errorMessage.unauthenticVersionMac = No se pudo autentificar la version de MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -15,7 +15,7 @@ initialize.button.ok = Créer le coffre
initialize.messageLabel.alreadyInitialized = Coffre déjà initialisé
initialize.messageLabel.initializationFailed = Impossible d'initialiser le coffre. Voir le fichier de log pour plus de détails.
# notfound.fxml
notfound.label = Coffre introuvable. A t'il été déplacé?
notfound.label = Coffre introuvable. A-t-il été déplacé?
# upgrade.fxml
upgrade.button = Mettre à niveau
upgrade.version3dropBundleExtension.msg = Ce coffre doit être converti dans un format plus récent.\n"%1$s" sera renommé en "%2$s".\nAssurez-vous que la synchronisation est terminée avant de continuer.
@@ -44,7 +44,6 @@ changePassword.button.change = Modification du mot de masse
changePassword.errorMessage.wrongPassword = Mot de passe incorrect
# En français, on dit déchiffrement lorsque la clé est connue
changePassword.errorMessage.decryptionFailed = Echec du déchiffrement
changePassword.infoMessage.success = Mot de passe modifié
# unlocked.fxml
unlocked.button.lock = Verrouiller le coffre
unlocked.moreOptions.reveal = Voir le lecteur
@@ -58,7 +57,7 @@ unlocked.label.statsDecrypted = déchiffré
unlocked.ioGraph.yAxis.label = Débit (MiB/s)
# mac_warnings.fxml
macWarnings.windowTitle = Attention - Fichier corrompu dans %s
macWarnings.message = Cryptomator a détecté des corruptions de données dans les fichiers suivants\:
macWarnings.message = Cryptomator a détecté des corruptions de données dans les fichiers suivants \:
macWarnings.moreInformationButton = En savoir plus
macWarnings.whitelistButton = Déchiffrer tout de même
# settings.fxml
@@ -82,12 +81,17 @@ initialize.messageLabel.passwordStrength.4 = Très fort
initialize.label.doNotForget = ATTENTION \: Si vous oubliez votre mot de passe, il n'y aura aucun moyen de récupérer vos données.
main.directoryList.remove.confirmation.title = Retirer un coffre
main.directoryList.remove.confirmation.header = Voulez-vous vraiment retirer ce coffre ?
main.directoryList.remove.confirmation.content = Le coffre sera simplement retiré de la liste. Pour le supprimer complètement, supprimez les fichiers depuis votre système de fichiers.
main.directoryList.remove.confirmation.content = Le coffre sera seulement retiré de la liste. Pour le supprimer complètement, supprimez les fichiers depuis votre système de fichiers.
upgrade.version3to4.msg = Ce coffre doit être converti dans un nouveau format. Les noms de dossiers chiffrés seront mis à jour.\nMerci de vous assurer que la procédure de synchronisation est terminée avant de continuer.
upgrade.version3to4.err.io = La migration a échoué à cause d'une erreur d'entrée/sortie. Référez-vous au fichier log pour plus de détails.
settings.prefGvfsScheme.label = Schéma d'URI WebDAV
# upgrade.fxml
upgrade.confirmation.label = Oui, je suis certain que la synchronisation est finie
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
upgrade.confirmation.label = Oui, je suis certain que la synchronisation est terminée
initialize.messageLabel.notEmpty = Le coffre n'est pas vide
unlock.label.savePassword = Se souvenir du mot de passe
unlock.errorMessage.unauthenticVersionMac = Impossible d'authentifier la version MAC
unlocked.label.mountFailed = Echec de connexion au lecteur
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Összes Cryptomator verzió
changePassword.button.change = Jelszó megváltoztatása
changePassword.errorMessage.wrongPassword = Hibás jelszó
changePassword.errorMessage.decryptionFailed = A titkosítás feloldása meghíusúlt
changePassword.infoMessage.success = Jelszó megváltoztatva
# unlocked.fxml
unlocked.button.lock = Széf lezárása
unlocked.moreOptions.reveal = Meghajtó felfedése
@@ -87,4 +86,9 @@ settings.prefGvfsScheme.label = WebDAV séma
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Tutte le versioni di Cryptomator
changePassword.button.change = Cambia la password
changePassword.errorMessage.wrongPassword = Password errata
changePassword.errorMessage.decryptionFailed = Decriptaggio fallito
changePassword.infoMessage.success = Password cambiata
# unlocked.fxml
unlocked.button.lock = Blocca vault
unlocked.moreOptions.reveal = Apri il disco
@@ -87,4 +86,9 @@ settings.prefGvfsScheme.label = WebDAV scheme
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = 모든 Cryptomator 버전
changePassword.button.change = 비밀번호 변경
changePassword.errorMessage.wrongPassword = 틀린 비밀번호
changePassword.errorMessage.decryptionFailed = 복호화 실패
changePassword.infoMessage.success = 비밀번호 변경
# unlocked.fxml
unlocked.button.lock = 보관함 잠그기
unlocked.moreOptions.reveal = 드라이브 표시
@@ -85,6 +84,11 @@ upgrade.version3to4.err.io = 입출력 예외 문제로 마이그레이션이
settings.prefGvfsScheme.label = WebDAV sceme
# upgrade.fxml
upgrade.confirmation.label = 네. 동기화가 완료되었음을 확인하였습니다.
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
initialize.messageLabel.notEmpty = 보관함이 비어있지 않음
unlock.label.savePassword = 비밀번호 저장
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Visas Cryptomator versijas
changePassword.button.change = Mainīt paroli
changePassword.errorMessage.wrongPassword = Nepareiza parole
changePassword.errorMessage.decryptionFailed = Atšifrēšana neizdevās
changePassword.infoMessage.success = Parole nomainīta
# unlocked.fxml
unlocked.button.lock = Aizslēgt glabātuvi
unlocked.moreOptions.reveal = Atklāt disku
@@ -88,4 +87,9 @@ settings.prefGvfsScheme.label = WebDAV shēma
upgrade.confirmation.label = Jā, esmu pārliecinājies, ka sinhronizācija ir pabeigta.
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -3,10 +3,10 @@ app.name = Cryptomator
main.emptyListInstructions = Klik hier om een kluis toe te voegen
main.directoryList.contextMenu.remove = Verwijder van lijst
main.directoryList.contextMenu.changePassword = Verander wachtwoord
main.addDirectory.contextMenu.new = Creeer nieuwe kluis
main.addDirectory.contextMenu.new = Creëer nieuwe kluis
main.addDirectory.contextMenu.open = Open bestaande kluis
# welcome.fxml
welcome.checkForUpdates.label.currentlyChecking = Controleren op Updates...
welcome.checkForUpdates.label.currentlyChecking = Controleren op updates...
welcome.newVersionMessage = Versie %1$s kan worden gedownload.\nDit is %2$s.
# initialize.fxml
initialize.label.password = Wachtwoord
@@ -32,8 +32,8 @@ unlock.button.advancedOptions.hide = Minder opties
unlock.choicebox.winDriveLetter.auto = Automatisch toekennen
unlock.errorMessage.wrongPassword = Verkeerd wachtwoord
unlock.errorMessage.mountingFailed = Mounten mislukt. Zie logbestand voor details.
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Niet ondersteunde kluis. Deze kluis is gecreëerd met een oudere versie van Cryptomator.
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Niet ondersteunde kluis. Deze kluis is gecreëerd met een nieuwere versie van Cryptomator.
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Kluis ontoegankelijk. Deze kluis is gecreëerd met een oudere versie van Cryptomator.
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Kluis ontoegankelijk. Deze kluis is gecreëerd met een nieuwere versie van Cryptomator.
unlock.messageLabel.startServerFailed = WebDAV server starten mislukt.
# change_password.fxml
changePassword.label.oldPassword = Huidig wachtwoord
@@ -43,12 +43,11 @@ changePassword.label.downloadsPageLink = Alle Cryptomator versies
changePassword.button.change = Verander wachtwoord
changePassword.errorMessage.wrongPassword = Alle Cryptomator versies
changePassword.errorMessage.decryptionFailed = Decoderen mislukt
changePassword.infoMessage.success = Wachtwoord verandert
# unlocked.fxml
unlocked.button.lock = Vergrendel kluis
unlocked.moreOptions.reveal = Maak schijf zichtbaar
unlocked.moreOptions.copyUrl = Kopieer WebDAV URL
unlocked.label.revealFailed = Commando mislukt
unlocked.label.revealFailed = Opdracht mislukt
unlocked.label.unmountFailed = Uitwerpen schijf mislukt
unlocked.label.statsEncrypted = versleuteld
unlocked.label.statsDecrypted = gedecodeerd
@@ -57,7 +56,7 @@ unlocked.ioGraph.yAxis.label = Doorvoer (MiB/s)
macWarnings.windowTitle = Pas op - Corrupt bestand in %s
macWarnings.message = Cryptomator heeft mogelijk kwaadwillende corrupte items aangetroffen in de volgende bestanden\:
macWarnings.moreInformationButton = Leer meer
macWarnings.whitelistButton = Doorgaan met decoderen van selectie
macWarnings.whitelistButton = Desondanks selectie decoderen
# settings.fxml
settings.version.label = Versie %s
settings.checkForUpdates.label = Controleer op updates
@@ -81,10 +80,15 @@ main.directoryList.remove.confirmation.title = Verwijder Kluis
main.directoryList.remove.confirmation.header = Weet je zeker dat je deze kluis wilt verwijderen?
main.directoryList.remove.confirmation.content = De kluis zal alleen van de lijst worden verwijdert. Verwijder de bestanden van het bestandssysteem voor permanente verwijdering.
upgrade.version3to4.msg = Deze kluis dient gemigreerd te worden naar een nieuwer type. \nVersleutelde mapnamen zullen worden geüpdatet. \nZorg ervoor dat de synchronisatie voltooid is alvorens door te gaan.
upgrade.version3to4.err.io = Migratie mislukt door een I/O Exception. Zie logbestand voor details.
settings.prefGvfsScheme.label = WebDAV scheme
upgrade.version3to4.err.io = I/O Exception\: migratie mislukt. Zie logbestand voor details.
settings.prefGvfsScheme.label = WebDAV schema
# upgrade.fxml
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
upgrade.confirmation.label = Ja, ik heb geverifieerd dat de synchronisatie voltooid is
initialize.messageLabel.notEmpty = Kluis niet leeg
unlock.label.savePassword = Wachtwoord bewaren
unlock.errorMessage.unauthenticVersionMac = MAC authenticatie mislukt
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Wszystkie wersje Cryptomatora
changePassword.button.change = Zmień hasło
changePassword.errorMessage.wrongPassword = Złe hasło
changePassword.errorMessage.decryptionFailed = Błąd deszyfracji
changePassword.infoMessage.success = Hasło zmienione
# unlocked.fxml
unlocked.button.lock = Zablokuj kryptę
unlocked.moreOptions.reveal = Zwolnij napęd
@@ -85,6 +84,11 @@ upgrade.version3to4.err.io = Błąd migracji I/O Exception. Sprawdź logi
settings.prefGvfsScheme.label = Schemat WebDAV
# upgrade.fxml
upgrade.confirmation.label = Tak, jestem pewien, że zakończyłem synchronizacje
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
initialize.messageLabel.notEmpty = Krypta pusta
unlock.label.savePassword = Zapisz hasło
unlock.errorMessage.unauthenticVersionMac = Nie udało się uwierzytelnić wersji MAC
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -1,24 +1,24 @@
app.name = Cryptomator
# main.fxml
main.emptyListInstructions = Clique aqui para adicionar uma caixa-forte
main.emptyListInstructions = Clique aqui para adicionar um cofre
main.directoryList.contextMenu.remove = Remover da lista
main.directoryList.contextMenu.changePassword = Alterar senha
main.addDirectory.contextMenu.new = Criar nova caixa-forte
main.addDirectory.contextMenu.open = Abrir caixa-forte existente
main.addDirectory.contextMenu.new = Criar um novo cofre
main.addDirectory.contextMenu.open = Abrir um cofre já existente
# welcome.fxml
welcome.checkForUpdates.label.currentlyChecking = Buscando por atualizações...
welcome.newVersionMessage = Versão %1$s pode ser abaixada. Esta é a versão %2$s.
welcome.newVersionMessage = Versão %1$s pode ser baixada. Esta é a versão %2$s.
# initialize.fxml
initialize.label.password = Senha
initialize.label.retypePassword = Redigitar senha
initialize.button.ok = Criar caixa-forte
initialize.messageLabel.alreadyInitialized = Caixa-forte já inicializada
initialize.messageLabel.initializationFailed = Não pôde inicializar a caixa-forte. Ver arquivo de log para mais detalhes.
initialize.label.retypePassword = Redigite a senha
initialize.button.ok = Criar cofre
initialize.messageLabel.alreadyInitialized = Cofre já inicializado
initialize.messageLabel.initializationFailed = Não pôde inicializar o cofre. Veja o arquivo de log para mais detalhes.
# notfound.fxml
notfound.label = A caixa-forte não pode ser encontrada. Ela foi movida?
notfound.label = O cofre não pode ser encontrado. Pode ter sido movido?
# upgrade.fxml
upgrade.button = Atualizar caixa-forte
upgrade.version3dropBundleExtension.msg = Esta caixa-forte tem que ser a migrada a um novo formato. "%1$s" será renomeada para "%2$s". Por favor assegure-se de que a sincronização foi finalizada antes de proceder com a migração.
upgrade.button = Atualizar cofre
upgrade.version3dropBundleExtension.msg = Esse cofre tem que ser migrado paraa um novo formato. "%1$s" será renomeada para "%2$s". Por favor assegure-se de que a sincronização foi finalizada antes de proceder com a migração.
upgrade.version3dropBundleExtension.err.alreadyExists = A migração automática falhou. "%s" já existe.
# unlock.fxml
unlock.label.password = Senha
@@ -26,45 +26,48 @@ unlock.label.mountName = Nome do drive
unlock.label.winDriveLetter = Letra do drive
unlock.label.downloadsPageLink = Todas as versões do Cryptomator
unlock.label.advancedHeading = Opções avançadas
unlock.button.unlock = Abrir caixa-forte
unlock.button.unlock = Abrir cofre
unlock.button.advancedOptions.show = Mais opções
unlock.button.advancedOptions.hide = Menos opções
unlock.choicebox.winDriveLetter.auto = Atribuir automaticamente
unlock.errorMessage.wrongPassword = Senha errada
unlock.errorMessage.mountingFailed = Falha ao montar. Ver arquivo de log para mais detalhes.
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Caixa-forte não suportada. Esta caixa-forte foi criada por uma versão antiga do Cryptomator.
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Caixa-forte não suportada. Esta caixa-forte foi criada por uma versão mais nova do Cryptomator.
unlock.errorMessage.mountingFailed = Falha ao montar. Veja o arquivo de log para mais detalhes.
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Cofre não suportado. Esse cofre foi criado por uma versão antiga do Cryptomator.
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Cofre não suportado. Esse cofre foi criado por uma versão mais nova do Cryptomator.
unlock.messageLabel.startServerFailed = Falha ao iniciar servidor WebDAV.
# change_password.fxml
changePassword.label.oldPassword = Senha anterior
changePassword.label.oldPassword = Senha atual
changePassword.label.newPassword = Nova senha
changePassword.label.retypePassword = Re-digitar senha
changePassword.label.downloadsPageLink = Todas as versões do Cryptomator
changePassword.button.change = Alterar senha
changePassword.errorMessage.wrongPassword = Senha incorreta
changePassword.errorMessage.decryptionFailed = Falha ao desencriptar
changePassword.infoMessage.success = Senha alterada
# unlocked.fxml
unlocked.button.lock = Fechar caixa-forte
unlocked.button.lock = Fechar cofre
unlocked.moreOptions.reveal = Mostrar drive
unlocked.moreOptions.copyUrl = Copiar URL WebDAV
unlocked.label.revealFailed = Falha ao mostrar drive
unlocked.label.unmountFailed = Falha ao ejetar drive
unlocked.label.statsEncrypted = encriptado
unlocked.label.statsDecrypted = desencriptado
unlocked.label.statsEncrypted = Encriptado
unlocked.label.statsDecrypted = Desencriptado
unlocked.ioGraph.yAxis.label = Taxa de transferência (MiB/s)
# mac_warnings.fxml
macWarnings.windowTitle = Perigo - Arquivo corrompido na %s
# Fuzzy
macWarnings.message = Cryptomator detectou potenciais corrupções maliciosas nos seguintes arquivos\:
macWarnings.moreInformationButton = Saiba mais
# Fuzzy
macWarnings.whitelistButton = Desencriptar selecionado de qualquer modo
# settings.fxml
settings.version.label = Versão %s
settings.checkForUpdates.label = Verificar por atualizações
settings.port.label = Port WebDAV *
# Fuzzy
settings.port.label = Porta WebDAV *
settings.port.prompt = 0 \= Escolher automaticamente
# Fuzzy
settings.useipv6.label = Usar IPv6 literal
settings.requiresRestartLabel = * Cryptomator necessita ser reiniciado
settings.requiresRestartLabel = * Cryptomator precisa ser reiniciado
# tray icon
tray.menu.open = Abrir
tray.menu.quit = Sair
@@ -77,14 +80,21 @@ initialize.messageLabel.passwordStrength.2 = Razoável
initialize.messageLabel.passwordStrength.3 = Forte
initialize.messageLabel.passwordStrength.4 = Muito forte
initialize.label.doNotForget = IMPORTANTE\: se você esquecer a sua senha, não haverá como recuperar os seus dados.
main.directoryList.remove.confirmation.title = Remover caixa-forte
main.directoryList.remove.confirmation.header = Você realmente quer remover esta caixa-forte?
main.directoryList.remove.confirmation.content = A caixa-forte somente será removida da lista. Para apagá-la permanentemente, por favor apagar os arquivos do seu sistema de arquivos.
upgrade.version3to4.msg = Esta caixa-forte tem que ser migrada a um novo formato. Os nomes das pastas encriptadas serão atualizados. Por favor assegure-se de que a sincronização foi finalizada antes de proceder com a migração.
upgrade.version3to4.err.io = Falha na migração devido a um erro de E/S. Ver arquivo de log para mais detalhes.
settings.prefGvfsScheme.label = WebDAV scheme
main.directoryList.remove.confirmation.title = Remover cofre
main.directoryList.remove.confirmation.header = Você realmente quer remover esse cofre?
main.directoryList.remove.confirmation.content = O cofre somente será removido da lista. Para apagá-lo permanentemente, por favor apagar os arquivos do seu sistema de arquivos.
upgrade.version3to4.msg = Esse cofre tem que ser migrado a um novo formato. Os nomes das pastas encriptadas serão atualizados. Por favor assegure-se de que a sincronização foi finalizada antes de proceder com a migração.
upgrade.version3to4.err.io = Falha na migração devido a um erro de E/S. Veja o arquivo de log para mais detalhes.
# Fuzzy
settings.prefGvfsScheme.label = Esquema WebDAV
# upgrade.fxml
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
upgrade.confirmation.label = Sim, tenho certeza de que a sincronização foi concluída
initialize.messageLabel.notEmpty = Cofre não vazio
unlock.label.savePassword = Salvar senha
# Fuzzy
unlock.errorMessage.unauthenticVersionMac = Não foi possível autenticar a versão MAC
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -44,7 +44,6 @@ changePassword.label.downloadsPageLink = Все версии Cryptomator
changePassword.button.change = Сменить пароль
changePassword.errorMessage.wrongPassword = Неверный пароль
changePassword.errorMessage.decryptionFailed = Ошибка дешифрования
changePassword.infoMessage.success = Пароль изменён
# unlocked.fxml
unlocked.button.lock = Заблокировать хранилище
# Does it mean "open" drive?
@@ -87,6 +86,11 @@ upgrade.version3to4.err.io = Преобразование не выполнен
settings.prefGvfsScheme.label = Схема WebDAV
# upgrade.fxml
upgrade.confirmation.label = Да, синхронизация точно завершена
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
initialize.messageLabel.notEmpty = Хранилище не пусто
unlock.label.savePassword = Сохранить пароль
unlock.errorMessage.unauthenticVersionMac = Не удалось идентифицировать версию MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -46,7 +46,6 @@ changePassword.label.downloadsPageLink = Všetky verzie Cryptomatoru.
changePassword.button.change = Zmeniť heslo
changePassword.errorMessage.wrongPassword = Nesprávne heslo
changePassword.errorMessage.decryptionFailed = Dešifrovanie zlyhalo.
changePassword.infoMessage.success = Heslo zmenené
# unlocked.fxml
unlocked.button.lock = Zamknúť trezor
unlocked.moreOptions.reveal = Odhaliť jednotku
@@ -90,4 +89,9 @@ settings.prefGvfsScheme.label = WebDAV scheme
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Tüm Cryptomator sürümleri
changePassword.button.change = Şifreyi değiştir
changePassword.errorMessage.wrongPassword = Yanlış şifre
changePassword.errorMessage.decryptionFailed = Şifre çözme başarısız
changePassword.infoMessage.success = Şifre değiştirildi.
# unlocked.fxml
unlocked.button.lock = Kasayı kilitle
unlocked.moreOptions.reveal = Sürücüyü göster
@@ -87,4 +86,9 @@ settings.prefGvfsScheme.label = WebDAV scheme
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -43,7 +43,6 @@ changePassword.label.downloadsPageLink = Всі версії Cryptomator
changePassword.button.change = Змінити пароль
changePassword.errorMessage.wrongPassword = Пароль невірний
changePassword.errorMessage.decryptionFailed = Розшифрування невдале
changePassword.infoMessage.success = Пароль змінений
# unlocked.fxml
unlocked.button.lock = Заблокувати сховище
unlocked.moreOptions.reveal = Відкрити накопичувач
@@ -87,4 +86,9 @@ settings.prefGvfsScheme.label = WebDAV scheme
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
initialize.messageLabel.notEmpty = Vault not empty
unlock.label.savePassword = Save password
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -0,0 +1,96 @@
app.name = Cryptomator
# main.fxml
main.emptyListInstructions = 单击此处添加保管库
main.directoryList.contextMenu.remove = 从列表中删除
main.directoryList.contextMenu.changePassword = 更改密码
main.addDirectory.contextMenu.new = 创建新保管库
main.addDirectory.contextMenu.open = 打开现有保管库
# welcome.fxml
welcome.checkForUpdates.label.currentlyChecking = 正在检查更新……
welcome.newVersionMessage = 发现新版本版本%1$s\n当前版本%2$s
# initialize.fxml
initialize.label.password = 密码
initialize.label.retypePassword = 确认密码
initialize.button.ok = 创建保管库
initialize.messageLabel.alreadyInitialized = 保管库已初始化
initialize.messageLabel.initializationFailed = 无法初始化保管库。 有关详情,请参阅日志文件。
# notfound.fxml
notfound.label = 找不到保险柜。 是否已被移动?
# upgrade.fxml
upgrade.button = 升级保险柜
upgrade.version3dropBundleExtension.msg = 此保管库需要迁移到较新的格式。\n"%1$s"将重命名为"%2$s"。\n请确保同步已完成然后再继续。
upgrade.version3dropBundleExtension.err.alreadyExists = 自动迁移失败。\n"%s"已存在
# unlock.fxml
unlock.label.password = 密码
unlock.label.mountName = 驱动器名称
unlock.label.winDriveLetter = 驱动器号
unlock.label.downloadsPageLink = 所有Cryptomator版本
unlock.label.advancedHeading = 高级选项
unlock.button.unlock = 保险柜解锁
unlock.button.advancedOptions.show = 更多选项
unlock.button.advancedOptions.hide = 更少选项
unlock.choicebox.winDriveLetter.auto = 自动分配
unlock.errorMessage.wrongPassword = 密码错误
unlock.errorMessage.mountingFailed = 挂载失败。有关详情,请参阅日志文件。
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = 不支持的保管库。 此保管库由旧版本的Cryptomator创建。
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = 不支持的保管库。 此保管库由较新版本的Cryptomator创建。
unlock.messageLabel.startServerFailed = 启动WebDAV服务器失败。
# change_password.fxml
changePassword.label.oldPassword = 旧密码
changePassword.label.newPassword = 新密码
changePassword.label.retypePassword = 确认新密码
changePassword.label.downloadsPageLink = 所有Cryptomator版本
changePassword.button.change = 更改密码
changePassword.errorMessage.wrongPassword = 密码错误
changePassword.errorMessage.decryptionFailed = 解密失败
# unlocked.fxml
unlocked.button.lock = 保险柜上锁
unlocked.moreOptions.reveal = 显示驱动器
unlocked.moreOptions.copyUrl = 复制WebDAV地址(URL)
unlocked.label.revealFailed = 命令失败
unlocked.label.unmountFailed = 弹出驱动器失败
unlocked.label.statsEncrypted = 加密
unlocked.label.statsDecrypted = 解密
unlocked.ioGraph.yAxis.label = 吞吐量(Mib/s)
# mac_warnings.fxml
macWarnings.windowTitle = 危险 - 在%s有文件损坏
macWarnings.message = Cryptomator检测到以下文件中的潜在恶意损坏
macWarnings.moreInformationButton = 了解更多
macWarnings.whitelistButton = 任然解密选择项
# settings.fxml
settings.version.label = 版本%s
settings.checkForUpdates.label = 检查更新
# What's the "*" mean?
settings.port.label = WebDAV 端口 *
settings.port.prompt = 0 \=自动选择
settings.useipv6.label = 使用IPv6
settings.requiresRestartLabel = * Cryptomator需要重新启动
# tray icon
tray.menu.open = 打开
tray.menu.quit = 退出
tray.infoMsg.title = 仍在运行
tray.infoMsg.msg = Cryptomator仍在运行。 从托盘图标中退出。
tray.infoMsg.msg.osx = Cryptomator仍在运行。 从菜单栏图标中退出。
initialize.messageLabel.passwordStrength.0 = 非常简单
initialize.messageLabel.passwordStrength.1 = 简单
initialize.messageLabel.passwordStrength.2 = 平均水平
initialize.messageLabel.passwordStrength.3 = 强壮
initialize.messageLabel.passwordStrength.4 = 非常强壮
initialize.label.doNotForget = 重要信息:如果您忘记了密码,将无法恢复您的数据。
main.directoryList.remove.confirmation.title = 移除保险柜
main.directoryList.remove.confirmation.header = 您确定要删除此保管库吗?
main.directoryList.remove.confirmation.content = 文件库将仅从列表中删除。 要永久删除它,请从文件系统中删除这些文件。
upgrade.version3to4.msg = 此保管库需要迁移到较新的格式。\n加密的文件夹名称将更新。\n请确保同步已完成然后再继续。
upgrade.version3to4.err.io = 由于I/O异常迁移失败。有关详情请参阅日志文件。
settings.prefGvfsScheme.label = WebDAV方案
# upgrade.fxml
upgrade.confirmation.label = 是的,我确保同步已完成
initialize.messageLabel.notEmpty = 保险柜非空
unlock.label.savePassword = 保存密码
# This Mac means Mac(Apple) or Mac address?
unlock.errorMessage.unauthenticVersionMac = 无法验证消息验证代码的版本。
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -0,0 +1,94 @@
app.name = Cryptomator
# main.fxml
main.emptyListInstructions = 按這裡新增檔案庫
main.directoryList.contextMenu.remove = 從清單移除
main.directoryList.contextMenu.changePassword = 變更密碼
main.addDirectory.contextMenu.new = 建立新的檔案庫
main.addDirectory.contextMenu.open = 打開現有的檔案庫
# welcome.fxml
welcome.checkForUpdates.label.currentlyChecking = 檢查更新...
welcome.newVersionMessage = 版本%1$s可下載。這是%2$s。
# initialize.fxml
initialize.label.password = 密碼
initialize.label.retypePassword = 重新輸入密碼
initialize.button.ok = 建立檔案庫
initialize.messageLabel.alreadyInitialized = 已初始化檔案庫
initialize.messageLabel.initializationFailed = 無法初始化檔案庫。取得詳細資訊,請查看紀錄。
# notfound.fxml
notfound.label = 無法找到檔案庫。已經移置別的地方?
# upgrade.fxml
upgrade.button = 升級檔案庫
upgrade.version3dropBundleExtension.msg = 這個檔案庫需要被轉移到新的格式。\n"%1$s"將會重新命名為"%2$s"。\n在進行之前請確認同步已完成。
upgrade.version3dropBundleExtension.err.alreadyExists = 自動轉移失敗。\n"%s"已存在。
# unlock.fxml
unlock.label.password = 密碼
unlock.label.mountName = 磁碟名稱
unlock.label.winDriveLetter = 磁碟代號
unlock.label.downloadsPageLink = 所有的Cryptomator版本
unlock.label.advancedHeading = 進階選項
unlock.button.unlock = 解鎖檔案庫
unlock.button.advancedOptions.show = 更多選項
unlock.button.advancedOptions.hide = 更少選項
unlock.choicebox.winDriveLetter.auto = 自動指定
unlock.errorMessage.wrongPassword = 錯誤的密碼
unlock.errorMessage.mountingFailed = 掛載失敗。取得詳細資訊,請查看紀錄。
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = 不支援的檔案庫。這個檔案庫是由舊版本的Cryptomator所建立的。
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = 不支援的檔案庫。這個檔案庫是由新版本的Cryptomator所建立的。
unlock.messageLabel.startServerFailed = 啟動WebDAV的伺服器失敗。
# change_password.fxml
changePassword.label.oldPassword = 舊密碼
changePassword.label.newPassword = 新密碼
changePassword.label.retypePassword = 重新輸入密碼
changePassword.label.downloadsPageLink = 所有的Cryptomator版本
changePassword.button.change = 變更密碼
changePassword.errorMessage.wrongPassword = 錯誤的密碼
changePassword.errorMessage.decryptionFailed = 解密失敗
# unlocked.fxml
unlocked.button.lock = 鎖住檔案庫
unlocked.moreOptions.reveal = 打開磁碟
unlocked.moreOptions.copyUrl = 複製WebDAV的網址
unlocked.label.revealFailed = 指令錯誤
unlocked.label.unmountFailed = 插入磁碟錯誤
unlocked.label.statsEncrypted = 加密的
unlocked.label.statsDecrypted = 解密的
unlocked.ioGraph.yAxis.label = 傳輸量MIB / S
# mac_warnings.fxml
macWarnings.windowTitle = 危險 - 損壞的檔案在%s
macWarnings.message = Cryptomator在下列檔案中偵測到潛在的損壞威脅
macWarnings.moreInformationButton = 取得更多
macWarnings.whitelistButton = 總是解密所選的
# settings.fxml
settings.version.label = 版本%s
settings.checkForUpdates.label = 檢查更新
settings.port.label = WebDAV的埠號*
settings.port.prompt = 0 \=自動選擇
settings.useipv6.label = 使用IPv6
settings.requiresRestartLabel = * Cryptomator需要更新
# tray icon
tray.menu.open = 打開
tray.menu.quit = 離開
tray.infoMsg.title = 仍然在執行
tray.infoMsg.msg = Cryptomator仍然在運作。從工具列的圖示點選離開。
tray.infoMsg.msg.osx = Cryptomator仍然在運作。從選單列上點選離開。
initialize.messageLabel.passwordStrength.0 = 非常弱的
initialize.messageLabel.passwordStrength.1 = 弱的
initialize.messageLabel.passwordStrength.2 = 正常的
initialize.messageLabel.passwordStrength.3 = 強的
initialize.messageLabel.passwordStrength.4 = 非常強的
initialize.label.doNotForget = 重要:如果你忘記的密碼,就無法還原你的資料。
main.directoryList.remove.confirmation.title = 移除檔案庫
main.directoryList.remove.confirmation.header = 你真的想要移除這個檔案庫?
main.directoryList.remove.confirmation.content = 這個檔案庫只會從清單中移除。如果要永久刪除,請從檔案系統中刪除。
upgrade.version3to4.msg = 這個檔案庫需要被轉移到新的格式。\n加密的資料夾名稱將會被更新。\n在進行之前請確認同步已完成。
upgrade.version3to4.err.io = 由於I/O的例外轉移失敗。取得詳細資訊請查看紀錄。
settings.prefGvfsScheme.label = WebDAV的格式
# upgrade.fxml
upgrade.confirmation.label = 是的,請確認同步已完成。
initialize.messageLabel.notEmpty = 檔案庫不是空的
unlock.label.savePassword = 儲存密碼
unlock.errorMessage.unauthenticVersionMac = 無法認證消息驗證碼版本。
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -0,0 +1,94 @@
app.name = Cryptomator
# main.fxml
main.emptyListInstructions = 按這裡新增檔案庫
main.directoryList.contextMenu.remove = 從清單移除
main.directoryList.contextMenu.changePassword = 變更密碼
main.addDirectory.contextMenu.new = 建立新的檔案庫
main.addDirectory.contextMenu.open = 打開現有的檔案庫
# welcome.fxml
welcome.checkForUpdates.label.currentlyChecking = 檢查更新...
welcome.newVersionMessage = 版本 %1$s 可下載。這是 %2$s 。
# initialize.fxml
initialize.label.password = 密碼
initialize.label.retypePassword = 重新輸入密碼
initialize.button.ok = 建立檔案庫
initialize.messageLabel.alreadyInitialized = 已初始化檔案庫
initialize.messageLabel.initializationFailed = 無法初始化檔案庫。取得詳細資訊,請查看紀錄。
# notfound.fxml
notfound.label = 無法找到檔案庫。已經移置別的地方?
# upgrade.fxml
upgrade.button = 升級檔案庫
upgrade.version3dropBundleExtension.msg = 這個檔案庫需要被轉移到新的格式。\n"%1$s" 將會重新命名為 "%2$s"。\n在進行之前請確認同步已完成。
upgrade.version3dropBundleExtension.err.alreadyExists = 自動轉移失敗。\n"%s" 已存在。
# unlock.fxml
unlock.label.password = 密碼
unlock.label.mountName = 磁碟名稱
unlock.label.winDriveLetter = 磁碟代號
unlock.label.downloadsPageLink = 所有的 Cryptomator 版本
unlock.label.advancedHeading = 進階選項
unlock.button.unlock = 解鎖檔案庫
unlock.button.advancedOptions.show = 更多選項
unlock.button.advancedOptions.hide = 更少選項
unlock.choicebox.winDriveLetter.auto = 自動指定
unlock.errorMessage.wrongPassword = 錯誤的密碼
unlock.errorMessage.mountingFailed = 掛載失敗。取得詳細資訊,請查看紀錄。
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = 不支援的檔案庫。這個檔案庫是由舊版本的 Cryptomator 所建立的。
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = 不支援的檔案庫。這個檔案庫是由新版本的 Cryptomator 所建立的。
unlock.messageLabel.startServerFailed = 啟動 WebDAV 伺服器失敗。
# change_password.fxml
changePassword.label.oldPassword = 舊密碼
changePassword.label.newPassword = 新密碼
changePassword.label.retypePassword = 重新輸入密碼
changePassword.label.downloadsPageLink = 所有的 Cryptomator 版本
changePassword.button.change = 變更密碼
changePassword.errorMessage.wrongPassword = 錯誤的密碼
changePassword.errorMessage.decryptionFailed = 解密失敗
# unlocked.fxml
unlocked.button.lock = 鎖住檔案庫
unlocked.moreOptions.reveal = 打開磁碟
unlocked.moreOptions.copyUrl = 複製 WebDAV 網址
unlocked.label.revealFailed = 指令錯誤
unlocked.label.unmountFailed = 插入磁碟錯誤
unlocked.label.statsEncrypted = 加密的
unlocked.label.statsDecrypted = 解密的
unlocked.ioGraph.yAxis.label = 傳輸量 (MiB/s)
# mac_warnings.fxml
macWarnings.windowTitle = 危險 - 損壞的檔案在 %s
macWarnings.message = Cryptomator 在下列檔案中,偵測到潛在的損壞威脅:
macWarnings.moreInformationButton = 取得更多
macWarnings.whitelistButton = 總是解密所選的
# settings.fxml
settings.version.label = 版本 %s
settings.checkForUpdates.label = 檢查更新
settings.port.label = WebDAV 埠號 *
settings.port.prompt = 0 \= 自動選擇
settings.useipv6.label = 使用 IPv6 literal
settings.requiresRestartLabel = * Cryptomator 需要更新
# tray icon
tray.menu.open = 打開
tray.menu.quit = 離開
tray.infoMsg.title = 仍然在執行
tray.infoMsg.msg = Cryptomator 仍然在運作。從工具列的圖示點選離開。
tray.infoMsg.msg.osx = Cryptomator 仍然在運作。從選單列上點選離開。
initialize.messageLabel.passwordStrength.0 = 非常弱的
initialize.messageLabel.passwordStrength.1 = 弱的
initialize.messageLabel.passwordStrength.2 = 正常的
initialize.messageLabel.passwordStrength.3 = 強的
initialize.messageLabel.passwordStrength.4 = 非常強的
initialize.label.doNotForget = 重要:如果你忘記的密碼,就無法還原你的資料。
main.directoryList.remove.confirmation.title = 移除檔案庫
main.directoryList.remove.confirmation.header = 你真的想要移除這個檔案庫?
main.directoryList.remove.confirmation.content = 這個檔案庫只會從清單中移除。如果要永久刪除,請從檔案系統中刪除。
upgrade.version3to4.msg = 這個檔案庫需要被轉移到新的格式。\n加密的資料夾名稱將會被更新。\n在進行之前請確認同步已完成。
upgrade.version3to4.err.io = 由於 I/O 的例外,轉移失敗。取得詳細資訊,請查看紀錄。
settings.prefGvfsScheme.label = WebDAV 格式
# upgrade.fxml
upgrade.confirmation.label = 是的,請確認同步已完成。
initialize.messageLabel.notEmpty = 檔案庫不是空的
unlock.label.savePassword = 儲存密碼
unlock.errorMessage.unauthenticVersionMac = 無法認證消息驗證碼版本。
unlocked.label.mountFailed = Connecting drive failed
unlock.savePassword.delete.confirmation.title = Delete Saved Password
unlock.savePassword.delete.confirmation.header = Do you really want to delete the saved password of this vault?
unlock.savePassword.delete.confirmation.content = The saved password of this vault will be immediately deleted from your system keychain. If you'd like to save your password again, you'd have to unlock your vault with the "Save password" option enabled.
settings.debugMode.label = Debug mode *

View File

@@ -27,9 +27,13 @@
</Appenders>
<Loggers>
<!-- package-specific config: -->
<Logger name="org.cryptomator" level="DEBUG" />
<Logger name="org.eclipse.jetty.server.Server" level="DEBUG" />
<!--
= NOTE =
All loggers below are set to info.
This is required to allow changing the levels of the loggers programmatically.
-->
<Logger name="org.cryptomator" level="INFO" />
<Logger name="org.eclipse.jetty.server.Server" level="INFO" />
<Logger name="org.cryptomator.ui.model" level="INFO">
<AppenderRef ref="UpgradeLog" />
</Logger>

View File

@@ -6,7 +6,7 @@
* Contributors:
* Sebastian Stenzel - initial API and implementation
*******************************************************************************/
package org.cryptomator.ui;
package org.cryptomator.ui.settings;
import java.io.IOException;
import java.io.InputStream;
@@ -31,7 +31,8 @@ public class LocalizationTest {
private static final Logger LOG = LoggerFactory.getLogger(LocalizationTest.class);
private static final String RESOURCE_FOLDER_PATH = "/localization/";
private static final String REF_FILE_NAME = "en.txt";
private static final String[] LANG_FILE_NAMES = {"de.txt", "es.txt", "fr.txt", "hu.txt", "it.txt", "kr.txt", "lv.txt", "nl.txt", "pl.txt", "pt.txt", "ru.txt", "sk.txt", "tr.txt", "uk.txt"};
private static final String[] LANG_FILE_NAMES = {"de.txt", "es.txt", "fr.txt", "hu.txt", "it.txt", "kr.txt", "lv.txt", "nl.txt", "pl.txt", "pt.txt", "ru.txt", "sk.txt", "tr.txt", "uk.txt", "zh_HK.txt", "zh_TW.txt",
"zh.txt"};
/*
* @see Formatter