diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 8420604c9..5ff15576d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -19,8 +19,10 @@ import net.i2p.client.I2PSession; import net.i2p.data.Base32; import net.i2p.data.Destination; import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel; +import net.i2p.util.FileUtil; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; +import net.i2p.util.SecureFile; import net.i2p.util.SecureFileOutputStream; /** @@ -43,6 +45,8 @@ public class TunnelController implements Logging { private boolean _running; private boolean _starting; + private static final String KEY_BACKUP_DIR = "i2ptunnel-keyBackup"; + /** * Create a new controller for a tunnel out of the specific config options. * The config may contain a large number of options - only ones that begin in @@ -102,8 +106,19 @@ public class TunnelController implements Logging { Destination dest = client.createDestination(fos); String destStr = dest.toBase64(); log("Private key created and saved in " + keyFile.getAbsolutePath()); + log("You should backup this file in a secure place."); log("New destination: " + destStr); log("Base32: " + Base32.encode(dest.calculateHash().getData()) + ".b32.i2p"); + File backupDir = new SecureFile(I2PAppContext.getGlobalContext().getConfigDir(), KEY_BACKUP_DIR); + if (backupDir.exists() || backupDir.mkdir()) { + String name = keyFile.getName(); + if (name.endsWith(".dat")) + name = name.substring(0, name.length() - 4); + name += "-" + I2PAppContext.getGlobalContext().clock().now() + ".dat"; + File backup = new File(backupDir, name); + if (FileUtil.copy(keyFile, backup, false, true)) + log("Private key backup saved to " + backup.getAbsolutePath()); + } } catch (I2PException ie) { if (_log.shouldLog(Log.ERROR)) _log.error("Error creating new destination", ie); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java index 5592b5b87..3262cf711 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java @@ -20,6 +20,7 @@ import net.i2p.data.DataHelper; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; import net.i2p.util.OrderedProperties; +import net.i2p.util.SystemVersion; /** * Coordinate a set of tunnels within the JVM, loading and storing their config @@ -50,7 +51,7 @@ public class TunnelControllerGroup implements ClientApp { /** * In I2PAppContext will instantiate if necessary and always return non-null. - * As of 0.9.4, when in RouterContext, will return null + * As of 0.9.4, when in RouterContext, will return null (except in Android) * if the TCG has not yet been started by the router. * * @throws IllegalArgumentException if unable to load from i2ptunnel.config @@ -59,7 +60,7 @@ public class TunnelControllerGroup implements ClientApp { synchronized (TunnelControllerGroup.class) { if (_instance == null) { I2PAppContext ctx = I2PAppContext.getGlobalContext(); - if (!ctx.isRouterContext()) { + if (SystemVersion.isAndroid() || !ctx.isRouterContext()) { _instance = new TunnelControllerGroup(ctx, null, null); _instance.startup(); } // else wait for the router to start it