From 65a4f8b659299c2b3efa3223b69118f471fa04d5 Mon Sep 17 00:00:00 2001 From: knaccc Date: Mon, 4 Feb 2019 00:14:21 +0000 Subject: [PATCH] produce fat JAR for non-module dependencies, to prevent split-package warnings and classpath issues added ability to create HTTP proxy tunnel quit immediately it we detect i2p-zero is already running (by checking for tunnelcontrol port 30000 in use) after attempted shutdown, force shutdown after 2 seconds. this is because if there is a shutdown prior to tunnels having opened, there could be a delay of up to 20 seconds before those opening tunnels exit their sleep and start responding added GUI tab to set up a personal eepsite (via embedded jetty) --- README.md | 16 +- bin/build-all.sh | 2 + bin/build-launcher.sh | 30 +- bin/convert-jars-to-modules.sh | 45 ++- bin/import-packages.sh | 12 + .../org.getmonero.i2p.zero.gui.iml | 18 +- .../i2p/zero/gui/AddTunnelController.java | 25 +- .../getmonero/i2p/zero/gui/Controller.java | 142 +++++++- .../src/org/getmonero/i2p/zero/gui/Gui.java | 13 + .../org/getmonero/i2p/zero/gui/addTunnel.fxml | 21 +- .../src/org/getmonero/i2p/zero/gui/gui.fxml | 35 +- .../org.getmonero.i2p.zero.iml | 56 +-- org.getmonero.i2p.zero/src/module-info.java | 7 +- .../src/org/getmonero/i2p/zero/Main.java | 10 +- .../org/getmonero/i2p/zero/RouterWrapper.java | 8 +- .../org/getmonero/i2p/zero/TunnelControl.java | 320 +++++++++++++++--- 16 files changed, 570 insertions(+), 190 deletions(-) diff --git a/README.md b/README.md index 98cbe65..aefa02a 100755 --- a/README.md +++ b/README.md @@ -83,18 +83,13 @@ I2P router launched. Press Ctrl-C to gracefully shut down the router (or send the SIGINT signal to the process). ``` -## Check that the I2P router is running and that it is listening for SAM connections - -`fuser 7656/tcp` - - ## Tunnel control Note that it may take a short while for new tunnels to be set up. Call the `dist/linux/router/bin/tunnel-control.sh` script as follows to create and destroy tunnels: -#### Get the router reachability status. Returns a string such as "Testing", "Tirewalled", "Running", "Error" +#### Get the router reachability status. Returns a string such as "Testing", "Firewalled", "Running", "Error" `tunnel-control.sh router.reachability` @@ -113,6 +108,7 @@ specified host and port. Note that the base 32 I2P destination address determini `tunnel-control.sh server.state ` `tunnel-control.sh client.state ` +`tunnel-control.sh http.state ` `tunnel-control.sh socks.state ` @@ -130,6 +126,14 @@ specified host and port. Note that the base 32 I2P destination address determini `tunnel-control.sh client.destroy ` +#### Create an http proxy (for accessing .i2p web sites), listening on the specified port + +`tunnel-control.sh http.create ` + +#### Destroy the http proxy listening on the specified port + +`tunnel-control.sh http.destroy ` + #### Create a socks tunnel, listening on the specified port `tunnel-control.sh socks.create ` diff --git a/bin/build-all.sh b/bin/build-all.sh index 8ac98da..10b7252 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -6,6 +6,8 @@ else basedir=$(dirname $(dirname $(readlink -fm $0))) fi +rm -fr "$basedir/target" "$basedir/dist" + # retrieve the I2P Java sources, OpenJDK and the Ant build tool "$basedir"/bin/import-packages.sh diff --git a/bin/build-launcher.sh b/bin/build-launcher.sh index ee88b9e..ab5aa9a 100755 --- a/bin/build-launcher.sh +++ b/bin/build-launcher.sh @@ -8,21 +8,23 @@ fi source "$basedir/bin/java-config.sh" -rm -fr target/org.getmonero.i2p.zero/classes -rm -fr target/org.getmonero.i2p.zero.gui/classes -# compile the Main class that starts the I2P router and SAM listener -echo "*** Compiling Main class" -$JAVA_HOME/bin/javac --module-path import/lib -d target/org.getmonero.i2p.zero/classes $(find org.getmonero.i2p.zero/src -name '*.java') -$JAVA_HOME/bin/javac --module-path import/lib:import/javafx-sdks/linux/javafx-sdk-$JAVAFX_VERSION/lib:target/org.getmonero.i2p.zero/classes -d target/org.getmonero.i2p.zero.gui/classes $(find org.getmonero.i2p.zero.gui/src -name '*.java') -cp -r org.getmonero.i2p.zero.gui/src/* target/org.getmonero.i2p.zero.gui/classes -find target -type f -name '*.java' -delete +echo "*** Compiling CLI" +$JAVA_HOME/bin/javac --module-path target/modules/combined.jar -d target/classes/org.getmonero.i2p.zero $(find org.getmonero.i2p.zero/src -name '*.java') -# package as a modular jar -echo "*** Packaging as a modular jar" -$JAVA_HOME/bin/jar --create --file target/org.getmonero.i2p.zero.jar --main-class org.getmonero.i2p.zero.Main -C target/org.getmonero.i2p.zero/classes . -$JAVA_HOME/bin/jar --create --file target/org.getmonero.i2p.zero.gui.jar --main-class org.getmonero.i2p.zero.gui.Gui -C target/org.getmonero.i2p.zero.gui/classes . +echo "*** Packaging CLI as a modular jar" +$JAVA_HOME/bin/jar --create --file target/org.getmonero.i2p.zero.jar --main-class org.getmonero.i2p.zero.Main -C target/classes/org.getmonero.i2p.zero . +echo "*** Compiling GUI" +$JAVA_HOME/bin/javac --module-path target/org.getmonero.i2p.zero.jar:target/modules/combined.jar:import/javafx-sdks/linux/javafx-sdk-$JAVAFX_VERSION/lib -d target/classes/org.getmonero.i2p.zero.gui $(find org.getmonero.i2p.zero.gui/src -name '*.java') + +cp -r org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/*.{css,png,fxml,ttf} target/classes/org.getmonero.i2p.zero.gui/org/getmonero/i2p/zero/gui/ + +echo "*** Packaging GUI as a modular jar" +$JAVA_HOME/bin/jar --create --file target/org.getmonero.i2p.zero.gui.jar --main-class org.getmonero.i2p.zero.gui.Gui -C target/classes/org.getmonero.i2p.zero.gui . + + + hh rm -fr "$basedir/dist" for i in linux mac win linux-gui mac-gui win-gui; do mkdir -p "$basedir/dist/$i"; done @@ -39,8 +41,8 @@ for i in linux mac win; do JAVA_HOME_VARIANT=${JAVA_HOME_WIN} ;; esac echo "Using JAVA_HOME_VARIANT: $JAVA_HOME_VARIANT" - "$JAVA_HOME"/bin/jlink --module-path "${JAVA_HOME_VARIANT}/jmods":target/modules:target/org.getmonero.i2p.zero.jar --add-modules org.getmonero.i2p.zero --output dist/$i/router --compress 2 --no-header-files --no-man-pages - "$JAVA_HOME"/bin/jlink --module-path "${JAVA_HOME_VARIANT}/jmods":import/javafx-jmods/$i/javafx-jmods-${JAVAFX_VERSION}:target/modules:target/org.getmonero.i2p.zero.jar:target/org.getmonero.i2p.zero.gui.jar --add-modules org.getmonero.i2p.zero,org.getmonero.i2p.zero.gui,javafx.controls,javafx.fxml,java.desktop --output dist/$i-gui/router --compress 2 --no-header-files --no-man-pages + "$JAVA_HOME"/bin/jlink --module-path "${JAVA_HOME_VARIANT}/jmods":target/modules:target/org.getmonero.i2p.zero.jar --add-modules combined,org.getmonero.i2p.zero --output dist/$i/router --compress 2 --no-header-files --no-man-pages + "$JAVA_HOME"/bin/jlink --module-path "${JAVA_HOME_VARIANT}/jmods":import/javafx-jmods/$i/javafx-jmods-${JAVAFX_VERSION}:target/modules:target/org.getmonero.i2p.zero.jar:target/org.getmonero.i2p.zero.gui.jar --add-modules combined,org.getmonero.i2p.zero,org.getmonero.i2p.zero.gui,javafx.controls,javafx.fxml,java.desktop --output dist/$i-gui/router --compress 2 --no-header-files --no-man-pages done for i in linux mac linux-gui mac-gui; do diff --git a/bin/convert-jars-to-modules.sh b/bin/convert-jars-to-modules.sh index 2efc925..b87e1b0 100755 --- a/bin/convert-jars-to-modules.sh +++ b/bin/convert-jars-to-modules.sh @@ -8,20 +8,37 @@ fi source "$basedir/bin/java-config.sh" +cp "$basedir"/import/jetty-lib/*.jar "$basedir/import/lib/" + +rm -fr "$basedir/target/lib-combined" +rm -fr "$basedir/target/lib-combined-tmp" +mkdir -p "$basedir/target/lib-combined" +mkdir -p "$basedir/target/lib-combined-tmp" + jarPaths=`find "$basedir/import/lib" -name '*.jar'` +combinedJarPath="$basedir/target/lib-combined/combined.jar" +for jarPath in $jarPaths; do unzip -quo $jarPath -d "$basedir/target/lib-combined-tmp"; done +jar cf "$combinedJarPath" -C "$basedir/target/lib-combined-tmp" . +rm -fr "$basedir/target/module-info" +mkdir -p "$basedir/target/module-info" +rm -fr "$basedir/target/modules" mkdir -p "$basedir/target/modules" -rm -f "$basedir/target/modules"/* - -for jarPath in $jarPaths; do - moduleName=$(basename "${jarPath%.*}") - echo "*** Determining dependencies for $moduleName" - "$JAVA_HOME"/bin/jdeps --module-path "$basedir/import/lib" --add-modules=ALL-MODULE-PATH --generate-module-info "$basedir/target/module-info" "$jarPath" -done -for jarPath in $jarPaths; do - moduleName=$(basename "${jarPath%.*}") - echo "*** Creating new modular jar for $moduleName" - "$JAVA_HOME"/bin/javac --module-path "$basedir/import/lib" --patch-module $moduleName=$jarPath $basedir/target/module-info/$moduleName/module-info.java - cp $jarPath "$basedir/target/modules/" - "$JAVA_HOME"/bin/jar uf "$basedir/target/modules/${moduleName}.jar" -C "$basedir/target/module-info/$moduleName" module-info.class -done + +echo "*** Determining dependencies for $combinedJarPath" +"$JAVA_HOME"/bin/jdeps --add-modules=ALL-MODULE-PATH --generate-module-info "$basedir/target/module-info" "$combinedJarPath" + +if [ $(uname -s) = Darwin ]; then + sed -i '' -e '$ d' "$basedir/target/module-info/combined/module-info.java" +else + sed -i '$ d' "$basedir/target/module-info/combined/module-info.java" +fi +echo 'uses org.eclipse.jetty.http.HttpFieldPreEncoder; }' >> "$basedir/target/module-info/combined/module-info.java" + + +echo "*** Creating new combined modular jar" +"$JAVA_HOME"/bin/javac --module-path "$combinedJarPath/combined" --patch-module combined=$combinedJarPath $basedir/target/module-info/combined/module-info.java +cp $combinedJarPath "$basedir/target/modules/" +"$JAVA_HOME"/bin/jar uf "$basedir/target/modules/combined.jar" -C "$basedir/target/module-info/combined" module-info.class + + diff --git a/bin/import-packages.sh b/bin/import-packages.sh index 3cc24a9..9c8e843 100755 --- a/bin/import-packages.sh +++ b/bin/import-packages.sh @@ -37,6 +37,18 @@ if [ ! -d "$basedir/import/apache-ant-1.10.5" ]; then tar zxvf apache-ant-1.10.5-bin.tar.gz fi +if [ ! -d "$basedir/import/jetty-lib" ]; then + mkdir -p jetty-lib + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/eclipse/jetty/jetty-server/9.4.14.v20181114/jetty-server-9.4.14.v20181114.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/eclipse/jetty/jetty-util/9.4.14.v20181114/jetty-util-9.4.14.v20181114.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/eclipse/jetty/jetty-http/9.4.14.v20181114/jetty-http-9.4.14.v20181114.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/eclipse/jetty/jetty-io/9.4.14.v20181114/jetty-io-9.4.14.v20181114.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/slf4j/slf4j-simple/1.7.25/slf4j-simple-1.7.25.jar + wget --directory-prefix=jetty-lib http://central.maven.org/maven2/org/eclipse/jetty/jetty-jmx/9.4.14.v20181114/jetty-jmx-9.4.14.v20181114.jar +fi + if [ ! -d "$basedir/import/javafx-sdks" ]; then mkdir -p javafx-sdks mkdir -p javafx-sdks/linux javafx-sdks/mac javafx-sdks/win diff --git a/org.getmonero.i2p.zero.gui/org.getmonero.i2p.zero.gui.iml b/org.getmonero.i2p.zero.gui/org.getmonero.i2p.zero.gui.iml index a42f527..ceefdf6 100644 --- a/org.getmonero.i2p.zero.gui/org.getmonero.i2p.zero.gui.iml +++ b/org.getmonero.i2p.zero.gui/org.getmonero.i2p.zero.gui.iml @@ -7,11 +7,10 @@ - - + @@ -20,7 +19,7 @@ - + @@ -29,7 +28,7 @@ - + @@ -38,7 +37,7 @@ - + @@ -47,7 +46,7 @@ - + @@ -56,7 +55,7 @@ - + @@ -65,7 +64,7 @@ - + @@ -74,11 +73,12 @@ - + + \ No newline at end of file diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/AddTunnelController.java b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/AddTunnelController.java index fa0ff46..0e5c0f8 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/AddTunnelController.java +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/AddTunnelController.java @@ -12,12 +12,14 @@ public class AddTunnelController { @FXML Pane clientTunnelConfigPane; @FXML Pane serverTunnelConfigPane; + @FXML Pane httpProxyConfigPane; @FXML Pane socksProxyConfigPane; @FXML Button addButton; @FXML Button cancelButton; @FXML ToggleGroup tunnelType; @FXML RadioButton clientTunnelRadioButton; @FXML RadioButton serverTunnelRadioButton; + @FXML RadioButton httpProxyRadioButton; @FXML RadioButton socksProxyRadioButton; @FXML TextField clientDestAddrField; @FXML TextField clientPortField; @@ -26,6 +28,7 @@ public class AddTunnelController { @FXML TextField serverKeyField; @FXML TextField serverAddrField; @FXML TextField socksPortField; + @FXML TextField httpProxyPortField; private void updateAddButtonState() { @@ -38,6 +41,9 @@ public class AddTunnelController { else if(tunnelType.getSelectedToggle().equals(socksProxyRadioButton)) { addButton.setDisable(Stream.of(socksPortField).anyMatch(f->f.getText().isBlank())); } + else if(tunnelType.getSelectedToggle().equals(httpProxyRadioButton)) { + addButton.setDisable(Stream.of(httpProxyPortField).anyMatch(f->f.getText().isBlank())); + } } @FXML @@ -45,6 +51,7 @@ public class AddTunnelController { serverTunnelConfigPane.setVisible(false); socksProxyConfigPane.setVisible(false); + httpProxyConfigPane.setVisible(false); addButton.setOnAction(ev->{ try { @@ -52,13 +59,16 @@ public class AddTunnelController { var tunnelControl = controller.getRouterWrapper().getTunnelControl(); var tunnelList = tunnelControl.getTunnelList(); if (tunnelType.getSelectedToggle().equals(clientTunnelRadioButton)) { - Tunnel t = new TunnelControl.ClientTunnel(clientDestAddrField.getText(), Integer.parseInt(clientPortField.getText())); + Tunnel t = new TunnelControl.ClientTunnel(clientDestAddrField.getText(), Integer.parseInt(clientPortField.getText())).start(); tunnelList.addTunnel(t); } else if (tunnelType.getSelectedToggle().equals(serverTunnelRadioButton)) { - Tunnel t = new TunnelControl.ServerTunnel(serverHostField.getText(), Integer.parseInt(serverPortField.getText()), new TunnelControl.KeyPair(serverKeyField.getText()), tunnelControl.getTunnelControlTempDir()); + Tunnel t = new TunnelControl.ServerTunnel(serverHostField.getText(), Integer.parseInt(serverPortField.getText()), new TunnelControl.KeyPair(serverKeyField.getText()), tunnelControl.getTunnelControlTempDir()).start(); tunnelList.addTunnel(t); } else if (tunnelType.getSelectedToggle().equals(socksProxyRadioButton)) { - Tunnel t = new TunnelControl.SocksTunnel(Integer.parseInt(socksPortField.getText())); + Tunnel t = new TunnelControl.SocksTunnel(Integer.parseInt(socksPortField.getText())).start(); + tunnelList.addTunnel(t); + } else if (tunnelType.getSelectedToggle().equals(httpProxyRadioButton)) { + Tunnel t = new TunnelControl.HttpClientTunnel(Integer.parseInt(httpProxyPortField.getText())).start(); tunnelList.addTunnel(t); } clientTunnelConfigPane.getScene().getWindow().hide(); @@ -80,17 +90,18 @@ public class AddTunnelController { tunnelType.selectedToggleProperty().addListener((ov, oldToggle, newToggle)-> { try { - var tunnelControl = Gui.instance.getController().getRouterWrapper().getTunnelControl(); clientTunnelConfigPane.setVisible(false); serverTunnelConfigPane.setVisible(false); + httpProxyConfigPane.setVisible(false); socksProxyConfigPane.setVisible(false); if (newToggle.equals(clientTunnelRadioButton)) clientTunnelConfigPane.setVisible(true); if (newToggle.equals(serverTunnelRadioButton)) { var keyPair = TunnelControl.KeyPair.gen(); - serverKeyField.setText(keyPair.seckey + "," + keyPair.pubkey); + serverKeyField.setText(keyPair.toString()); serverAddrField.setText(keyPair.b32Dest); serverTunnelConfigPane.setVisible(true); } + if (newToggle.equals(httpProxyRadioButton)) httpProxyConfigPane.setVisible(true); if (newToggle.equals(socksProxyRadioButton)) socksProxyConfigPane.setVisible(true); updateAddButtonState(); } @@ -106,13 +117,11 @@ public class AddTunnelController { String key = newValue; if(key!=null && !key.isEmpty()) { try { - TunnelControl.KeyPair keyPair = new TunnelControl.KeyPair(key); - serverAddrField.setText(keyPair.b32Dest); + serverAddrField.setText(new TunnelControl.KeyPair(key).b32Dest); } catch (Exception e) { // ignore exception. user may be part way through entering string } - } }); diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java index 19c13ce..10d48f5 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java @@ -15,27 +15,32 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; +import javafx.stage.DirectoryChooser; import javafx.stage.Modality; import javafx.stage.Stage; import org.getmonero.i2p.zero.RouterWrapper; -import static org.getmonero.i2p.zero.TunnelControl.Tunnel; +import org.getmonero.i2p.zero.TunnelControl; +import static org.getmonero.i2p.zero.TunnelControl.*; + +import java.io.File; import java.text.DecimalFormat; -import java.util.List; +import java.util.Optional; import java.util.Properties; +import java.util.stream.Stream; public class Controller { private RouterWrapper routerWrapper; - @FXML - private BorderPane rootBorderPane; + @FXML private BorderPane rootBorderPane; @FXML private Slider bandwidthSlider; @FXML private Label maxBandwidthLabel; @FXML private ImageView masterToggle; @FXML private AnchorPane bandwidthDisabledOverlay; @FXML private Tab bandwidthTab; @FXML private Tab tunnelsTab; + @FXML private Tab eepSiteTab; @FXML private Tab helpTab; @FXML private Label statusLabel; @FXML private Button tunnelAddButton; @@ -54,17 +59,32 @@ public class Controller { @FXML private Label bandwidthOut5m; @FXML private Label bandwidthOutAll; @FXML private Label totalTransferredOut; + @FXML private CheckBox eepSiteEnableCheckbox; + @FXML private TextField eepSiteAddrField; + @FXML private TextField eepSiteSecretKeyField; + @FXML private Button eepSiteGenButton; + @FXML private TextField eepSiteContentDirField; + @FXML private Button eepSiteContentDirChooseButton; + @FXML private TextField eepSiteLogsDirField; + @FXML private Button eepSiteLogsDirChooseButton; + @FXML private CheckBox eepSiteEnableLogsCheckbox; + @FXML private CheckBox eepSiteAllowDirBrowsingCheckbox; + @FXML private TextField eepSiteLocalPortField; + DecimalFormat format2dp = new DecimalFormat("0.00"); private boolean masterState = true; private final ObservableList tunnelTableList = FXCollections.observableArrayList(); - + private boolean eepSiteTabInitialized = false; + private Stage getStage() { return (Stage) rootBorderPane.getScene().getWindow(); } @FXML private void initialize() { + DirectoryChooser directoryChooser = new DirectoryChooser(); + typeCol.setCellValueFactory(new PropertyValueFactory("type")); stateCol.setCellValueFactory(new PropertyValueFactory("state")); hostCol.setCellValueFactory(new PropertyValueFactory("host")); @@ -115,12 +135,99 @@ public class Controller { stage.setHeight(370); } else if(tunnelsTab.isSelected()) { - stage.setWidth(900); + stage.setWidth(830); + } + else if(eepSiteTab.isSelected()) { + stage.setWidth(830); + stage.setHeight(500); + + if(!eepSiteTabInitialized) { + EepSiteTunnel eepSiteTunnel = getEepSiteTunnel(); + eepSiteSecretKeyField.setText(eepSiteTunnel.keyPair.toString()); + eepSiteAddrField.setText("http://" + eepSiteTunnel.keyPair.b32Dest); + eepSiteContentDirField.setText(eepSiteTunnel.contentDir); + eepSiteLogsDirField.setText(eepSiteTunnel.logsDir); + eepSiteEnableCheckbox.setSelected(eepSiteTunnel.enabled); + eepSiteEnableLogsCheckbox.setSelected(eepSiteTunnel.enableLogs); + eepSiteAllowDirBrowsingCheckbox.setSelected(eepSiteTunnel.allowDirectoryBrowsing); + eepSiteLocalPortField.setText(eepSiteTunnel.port + ""); + eepSiteTabInitialized = true; + + // modifying eepSiteSecretKeyField/eepSiteLocalPortField will require the eepsite tunnel to be destroyed + // and later recreated whenever the user is finished editing settings and ticks the enabled box again + eepSiteSecretKeyField.textProperty().addListener((observable, oldValue, newValue) -> { + eepSiteAddrField.setText(""); + String key = newValue; + if(key!=null && !key.isEmpty()) { + try { + eepSiteAddrField.setText("http://" + new TunnelControl.KeyPair(key).b32Dest); + } + catch (Exception e2) { + // ignore exception. user may be part way through entering string + } + eepSiteEnableCheckbox.setSelected(false); + } + }); + eepSiteGenButton.setOnAction(ev->{ + getEepSiteTunnel().keyPair = KeyPair.gen(); + eepSiteSecretKeyField.setText(getEepSiteTunnel().keyPair.toString()); + }); + eepSiteLocalPortField.textProperty().addListener((ov, oldValue, newValue)->{ + eepSiteEnableCheckbox.setSelected(false); + getEepSiteTunnel().port = Integer.parseInt(newValue); + save(); + eepSiteEnableCheckbox.setSelected(false); + }); + + eepSiteEnableCheckbox.selectedProperty().addListener((ov, oldValue, newValue)->{ + getEepSiteTunnel().enabled = newValue; + if(oldValue!=newValue) { + save(); + getRouterWrapper().getTunnelControl().getTunnelList().fireChangeEvent(); + if(getEepSiteTunnel().enabled) { + getEepSiteTunnel().start(); + } + else { + getEepSiteTunnel().destroy(); + } + } + }); + + + // changing eepSiteContentDirChooseButton/eepSiteLogsDirChooseButton/eepSiteEnableLogsCheckbox/eepSiteAllowDirBrowsingCheckbox only requires a jetty restart + eepSiteContentDirChooseButton.setOnAction(ev->{ + File selectedDirectory = directoryChooser.showDialog(getStage()); + if (selectedDirectory!=null) { + eepSiteContentDirField.setText(selectedDirectory.getAbsolutePath()); + getEepSiteTunnel().contentDir = selectedDirectory.getAbsolutePath(); + save(); + if(getEepSiteTunnel().enabled) restartJetty(); + } + }); + eepSiteLogsDirChooseButton.setOnAction(ev->{ + File selectedDirectory = directoryChooser.showDialog(getStage()); + if (selectedDirectory!=null) { + eepSiteLogsDirField.setText(selectedDirectory.getAbsolutePath()); + getEepSiteTunnel().logsDir = selectedDirectory.getAbsolutePath(); + save(); + if(getEepSiteTunnel().enabled) restartJetty(); + } + }); + eepSiteEnableLogsCheckbox.selectedProperty().addListener((ov, oldValue, newValue)->{ + getEepSiteTunnel().enableLogs = newValue; + save(); + if(getEepSiteTunnel().enabled) restartJetty(); + }); + eepSiteAllowDirBrowsingCheckbox.selectedProperty().addListener((ov, oldValue, newValue)->{ + getEepSiteTunnel().allowDirectoryBrowsing = newValue; + save(); + if(getEepSiteTunnel().enabled) restartJetty(); + }); + + } } }; - bandwidthTab.setOnSelectionChanged(tabSelectionEventHandler); - tunnelsTab.setOnSelectionChanged(tabSelectionEventHandler); - helpTab.setOnSelectionChanged(tabSelectionEventHandler); + Stream.of(bandwidthTab, tunnelsTab, eepSiteTab, helpTab).forEach(tab->tab.setOnSelectionChanged(tabSelectionEventHandler)); bandwidthSlider.valueProperty().addListener((observableValue, oldValue, newValue)-> { maxBandwidthLabel.setText(String.format("%.1f", newValue.floatValue()) + " Mbps"); @@ -155,7 +262,7 @@ public class Controller { var tunnelList = getRouterWrapper().getTunnelControl().getTunnelList(); tunnelList.addChangeListener(tunnels->{ tunnelTableList.clear(); - tunnelTableList.addAll(tunnels); + tunnels.stream().filter(Tunnel::getEnabled).forEach(tunnelTableList::add); }); }).start(); @@ -184,8 +291,6 @@ public class Controller { }); bandwidthUpdateThread.start(); - Runtime.getRuntime().addShutdownHook(new Thread(()->bandwidthUpdateThread.interrupt())); - } public RouterWrapper getRouterWrapper() { @@ -210,5 +315,18 @@ public class Controller { } + private void restartJetty() { + Optional eepSiteTunnelOptional = getRouterWrapper().getTunnelControl().getTunnelList().getTunnelsCopyStream().filter(t->t.getType().equals("eepsite")).findFirst(); + EepSiteTunnel eepSiteTunnel = (EepSiteTunnel) eepSiteTunnelOptional.get(); + eepSiteTunnel.stopJetty(); + new Thread(()->eepSiteTunnel.startJetty()).start(); + } + private void save() { + getRouterWrapper().getTunnelControl().getTunnelList().save(); + } + private EepSiteTunnel getEepSiteTunnel() { + return getRouterWrapper().getTunnelControl().getEepSiteTunnel(); + } + } diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java index 389d4b0..bdd08f1 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Gui.java @@ -7,8 +7,10 @@ import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; +import javafx.scene.control.Alert; import javafx.scene.image.Image; import javafx.stage.Stage; +import org.getmonero.i2p.zero.TunnelControl; import javax.imageio.ImageIO; @@ -22,6 +24,15 @@ public class Gui extends Application { @Override public void start(Stage primaryStage) throws Exception{ + if(TunnelControl.isPortInUse()) { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setTitle("Error"); + alert.setHeaderText(null); + alert.setContentText("I2P-zero is already running"); + alert.showAndWait(); + System.exit(1); + } + instance = this; String osName = System.getProperty("os.name"); if(osName.startsWith("Mac")) { @@ -36,6 +47,8 @@ public class Gui extends Application { controller = loader.getController(); primaryStage.setTitle("I2P-zero"); + primaryStage.setWidth(360); + primaryStage.setHeight(340); primaryStage.setMinWidth(360); primaryStage.setMinHeight(370); Scene scene = new Scene(root); diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/addTunnel.fxml b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/addTunnel.fxml index 23aa442..cd1f017 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/addTunnel.fxml +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/addTunnel.fxml @@ -8,7 +8,7 @@ - + @@ -18,10 +18,10 @@ - -