diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 2f1619d5c9..11aa025bc9 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -254,6 +254,8 @@ public class TunnelController implements Logging { File altFile = getAlternatePrivateKeyFile(); if (altFile == null) return false; + if (altFile.equals(keyFile)) + return false; if (altFile.exists()) return true; PrivateKeyFile pkf = new PrivateKeyFile(keyFile); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java index 26f4265e02..2a684c7e40 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java @@ -264,14 +264,23 @@ public class GeneralHelper { return (tun != null && tun.getSpoofedHost() != null) ? tun.getSpoofedHost() : ""; } + /** + * @return path, non-null, non-empty + */ public String getPrivateKeyFile(int tunnel) { return getPrivateKeyFile(_group, tunnel); } + /** + * @return path, non-null, non-empty + */ public String getPrivateKeyFile(TunnelControllerGroup tcg, int tunnel) { TunnelController tun = getController(tcg, tunnel); - if (tun != null && tun.getPrivKeyFile() != null) - return tun.getPrivKeyFile(); + if (tun != null) { + String rv = tun.getPrivKeyFile(); + if (rv != null) + return rv; + } if (tunnel < 0) tunnel = tcg == null ? 999 : tcg.getControllers().size(); String rv = "i2ptunnel" + tunnel + "-privKeys.dat"; @@ -284,6 +293,28 @@ public class GeneralHelper { return rv; } + /** + * @return path or "" + * @since 0.9.30 + */ + public String getAltPrivateKeyFile(int tunnel) { + return getAltPrivateKeyFile(_group, tunnel); + } + + /** + * @return path or "" + * @since 0.9.30 + */ + public String getAltPrivateKeyFile(TunnelControllerGroup tcg, int tunnel) { + TunnelController tun = getController(tcg, tunnel); + if (tun != null) { + File f = tun.getAlternatePrivateKeyFile(); + if (f != null) + return f.getAbsolutePath(); + } + return ""; + } + public String getClientInterface(int tunnel) { TunnelController tun = getController(tunnel); if (tun != null) { @@ -357,6 +388,29 @@ public class GeneralHelper { return null; } + /** + * Works even if tunnel is not running. + * @return Destination or null + * @since 0.9.30 + */ + public Destination getAltDestination(int tunnel) { + TunnelController tun = getController(tunnel); + if (tun != null) { + // do this the hard way + File keyFile = tun.getAlternatePrivateKeyFile(); + if (keyFile != null) { + PrivateKeyFile pkf = new PrivateKeyFile(keyFile); + try { + Destination rv = pkf.getDestination(); + if (rv != null) + return rv; + } catch (I2PException e) { + } catch (IOException e) {} + } + } + return null; + } + public boolean shouldStartAutomatically(int tunnel) { TunnelController tun = getController(tunnel); return tun != null ? tun.getStartOnLoad() : false; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java index 6dd91cce36..d381939a11 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java @@ -161,6 +161,16 @@ public class TunnelConfig { public String getPrivKeyFile() { return _privKeyFile; } + + /** + * What filename is this server tunnel's alternate private keys stored in + * @since 0.9.30 + */ + public void setAltPrivKeyFile(String file) { + if (file != null) + _otherOptions.put(I2PTunnelServer.PROP_ALT_PKF, file.trim()); + } + /** * If called with any value, we want this tunnel to start whenever it is * loaded (aka right now and whenever the router is started up) @@ -725,7 +735,8 @@ public class TunnelConfig { PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY, PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY, PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE, - "inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey" + "inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey", + I2PTunnelServer.PROP_ALT_PKF }; private static final String _httpServerOpts[] = { I2PTunnelHTTPServer.OPT_POST_WINDOW, diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java index f252faade8..99317e54b0 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java @@ -70,6 +70,14 @@ public class EditBean extends IndexBean { public String getPrivateKeyFile(int tunnel) { return _helper.getPrivateKeyFile(tunnel); } + + /** + * @return path or "" + * @since 0.9.30 + */ + public String getAltPrivateKeyFile(int tunnel) { + return _helper.getAltPrivateKeyFile(tunnel); + } /**** public String getNameSignature(int tunnel) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index fe1c30b17b..be841b817c 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -488,6 +488,39 @@ public class IndexBean { return d.toBase32(); return ""; } + + /** + * Works even if tunnel is not running. + * @return Destination or null + * @since 0.9.30 + */ + protected Destination getAltDestination(int tunnel) { + return _helper.getAltDestination(tunnel); + } + + /** + * Works even if tunnel is not running. + * @return Base64 or "" + * @since 0.9.30 + */ + public String getAltDestinationBase64(int tunnel) { + Destination d = getAltDestination(tunnel); + if (d != null) + return d.toBase64(); + return ""; + } + + /** + * Works even if tunnel is not running. + * @return "{52 chars}.b32.i2p" or "" + * @since 0.9.30 + */ + public String getAltDestHashBase32(int tunnel) { + Destination d = getAltDestination(tunnel); + if (d != null) + return d.toBase32(); + return ""; + } /** * For index.jsp @@ -613,10 +646,20 @@ public class IndexBean { public void setSpoofedHost(String host) { _config.setSpoofedHost(host); } + /** What filename is this server tunnel's private keys stored in */ public void setPrivKeyFile(String file) { _config.setPrivKeyFile(file); } + + /** + * What filename is this server tunnel's alternate private keys stored in + * @since 0.9.30 + */ + public void setAltPrivKeyFile(String file) { + _config.setAltPrivKeyFile(file); + } + /** * If called with any value (and the form submitted with action=Remove), * we really do want to stop and remove the tunnel. diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp index f2e5204e85..c93ceb6ac1 100644 --- a/apps/i2ptunnel/jsp/editServer.jsp +++ b/apps/i2ptunnel/jsp/editServer.jsp @@ -669,8 +669,9 @@ input.default { width: 1px; height: 1px; visibility: hidden; } <% **********************/ %> - <% if (true /* editBean.isAdvanced() */ ) { - int currentSigType = editBean.getSigType(curTunnel, tunnelType); + <% + int currentSigType = editBean.getSigType(curTunnel, tunnelType); + if (true /* editBean.isAdvanced() */ ) { %>