mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-15 01:01:26 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cef3a5fc77 | ||
|
|
9956f43fd9 | ||
|
|
2b84593bde | ||
|
|
4e728fd387 | ||
|
|
438ade1106 | ||
|
|
fe54f4ec66 | ||
|
|
fe86b4c593 | ||
|
|
a583afeb60 | ||
|
|
a585d3cf16 | ||
|
|
3db757193e | ||
|
|
bac1d6fd83 | ||
|
|
39ee8a9cde | ||
|
|
1263b3af81 | ||
|
|
dafa29d8a3 | ||
|
|
2bc6fe89ad | ||
|
|
8439216233 | ||
|
|
aab616d184 | ||
|
|
70c3a38c49 | ||
|
|
c64294ac3e | ||
|
|
82330db871 | ||
|
|
c54a721f9a | ||
|
|
355bbb5459 | ||
|
|
63daa0f121 | ||
|
|
50885d5c7c | ||
|
|
4d68818ec5 | ||
|
|
6fb20dd509 | ||
|
|
2bb87dfa96 | ||
|
|
2fa04d7b7c |
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -37,6 +37,8 @@ interface CryptomatorComponent {
|
||||
|
||||
ExitUtil exitUtil();
|
||||
|
||||
DebugMode debugMode();
|
||||
|
||||
Optional<MacFunctions> nativeMacFunctions();
|
||||
|
||||
}
|
||||
|
||||
75
main/ui/src/main/java/org/cryptomator/ui/DebugMode.java
Normal file
75
main/ui/src/main/java/org/cryptomator/ui/DebugMode.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(() -> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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="" styleClass="ionicons"/></graphic>
|
||||
</MenuItem>
|
||||
<MenuItem text="%unlocked.moreOptions.copyUrl" onAction="#didClickCopyUrl">
|
||||
|
||||
@@ -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 *
|
||||
@@ -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
|
||||
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
@@ -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 *
|
||||
96
main/ui/src/main/resources/localization/zh.txt
Normal file
96
main/ui/src/main/resources/localization/zh.txt
Normal 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 *
|
||||
94
main/ui/src/main/resources/localization/zh_HK.txt
Normal file
94
main/ui/src/main/resources/localization/zh_HK.txt
Normal 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 *
|
||||
94
main/ui/src/main/resources/localization/zh_TW.txt
Normal file
94
main/ui/src/main/resources/localization/zh_TW.txt
Normal 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 *
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user