- Version 0.1.0

- Automounting (OS X only atm)
- Automatic TCP ports
- Added icon
This commit is contained in:
Sebastian Stenzel
2014-11-30 00:10:06 +01:00
parent be38432e73
commit c322b0488e
18 changed files with 202 additions and 175 deletions

View File

@@ -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);
}
}

View File

@@ -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<KeyEvent> {
@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<Boolean> {
@Override
public void changed(ObservableValue<? extends Boolean> 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()));
}
}
}
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<GridPane fx:id="rootGridPane" fx:controller="org.cryptomator.ui.AdvancedController" xmlns:fx="http://javafx.com/fxml" styleClass="root" gridLinesVisible="false" vgap="5" hgap="5" prefWidth="480">
<stylesheets>
<URL value="@panels.css" />
</stylesheets>
<padding>
<Insets top="10" right="10" bottom="10" left="10" />
</padding>
<columnConstraints>
<ColumnConstraints minWidth="150" maxWidth="150" hgrow="NEVER" />
<ColumnConstraints minWidth="250" hgrow="ALWAYS" />
</columnConstraints>
<children>
<!-- Row 0 -->
<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="%advanced.label.port" GridPane.halignment="RIGHT" />
<TextField fx:id="portTextField" GridPane.rowIndex="0" GridPane.columnIndex="1" />
</children>
</GridPane>

View File

@@ -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.

Binary file not shown.

View File

@@ -21,7 +21,6 @@
<fx:define>
<fx:include fx:id="initializePanel" source="initialize.fxml" />
<fx:include fx:id="accessPanel" source="access.fxml" />
<fx:include fx:id="advancedPanel" source="advanced.fxml" />
</fx:define>
<children>
@@ -32,7 +31,6 @@
</fx:define>
<ToggleButton text="%toolbarbutton.initialize" toggleGroup="$toolbarButtonGroup" onAction="#showInitializePane" />
<ToggleButton text="%toolbarbutton.access" toggleGroup="$toolbarButtonGroup" onAction="#showAccessPane" selected="true" />
<ToggleButton text="%toolbarbutton.advanced" toggleGroup="$toolbarButtonGroup" onAction="#showAdvancedPane" />
</items>
</ToolBar>
<fx:reference source="accessPanel"/>