diff --git a/main/core/pom.xml b/main/core/pom.xml index cfd19cab9..d23e756e7 100644 --- a/main/core/pom.xml +++ b/main/core/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.1.0-SNAPSHOT + 0.1.0 core Cryptomator core I/O module @@ -28,7 +28,6 @@ org.cryptomator crypto-api - ${project.parent.version} diff --git a/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java b/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java index da4d85322..69ec48815 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java +++ b/main/core/src/main/java/org/cryptomator/webdav/WebDAVServer.java @@ -22,6 +22,7 @@ public final class WebDAVServer { private static final Logger LOG = LoggerFactory.getLogger(WebDAVServer.class); private static final WebDAVServer INSTANCE = new WebDAVServer(); + private static final String LOCALHOST = "127.0.0.1"; private final Server server = new Server(); private WebDAVServer() { @@ -32,11 +33,14 @@ public final class WebDAVServer { return INSTANCE; } - public boolean start(final String workDir, final int port, final Cryptor cryptor) { + /** + * @param workDir Path of encrypted folder. + * @param cryptor A fully initialized cryptor instance ready to en- or decrypt streams. + * @return port, on which the server did start + */ + public int start(final String workDir, final Cryptor cryptor) { final ServerConnector connector = new ServerConnector(server); - connector.setHost("127.0.0.1"); - connector.setPort(port); - server.setConnectors(new Connector[] {connector}); + connector.setHost(LOCALHOST); final String contextPath = "/"; @@ -46,12 +50,13 @@ public final class WebDAVServer { server.setHandler(context); try { + server.setConnectors(new Connector[] {connector}); server.start(); } catch (Exception ex) { LOG.error("Server couldn't be started", ex); } - return server.isStarted(); + return connector.getLocalPort(); } public boolean isRunning() { @@ -68,7 +73,7 @@ public final class WebDAVServer { } private ServletHolder getMiltonServletHolder(final String workDir, final String contextPath, final Cryptor cryptor) { - final ServletHolder result = new ServletHolder("OCE-WebDAV-Servlet", new WebDavServlet(cryptor)); + final ServletHolder result = new ServletHolder("Cryptomator-WebDAV-Servlet", new WebDavServlet(cryptor)); result.setInitParameter(WebDavServlet.CFG_FS_ROOT, workDir); result.setInitParameter(WebDavServlet.CFG_HTTP_ROOT, contextPath); return result; diff --git a/main/crypto-aes/pom.xml b/main/crypto-aes/pom.xml index 1f09c76f2..c05dee070 100644 --- a/main/crypto-aes/pom.xml +++ b/main/crypto-aes/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.1.0-SNAPSHOT + 0.1.0 crypto-aes Cryptomator cryptographic module (AES) @@ -22,7 +22,6 @@ org.cryptomator crypto-api - ${project.parent.version} diff --git a/main/crypto-api/pom.xml b/main/crypto-api/pom.xml index 072fa335e..894471358 100644 --- a/main/crypto-api/pom.xml +++ b/main/crypto-api/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.1.0-SNAPSHOT + 0.1.0 crypto-api Cryptomator cryptographic module API diff --git a/main/pom.xml b/main/pom.xml index ed50f873c..3c66b30fb 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -11,12 +11,22 @@ 4.0.0 org.cryptomator main - 0.1.0-SNAPSHOT + 0.1.0 pom Cryptomator + cryptomator.org + http://cryptomator.org + + + + Sebastian Stenzel + sebastian.stenzel@gmail.com + +1 + + UTF-8 @@ -31,15 +41,30 @@ 1.9 - - - Sebastian Stenzel - sebastian.stenzel@gmail.com - - - + + + org.cryptomator + core + ${project.version} + + + org.cryptomator + crypto-api + ${project.version} + + + org.cryptomator + crypto-aes + ${project.version} + + + org.cryptomator + ui + ${project.version} + + log4j diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 3cc4baff0..ac5a0ab03 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -1,16 +1,24 @@ - + 4.0.0 org.cryptomator main - 0.1.0-SNAPSHOT + 0.1.0 ui Cryptomator GUI + Cryptomator org.cryptomator.ui.MainApplication ${java.home}/../lib/ant-javafx.jar @@ -19,12 +27,10 @@ org.cryptomator core - ${project.parent.version} org.cryptomator crypto-aes - ${project.parent.version} @@ -91,7 +97,7 @@ - + @@ -102,9 +108,9 @@ - - - + + + diff --git a/main/ui/src/main/java/org/cryptomator/ui/AccessController.java b/main/ui/src/main/java/org/cryptomator/ui/AccessController.java index 07243d78a..47dc60504 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/AccessController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/AccessController.java @@ -43,6 +43,8 @@ import org.cryptomator.crypto.exceptions.WrongPasswordException; import org.cryptomator.ui.controls.SecPasswordField; import org.cryptomator.ui.settings.Settings; import org.cryptomator.ui.util.MasterKeyFilter; +import org.cryptomator.ui.util.WebDavMounter; +import org.cryptomator.ui.util.WebDavMounter.CommandFailedException; import org.cryptomator.webdav.WebDAVServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -197,21 +199,29 @@ public class AccessController implements Initializable { } private void tryStart() { - try { - final Settings settings = Settings.load(); - if (WebDAVServer.getInstance().start(settings.getWebdavWorkDir(), settings.getPort(), cryptor)) { - startServerButton.setText(localization.getString("access.button.stopServer")); - passwordField.setDisable(true); + final Settings settings = Settings.load(); + final int webdavPort = WebDAVServer.getInstance().start(settings.getWebdavWorkDir(), cryptor); + if (webdavPort > 0) { + startServerButton.setText(localization.getString("access.button.stopServer")); + passwordField.setDisable(true); + try { + WebDavMounter.mount(webdavPort); + } catch (CommandFailedException e) { + messageLabel.setText(String.format(localization.getString("access.messageLabel.mountFailed"), webdavPort)); + LOG.error("Mounting WebDAV share failed.", e); } - } catch (NumberFormatException ex) { - LOG.error("Invalid port", ex); } } private void tryStop() { - if (WebDAVServer.getInstance().stop()) { - startServerButton.setText(localization.getString("access.button.startServer")); - passwordField.setDisable(false); + try { + WebDavMounter.unmount(5); + if (WebDAVServer.getInstance().stop()) { + startServerButton.setText(localization.getString("access.button.startServer")); + passwordField.setDisable(false); + } + } catch (CommandFailedException e) { + LOG.warn("Unmounting WebDAV share failed.", e); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/AdvancedController.java b/main/ui/src/main/java/org/cryptomator/ui/AdvancedController.java deleted file mode 100644 index d1eb684cf..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/AdvancedController.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 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 - ******************************************************************************/ -package org.cryptomator.ui; - -import java.net.URL; -import java.util.ResourceBundle; - -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; -import javafx.fxml.FXML; -import javafx.fxml.Initializable; -import javafx.scene.control.TextField; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.GridPane; - -import org.apache.commons.lang3.CharUtils; -import org.cryptomator.ui.settings.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AdvancedController implements Initializable { - - private static final Logger LOG = LoggerFactory.getLogger(AdvancedController.class); - - @FXML - private GridPane rootGridPane; - - @FXML - private TextField portTextField; - - @Override - public void initialize(URL url, ResourceBundle rb) { - portTextField.setText(String.valueOf(Settings.load().getPort())); - portTextField.addEventFilter(KeyEvent.KEY_TYPED, new NumericKeyTypeEventFilter()); - portTextField.focusedProperty().addListener(new PortTextFieldFocusListener()); - } - - /** - * Consumes key events, if typed key is not 0-9. - */ - private static final class NumericKeyTypeEventFilter implements EventHandler { - @Override - public void handle(KeyEvent t) { - if (t.getCharacter() == null || t.getCharacter().length() == 0) { - return; - } - char c = t.getCharacter().charAt(0); - if (!CharUtils.isAsciiNumeric(c)) { - t.consume(); - } - } - } - - /** - * Saves port settings, when textfield loses focus. - */ - private class PortTextFieldFocusListener implements ChangeListener { - @Override - public void changed(ObservableValue property, Boolean wasFocused, Boolean isFocused) { - final Settings settings = Settings.load(); - try { - int port = Integer.valueOf(portTextField.getText()); - settings.setPort(port); - } catch (NumberFormatException ex) { - LOG.warn("Invalid port " + portTextField.getText()); - portTextField.setText(String.valueOf(settings.getPort())); - } - } - } - -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java b/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java index 1e978775b..f1d914ee0 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java @@ -18,10 +18,16 @@ import javafx.scene.Scene; import javafx.stage.Stage; import org.cryptomator.ui.settings.Settings; +import org.cryptomator.ui.util.WebDavMounter; +import org.cryptomator.ui.util.WebDavMounter.CommandFailedException; import org.cryptomator.webdav.WebDAVServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MainApplication extends Application { + private static final Logger LOG = LoggerFactory.getLogger(MainApplication.class); + public static void main(String[] args) { launch(args); } @@ -40,6 +46,11 @@ public class MainApplication extends Application { @Override public void stop() throws Exception { + try { + WebDavMounter.unmount(5); + } catch (CommandFailedException e) { + LOG.warn("Unmounting WebDAV share failed.", e); + } WebDAVServer.getInstance().stop(); Settings.save(); super.stop(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/MainController.java index 94ec34438..e417f1c53 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/MainController.java @@ -10,38 +10,42 @@ package org.cryptomator.ui; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.control.ToggleGroup; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; public class MainController { - + + @FXML + private ToggleGroup toolbarButtonGroup; + @FXML private VBox rootVBox; - + @FXML private Pane initializePanel; - + @FXML private Pane accessPanel; - + @FXML private Pane advancedPanel; - + @FXML protected void showInitializePane(ActionEvent event) { showPanel(initializePanel); } - + @FXML protected void showAccessPane(ActionEvent event) { showPanel(accessPanel); } - + @FXML protected void showAdvancedPane(ActionEvent event) { showPanel(advancedPanel); } - + private void showPanel(Pane panel) { rootVBox.getChildren().remove(1); rootVBox.getChildren().add(panel); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java b/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java index 38e8655f0..b5bf8f68a 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java @@ -1,3 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + ******************************************************************************/ package org.cryptomator.ui.controls; import javafx.beans.value.ChangeListener; diff --git a/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java b/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java index f470bd310..0d095ec86 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java +++ b/main/ui/src/main/java/org/cryptomator/ui/settings/Settings.java @@ -18,6 +18,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,20 +36,18 @@ public class Settings implements Serializable { private static Settings INSTANCE = null; static { - final String home = System.getProperty("user.home", "."); final String appdata = System.getenv("APPDATA"); - final String os = System.getProperty("os.name").toLowerCase(); final FileSystem fs = FileSystems.getDefault(); - if (os.contains("win") && appdata != null) { + if (SystemUtils.IS_OS_WINDOWS && appdata != null) { SETTINGS_DIR = fs.getPath(appdata, "opencloudencryptor"); - } else if (os.contains("win") && appdata == null) { - SETTINGS_DIR = fs.getPath(home, ".opencloudencryptor"); - } else if (os.contains("mac")) { - SETTINGS_DIR = fs.getPath(home, "Library/Application Support/opencloudencryptor"); + } else if (SystemUtils.IS_OS_WINDOWS && appdata == null) { + SETTINGS_DIR = fs.getPath(SystemUtils.USER_HOME, ".opencloudencryptor"); + } else if (SystemUtils.IS_OS_MAC_OSX) { + SETTINGS_DIR = fs.getPath(SystemUtils.USER_HOME, "Library/Application Support/opencloudencryptor"); } else { // (os.contains("solaris") || os.contains("sunos") || os.contains("linux") || os.contains("unix")) - SETTINGS_DIR = fs.getPath(home, ".opencloudencryptor"); + SETTINGS_DIR = fs.getPath(SystemUtils.USER_HOME, ".opencloudencryptor"); } } @@ -113,10 +112,12 @@ public class Settings implements Serializable { this.username = username; } + @Deprecated public int getPort() { return port; } + @Deprecated public void setPort(int port) { this.port = port; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java b/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java index c747c749e..844f42acc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java @@ -1,3 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + ******************************************************************************/ package org.cryptomator.ui.util; import java.io.IOException; diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java new file mode 100644 index 000000000..72c39e757 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/util/WebDavMounter.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + ******************************************************************************/ +package org.cryptomator.ui.util; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.SystemUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class WebDavMounter { + + private static final Logger LOG = LoggerFactory.getLogger(WebDavMounter.class); + private static final int CMD_DEFAULT_TIMEOUT = 1; + + private WebDavMounter() { + throw new IllegalStateException("not instantiable."); + } + + public static void mount(int localPort) throws CommandFailedException { + if (SystemUtils.IS_OS_MAC_OSX) { + exec("mkdir /Volumes/Cryptomator", CMD_DEFAULT_TIMEOUT); + exec("mount_webdav -S -v Cryptomator localhost:" + localPort + " /Volumes/Cryptomator", CMD_DEFAULT_TIMEOUT); + exec("open /Volumes/Cryptomator", CMD_DEFAULT_TIMEOUT); + } + } + + public static void unmount(int timeout) throws CommandFailedException { + if (SystemUtils.IS_OS_MAC_OSX) { + exec("umount /Volumes/Cryptomator", timeout); + } + } + + private static void exec(String cmd, int timoutSeconds) throws CommandFailedException { + try { + final Process proc = Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", cmd}); + if (proc.waitFor(timoutSeconds, TimeUnit.SECONDS)) { + proc.destroy(); + } + if (proc.exitValue() != 0) { + throw new CommandFailedException(IOUtils.toString(proc.getErrorStream())); + } + } catch (IOException | InterruptedException | IllegalThreadStateException e) { + LOG.error("Command execution failed.", e); + throw new CommandFailedException(e); + } + + } + + public static class CommandFailedException extends Exception { + + private static final long serialVersionUID = 5784853630182321479L; + + private CommandFailedException(String message) { + super(message); + } + + private CommandFailedException(Throwable cause) { + super(cause); + } + + } + +} diff --git a/main/ui/src/main/resources/advanced.fxml b/main/ui/src/main/resources/advanced.fxml deleted file mode 100644 index 0bcc1c537..000000000 --- a/main/ui/src/main/resources/advanced.fxml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/main/ui/src/main/resources/localization.properties b/main/ui/src/main/resources/localization.properties index 280b284b6..2394ed932 100644 --- a/main/ui/src/main/resources/localization.properties +++ b/main/ui/src/main/resources/localization.properties @@ -9,7 +9,6 @@ # main.fxml toolbarbutton.initialize=Initialize Vault toolbarbutton.access=Access Vault -toolbarbutton.advanced=Advanced Settings # initialize.fxml initialize.label.workDir=New vault location @@ -32,6 +31,4 @@ access.messageLabel.wrongPassword=Wrong password. access.messageLabel.invalidStorageLocation=Vault directory invalid. access.messageLabel.decryptionFailed=Decryption failed. access.messageLabel.unsupportedKeyLengthInstallJCE=Decryption failed. Please install Oracle JCE. - -# advanced.fxml -advanced.label.port=WebDAV Port +access.messageLabel.mountFailed=Mounting WebDAV share (Port %d) failed. diff --git a/main/ui/src/main/resources/logo.icns b/main/ui/src/main/resources/logo.icns new file mode 100644 index 000000000..f2eb85138 Binary files /dev/null and b/main/ui/src/main/resources/logo.icns differ diff --git a/main/ui/src/main/resources/main.fxml b/main/ui/src/main/resources/main.fxml index 2b08770b0..f1fe478a3 100644 --- a/main/ui/src/main/resources/main.fxml +++ b/main/ui/src/main/resources/main.fxml @@ -21,7 +21,6 @@ - @@ -32,7 +31,6 @@ -