mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-22 20:51:27 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d57ebb24a | ||
|
|
f12168ca94 | ||
|
|
d397f59565 | ||
|
|
77aaeabcde | ||
|
|
768f291ff7 | ||
|
|
6a374cc237 | ||
|
|
0133ec8fdf |
@@ -39,7 +39,7 @@ addons:
|
|||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
provider: releases
|
||||||
prerelease: true
|
prerelease: false
|
||||||
api_key:
|
api_key:
|
||||||
secure: "ZjE1j93v3qbPIe2YbmhS319aCbMdLQw0HuymmluTurxXsZtn9D4t2+eTr99vBVxGRuB5lzzGezPR5zjk5W7iHF7xhwrawXrFzr2rPJWzWFt0aM+Ry2njU1ROTGGXGTbv4anWeBlgMxLEInTAy/9ytOGNJlec83yc0THpOY2wxnk="
|
secure: "ZjE1j93v3qbPIe2YbmhS319aCbMdLQw0HuymmluTurxXsZtn9D4t2+eTr99vBVxGRuB5lzzGezPR5zjk5W7iHF7xhwrawXrFzr2rPJWzWFt0aM+Ry2njU1ROTGGXGTbv4anWeBlgMxLEInTAy/9ytOGNJlec83yc0THpOY2wxnk="
|
||||||
file: main/uber-jar/target/Cryptomator-$TRAVIS_TAG.jar
|
file: main/uber-jar/target/Cryptomator-$TRAVIS_TAG.jar
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Copyright (c) 2015 Markus Kreusch This file is licensed under the terms
|
<!--
|
||||||
of the MIT license. See the LICENSE.txt file for more info. -->
|
Copyright (c) 2015 Markus Kreusch
|
||||||
|
This file is licensed under the terms of the MIT license.
|
||||||
|
See the LICENSE.txt file for more info.
|
||||||
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commons-test</artifactId>
|
<artifactId>commons-test</artifactId>
|
||||||
<name>Cryptomator common test dependencies</name>
|
<name>Cryptomator common test dependencies</name>
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Copyright (c) 2015 Markus Kreusch This file is licensed under the terms
|
<!--
|
||||||
of the MIT license. See the LICENSE.txt file for more info. -->
|
Copyright (c) 2015 Markus Kreusch
|
||||||
|
This file is licensed under the terms of the MIT license.
|
||||||
|
See the LICENSE.txt file for more info.
|
||||||
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commons</artifactId>
|
<artifactId>commons</artifactId>
|
||||||
<name>Cryptomator common</name>
|
<name>Cryptomator common</name>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-api</artifactId>
|
<artifactId>filesystem-api</artifactId>
|
||||||
<name>Cryptomator filesystem: API</name>
|
<name>Cryptomator filesystem: API</name>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.Optional;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.cryptomator.common.WeakValuedCache;
|
import org.cryptomator.common.WeakValuedCache;
|
||||||
|
import org.cryptomator.common.streams.AutoClosingStream;
|
||||||
import org.cryptomator.filesystem.File;
|
import org.cryptomator.filesystem.File;
|
||||||
import org.cryptomator.filesystem.Folder;
|
import org.cryptomator.filesystem.Folder;
|
||||||
import org.cryptomator.filesystem.Node;
|
import org.cryptomator.filesystem.Node;
|
||||||
@@ -35,7 +36,7 @@ public abstract class DelegatingFolder<D extends DelegatingFolder<D, F>, F exten
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<? extends Node> children() throws UncheckedIOException {
|
public Stream<? extends Node> children() throws UncheckedIOException {
|
||||||
return Stream.concat(folders(), files());
|
return AutoClosingStream.from(Stream.concat(folders(), files()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-crypto-integration-tests</artifactId>
|
<artifactId>filesystem-crypto-integration-tests</artifactId>
|
||||||
<name>Cryptomator filesystem: Encryption layer tests</name>
|
<name>Cryptomator filesystem: Encryption layer tests</name>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-crypto</artifactId>
|
<artifactId>filesystem-crypto</artifactId>
|
||||||
<name>Cryptomator filesystem: Encryption layer</name>
|
<name>Cryptomator filesystem: Encryption layer</name>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.util.stream.Stream;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.cryptomator.common.LazyInitializer;
|
import org.cryptomator.common.LazyInitializer;
|
||||||
import org.cryptomator.common.WeakValuedCache;
|
import org.cryptomator.common.WeakValuedCache;
|
||||||
|
import org.cryptomator.common.streams.AutoClosingStream;
|
||||||
import org.cryptomator.crypto.engine.Cryptor;
|
import org.cryptomator.crypto.engine.Cryptor;
|
||||||
import org.cryptomator.filesystem.Deleter;
|
import org.cryptomator.filesystem.Deleter;
|
||||||
import org.cryptomator.filesystem.File;
|
import org.cryptomator.filesystem.File;
|
||||||
@@ -74,13 +75,13 @@ class CryptoFolder extends CryptoNode implements Folder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<? extends Node> children() {
|
public Stream<? extends Node> children() {
|
||||||
return Stream.concat(files(), folders());
|
return AutoClosingStream.from(Stream.concat(files(), folders()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<CryptoFile> files() {
|
public Stream<CryptoFile> files() {
|
||||||
assert forceGetPhysicalFolder().exists();
|
final Stream<? extends File> files = physicalFolder().filter(Folder::exists).map(Folder::files).orElse(Stream.empty());
|
||||||
return forceGetPhysicalFolder().files().map(File::name).filter(isEncryptedFileName()).map(this::decryptChildFileName).map(this::file);
|
return files.map(File::name).filter(isEncryptedFileName()).map(this::decryptChildFileName).map(this::file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<String> isEncryptedFileName() {
|
private Predicate<String> isEncryptedFileName() {
|
||||||
@@ -103,8 +104,8 @@ class CryptoFolder extends CryptoNode implements Folder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<CryptoFolder> folders() {
|
public Stream<CryptoFolder> folders() {
|
||||||
assert forceGetPhysicalFolder().exists();
|
final Stream<? extends File> files = physicalFolder().filter(Folder::exists).map(Folder::files).orElse(Stream.empty());
|
||||||
return forceGetPhysicalFolder().files().map(File::name).filter(isEncryptedDirectoryName()).map(this::decryptChildFolderName).map(this::folder);
|
return files.map(File::name).filter(isEncryptedDirectoryName()).map(this::decryptChildFolderName).map(this::folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<String> isEncryptedDirectoryName() {
|
private Predicate<String> isEncryptedDirectoryName() {
|
||||||
@@ -189,7 +190,7 @@ class CryptoFolder extends CryptoNode implements Folder {
|
|||||||
Folder physicalFolder = forceGetPhysicalFolder();
|
Folder physicalFolder = forceGetPhysicalFolder();
|
||||||
physicalFolder.delete();
|
physicalFolder.delete();
|
||||||
Folder physicalFolderParent = physicalFolder.parent().get();
|
Folder physicalFolderParent = physicalFolder.parent().get();
|
||||||
if (physicalFolderParent.folders().count() == 0) {
|
if (physicalFolderParent.exists() && physicalFolderParent.folders().count() == 0) {
|
||||||
physicalFolderParent.delete();
|
physicalFolderParent.delete();
|
||||||
}
|
}
|
||||||
forceGetPhysicalFile().delete();
|
forceGetPhysicalFile().delete();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-inmemory</artifactId>
|
<artifactId>filesystem-inmemory</artifactId>
|
||||||
<name>Cryptomator filesystem: In-memory mock</name>
|
<name>Cryptomator filesystem: In-memory mock</name>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-invariants-tests</artifactId>
|
<artifactId>filesystem-invariants-tests</artifactId>
|
||||||
<name>Cryptomator filesystem: Invariants tests</name>
|
<name>Cryptomator filesystem: Invariants tests</name>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-nameshortening</artifactId>
|
<artifactId>filesystem-nameshortening</artifactId>
|
||||||
<name>Cryptomator filesystem: Name shortening layer</name>
|
<name>Cryptomator filesystem: Name shortening layer</name>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-nio</artifactId>
|
<artifactId>filesystem-nio</artifactId>
|
||||||
<name>Cryptomator filesystem: NIO-based physical layer</name>
|
<name>Cryptomator filesystem: NIO-based physical layer</name>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>filesystem-stats</artifactId>
|
<artifactId>filesystem-stats</artifactId>
|
||||||
<name>Cryptomator filesystem: Throughput statistics</name>
|
<name>Cryptomator filesystem: Throughput statistics</name>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>frontend-api</artifactId>
|
<artifactId>frontend-api</artifactId>
|
||||||
<name>Cryptomator frontend: API</name>
|
<name>Cryptomator frontend: API</name>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import java.util.Optional;
|
|||||||
public interface Frontend extends AutoCloseable {
|
public interface Frontend extends AutoCloseable {
|
||||||
|
|
||||||
public enum MountParam {
|
public enum MountParam {
|
||||||
MOUNT_NAME, WIN_DRIVE_LETTER
|
MOUNT_NAME, HOSTNAME, WIN_DRIVE_LETTER
|
||||||
}
|
}
|
||||||
|
|
||||||
void mount(Map<MountParam, Optional<String>> map) throws CommandFailedException;
|
void mount(Map<MountParam, Optional<String>> map) throws CommandFailedException;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>frontend-webdav</artifactId>
|
<artifactId>frontend-webdav</artifactId>
|
||||||
<name>Cryptomator frontend: WebDAV frontend</name>
|
<name>Cryptomator frontend: WebDAV frontend</name>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.apache.jackrabbit.webdav.property.DavProperty;
|
|||||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||||
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
||||||
import org.apache.jackrabbit.webdav.property.ResourceType;
|
import org.apache.jackrabbit.webdav.property.ResourceType;
|
||||||
|
import org.cryptomator.common.streams.AutoClosingStream;
|
||||||
import org.cryptomator.filesystem.Folder;
|
import org.cryptomator.filesystem.Folder;
|
||||||
import org.cryptomator.filesystem.Node;
|
import org.cryptomator.filesystem.Node;
|
||||||
import org.cryptomator.filesystem.WritableFile;
|
import org.cryptomator.filesystem.WritableFile;
|
||||||
@@ -90,7 +91,8 @@ class DavFolder extends DavNode<FolderLocator> {
|
|||||||
public DavResourceIterator getMembers() {
|
public DavResourceIterator getMembers() {
|
||||||
final Stream<DavFolder> folders = node.folders().map(this::folderToDavFolder);
|
final Stream<DavFolder> folders = node.folders().map(this::folderToDavFolder);
|
||||||
final Stream<DavFile> files = node.files().map(this::fileToDavFile);
|
final Stream<DavFile> files = node.files().map(this::fileToDavFile);
|
||||||
return new DavResourceIteratorImpl(Stream.concat(folders, files).collect(Collectors.toList()));
|
final Stream<DavResource> members = AutoClosingStream.from(Stream.concat(folders, files));
|
||||||
|
return new DavResourceIteratorImpl(members.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DavFolder folderToDavFolder(FolderLocator memberFolder) {
|
private DavFolder folderToDavFolder(FolderLocator memberFolder) {
|
||||||
@@ -115,9 +117,15 @@ class DavFolder extends DavNode<FolderLocator> {
|
|||||||
* Error 404 if no child with the given name exists
|
* Error 404 if no child with the given name exists
|
||||||
*/
|
*/
|
||||||
private Node getMemberNode(String name) throws DavException {
|
private Node getMemberNode(String name) throws DavException {
|
||||||
return node.children().filter(c -> c.name().equals(name)).findAny().orElseThrow(() -> {
|
Node file = node.file(name);
|
||||||
return new DavException(DavServletResponse.SC_NOT_FOUND, "No such file or directory: " + node.getResourcePath() + name);
|
Node folder = node.folder(name);
|
||||||
});
|
if (file.exists()) {
|
||||||
|
return file;
|
||||||
|
} else if (folder.exists()) {
|
||||||
|
return folder;
|
||||||
|
} else {
|
||||||
|
throw new DavException(DavServletResponse.SC_NOT_FOUND, "No such file or directory: " + node.getResourcePath() + name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ package org.cryptomator.frontend.webdav.mount;
|
|||||||
import static org.cryptomator.frontend.webdav.mount.command.Script.fromLines;
|
import static org.cryptomator.frontend.webdav.mount.command.Script.fromLines;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -31,14 +32,15 @@ import org.cryptomator.frontend.webdav.mount.command.Script;
|
|||||||
/**
|
/**
|
||||||
* A {@link WebDavMounterStrategy} utilizing the "net use" command.
|
* A {@link WebDavMounterStrategy} utilizing the "net use" command.
|
||||||
* <p>
|
* <p>
|
||||||
* Tested on Windows 7 but should also work on Windows 8.
|
* Tested on Windows 7, 8.1 and 10.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
||||||
|
|
||||||
private static final Pattern WIN_MOUNT_DRIVELETTER_PATTERN = Pattern.compile("\\s*([A-Z]):\\s*");
|
private static final Pattern WIN_MOUNT_DRIVELETTER_PATTERN = Pattern.compile("\\s*([A-Z]):\\s*");
|
||||||
private static final int MAX_MOUNT_ATTEMPTS = 8;
|
private static final String AUTO_ASSIGN_DRIVE_LETTER = "*";
|
||||||
private static final char AUTO_ASSIGN_DRIVE_LETTER = '*';
|
private static final String LOCALHOST = "localhost";
|
||||||
|
private static final int MOUNT_TIMEOUT_SECONDS = 60;
|
||||||
private final WindowsDriveLetters driveLetters;
|
private final WindowsDriveLetters driveLetters;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -58,56 +60,41 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
|
public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
|
||||||
final Character driveLetter = mountParams.get(MountParam.WIN_DRIVE_LETTER).map(CharUtils::toCharacterObject).orElse(AUTO_ASSIGN_DRIVE_LETTER);
|
final String driveLetter = mountParams.getOrDefault(MountParam.WIN_DRIVE_LETTER, Optional.of(AUTO_ASSIGN_DRIVE_LETTER)).orElse(AUTO_ASSIGN_DRIVE_LETTER);
|
||||||
if (driveLetters.getOccupiedDriveLetters().contains(driveLetter)) {
|
if (driveLetters.getOccupiedDriveLetters().contains(CharUtils.toChar(driveLetter))) {
|
||||||
throw new CommandFailedException("Drive letter occupied.");
|
throw new CommandFailedException("Drive letter occupied.");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String driveLetterStr = driveLetter.charValue() == AUTO_ASSIGN_DRIVE_LETTER ? CharUtils.toString(AUTO_ASSIGN_DRIVE_LETTER) : driveLetter + ":";
|
final String hostname = mountParams.getOrDefault(MountParam.HOSTNAME, Optional.of(LOCALHOST)).orElse(LOCALHOST);
|
||||||
final Script localhostMountScript = fromLines("net use %DRIVE_LETTER% \\\\localhost@%DAV_PORT%\\DavWWWRoot%DAV_UNC_PATH% /persistent:no");
|
|
||||||
localhostMountScript.addEnv("DRIVE_LETTER", driveLetterStr);
|
|
||||||
localhostMountScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
|
|
||||||
localhostMountScript.addEnv("DAV_UNC_PATH", uri.getRawPath().replace('/', '\\'));
|
|
||||||
CommandResult mountResult;
|
|
||||||
try {
|
try {
|
||||||
mountResult = localhostMountScript.execute(5, TimeUnit.SECONDS);
|
final URI adjustedUri = new URI(uri.getScheme(), uri.getUserInfo(), hostname, uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment());
|
||||||
} catch (CommandFailedException ex) {
|
CommandResult mountResult = mount(adjustedUri, driveLetter);
|
||||||
final Script ipv6literaltMountScript = fromLines("net use %DRIVE_LETTER% \\\\0--1.ipv6-literal.net@%DAV_PORT%\\DavWWWRoot%DAV_UNC_PATH% /persistent:no");
|
return new WindowsWebDavMount(AUTO_ASSIGN_DRIVE_LETTER.equals(driveLetter) ? getDriveLetter(mountResult.getStdOut()) : driveLetter);
|
||||||
ipv6literaltMountScript.addEnv("DRIVE_LETTER", driveLetterStr);
|
} catch (URISyntaxException e) {
|
||||||
ipv6literaltMountScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
|
throw new IllegalArgumentException("Invalid host: " + hostname);
|
||||||
ipv6literaltMountScript.addEnv("DAV_UNC_PATH", uri.getRawPath().replace('/', '\\'));
|
|
||||||
final Script proxyBypassScript = fromLines(
|
|
||||||
"reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\" /v \"ProxyOverride\" /d \"<local>;0--1.ipv6-literal.net;0--1.ipv6-literal.net:%DAV_PORT%\" /f");
|
|
||||||
proxyBypassScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
|
|
||||||
mountResult = bypassProxyAndRetryMount(localhostMountScript, ipv6literaltMountScript, proxyBypassScript);
|
|
||||||
}
|
}
|
||||||
return new WindowsWebDavMount(driveLetter.charValue() == AUTO_ASSIGN_DRIVE_LETTER ? getDriveLetter(mountResult.getStdOut()) : driveLetter);
|
}
|
||||||
|
|
||||||
|
private CommandResult mount(URI uri, String driveLetter) throws CommandFailedException {
|
||||||
|
final Script proxyBypassScript = fromLines(
|
||||||
|
"reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\" /v \"ProxyOverride\" /d \"<local>;%DAV_HOST%;%DAV_HOST%:%DAV_PORT%\" /f");
|
||||||
|
proxyBypassScript.addEnv("DAV_HOST", uri.getHost());
|
||||||
|
proxyBypassScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
|
||||||
|
proxyBypassScript.execute();
|
||||||
|
|
||||||
|
final String driveLetterStr = AUTO_ASSIGN_DRIVE_LETTER.equals(driveLetter) ? AUTO_ASSIGN_DRIVE_LETTER : driveLetter + ":";
|
||||||
|
final Script mountScript = fromLines("net use %DRIVE_LETTER% \\\\%DAV_HOST%@%DAV_PORT%\\DavWWWRoot%DAV_UNC_PATH% /persistent:no");
|
||||||
|
mountScript.addEnv("DRIVE_LETTER", driveLetterStr);
|
||||||
|
mountScript.addEnv("DAV_HOST", uri.getHost());
|
||||||
|
mountScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
|
||||||
|
mountScript.addEnv("DAV_UNC_PATH", uri.getRawPath().replace('/', '\\'));
|
||||||
|
return mountScript.execute(MOUNT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandResult bypassProxyAndRetryMount(Script localhostMountScript, Script ipv6literalMountScript, Script proxyBypassScript) throws CommandFailedException {
|
private String getDriveLetter(String result) throws CommandFailedException {
|
||||||
CommandFailedException latestException = null;
|
|
||||||
for (int i = 0; i < MAX_MOUNT_ATTEMPTS; i++) {
|
|
||||||
try {
|
|
||||||
// wait a moment before next attempt
|
|
||||||
Thread.sleep(5000);
|
|
||||||
proxyBypassScript.execute();
|
|
||||||
// alternate localhost and 0--1.ipv6literal.net
|
|
||||||
final Script mountScript = (i % 2 == 0) ? localhostMountScript : ipv6literalMountScript;
|
|
||||||
return mountScript.execute(3, TimeUnit.SECONDS);
|
|
||||||
} catch (CommandFailedException ex) {
|
|
||||||
latestException = ex;
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
throw new CommandFailedException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw latestException;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Character getDriveLetter(String result) throws CommandFailedException {
|
|
||||||
final Matcher matcher = WIN_MOUNT_DRIVELETTER_PATTERN.matcher(result);
|
final Matcher matcher = WIN_MOUNT_DRIVELETTER_PATTERN.matcher(result);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
return CharUtils.toCharacterObject(matcher.group(1));
|
return matcher.group(1);
|
||||||
} else {
|
} else {
|
||||||
throw new CommandFailedException("Failed to get a drive letter from net use output.");
|
throw new CommandFailedException("Failed to get a drive letter from net use output.");
|
||||||
}
|
}
|
||||||
@@ -118,10 +105,10 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
|||||||
private final Script openExplorerScript;
|
private final Script openExplorerScript;
|
||||||
private final Script unmountScript;
|
private final Script unmountScript;
|
||||||
|
|
||||||
private WindowsWebDavMount(Character driveLetter) {
|
private WindowsWebDavMount(String driveLetter) {
|
||||||
this.driveLetter = driveLetter;
|
this.driveLetter = CharUtils.toCharacterObject(driveLetter);
|
||||||
this.openExplorerScript = fromLines("start explorer.exe " + driveLetter + ":");
|
this.openExplorerScript = fromLines("start explorer.exe " + driveLetter + ":");
|
||||||
this.unmountScript = fromLines("net use " + driveLetter + ": /delete").addEnv("DRIVE_LETTER", Character.toString(driveLetter));
|
this.unmountScript = fromLines("net use " + driveLetter + ": /delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>Cryptomator</name>
|
<name>Cryptomator</name>
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>uber-jar</artifactId>
|
<artifactId>uber-jar</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>main</artifactId>
|
<artifactId>main</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>ui</artifactId>
|
<artifactId>ui</artifactId>
|
||||||
<name>Cryptomator GUI</name>
|
<name>Cryptomator GUI</name>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import javax.inject.Inject;
|
|||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.apache.commons.lang3.CharUtils;
|
import org.apache.commons.lang3.CharUtils;
|
||||||
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.ui.settings.Localization;
|
import org.cryptomator.ui.settings.Localization;
|
||||||
import org.cryptomator.ui.settings.Settings;
|
import org.cryptomator.ui.settings.Settings;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
@@ -43,6 +44,9 @@ public class SettingsController extends AbstractFXMLViewController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TextField portField;
|
private TextField portField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private CheckBox useIpv6Checkbox;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label versionLabel;
|
private Label versionLabel;
|
||||||
@@ -53,10 +57,13 @@ public class SettingsController extends AbstractFXMLViewController {
|
|||||||
checkForUpdatesCheckbox.setSelected(settings.isCheckForUpdatesEnabled() && !areUpdatesManagedExternally());
|
checkForUpdatesCheckbox.setSelected(settings.isCheckForUpdatesEnabled() && !areUpdatesManagedExternally());
|
||||||
portField.setText(String.valueOf(settings.getPort()));
|
portField.setText(String.valueOf(settings.getPort()));
|
||||||
portField.addEventFilter(KeyEvent.KEY_TYPED, this::filterNumericKeyEvents);
|
portField.addEventFilter(KeyEvent.KEY_TYPED, this::filterNumericKeyEvents);
|
||||||
|
useIpv6Checkbox.setDisable(!SystemUtils.IS_OS_WINDOWS);
|
||||||
|
useIpv6Checkbox.setSelected(SystemUtils.IS_OS_WINDOWS && settings.shouldUseIpv6());
|
||||||
versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion().orElse("SNAPSHOT")));
|
versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion().orElse("SNAPSHOT")));
|
||||||
|
|
||||||
EasyBind.subscribe(portField.textProperty(), this::portDidChange);
|
|
||||||
EasyBind.subscribe(checkForUpdatesCheckbox.selectedProperty(), settings::setCheckForUpdatesEnabled);
|
EasyBind.subscribe(checkForUpdatesCheckbox.selectedProperty(), settings::setCheckForUpdatesEnabled);
|
||||||
|
EasyBind.subscribe(portField.textProperty(), this::portDidChange);
|
||||||
|
EasyBind.subscribe(useIpv6Checkbox.selectedProperty(), settings::setUseIpv6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.cryptomator.frontend.webdav.mount.WindowsDriveLetters;
|
|||||||
import org.cryptomator.ui.controls.SecPasswordField;
|
import org.cryptomator.ui.controls.SecPasswordField;
|
||||||
import org.cryptomator.ui.model.Vault;
|
import org.cryptomator.ui.model.Vault;
|
||||||
import org.cryptomator.ui.settings.Localization;
|
import org.cryptomator.ui.settings.Localization;
|
||||||
|
import org.cryptomator.ui.settings.Settings;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -58,16 +59,18 @@ public class UnlockController extends AbstractFXMLViewController {
|
|||||||
private final Localization localization;
|
private final Localization localization;
|
||||||
private final ExecutorService exec;
|
private final ExecutorService exec;
|
||||||
private final Lazy<FrontendFactory> frontendFactory;
|
private final Lazy<FrontendFactory> frontendFactory;
|
||||||
|
private final Settings settings;
|
||||||
private final WindowsDriveLetters driveLetters;
|
private final WindowsDriveLetters driveLetters;
|
||||||
private final ChangeListener<Character> driveLetterChangeListener = this::winDriveLetterDidChange;
|
private final ChangeListener<Character> driveLetterChangeListener = this::winDriveLetterDidChange;
|
||||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UnlockController(Application app, Localization localization, ExecutorService exec, Lazy<FrontendFactory> frontendFactory, WindowsDriveLetters driveLetters) {
|
public UnlockController(Application app, Localization localization, ExecutorService exec, Lazy<FrontendFactory> frontendFactory, Settings settings, WindowsDriveLetters driveLetters) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.localization = localization;
|
this.localization = localization;
|
||||||
this.exec = exec;
|
this.exec = exec;
|
||||||
this.frontendFactory = frontendFactory;
|
this.frontendFactory = frontendFactory;
|
||||||
|
this.settings = settings;
|
||||||
this.driveLetters = driveLetters;
|
this.driveLetters = driveLetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +282,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
|||||||
|
|
||||||
private void unlock(CharSequence password) {
|
private void unlock(CharSequence password) {
|
||||||
try {
|
try {
|
||||||
vault.get().activateFrontend(frontendFactory.get(), password);
|
vault.get().activateFrontend(frontendFactory.get(), settings, password);
|
||||||
vault.get().reveal();
|
vault.get().reveal();
|
||||||
} catch (InvalidPassphraseException e) {
|
} catch (InvalidPassphraseException e) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import org.cryptomator.frontend.Frontend;
|
|||||||
import org.cryptomator.frontend.Frontend.MountParam;
|
import org.cryptomator.frontend.Frontend.MountParam;
|
||||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||||
import org.cryptomator.frontend.FrontendFactory;
|
import org.cryptomator.frontend.FrontendFactory;
|
||||||
|
import org.cryptomator.ui.settings.Settings;
|
||||||
import org.cryptomator.ui.util.DeferredClosable;
|
import org.cryptomator.ui.util.DeferredClosable;
|
||||||
import org.cryptomator.ui.util.DeferredCloser;
|
import org.cryptomator.ui.util.DeferredCloser;
|
||||||
import org.cryptomator.ui.util.FXThreads;
|
import org.cryptomator.ui.util.FXThreads;
|
||||||
@@ -112,7 +113,7 @@ public class Vault implements CryptoFileSystemDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void activateFrontend(FrontendFactory frontendFactory, CharSequence passphrase) throws FrontendCreationFailedException {
|
public synchronized void activateFrontend(FrontendFactory frontendFactory, Settings settings, CharSequence passphrase) throws FrontendCreationFailedException {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
FileSystem fs = getNioFileSystem();
|
FileSystem fs = getNioFileSystem();
|
||||||
@@ -123,7 +124,7 @@ public class Vault implements CryptoFileSystemDelegate {
|
|||||||
String contextPath = StringUtils.prependIfMissing(mountName, "/");
|
String contextPath = StringUtils.prependIfMissing(mountName, "/");
|
||||||
Frontend frontend = frontendFactory.create(statsFs, contextPath);
|
Frontend frontend = frontendFactory.create(statsFs, contextPath);
|
||||||
filesystemFrontend = closer.closeLater(frontend);
|
filesystemFrontend = closer.closeLater(frontend);
|
||||||
frontend.mount(getMountParams());
|
frontend.mount(getMountParams(settings));
|
||||||
success = true;
|
success = true;
|
||||||
} catch (UncheckedIOException | CommandFailedException e) {
|
} catch (UncheckedIOException | CommandFailedException e) {
|
||||||
throw new FrontendCreationFailedException(e);
|
throw new FrontendCreationFailedException(e);
|
||||||
@@ -140,10 +141,12 @@ public class Vault implements CryptoFileSystemDelegate {
|
|||||||
Platform.runLater(() -> unlocked.set(false));
|
Platform.runLater(() -> unlocked.set(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<MountParam, Optional<String>> getMountParams() {
|
private Map<MountParam, Optional<String>> getMountParams(Settings settings) {
|
||||||
|
String hostname = SystemUtils.IS_OS_WINDOWS && settings.shouldUseIpv6() ? "0--1.ipv6-literal.net" : "localhost";
|
||||||
return ImmutableMap.of( //
|
return ImmutableMap.of( //
|
||||||
MountParam.MOUNT_NAME, Optional.ofNullable(mountName), //
|
MountParam.MOUNT_NAME, Optional.ofNullable(mountName), //
|
||||||
MountParam.WIN_DRIVE_LETTER, Optional.ofNullable(CharUtils.toString(winDriveLetter)) //
|
MountParam.WIN_DRIVE_LETTER, Optional.ofNullable(CharUtils.toString(winDriveLetter)), //
|
||||||
|
MountParam.HOSTNAME, Optional.of(hostname) //
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import javax.inject.Singleton;
|
|||||||
|
|
||||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemFactory;
|
import org.cryptomator.filesystem.crypto.CryptoFileSystemFactory;
|
||||||
import org.cryptomator.filesystem.shortening.ShorteningFileSystemFactory;
|
import org.cryptomator.filesystem.shortening.ShorteningFileSystemFactory;
|
||||||
import org.cryptomator.frontend.webdav.mount.WebDavMounter;
|
|
||||||
import org.cryptomator.ui.util.DeferredCloser;
|
import org.cryptomator.ui.util.DeferredCloser;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -26,7 +25,7 @@ public class VaultFactory {
|
|||||||
private final DeferredCloser closer;
|
private final DeferredCloser closer;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public VaultFactory(ShorteningFileSystemFactory shorteningFileSystemFactory, CryptoFileSystemFactory cryptoFileSystemFactory, WebDavMounter mounter, DeferredCloser closer) {
|
public VaultFactory(ShorteningFileSystemFactory shorteningFileSystemFactory, CryptoFileSystemFactory cryptoFileSystemFactory, DeferredCloser closer) {
|
||||||
this.shorteningFileSystemFactory = shorteningFileSystemFactory;
|
this.shorteningFileSystemFactory = shorteningFileSystemFactory;
|
||||||
this.cryptoFileSystemFactory = cryptoFileSystemFactory;
|
this.cryptoFileSystemFactory = cryptoFileSystemFactory;
|
||||||
this.closer = closer;
|
this.closer = closer;
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ import org.cryptomator.ui.model.Vault;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||||
|
|
||||||
@JsonPropertyOrder(value = {"directories", "checkForUpdatesEnabled", "port", "numTrayNotifications"})
|
@JsonPropertyOrder(value = {"directories", "checkForUpdatesEnabled", "port", "useIpv6", "numTrayNotifications"})
|
||||||
public class Settings implements Serializable {
|
public class Settings implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 7609959894417878744L;
|
private static final long serialVersionUID = 7609959894417878744L;
|
||||||
public static final int MIN_PORT = 1024;
|
public static final int MIN_PORT = 1024;
|
||||||
public static final int MAX_PORT = 65535;
|
public static final int MAX_PORT = 65535;
|
||||||
public static final int DEFAULT_PORT = 0;
|
public static final int DEFAULT_PORT = 0;
|
||||||
|
public static final boolean DEFAULT_USE_IPV6 = false;
|
||||||
public static final Integer DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
public static final Integer DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||||
|
|
||||||
@JsonProperty("directories")
|
@JsonProperty("directories")
|
||||||
@@ -34,6 +35,9 @@ public class Settings implements Serializable {
|
|||||||
|
|
||||||
@JsonProperty("port")
|
@JsonProperty("port")
|
||||||
private Integer port;
|
private Integer port;
|
||||||
|
|
||||||
|
@JsonProperty("useIpv6")
|
||||||
|
private Boolean useIpv6;
|
||||||
|
|
||||||
@JsonProperty("numTrayNotifications")
|
@JsonProperty("numTrayNotifications")
|
||||||
private Integer numTrayNotifications;
|
private Integer numTrayNotifications;
|
||||||
@@ -86,6 +90,14 @@ public class Settings implements Serializable {
|
|||||||
return port == DEFAULT_PORT || port >= MIN_PORT && port <= MAX_PORT;
|
return port == DEFAULT_PORT || port >= MIN_PORT && port <= MAX_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldUseIpv6() {
|
||||||
|
return useIpv6 == null ? DEFAULT_USE_IPV6 : useIpv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseIpv6(boolean useIpv6) {
|
||||||
|
this.useIpv6 = useIpv6;
|
||||||
|
}
|
||||||
|
|
||||||
public Integer getNumTrayNotifications() {
|
public Integer getNumTrayNotifications() {
|
||||||
return numTrayNotifications == null ? DEFAULT_NUM_TRAY_NOTIFICATIONS : numTrayNotifications;
|
return numTrayNotifications == null ? DEFAULT_NUM_TRAY_NOTIFICATIONS : numTrayNotifications;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,10 @@
|
|||||||
<!-- Row 1 -->
|
<!-- Row 1 -->
|
||||||
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%settings.port.label" cacheShape="true" cache="true" />
|
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%settings.port.label" cacheShape="true" cache="true" />
|
||||||
<TextField GridPane.rowIndex="1" GridPane.columnIndex="1" fx:id="portField" cacheShape="true" cache="true" promptText="%settings.port.prompt" />
|
<TextField GridPane.rowIndex="1" GridPane.columnIndex="1" fx:id="portField" cacheShape="true" cache="true" promptText="%settings.port.prompt" />
|
||||||
|
|
||||||
|
<!-- Row 2 -->
|
||||||
|
<Label GridPane.rowIndex="2" GridPane.columnIndex="0" text="%settings.useipv6.label" cacheShape="true" cache="true" />
|
||||||
|
<CheckBox GridPane.rowIndex="2" GridPane.columnIndex="1" fx:id="useIpv6Checkbox" cacheShape="true" cache="true" />
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
<Label VBox.vgrow="NEVER" text="%settings.requiresRestartLabel" alignment="CENTER" cacheShape="true" cache="true" />
|
<Label VBox.vgrow="NEVER" text="%settings.requiresRestartLabel" alignment="CENTER" cacheShape="true" cache="true" />
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ settings.version.label=Version %s
|
|||||||
settings.checkForUpdates.label=Check for updates
|
settings.checkForUpdates.label=Check for updates
|
||||||
settings.port.label=WebDAV Port *
|
settings.port.label=WebDAV Port *
|
||||||
settings.port.prompt=0 = Choose automatically
|
settings.port.prompt=0 = Choose automatically
|
||||||
|
settings.useipv6.label=Use IPv6 literal
|
||||||
settings.requiresRestartLabel=* Cryptomator needs to restart
|
settings.requiresRestartLabel=* Cryptomator needs to restart
|
||||||
|
|
||||||
# tray icon
|
# tray icon
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ settings.version.label=Version %s
|
|||||||
settings.checkForUpdates.label=Auf Updates prüfen
|
settings.checkForUpdates.label=Auf Updates prüfen
|
||||||
settings.port.label=WebDAV Port *
|
settings.port.label=WebDAV Port *
|
||||||
settings.port.prompt=0 = Automatisch wählen
|
settings.port.prompt=0 = Automatisch wählen
|
||||||
|
settings.useipv6.label=IPv6-Literal nutzen
|
||||||
settings.requiresRestartLabel=* benötigt Neustart von Cryptomator
|
settings.requiresRestartLabel=* benötigt Neustart von Cryptomator
|
||||||
|
|
||||||
# tray icon
|
# tray icon
|
||||||
|
|||||||
Reference in New Issue
Block a user