diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index 68533f7ef..7f415894d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -10,31 +10,46 @@ import java.util.StringTokenizer; import net.i2p.I2PAppContext; import net.i2p.apps.systray.SysTray; +import net.i2p.data.Base32; import net.i2p.data.DataHelper; import net.i2p.router.RouterContext; import net.i2p.util.FileUtil; import net.i2p.util.I2PAppThread; import net.i2p.util.SecureDirectory; +import net.i2p.util.SecureFileOutputStream; +import net.i2p.util.ShellCommand; import org.mortbay.http.DigestAuthenticator; import org.mortbay.http.HashUserRealm; import org.mortbay.http.SecurityConstraint; +import org.mortbay.http.SslListener; import org.mortbay.http.handler.SecurityHandler; import org.mortbay.jetty.Server; import org.mortbay.jetty.servlet.WebApplicationContext; import org.mortbay.jetty.servlet.WebApplicationHandler; +import org.mortbay.util.InetAddrPort; public class RouterConsoleRunner { private Server _server; - private String _listenPort = "7657"; - private String _listenHost = "127.0.0.1"; - private String _webAppsDir = "./webapps/"; + private String _listenPort; + private String _listenHost; + private String _sslListenPort; + private String _sslListenHost; + private String _webAppsDir; private static final String PROP_WEBAPP_CONFIG_FILENAME = "router.webappsConfigFile"; private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config"; private static final DigestAuthenticator authenticator = new DigestAuthenticator(); public static final String ROUTERCONSOLE = "routerconsole"; public static final String PREFIX = "webapps."; public static final String ENABLED = ".startOnLoad"; + private static final String PROP_KEYSTORE_PASSWORD = "routerconsole.keystorePassword"; + private static final String DEFAULT_KEYSTORE_PASSWORD = "changeit"; + private static final String PROP_KEY_PASSWORD = "routerconsole.keyPassword"; + private static final String DEFAULT_LISTEN_PORT = "7657"; + private static final String DEFAULT_LISTEN_HOST = "127.0.0.1"; + private static final String DEFAULT_WEBAPPS_DIR = "./webapps/"; + private static final String USAGE = "Bad RouterConsoleRunner arguments, check clientApp.0.args in your clients.config file! " + + "Usage: [[port host[,host]] [-s sslPort [host[,host]]] [webAppsDir]]"; static { System.setProperty("org.mortbay.http.Version.paranoid", "true"); @@ -42,6 +57,27 @@ public class RouterConsoleRunner { } /** + *
+ * non-SSL: + * RouterConsoleRunner + * RouterConsoleRunner 7657 + * RouterConsoleRunner 7657 127.0.0.1 + * RouterConsoleRunner 7657 127.0.0.1,::1 + * RouterConsoleRunner 7657 127.0.0.1,::1 ./webapps/ + * + * SSL: + * RouterConsoleRunner -s 7657 + * RouterConsoleRunner -s 7657 127.0.0.1 + * RouterConsoleRunner -s 7657 127.0.0.1,::1 + * RouterConsoleRunner -s 7657 127.0.0.1,::1 ./webapps/ + * + * If using both, non-SSL must be first: + * RouterConsoleRunner 7657 127.0.0.1 -s 7667 + * RouterConsoleRunner 7657 127.0.0.1 -s 7667 127.0.0.1 + * RouterConsoleRunner 7657 127.0.0.1,::1 -s 7667 127.0.0.1,::1 + * RouterConsoleRunner 7657 127.0.0.1,::1 -s 7667 127.0.0.1,::1 ./webapps/ + *+ * * @param args second arg may be a comma-separated list of bind addresses, * for example ::1,127.0.0.1 * On XP, the other order (127.0.0.1,::1) fails the IPV6 bind, @@ -50,10 +86,40 @@ public class RouterConsoleRunner { * So the wise choice is ::1,127.0.0.1 */ public RouterConsoleRunner(String args[]) { - if (args.length == 3) { - _listenPort = args[0].trim(); - _listenHost = args[1].trim(); - _webAppsDir = args[2].trim(); + if (args.length == 0) { + // _listenHost and _webAppsDir are defaulted above + _listenPort = DEFAULT_LISTEN_PORT; + } else { + boolean ssl = false; + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-s")) + ssl = true; + else if ((!ssl) && _listenPort == null) + _listenPort = args[i]; + else if ((!ssl) && _listenHost == null) + _listenHost = args[i]; + else if (ssl && _sslListenPort == null) + _sslListenPort = args[i]; + else if (ssl && _sslListenHost == null) + _sslListenHost = args[i]; + else if (_webAppsDir == null) + _webAppsDir = args[i]; + else { + System.err.println(USAGE); + throw new IllegalArgumentException(USAGE); + } + } + } + if (_listenHost == null) + _listenHost = DEFAULT_LISTEN_HOST; + if (_sslListenHost == null) + _sslListenHost = _listenHost; + if (_webAppsDir == null) + _webAppsDir = DEFAULT_WEBAPPS_DIR; + // _listenPort and _sslListenPort are not defaulted, if one or the other is null, do not enable + if (_listenPort == null && _sslListenPort == null) { + System.err.println(USAGE); + throw new IllegalArgumentException(USAGE); } } @@ -96,22 +162,63 @@ public class RouterConsoleRunner { List
STDIN
of the shell process via {@link #getInputStream()}.
*
+ * Warning, no good way to quote or escape spaces in arguments with this method.
+ * @deprecated unused
+ *
* @param shellCommand The command for the shell to execute.
*/
public void execute(String shellCommand) {
@@ -215,6 +219,9 @@ public class ShellCommand {
* Input can be passed to the STDIN
of the shell process via
* {@link #getInputStream()}.
*
+ * Warning, no good way to quote or escape spaces in arguments with this method.
+ * @deprecated unused
+ *
* @param shellCommand The command for the shell to execute.
* @return true
if the spawned shell process
* returns an exit status of 0 (indicating success),
@@ -237,6 +244,9 @@ public class ShellCommand {
* {@link #getErrorStream()}, respectively. Input can be passed to the
* STDIN
of the shell process via {@link #getInputStream()}.
*
+ * Warning, no good way to quote or escape spaces in arguments with this method.
+ * @deprecated unused
+ *
* @param shellCommand The command for the shell to execute.
* @param seconds The method will return true
if this
* number of seconds elapses without the process
@@ -276,6 +286,9 @@ public class ShellCommand {
* without waiting for an exit status. Any output produced by the executed
* command will not be displayed.
*
+ * Warning, no good way to quote or escape spaces in arguments with this method.
+ * @deprecated unused
+ *
* @param shellCommand The command for the shell to execute.
* @throws IOException
*/
@@ -288,6 +301,8 @@ public class ShellCommand {
* all of the command's resulting shell processes have completed. Any output
* produced by the executed command will not be displayed.
*
+ * Warning, no good way to quote or escape spaces in arguments with this method.
+ *
* @param shellCommand The command for the shell to execute.
* @return true
if the spawned shell process
* returns an exit status of 0 (indicating success),
@@ -307,7 +322,12 @@ public class ShellCommand {
* specified number of seconds has elapsed first. Any output produced by the
* executed command will not be displayed.
*
- * @param shellCommand The command for the shell to execute.
+ * Warning, no good way to quote or escape spaces in arguments when shellCommand is a String.
+ * Use a String array for best results, especially on Windows.
+ *
+ * @param shellCommand The command for the shell to execute, as a String.
+ * You can't quote arguments successfully.
+ * See Runtime.exec(String) for more info.
* @param seconds The method will return true
if this
* number of seconds elapses without the process
* returning an exit status. A value of 0
@@ -317,7 +337,33 @@ public class ShellCommand {
* else false
.
*/
public synchronized boolean executeSilentAndWaitTimed(String shellCommand, int seconds) {
+ return executeSAWT(shellCommand, seconds);
+ }
+ /**
+ * Passes a command to the shell for execution. This method blocks until
+ * all of the command's resulting shell processes have completed unless a
+ * specified number of seconds has elapsed first. Any output produced by the
+ * executed command will not be displayed.
+ *
+ * @param commandArray The command for the shell to execute,
+ * as a String[].
+ * See Runtime.exec(String[]) for more info.
+ * @param seconds The method will return true
if this
+ * number of seconds elapses without the process
+ * returning an exit status. A value of 0
+ * here disables waiting.
+ * @return true
if the spawned shell process
+ * returns an exit status of 0 (indicating success),
+ * else false
.
+ * @since 0.8.3
+ */
+ public synchronized boolean executeSilentAndWaitTimed(String[] commandArray, int seconds) {
+ return executeSAWT(commandArray, seconds);
+ }
+
+ /** @since 0.8.3 */
+ private boolean executeSAWT(Object shellCommand, int seconds) {
_commandThread = new CommandThread(this, shellCommand, CONSUME_OUTPUT);
_commandThread.start();
try {
@@ -364,7 +410,10 @@ public class ShellCommand {
return;
}
- private boolean execute(String shellCommand, boolean consumeOutput, boolean waitForExitStatus) {
+ /**
+ * @param shellCommand either a String or a String[] (since 0.8.3) - quick hack
+ */
+ private boolean execute(Object shellCommand, boolean consumeOutput, boolean waitForExitStatus) {
StreamConsumer processStderrConsumer;
StreamConsumer processStdoutConsumer;
@@ -374,7 +423,13 @@ public class ShellCommand {
StreamReader processStdoutReader;
try {
- _process = Runtime.getRuntime().exec(shellCommand, null);
+ // easy way so we don't have to copy this whole method
+ if (shellCommand instanceof String)
+ _process = Runtime.getRuntime().exec((String)shellCommand);
+ else if (shellCommand instanceof String[])
+ _process = Runtime.getRuntime().exec((String[])shellCommand);
+ else
+ throw new ClassCastException("shell command must be a String or a String[]");
if (consumeOutput) {
processStderrConsumer = new StreamConsumer(_process.getErrorStream());
processStderrConsumer.start();
diff --git a/installer/resources/clients.config b/installer/resources/clients.config
index f82aec526..08c6c62ba 100644
--- a/installer/resources/clients.config
+++ b/installer/resources/clients.config
@@ -6,6 +6,21 @@
#
# fire up the web console
+## There are several choices, here are some examples:
+## non-SSL, bind to local IPv4 only
+#clientApp.0.args=7657 127.0.0.1 ./webapps/
+## non-SSL, bind to local IPv6 only
+#clientApp.0.args=7657 ::1 ./webapps/
+## non-SSL, bind to all IPv4 addresses
+#clientApp.0.args=7657 0.0.0.0 ./webapps/
+## non-SSL, bind to all IPv6 addresses
+#clientApp.0.args=7657 :: ./webapps/
+## For SSL only, change clientApp.4.args below to https://
+## SSL only
+#clientApp.0.args=-s 7657 ::1,127.0.0.1 ./webapps/
+## non-SSL and SSL
+#clientApp.0.args=7657 ::1,127.0.0.1 -s 7667 ::1,127.0.0.1 ./webapps/
+## non-SSL only, both IPv6 and IPv4 local interfaces
clientApp.0.args=7657 ::1,127.0.0.1 ./webapps/
clientApp.0.main=net.i2p.router.web.RouterConsoleRunner
clientApp.0.name=I2P Router Console