mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-19 17:16:53 -04:00
first compile-clean attempt to integrate the layered I/O subsystem with the existing UI
This commit is contained in:
@@ -2,12 +2,10 @@ package org.cryptomator.filesystem.crypto;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@Singleton
|
||||
@Component(modules = CryptoEngineModule.class)
|
||||
@Component(modules = CryptoFileSystemModule.class)
|
||||
interface CryptoFileSystemComponent {
|
||||
|
||||
CryptoFileSystemFactory cryptoFileSystemFactory();
|
||||
|
||||
@@ -5,6 +5,7 @@ import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.crypto.engine.Cryptor;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
import org.cryptomator.filesystem.blockaligned.BlockAlignedFileSystemFactory;
|
||||
@@ -24,7 +25,7 @@ public class CryptoFileSystemFactory {
|
||||
this.blockAlignedFileSystemFactory = blockAlignedFileSystemFactory;
|
||||
}
|
||||
|
||||
public FileSystem get(Folder root, CharSequence passphrase, CryptoFileSystemDelegate delegate) {
|
||||
public FileSystem get(Folder root, CharSequence passphrase, CryptoFileSystemDelegate delegate) throws InvalidPassphraseException {
|
||||
final FileSystem nameShorteningFs = shorteningFileSystemFactory.get(root);
|
||||
final FileSystem cryptoFs = new CryptoFileSystem(nameShorteningFs, cryptorProvider.get(), delegate, passphrase);
|
||||
return blockAlignedFileSystemFactory.get(cryptoFs);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.cryptomator.filesystem.crypto;
|
||||
|
||||
import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
|
||||
|
||||
import dagger.Module;
|
||||
|
||||
@Module(includes = CryptoEngineModule.class)
|
||||
public class CryptoFileSystemModule {
|
||||
|
||||
}
|
||||
1
main/frontend-api/.gitignore
vendored
Normal file
1
main/frontend-api/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target/
|
||||
27
main/frontend-api/pom.xml
Normal file
27
main/frontend-api/pom.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 2016 Sebastian Stenzel
|
||||
This file is licensed under the terms of the MIT license.
|
||||
See the LICENSE.txt file for more info.
|
||||
|
||||
Contributors:
|
||||
Sebastian Stenzel - initial API and implementation
|
||||
-->
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>0.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>frontend-api</artifactId>
|
||||
<name>Cryptomator frontend: API</name>
|
||||
<description>API for filesystem frontends</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>filesystem-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.cryptomator.frontend;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Frontend extends AutoCloseable {
|
||||
|
||||
public enum MountParam {
|
||||
MOUNT_NAME, WIN_DRIVE_LETTER
|
||||
}
|
||||
|
||||
boolean mount(Map<MountParam, Optional<String>> map);
|
||||
|
||||
void unmount();
|
||||
|
||||
void reveal();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.cryptomator.frontend;
|
||||
|
||||
public class FrontendCreationFailedException extends Exception {
|
||||
|
||||
public FrontendCreationFailedException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.cryptomator.frontend;
|
||||
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
|
||||
public interface FrontendFactory {
|
||||
|
||||
/**
|
||||
* Provides a new frontend to access the given folder.
|
||||
*
|
||||
* @param root Root resource accessible through this frontend.
|
||||
* @param uniqueName Name of the frontend, i.e. used to create subresources for the different frontends inside of a common virtual drive.
|
||||
* @return A new frontend
|
||||
* @throws FrontendCreationFailedException If creation was not possible.
|
||||
*/
|
||||
Frontend create(Folder root, String uniqueName) throws FrontendCreationFailedException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Sebastian Stenzel and others.
|
||||
* This file is licensed under the terms of the MIT license.
|
||||
* See the LICENSE.txt file for more info.
|
||||
*
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
/**
|
||||
* Provides frontends for {@link org.cryptomator.filesystem.FileSystem FileSystems}.
|
||||
*/
|
||||
package org.cryptomator.frontend;
|
||||
@@ -15,7 +15,7 @@
|
||||
<version>0.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>frontend-webdav</artifactId>
|
||||
<name>Jackrabbit-based WebDAV filesystem frontend</name>
|
||||
<name>Cryptomator frontend: WebDAV frontend</name>
|
||||
<description>Provides access via WebDAV to filesystems</description>
|
||||
|
||||
<properties>
|
||||
@@ -32,6 +32,10 @@
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>frontend-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackrabbit -->
|
||||
<dependency>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.webdav.server;
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cryptomator.frontend.Frontend;
|
||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.CommandFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.WebDavMount;
|
||||
import org.cryptomator.frontend.webdav.mount.WebDavMounterProvider;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
||||
class WebDavFrontend implements Frontend {
|
||||
|
||||
private final WebDavMounterProvider webdavMounterProvider;
|
||||
private final ServletContextHandler handler;
|
||||
private final URI uri;
|
||||
private WebDavMount mount;
|
||||
|
||||
public WebDavFrontend(WebDavMounterProvider webdavMounterProvider, ServletContextHandler handler, URI uri) throws FrontendCreationFailedException {
|
||||
this.webdavMounterProvider = webdavMounterProvider;
|
||||
this.handler = handler;
|
||||
this.uri = uri;
|
||||
try {
|
||||
handler.start();
|
||||
} catch (Exception e) {
|
||||
throw new FrontendCreationFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
unmount();
|
||||
handler.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mount(Map<MountParam, Optional<String>> mountParams) {
|
||||
try {
|
||||
mount = webdavMounterProvider.get().mount(uri, mountParams);
|
||||
return true;
|
||||
} catch (CommandFailedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmount() {
|
||||
if (mount != null) {
|
||||
try {
|
||||
mount.unmount();
|
||||
} catch (CommandFailedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal() {
|
||||
if (mount != null) {
|
||||
try {
|
||||
mount.reveal();
|
||||
} catch (CommandFailedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.webdav.server;
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -10,6 +10,10 @@ import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
import org.cryptomator.frontend.Frontend;
|
||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||
import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.frontend.webdav.mount.WebDavMounterProvider;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
@@ -21,7 +25,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Singleton
|
||||
public class WebDavServer {
|
||||
public class WebDavServer implements FrontendFactory {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebDavServer.class);
|
||||
private static final String LOCALHOST = SystemUtils.IS_OS_WINDOWS ? "::1" : "localhost";
|
||||
@@ -34,15 +38,17 @@ public class WebDavServer {
|
||||
private final ServerConnector localConnector;
|
||||
private final ContextHandlerCollection servletCollection;
|
||||
private final WebDavServletContextFactory servletContextFactory;
|
||||
private final WebDavMounterProvider webdavMounterProvider;
|
||||
|
||||
@Inject
|
||||
WebDavServer(WebDavServletContextFactory servletContextFactory) {
|
||||
WebDavServer(WebDavServletContextFactory servletContextFactory, WebDavMounterProvider webdavMounterProvider) {
|
||||
final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(MAX_PENDING_REQUESTS);
|
||||
final ThreadPool tp = new QueuedThreadPool(MAX_THREADS, MIN_THREADS, THREAD_IDLE_SECONDS, queue);
|
||||
this.server = new Server(tp);
|
||||
this.localConnector = new ServerConnector(server);
|
||||
this.servletCollection = new ContextHandlerCollection();
|
||||
this.servletContextFactory = servletContextFactory;
|
||||
this.webdavMounterProvider = webdavMounterProvider;
|
||||
|
||||
localConnector.setHost(LOCALHOST);
|
||||
server.setConnectors(new Connector[] {localConnector});
|
||||
@@ -82,17 +88,27 @@ public class WebDavServer {
|
||||
}
|
||||
}
|
||||
|
||||
public ServletContextHandler addServlet(Folder root, String contextPath) {
|
||||
// visible for testing
|
||||
ServletContextHandler addServlet(Folder root, URI contextRoot) {
|
||||
ServletContextHandler handler = servletContextFactory.create(contextRoot, root);
|
||||
servletCollection.addHandler(handler);
|
||||
servletCollection.mapContexts();
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frontend create(Folder root, String contextPath) throws FrontendCreationFailedException {
|
||||
if (!contextPath.startsWith("/")) {
|
||||
throw new IllegalArgumentException("contextPath must begin with '/'");
|
||||
}
|
||||
final URI uri;
|
||||
try {
|
||||
uri = new URI("http", null, LOCALHOST, getPort(), contextPath, null, null);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
ServletContextHandler handler = servletContextFactory.create(uri, root);
|
||||
servletCollection.addHandler(handler);
|
||||
servletCollection.mapContexts();
|
||||
return handler;
|
||||
final ServletContextHandler handler = addServlet(root, uri);
|
||||
return new WebDavFrontend(webdavMounterProvider, handler, uri);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.webdav.server;
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.EnumSet;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
abstract class AbstractWebDavMount implements WebDavMount {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
public class CommandFailedException extends Exception {
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
* Contributors:
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cryptomator.frontend.Frontend.MountParam;
|
||||
|
||||
/**
|
||||
* A WebDavMounter acting as fallback if no other mounter works.
|
||||
*
|
||||
@@ -8,7 +8,7 @@
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
* Mohit Raju - Added fallback schema-name "webdav" when opening file managers
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
@@ -18,13 +18,15 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.util.command.Script;
|
||||
import org.cryptomator.frontend.Frontend.MountParam;
|
||||
import org.cryptomator.frontend.webdav.mount.command.Script;
|
||||
|
||||
@Singleton
|
||||
final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy {
|
||||
|
||||
|
||||
@Inject
|
||||
LinuxGvfsWebDavMounter() {}
|
||||
LinuxGvfsWebDavMounter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldWork() {
|
||||
@@ -40,7 +42,7 @@ final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warmUp(int serverPort) {
|
||||
// no-op
|
||||
@@ -48,32 +50,29 @@ final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy {
|
||||
|
||||
@Override
|
||||
public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
|
||||
final Script mountScript = Script.fromLines(
|
||||
"set -x",
|
||||
"gvfs-mount \"dav:$DAV_SSP\"")
|
||||
.addEnv("DAV_SSP", uri.getRawSchemeSpecificPart());
|
||||
final Script mountScript = Script.fromLines("set -x", "gvfs-mount \"dav:$DAV_SSP\"").addEnv("DAV_SSP", uri.getRawSchemeSpecificPart());
|
||||
mountScript.execute();
|
||||
return new LinuxGvfsWebDavMount(uri);
|
||||
}
|
||||
|
||||
|
||||
private static class LinuxGvfsWebDavMount extends AbstractWebDavMount {
|
||||
private final URI webDavUri;
|
||||
private final Script testMountStillExistsScript;
|
||||
private final Script unmountScript;
|
||||
|
||||
|
||||
private LinuxGvfsWebDavMount(URI webDavUri) {
|
||||
this.webDavUri = webDavUri;
|
||||
this.testMountStillExistsScript = Script.fromLines("set -x", "test `gvfs-mount --list | grep \"$DAV_SSP\" | wc -l` -eq 1").addEnv("DAV_SSP", webDavUri.getRawSchemeSpecificPart());
|
||||
this.unmountScript = Script.fromLines("set -x", "gvfs-mount -u \"dav:$DAV_SSP\"").addEnv("DAV_SSP", webDavUri.getRawSchemeSpecificPart());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unmount() throws CommandFailedException {
|
||||
boolean mountStillExists;
|
||||
try {
|
||||
testMountStillExistsScript.execute();
|
||||
mountStillExists = true;
|
||||
} catch(CommandFailedException e) {
|
||||
} catch (CommandFailedException e) {
|
||||
mountStillExists = false;
|
||||
}
|
||||
// only attempt unmount if user didn't unmount manually:
|
||||
@@ -85,16 +84,16 @@ final class LinuxGvfsWebDavMounter implements WebDavMounterStrategy {
|
||||
@Override
|
||||
public void reveal() throws CommandFailedException {
|
||||
try {
|
||||
openMountWithWebdavUri("dav:"+webDavUri.getRawSchemeSpecificPart()).execute();
|
||||
openMountWithWebdavUri("dav:" + webDavUri.getRawSchemeSpecificPart()).execute();
|
||||
} catch (CommandFailedException exception) {
|
||||
openMountWithWebdavUri("webdav:"+webDavUri.getRawSchemeSpecificPart()).execute();
|
||||
openMountWithWebdavUri("webdav:" + webDavUri.getRawSchemeSpecificPart()).execute();
|
||||
}
|
||||
}
|
||||
|
||||
private Script openMountWithWebdavUri(String webdavUri){
|
||||
|
||||
private Script openMountWithWebdavUri(String webdavUri) {
|
||||
return Script.fromLines("set -x", "xdg-open \"$DAV_URI\"").addEnv("DAV_URI", webdavUri);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
* Sebastian Stenzel - initial API and implementation, strategy fine tuning
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
@@ -20,13 +20,15 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.util.command.Script;
|
||||
import org.cryptomator.frontend.Frontend.MountParam;
|
||||
import org.cryptomator.frontend.webdav.mount.command.Script;
|
||||
|
||||
@Singleton
|
||||
final class MacOsXWebDavMounter implements WebDavMounterStrategy {
|
||||
|
||||
|
||||
@Inject
|
||||
MacOsXWebDavMounter() {}
|
||||
MacOsXWebDavMounter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldWork() {
|
||||
@@ -43,31 +45,26 @@ final class MacOsXWebDavMounter implements WebDavMounterStrategy {
|
||||
final String mountName = mountParams.get(MountParam.MOUNT_NAME).orElseThrow(() -> {
|
||||
return new IllegalArgumentException("Missing mount parameter MOUNT_NAME.");
|
||||
});
|
||||
|
||||
|
||||
// we don't use the uri to derive a path, as it *could* be longer than 255 chars.
|
||||
final String path = "/Volumes/Cryptomator_" + UUID.randomUUID().toString();
|
||||
final Script mountScript = Script.fromLines(
|
||||
"mkdir \"$MOUNT_PATH\"",
|
||||
"mount_webdav -S -v $MOUNT_NAME \"$DAV_AUTHORITY$DAV_PATH\" \"$MOUNT_PATH\"")
|
||||
.addEnv("DAV_AUTHORITY", uri.getRawAuthority())
|
||||
.addEnv("DAV_PATH", uri.getRawPath())
|
||||
.addEnv("MOUNT_PATH", path)
|
||||
.addEnv("MOUNT_NAME", mountName);
|
||||
final Script mountScript = Script.fromLines("mkdir \"$MOUNT_PATH\"", "mount_webdav -S -v $MOUNT_NAME \"$DAV_AUTHORITY$DAV_PATH\" \"$MOUNT_PATH\"").addEnv("DAV_AUTHORITY", uri.getRawAuthority())
|
||||
.addEnv("DAV_PATH", uri.getRawPath()).addEnv("MOUNT_PATH", path).addEnv("MOUNT_NAME", mountName);
|
||||
mountScript.execute();
|
||||
return new MacWebDavMount(path);
|
||||
}
|
||||
|
||||
|
||||
private static class MacWebDavMount extends AbstractWebDavMount {
|
||||
private final String mountPath;
|
||||
private final Script revealScript;
|
||||
private final Script unmountScript;
|
||||
|
||||
|
||||
private MacWebDavMount(String mountPath) {
|
||||
this.mountPath = mountPath;
|
||||
this.revealScript = Script.fromLines("open \"$MOUNT_PATH\"").addEnv("MOUNT_PATH", mountPath);
|
||||
this.unmountScript = Script.fromLines("diskutil umount $MOUNT_PATH").addEnv("MOUNT_PATH", mountPath);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unmount() throws CommandFailedException {
|
||||
// only attempt unmount if user didn't unmount manually:
|
||||
@@ -80,7 +77,7 @@ final class MacOsXWebDavMounter implements WebDavMounterStrategy {
|
||||
public void reveal() throws CommandFailedException {
|
||||
revealScript.execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
@@ -6,7 +6,7 @@
|
||||
* Contributors:
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
/**
|
||||
* A mounted webdav share.
|
||||
@@ -7,15 +7,15 @@
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
* Markus Kreusch - Refactored to use strategy pattern
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cryptomator.frontend.Frontend.MountParam;
|
||||
|
||||
public interface WebDavMounter {
|
||||
|
||||
public static enum MountParam {MOUNT_NAME, WIN_DRIVE_LETTER}
|
||||
|
||||
/**
|
||||
* Tries to mount a given webdav share.
|
||||
@@ -7,16 +7,14 @@
|
||||
* Markus Kreusch - Refactored to use strategy pattern
|
||||
* Sebastian Stenzel - Refactored to use Guice provider, added warmup-phase for windows mounts.
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.webdav.WebDavServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -27,15 +25,12 @@ public class WebDavMounterProvider implements Provider<WebDavMounter> {
|
||||
private final WebDavMounterStrategy choosenStrategy;
|
||||
|
||||
@Inject
|
||||
public WebDavMounterProvider(WebDavServer server, ExecutorService executorService, MountStrategies availableStrategies) {
|
||||
public WebDavMounterProvider(MountStrategies availableStrategies) {
|
||||
this.choosenStrategy = getStrategyWhichShouldWork(availableStrategies);
|
||||
executorService.execute(() -> {
|
||||
this.choosenStrategy.warmUp(server.getPort());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebDavMounterStrategy get() {
|
||||
public WebDavMounter get() {
|
||||
return this.choosenStrategy;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
* Sebastian Stenzel - minor strategy fine tuning
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
/**
|
||||
* A strategy able to mount a webdav share and display it to the user.
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static java.util.stream.IntStream.rangeClosed;
|
||||
@@ -7,9 +7,9 @@
|
||||
* Sebastian Stenzel - initial API and implementation, strategy fine tuning
|
||||
* Markus Kreusch - Refactored WebDavMounter to use strategy pattern
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.mount;
|
||||
package org.cryptomator.frontend.webdav.mount;
|
||||
|
||||
import static org.cryptomator.ui.util.command.Script.fromLines;
|
||||
import static org.cryptomator.frontend.webdav.mount.command.Script.fromLines;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
@@ -23,8 +23,9 @@ import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.CharUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.util.command.CommandResult;
|
||||
import org.cryptomator.ui.util.command.Script;
|
||||
import org.cryptomator.frontend.Frontend.MountParam;
|
||||
import org.cryptomator.frontend.webdav.mount.command.CommandResult;
|
||||
import org.cryptomator.frontend.webdav.mount.command.Script;
|
||||
|
||||
/**
|
||||
* A {@link WebDavMounterStrategy} utilizing the "net use" command.
|
||||
@@ -38,7 +39,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
||||
private static final int MAX_MOUNT_ATTEMPTS = 8;
|
||||
private static final char AUTO_ASSIGN_DRIVE_LETTER = '*';
|
||||
private final WindowsDriveLetters driveLetters;
|
||||
|
||||
|
||||
@Inject
|
||||
WindowsWebDavMounter(WindowsDriveLetters driveLetters) {
|
||||
this.driveLetters = driveLetters;
|
||||
@@ -60,7 +61,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
||||
if (driveLetters.getOccupiedDriveLetters().contains(driveLetter)) {
|
||||
throw new CommandFailedException("Drive letter occupied.");
|
||||
}
|
||||
|
||||
|
||||
final String driveLetterStr = driveLetter.charValue() == AUTO_ASSIGN_DRIVE_LETTER ? CharUtils.toString(AUTO_ASSIGN_DRIVE_LETTER) : driveLetter + ":";
|
||||
final Script localhostMountScript = fromLines("net use %DRIVE_LETTER% \\\\localhost@%DAV_PORT%\\DavWWWRoot%DAV_UNC_PATH% /persistent:no");
|
||||
localhostMountScript.addEnv("DRIVE_LETTER", driveLetterStr);
|
||||
@@ -74,13 +75,14 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
||||
ipv6literaltMountScript.addEnv("DRIVE_LETTER", driveLetterStr);
|
||||
ipv6literaltMountScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
|
||||
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");
|
||||
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 bypassProxyAndRetryMount(Script localhostMountScript, Script ipv6literalMountScript, Script proxyBypassScript) throws CommandFailedException {
|
||||
CommandFailedException latestException = null;
|
||||
for (int i = 0; i < MAX_MOUNT_ATTEMPTS; i++) {
|
||||
@@ -109,18 +111,18 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
||||
throw new CommandFailedException("Failed to get a drive letter from net use output.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class WindowsWebDavMount extends AbstractWebDavMount {
|
||||
private final Character driveLetter;
|
||||
private final Script openExplorerScript;
|
||||
private final Script unmountScript;
|
||||
|
||||
|
||||
private WindowsWebDavMount(Character driveLetter) {
|
||||
this.driveLetter = driveLetter;
|
||||
this.openExplorerScript = fromLines("start explorer.exe " + driveLetter + ":");
|
||||
this.unmountScript = fromLines("net use " + driveLetter + ": /delete").addEnv("DRIVE_LETTER", Character.toString(driveLetter));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unmount() throws CommandFailedException {
|
||||
// only attempt unmount if user didn't unmount manually:
|
||||
@@ -133,7 +135,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
|
||||
public void reveal() throws CommandFailedException {
|
||||
openExplorerScript.execute();
|
||||
}
|
||||
|
||||
|
||||
private boolean isVolumeMounted() {
|
||||
return driveLetters.getOccupiedDriveLetters().contains(driveLetter);
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
* Markus Kreusch
|
||||
* Sebastian Stenzel - using Futures, lazy loading for out/err.
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.command;
|
||||
package org.cryptomator.frontend.webdav.mount.command;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.io.IOException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.CommandFailedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Markus Kreusch
|
||||
* Sebastian Stenzel - Refactoring
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.command;
|
||||
package org.cryptomator.frontend.webdav.mount.command;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.commons.lang3.SystemUtils.IS_OS_UNIX;
|
||||
@@ -24,7 +24,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.CommandFailedException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -6,7 +6,7 @@
|
||||
* Contributors:
|
||||
* Sebastian Stenzel
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.command;
|
||||
package org.cryptomator.frontend.webdav.mount.command;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -17,7 +17,7 @@ import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.CommandFailedException;
|
||||
|
||||
final class FutureCommandResult implements Future<CommandResult>, Runnable {
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
* Contributors:
|
||||
* Markus Kreusch
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.util.command;
|
||||
package org.cryptomator.frontend.webdav.mount.command;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.CommandFailedException;
|
||||
|
||||
public final class Script {
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.webdav.server;
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
|
||||
@@ -27,7 +28,7 @@ public class InMemoryWebDavServer {
|
||||
server.start();
|
||||
|
||||
FileSystem fileSystem = setupFilesystem();
|
||||
ServletContextHandler servlet = server.addServlet(fileSystem, "/foo");
|
||||
ServletContextHandler servlet = server.addServlet(fileSystem, URI.create("http://localhost:8080/foo"));
|
||||
servlet.addFilter(LoggingHttpFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
servlet.start();
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.webdav.server;
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -36,7 +37,7 @@ public class NioWebDavServer {
|
||||
server.start();
|
||||
|
||||
FileSystem fileSystem = setupFilesystem();
|
||||
ServletContextHandler servlet = server.addServlet(fileSystem, "/foo");
|
||||
ServletContextHandler servlet = server.addServlet(fileSystem, URI.create("http://localhost:8080/foo"));
|
||||
servlet.addFilter(LoggingHttpFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
servlet.start();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package org.cryptomator.webdav.server;
|
||||
package org.cryptomator.frontend.webdav;
|
||||
|
||||
import static org.hamcrest.collection.IsArrayContaining.hasItemInArray;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@@ -49,7 +50,7 @@ public class WebDavServerTest {
|
||||
@Before
|
||||
public void startServlet() throws Exception {
|
||||
fs = new InMemoryFileSystem();
|
||||
servlet = SERVER.addServlet(fs, "/test");
|
||||
servlet = SERVER.addServlet(fs, URI.create("http://localhost:" + SERVER.getPort() + "/test"));
|
||||
servlet.start();
|
||||
servletRoot = "http://localhost:" + SERVER.getPort() + "/test";
|
||||
}
|
||||
43
main/pom.xml
43
main/pom.xml
@@ -52,19 +52,18 @@
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- modules -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons-test</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>filesystem-api</artifactId>
|
||||
@@ -91,22 +90,18 @@
|
||||
<artifactId>filesystem-crypto</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>frontend-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>frontend-webdav</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>crypto-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>crypto-aes</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>ui</artifactId>
|
||||
@@ -259,10 +254,8 @@
|
||||
<module>filesystem-nameshortening</module>
|
||||
<module>filesystem-crypto</module>
|
||||
<module>filesystem-invariants-tests</module>
|
||||
<module>frontend-api</module>
|
||||
<module>frontend-webdav</module>
|
||||
<module>crypto-api</module>
|
||||
<module>crypto-aes</module>
|
||||
<module>core</module>
|
||||
<module>ui</module>
|
||||
</modules>
|
||||
|
||||
|
||||
@@ -20,11 +20,23 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<artifactId>filesystem-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>crypto-aes</artifactId>
|
||||
<artifactId>filesystem-nio</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>filesystem-crypto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>frontend-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>frontend-webdav</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON -->
|
||||
|
||||
@@ -7,18 +7,17 @@ import java.util.concurrent.Executors;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.crypto.Cryptor;
|
||||
import org.cryptomator.crypto.SamplingCryptorDecorator;
|
||||
import org.cryptomator.crypto.aes256.CryptoModule;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemModule;
|
||||
import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.frontend.webdav.WebDavServer;
|
||||
import org.cryptomator.frontend.webdav.mount.WebDavMounter;
|
||||
import org.cryptomator.frontend.webdav.mount.WebDavMounterProvider;
|
||||
import org.cryptomator.ui.model.VaultObjectMapperProvider;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.cryptomator.ui.settings.SettingsProvider;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
import org.cryptomator.ui.util.DeferredCloser.Closer;
|
||||
import org.cryptomator.ui.util.SemVerComparator;
|
||||
import org.cryptomator.ui.util.mount.WebDavMounter;
|
||||
import org.cryptomator.ui.util.mount.WebDavMounterProvider;
|
||||
import org.cryptomator.webdav.WebDavServer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@@ -26,7 +25,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import javafx.application.Application;
|
||||
|
||||
@Module(includes = CryptoModule.class)
|
||||
@Module(includes = CryptoFileSystemModule.class)
|
||||
class CryptomatorModule {
|
||||
|
||||
private final Application application;
|
||||
@@ -83,18 +82,11 @@ class CryptomatorModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
WebDavServer provideWebDavServer() {
|
||||
final WebDavServer webDavServer = new WebDavServer();
|
||||
FrontendFactory provideFrontendFactory(WebDavServer webDavServer) {
|
||||
webDavServer.start();
|
||||
return closeLater(webDavServer, WebDavServer::stop);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("SamplingCryptor")
|
||||
Cryptor provideCryptor(Cryptor cryptor) {
|
||||
return SamplingCryptorDecorator.decorate(cryptor);
|
||||
}
|
||||
|
||||
private <T> T closeLater(T object, Closer<T> closer) {
|
||||
return deferredCloser.closeLater(object, closer).get().get();
|
||||
}
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.crypto.exceptions.UnsupportedKeyLengthException;
|
||||
import org.cryptomator.crypto.exceptions.UnsupportedVaultException;
|
||||
import org.cryptomator.crypto.exceptions.WrongPasswordException;
|
||||
import org.cryptomator.ui.controls.SecPasswordField;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -107,75 +96,80 @@ public class ChangePasswordController extends AbstractFXMLViewController {
|
||||
|
||||
@FXML
|
||||
private void didClickChangePasswordButton(ActionEvent event) {
|
||||
downloadsPageLink.setVisible(false);
|
||||
final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
|
||||
final Path masterKeyBackupPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_BACKUP_FILE);
|
||||
|
||||
// decrypt with old password:
|
||||
final CharSequence oldPassword = oldPasswordField.getCharacters();
|
||||
try (final InputStream masterKeyInputStream = Files.newInputStream(masterKeyPath, StandardOpenOption.READ)) {
|
||||
vault.getCryptor().decryptMasterKey(masterKeyInputStream, oldPassword);
|
||||
Files.copy(masterKeyPath, masterKeyBackupPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException ex) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.decryptionFailed"));
|
||||
LOG.error("Decryption failed for technical reasons.", ex);
|
||||
newPasswordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
return;
|
||||
} catch (WrongPasswordException e) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.wrongPassword"));
|
||||
newPasswordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
Platform.runLater(oldPasswordField::requestFocus);
|
||||
return;
|
||||
} catch (UnsupportedKeyLengthException ex) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedKeyLengthInstallJCE"));
|
||||
LOG.warn("Unsupported Key-Length. Please install Oracle Java Cryptography Extension (JCE).", ex);
|
||||
newPasswordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
return;
|
||||
} catch (UnsupportedVaultException e) {
|
||||
downloadsPageLink.setVisible(true);
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
} else if (e.isSoftwareOlderThanVault()) {
|
||||
messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
}
|
||||
newPasswordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
return;
|
||||
} finally {
|
||||
oldPasswordField.swipe();
|
||||
}
|
||||
|
||||
// when we reach this line, decryption was successful.
|
||||
|
||||
// encrypt with new password:
|
||||
final CharSequence newPassword = newPasswordField.getCharacters();
|
||||
try (final OutputStream masterKeyOutputStream = Files.newOutputStream(masterKeyPath, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC)) {
|
||||
vault.getCryptor().encryptMasterKey(masterKeyOutputStream, newPassword);
|
||||
messageText.setText(resourceBundle.getString("changePassword.infoMessage.success"));
|
||||
Platform.runLater(this::didChangePassword);
|
||||
// At this point the backup is still using the old password.
|
||||
// It will be changed as soon as the user unlocks the vault the next time.
|
||||
// This way he can still restore the old password, if he doesn't remember the new one.
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Re-encryption failed for technical reasons. Restoring Backup.", ex);
|
||||
this.restoreBackupQuietly();
|
||||
} finally {
|
||||
newPasswordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
}
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
/*
|
||||
* downloadsPageLink.setVisible(false);
|
||||
* final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
|
||||
* final Path masterKeyBackupPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_BACKUP_FILE);
|
||||
*
|
||||
* // decrypt with old password:
|
||||
* final CharSequence oldPassword = oldPasswordField.getCharacters();
|
||||
* try (final InputStream masterKeyInputStream = Files.newInputStream(masterKeyPath, StandardOpenOption.READ)) {
|
||||
* vault.getCryptor().decryptMasterKey(masterKeyInputStream, oldPassword);
|
||||
* Files.copy(masterKeyPath, masterKeyBackupPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
* } catch (IOException ex) {
|
||||
* messageText.setText(resourceBundle.getString("changePassword.errorMessage.decryptionFailed"));
|
||||
* LOG.error("Decryption failed for technical reasons.", ex);
|
||||
* newPasswordField.swipe();
|
||||
* retypePasswordField.swipe();
|
||||
* return;
|
||||
* } catch (WrongPasswordException e) {
|
||||
* messageText.setText(resourceBundle.getString("changePassword.errorMessage.wrongPassword"));
|
||||
* newPasswordField.swipe();
|
||||
* retypePasswordField.swipe();
|
||||
* Platform.runLater(oldPasswordField::requestFocus);
|
||||
* return;
|
||||
* } catch (UnsupportedKeyLengthException ex) {
|
||||
* messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedKeyLengthInstallJCE"));
|
||||
* LOG.warn("Unsupported Key-Length. Please install Oracle Java Cryptography Extension (JCE).", ex);
|
||||
* newPasswordField.swipe();
|
||||
* retypePasswordField.swipe();
|
||||
* return;
|
||||
* } catch (UnsupportedVaultException e) {
|
||||
* downloadsPageLink.setVisible(true);
|
||||
* if (e.isVaultOlderThanSoftware()) {
|
||||
* messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
* } else if (e.isSoftwareOlderThanVault()) {
|
||||
* messageText.setText(resourceBundle.getString("changePassword.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
* }
|
||||
* newPasswordField.swipe();
|
||||
* retypePasswordField.swipe();
|
||||
* return;
|
||||
* } finally {
|
||||
* oldPasswordField.swipe();
|
||||
* }
|
||||
*
|
||||
* // when we reach this line, decryption was successful.
|
||||
*
|
||||
* // encrypt with new password:
|
||||
* final CharSequence newPassword = newPasswordField.getCharacters();
|
||||
* try (final OutputStream masterKeyOutputStream = Files.newOutputStream(masterKeyPath, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC)) {
|
||||
* vault.getCryptor().encryptMasterKey(masterKeyOutputStream, newPassword);
|
||||
* messageText.setText(resourceBundle.getString("changePassword.infoMessage.success"));
|
||||
* Platform.runLater(this::didChangePassword);
|
||||
* // At this point the backup is still using the old password.
|
||||
* // It will be changed as soon as the user unlocks the vault the next time.
|
||||
* // This way he can still restore the old password, if he doesn't remember the new one.
|
||||
* } catch (IOException ex) {
|
||||
* LOG.error("Re-encryption failed for technical reasons. Restoring Backup.", ex);
|
||||
* this.restoreBackupQuietly();
|
||||
* } finally {
|
||||
* newPasswordField.swipe();
|
||||
* retypePasswordField.swipe();
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
private void restoreBackupQuietly() {
|
||||
final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
|
||||
final Path masterKeyBackupPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_BACKUP_FILE);
|
||||
try {
|
||||
Files.copy(masterKeyBackupPath, masterKeyPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Restoring Backup failed.", ex);
|
||||
}
|
||||
/*
|
||||
* final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
|
||||
* final Path masterKeyBackupPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_BACKUP_FILE);
|
||||
* try {
|
||||
* Files.copy(masterKeyBackupPath, masterKeyPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
* } catch (IOException ex) {
|
||||
* LOG.error("Restoring Backup failed.", ex);
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
private void didChangePassword() {
|
||||
|
||||
@@ -9,14 +9,8 @@
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -90,23 +84,11 @@ public class InitializeController extends AbstractFXMLViewController {
|
||||
@FXML
|
||||
protected void initializeVault(ActionEvent event) {
|
||||
setControlsDisabled(true);
|
||||
final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
|
||||
final CharSequence password = passwordField.getCharacters();
|
||||
try (OutputStream masterKeyOutputStream = Files.newOutputStream(masterKeyPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)) {
|
||||
vault.getCryptor().randomizeMasterKey();
|
||||
vault.getCryptor().encryptMasterKey(masterKeyOutputStream, password);
|
||||
final String dataRootDir = vault.getCryptor().encryptDirectoryPath("", FileSystems.getDefault().getSeparator());
|
||||
final Path dataRootPath = vault.getPath().resolve("d").resolve(dataRootDir);
|
||||
final Path metadataPath = vault.getPath().resolve("m");
|
||||
Files.createDirectories(dataRootPath);
|
||||
Files.createDirectories(metadataPath);
|
||||
if (listener != null) {
|
||||
listener.didInitialize(this);
|
||||
}
|
||||
final CharSequence passphrase = passwordField.getCharacters();
|
||||
try {
|
||||
vault.create(passphrase);
|
||||
} catch (FileAlreadyExistsException ex) {
|
||||
messageLabel.setText(resourceBundle.getString("initialize.messageLabel.alreadyInitialized"));
|
||||
} catch (InvalidPathException ex) {
|
||||
messageLabel.setText(resourceBundle.getString("initialize.messageLabel.invalidPath"));
|
||||
} catch (IOException ex) {
|
||||
LOG.error("I/O Exception", ex);
|
||||
} finally {
|
||||
|
||||
@@ -8,31 +8,22 @@
|
||||
******************************************************************************/
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Comparator;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
|
||||
import org.apache.commons.lang3.CharUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.crypto.exceptions.UnsupportedKeyLengthException;
|
||||
import org.cryptomator.crypto.exceptions.UnsupportedVaultException;
|
||||
import org.cryptomator.crypto.exceptions.WrongPasswordException;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.WindowsDriveLetters;
|
||||
import org.cryptomator.ui.controls.SecPasswordField;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.util.FXThreads;
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
import org.cryptomator.ui.util.mount.WindowsDriveLetters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -258,49 +249,30 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
setControlsDisabled(true);
|
||||
progressIndicator.setVisible(true);
|
||||
downloadsPageLink.setVisible(false);
|
||||
final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
|
||||
final Path masterKeyBackupPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_BACKUP_FILE);
|
||||
final CharSequence password = passwordField.getCharacters();
|
||||
try (final InputStream masterKeyInputStream = Files.newInputStream(masterKeyPath, StandardOpenOption.READ)) {
|
||||
vault.getCryptor().decryptMasterKey(masterKeyInputStream, password);
|
||||
if (!vault.startServer()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.messageLabel.startServerFailed"));
|
||||
vault.getCryptor().destroy();
|
||||
return;
|
||||
}
|
||||
// at this point we know for sure, that the masterkey can be decrypted, so lets make a backup:
|
||||
Files.copy(masterKeyPath, masterKeyBackupPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
vault.setUnlocked(true);
|
||||
final Future<Boolean> futureMount = exec.submit(vault::mount);
|
||||
try {
|
||||
vault.activateFrontend(password);
|
||||
Future<Boolean> futureMount = exec.submit(vault::mount);
|
||||
FXThreads.runOnMainThreadWhenFinished(exec, futureMount, this::unlockAndMountFinished);
|
||||
} catch (IOException ex) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.decryptionFailed"));
|
||||
LOG.error("Decryption failed for technical reasons.", ex);
|
||||
} catch (WrongPasswordException e) {
|
||||
} catch (InvalidPassphraseException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.wrongPassword"));
|
||||
Platform.runLater(passwordField::requestFocus);
|
||||
} catch (UnsupportedKeyLengthException ex) {
|
||||
} catch (FrontendCreationFailedException ex) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedKeyLengthInstallJCE"));
|
||||
LOG.warn("Unsupported Key-Length. Please install Oracle Java Cryptography Extension (JCE).", ex);
|
||||
} catch (UnsupportedVaultException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
downloadsPageLink.setVisible(true);
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
} else if (e.isSoftwareOlderThanVault()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
}
|
||||
} catch (DestroyFailedException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
LOG.error("Destruction of cryptor threw an exception.", e);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.decryptionFailed"));
|
||||
LOG.error("Decryption failed for technical reasons.", ex);
|
||||
// } catch (UnsupportedVaultException e) {
|
||||
// setControlsDisabled(false);
|
||||
// progressIndicator.setVisible(false);
|
||||
// downloadsPageLink.setVisible(true);
|
||||
// if (e.isVaultOlderThanSoftware()) {
|
||||
// messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
// } else if (e.isSoftwareOlderThanVault()) {
|
||||
// messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
// }
|
||||
} finally {
|
||||
passwordField.swipe();
|
||||
}
|
||||
@@ -317,18 +289,9 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
progressIndicator.setVisible(false);
|
||||
setControlsDisabled(false);
|
||||
if (vault.isUnlocked() && !mountSuccess) {
|
||||
exec.submit(() -> {
|
||||
vault.stopServer();
|
||||
vault.setUnlocked(false);
|
||||
});
|
||||
exec.submit(vault::deactivateFrontend);
|
||||
} else if (vault.isUnlocked() && mountSuccess) {
|
||||
exec.submit(() -> {
|
||||
try {
|
||||
vault.reveal();
|
||||
} catch (CommandFailedException e) {
|
||||
LOG.error("Failed to reveal mounted vault", e);
|
||||
}
|
||||
});
|
||||
exec.submit(vault::reveal);
|
||||
}
|
||||
if (mountSuccess && listener != null) {
|
||||
listener.didUnlock(this);
|
||||
|
||||
@@ -15,10 +15,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.cryptomator.crypto.CryptorIOSampling;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
|
||||
import javafx.animation.Animation;
|
||||
import javafx.animation.KeyFrame;
|
||||
@@ -30,7 +28,6 @@ import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart.Data;
|
||||
import javafx.scene.chart.XYChart.Series;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.stage.Stage;
|
||||
@@ -81,30 +78,21 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
|
||||
@FXML
|
||||
private void didClickRevealVault(ActionEvent event) {
|
||||
exec.submit(() -> {
|
||||
try {
|
||||
vault.reveal();
|
||||
} catch (CommandFailedException e) {
|
||||
Platform.runLater(() -> {
|
||||
messageLabel.setText(resourceBundle.getString("unlocked.label.revealFailed"));
|
||||
});
|
||||
}
|
||||
});
|
||||
exec.submit(vault::reveal);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void didClickCloseVault(ActionEvent event) {
|
||||
exec.submit(() -> {
|
||||
try {
|
||||
vault.unmount();
|
||||
} catch (CommandFailedException e) {
|
||||
Platform.runLater(() -> {
|
||||
messageLabel.setText(resourceBundle.getString("unlocked.label.unmountFailed"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
vault.stopServer();
|
||||
vault.setUnlocked(false);
|
||||
// try {
|
||||
vault.unmount();
|
||||
// } catch (CommandFailedException e) {
|
||||
// Platform.runLater(() -> {
|
||||
// messageLabel.setText(resourceBundle.getString("unlocked.label.unmountFailed"));
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
vault.deactivateFrontend();
|
||||
if (listener != null) {
|
||||
Platform.runLater(() -> {
|
||||
listener.didLock(this);
|
||||
@@ -129,7 +117,7 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
// IO Graph
|
||||
// ****************************************
|
||||
|
||||
private void startIoSampling(final CryptorIOSampling sampler) {
|
||||
private void startIoSampling(final Object sampler) {
|
||||
final Series<Number, Number> decryptedBytes = new Series<>();
|
||||
decryptedBytes.setName("decrypted");
|
||||
final Series<Number, Number> encryptedBytes = new Series<>();
|
||||
@@ -156,14 +144,14 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
private static final double BYTES_TO_MEGABYTES_FACTOR = 1.0 / IO_SAMPLING_INTERVAL / 1024.0 / 1024.0;
|
||||
private static final double SMOOTHING_FACTOR = 0.3;
|
||||
private static final long EFFECTIVELY_ZERO = 100000; // 100kb
|
||||
private final CryptorIOSampling sampler;
|
||||
private final Object sampler;
|
||||
private final Series<Number, Number> decryptedBytes;
|
||||
private final Series<Number, Number> encryptedBytes;
|
||||
private int step = 0;
|
||||
private long oldDecBytes = 0;
|
||||
private long oldEncBytes = 0;
|
||||
private final int step = 0;
|
||||
private final long oldDecBytes = 0;
|
||||
private final long oldEncBytes = 0;
|
||||
|
||||
public IoSamplingAnimationHandler(CryptorIOSampling sampler, Series<Number, Number> decryptedBytes, Series<Number, Number> encryptedBytes) {
|
||||
public IoSamplingAnimationHandler(Object sampler, Series<Number, Number> decryptedBytes, Series<Number, Number> encryptedBytes) {
|
||||
this.sampler = sampler;
|
||||
this.decryptedBytes = decryptedBytes;
|
||||
this.encryptedBytes = encryptedBytes;
|
||||
@@ -171,28 +159,30 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
step++;
|
||||
|
||||
final long decBytes = sampler.pollDecryptedBytes(true);
|
||||
final double smoothedDecBytes = oldDecBytes + SMOOTHING_FACTOR * (decBytes - oldDecBytes);
|
||||
final double smoothedDecMb = smoothedDecBytes * BYTES_TO_MEGABYTES_FACTOR;
|
||||
oldDecBytes = smoothedDecBytes > EFFECTIVELY_ZERO ? (long) smoothedDecBytes : 0l;
|
||||
decryptedBytes.getData().add(new Data<Number, Number>(step, smoothedDecMb));
|
||||
if (decryptedBytes.getData().size() > IO_SAMPLING_STEPS) {
|
||||
decryptedBytes.getData().remove(0);
|
||||
}
|
||||
|
||||
final long encBytes = sampler.pollEncryptedBytes(true);
|
||||
final double smoothedEncBytes = oldEncBytes + SMOOTHING_FACTOR * (encBytes - oldEncBytes);
|
||||
final double smoothedEncMb = smoothedEncBytes * BYTES_TO_MEGABYTES_FACTOR;
|
||||
oldEncBytes = smoothedEncBytes > EFFECTIVELY_ZERO ? (long) smoothedEncBytes : 0l;
|
||||
encryptedBytes.getData().add(new Data<Number, Number>(step, smoothedEncMb));
|
||||
if (encryptedBytes.getData().size() > IO_SAMPLING_STEPS) {
|
||||
encryptedBytes.getData().remove(0);
|
||||
}
|
||||
|
||||
xAxis.setLowerBound(step - IO_SAMPLING_STEPS);
|
||||
xAxis.setUpperBound(step);
|
||||
/*
|
||||
* step++;
|
||||
*
|
||||
* final long decBytes = sampler.pollDecryptedBytes(true);
|
||||
* final double smoothedDecBytes = oldDecBytes + SMOOTHING_FACTOR * (decBytes - oldDecBytes);
|
||||
* final double smoothedDecMb = smoothedDecBytes * BYTES_TO_MEGABYTES_FACTOR;
|
||||
* oldDecBytes = smoothedDecBytes > EFFECTIVELY_ZERO ? (long) smoothedDecBytes : 0l;
|
||||
* decryptedBytes.getData().add(new Data<Number, Number>(step, smoothedDecMb));
|
||||
* if (decryptedBytes.getData().size() > IO_SAMPLING_STEPS) {
|
||||
* decryptedBytes.getData().remove(0);
|
||||
* }
|
||||
*
|
||||
* final long encBytes = sampler.pollEncryptedBytes(true);
|
||||
* final double smoothedEncBytes = oldEncBytes + SMOOTHING_FACTOR * (encBytes - oldEncBytes);
|
||||
* final double smoothedEncMb = smoothedEncBytes * BYTES_TO_MEGABYTES_FACTOR;
|
||||
* oldEncBytes = smoothedEncBytes > EFFECTIVELY_ZERO ? (long) smoothedEncBytes : 0l;
|
||||
* encryptedBytes.getData().add(new Data<Number, Number>(step, smoothedEncMb));
|
||||
* if (encryptedBytes.getData().size() > IO_SAMPLING_STEPS) {
|
||||
* encryptedBytes.getData().remove(0);
|
||||
* }
|
||||
*
|
||||
* xAxis.setLowerBound(step - IO_SAMPLING_STEPS);
|
||||
* xAxis.setUpperBound(step);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,12 +206,14 @@ public class UnlockedController extends AbstractFXMLViewController {
|
||||
});
|
||||
|
||||
// sample crypto-throughput:
|
||||
stopIoSampling();
|
||||
if (vault.getCryptor() instanceof CryptorIOSampling) {
|
||||
startIoSampling((CryptorIOSampling) vault.getCryptor());
|
||||
} else {
|
||||
ioGraph.setVisible(false);
|
||||
}
|
||||
/*
|
||||
* stopIoSampling();
|
||||
* if (vault.getCryptor() instanceof CryptorIOSampling) {
|
||||
* startIoSampling((CryptorIOSampling) vault.getCryptor());
|
||||
* } else {
|
||||
* ioGraph.setVisible(false);
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
public LockListener getListener() {
|
||||
|
||||
@@ -2,6 +2,8 @@ package org.cryptomator.ui.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.Normalizer;
|
||||
@@ -11,62 +13,58 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
|
||||
import org.apache.commons.lang3.CharUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cryptomator.crypto.Cryptor;
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemDelegate;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemFactory;
|
||||
import org.cryptomator.filesystem.nio.NioFileSystem;
|
||||
import org.cryptomator.frontend.Frontend;
|
||||
import org.cryptomator.frontend.Frontend.MountParam;
|
||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||
import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.ui.util.DeferredClosable;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
import org.cryptomator.ui.util.FXThreads;
|
||||
import org.cryptomator.ui.util.mount.CommandFailedException;
|
||||
import org.cryptomator.ui.util.mount.WebDavMount;
|
||||
import org.cryptomator.ui.util.mount.WebDavMounter;
|
||||
import org.cryptomator.ui.util.mount.WebDavMounter.MountParam;
|
||||
import org.cryptomator.webdav.WebDavServer;
|
||||
import org.cryptomator.webdav.WebDavServer.ServletLifeCycleAdapter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import dagger.Lazy;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
public class Vault implements Serializable {
|
||||
public class Vault implements Serializable, CryptoFileSystemDelegate {
|
||||
|
||||
private static final long serialVersionUID = 3754487289683599469L;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Vault.class);
|
||||
|
||||
@Deprecated
|
||||
public static final String VAULT_FILE_EXTENSION = ".cryptomator";
|
||||
|
||||
@Deprecated
|
||||
public static final String VAULT_MASTERKEY_FILE = "masterkey.cryptomator";
|
||||
public static final String VAULT_MASTERKEY_BACKUP_FILE = "masterkey.cryptomator.bkup";
|
||||
|
||||
private final Path path;
|
||||
private final WebDavServer server;
|
||||
private final Cryptor cryptor;
|
||||
private final WebDavMounter mounter;
|
||||
private final Lazy<FrontendFactory> frontendFactory;
|
||||
private final DeferredCloser closer;
|
||||
private final CryptoFileSystemFactory cryptoFileSystemFactory;
|
||||
private final ObjectProperty<Boolean> unlocked = new SimpleObjectProperty<Boolean>(this, "unlocked", Boolean.FALSE);
|
||||
private final ObservableList<String> namesOfResourcesWithInvalidMac = FXThreads.observableListOnMainThread(FXCollections.observableArrayList());
|
||||
private final Set<String> whitelistedResourcesWithInvalidMac = new HashSet<>();
|
||||
|
||||
private String mountName;
|
||||
private Character winDriveLetter;
|
||||
private DeferredClosable<ServletLifeCycleAdapter> webDavServlet = DeferredClosable.empty();
|
||||
private DeferredClosable<WebDavMount> webDavMount = DeferredClosable.empty();
|
||||
private DeferredClosable<Frontend> filesystemFrontend = DeferredClosable.empty();
|
||||
|
||||
/**
|
||||
* Package private constructor, use {@link VaultFactory}.
|
||||
*/
|
||||
Vault(final Path vaultDirectoryPath, final WebDavServer server, final Cryptor cryptor, final WebDavMounter mounter, final DeferredCloser closer) {
|
||||
Vault(Path vaultDirectoryPath, Lazy<FrontendFactory> frontendFactory, CryptoFileSystemFactory cryptoFileSystemFactory, DeferredCloser closer) {
|
||||
this.path = vaultDirectoryPath;
|
||||
this.server = server;
|
||||
this.cryptor = cryptor;
|
||||
this.mounter = mounter;
|
||||
this.frontendFactory = frontendFactory;
|
||||
this.closer = closer;
|
||||
this.cryptoFileSystemFactory = cryptoFileSystemFactory;
|
||||
|
||||
try {
|
||||
setMountName(getName());
|
||||
@@ -84,35 +82,34 @@ public class Vault implements Serializable {
|
||||
return Files.isRegularFile(masterKeyPath);
|
||||
}
|
||||
|
||||
public synchronized boolean startServer() {
|
||||
namesOfResourcesWithInvalidMac.clear();
|
||||
whitelistedResourcesWithInvalidMac.clear();
|
||||
Optional<ServletLifeCycleAdapter> o = webDavServlet.get();
|
||||
if (o.isPresent() && o.get().isRunning()) {
|
||||
return false;
|
||||
public void create(CharSequence passphrase) throws IOException {
|
||||
try {
|
||||
FileSystem fs = NioFileSystem.rootedAt(path);
|
||||
if (fs.children().count() > 0) {
|
||||
throw new FileAlreadyExistsException(null, null, "Vault location not empty.");
|
||||
}
|
||||
cryptoFileSystemFactory.get(fs, passphrase, this);
|
||||
} catch (UncheckedIOException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
ServletLifeCycleAdapter servlet = server.createServlet(path, cryptor, namesOfResourcesWithInvalidMac, whitelistedResourcesWithInvalidMac, mountName);
|
||||
if (servlet.start()) {
|
||||
webDavServlet = closer.closeLater(servlet);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
public synchronized void activateFrontend(CharSequence passphrase) throws FrontendCreationFailedException {
|
||||
try {
|
||||
unmount();
|
||||
} catch (CommandFailedException e) {
|
||||
LOG.warn("Unmounting failed. Locking anyway...", e);
|
||||
FileSystem fs = NioFileSystem.rootedAt(path);
|
||||
FileSystem cryptoFs = cryptoFileSystemFactory.get(fs, passphrase, this);
|
||||
String contextPath = StringUtils.prependIfMissing(mountName, "/");
|
||||
Frontend frontend = frontendFactory.get().create(cryptoFs, contextPath);
|
||||
filesystemFrontend = closer.closeLater(frontend);
|
||||
setUnlocked(true);
|
||||
} catch (UncheckedIOException e) {
|
||||
throw new FrontendCreationFailedException(e);
|
||||
}
|
||||
webDavServlet.close();
|
||||
try {
|
||||
cryptor.destroy();
|
||||
} catch (DestroyFailedException e) {
|
||||
LOG.error("Destruction of cryptor throw an exception.", e);
|
||||
}
|
||||
whitelistedResourcesWithInvalidMac.clear();
|
||||
namesOfResourcesWithInvalidMac.clear();
|
||||
}
|
||||
|
||||
public synchronized void deactivateFrontend() {
|
||||
filesystemFrontend.close();
|
||||
setUnlocked(false);
|
||||
}
|
||||
|
||||
private Map<MountParam, Optional<String>> getMountParams() {
|
||||
@@ -123,32 +120,35 @@ public class Vault implements Serializable {
|
||||
}
|
||||
|
||||
public Boolean mount() {
|
||||
final ServletLifeCycleAdapter servlet = webDavServlet.get().orElse(null);
|
||||
if (servlet == null || !servlet.isRunning()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
webDavMount = closer.closeLater(mounter.mount(servlet.getServletUri(), getMountParams()));
|
||||
return true;
|
||||
} catch (CommandFailedException e) {
|
||||
LOG.warn("mount failed", e);
|
||||
// TODO exception handling
|
||||
Frontend frontend = filesystemFrontend.get().orElse(null);
|
||||
if (frontend == null) {
|
||||
return false;
|
||||
} else {
|
||||
return frontend.mount(getMountParams());
|
||||
}
|
||||
}
|
||||
|
||||
public void reveal() throws CommandFailedException {
|
||||
final WebDavMount mnt = webDavMount.get().orElse(null);
|
||||
if (mnt != null) {
|
||||
mnt.reveal();
|
||||
}
|
||||
public void reveal() {
|
||||
// TODO exception handling
|
||||
filesystemFrontend.get().ifPresent(Frontend::reveal);
|
||||
}
|
||||
|
||||
public void unmount() throws CommandFailedException {
|
||||
final WebDavMount mnt = webDavMount.get().orElse(null);
|
||||
if (mnt != null) {
|
||||
mnt.unmount();
|
||||
}
|
||||
webDavMount = DeferredClosable.empty();
|
||||
public void unmount() {
|
||||
// TODO exception handling
|
||||
filesystemFrontend.get().ifPresent(Frontend::unmount);
|
||||
}
|
||||
|
||||
/* Delegate Methods */
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(String cleartextPath) {
|
||||
namesOfResourcesWithInvalidMac.add(cleartextPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipAuthentication(String cleartextPath) {
|
||||
return namesOfResourcesWithInvalidMac.contains(cleartextPath);
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
@@ -164,9 +164,9 @@ public class Vault implements Serializable {
|
||||
return StringUtils.removeEnd(path.getFileName().toString(), VAULT_FILE_EXTENSION);
|
||||
}
|
||||
|
||||
public Cryptor getCryptor() {
|
||||
return cryptor;
|
||||
}
|
||||
// public Cryptor getCryptor() {
|
||||
// return cryptor;
|
||||
// }
|
||||
|
||||
public ObjectProperty<Boolean> unlockedProperty() {
|
||||
return unlocked;
|
||||
|
||||
@@ -3,33 +3,31 @@ package org.cryptomator.ui.model;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.crypto.Cryptor;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemFactory;
|
||||
import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.frontend.webdav.mount.WebDavMounter;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
import org.cryptomator.ui.util.mount.WebDavMounter;
|
||||
import org.cryptomator.webdav.WebDavServer;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
@Singleton
|
||||
public class VaultFactory {
|
||||
|
||||
private final WebDavServer server;
|
||||
private final Provider<Cryptor> cryptorProvider;
|
||||
private final WebDavMounter mounter;
|
||||
private final Lazy<FrontendFactory> frontendFactory;
|
||||
private final CryptoFileSystemFactory cryptoFileSystemFactory;
|
||||
private final DeferredCloser closer;
|
||||
|
||||
@Inject
|
||||
public VaultFactory(WebDavServer server, @Named("SamplingCryptor") Provider<Cryptor> cryptorProvider, WebDavMounter mounter, DeferredCloser closer) {
|
||||
this.server = server;
|
||||
this.cryptorProvider = cryptorProvider;
|
||||
this.mounter = mounter;
|
||||
public VaultFactory(Lazy<FrontendFactory> frontendFactory, CryptoFileSystemFactory cryptoFileSystemFactory, WebDavMounter mounter, DeferredCloser closer) {
|
||||
this.frontendFactory = frontendFactory;
|
||||
this.cryptoFileSystemFactory = cryptoFileSystemFactory;
|
||||
this.closer = closer;
|
||||
}
|
||||
|
||||
public Vault createVault(Path path) {
|
||||
return new Vault(path, server, cryptorProvider.get(), mounter, closer);
|
||||
return new Vault(path, frontendFactory, cryptoFileSystemFactory, closer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user