Files
i2p.firefox/java/net/i2p/router/WinLauncher.java

396 lines
13 KiB
Java
Raw Normal View History

2021-04-03 16:39:26 -04:00
package net.i2p.router;
import static net.i2p.update.UpdateType.*;
2021-04-03 16:39:26 -04:00
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
2021-04-03 16:39:26 -04:00
import java.util.*;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
2021-07-01 19:52:21 -04:00
import net.i2p.app.ClientAppManager;
import net.i2p.crypto.*;
import net.i2p.i2pfirefox.*;
import net.i2p.router.Router;
import net.i2p.router.RouterLaunch;
import net.i2p.update.*;
2021-07-01 19:52:21 -04:00
import net.i2p.update.UpdateManager;
import net.i2p.update.UpdatePostProcessor;
2021-04-03 16:39:26 -04:00
/**
* Launches a router from %PROGRAMFILES%/I2P using configuration data in
* %LOCALAPPDATA%/I2P.. Uses Java 9 APIs.
*
2021-04-03 16:39:26 -04:00
* Sets the following properties:
* i2p.dir.base - this points to the (read-only) resources inside the bundle
* i2p.dir.config this points to the (read-write) config directory in local
* appdata
2021-04-03 16:39:26 -04:00
* router.pid - the pid of the java process.
*/
public class WinLauncher extends CopyConfigDir {
static WindowsUpdatePostProcessor wupp = null;
private static Router i2pRouter;
2022-09-19 19:31:21 -04:00
public static void main(String[] args) {
2022-09-10 23:51:13 -04:00
setupLauncher();
2022-09-13 22:53:12 -04:00
initLogger();
2022-10-01 22:00:58 -04:00
int privateBrowsing = 0;
boolean usabilityMode = false;
boolean chromiumFirst = false;
int proxyTimeoutTime = 200;
2022-09-07 02:28:23 -04:00
ArrayList<String> newArgsList = new ArrayList<String>();
if (args != null) {
if (args.length > 0) {
2022-09-07 02:28:23 -04:00
for (String arg : args) {
if (arg.equals("-private")) {
2022-10-01 22:00:58 -04:00
privateBrowsing = 1;
2022-09-07 02:28:23 -04:00
logger.info(
"Private browsing is true, profile will be discarded at end of session.");
} else if (arg.equals("-chromium")) {
chromiumFirst = true;
logger.info("Chromium will be selected before Firefox.");
} else if (arg.equals("-usability")) {
usabilityMode = true;
logger.info(
"Usability mode is true, using alternate extensions loadout.");
} else if (arg.equals("-noproxycheck")) {
proxyTimeoutTime = 0;
logger.info("Proxy timeout time set to zero");
2022-09-07 02:28:23 -04:00
} else {
// make an effort to not let people launch into sites if the proxy
// isn't quite ready yet, but also disable the proxy timeout if
// they're reaching a router console
if (arg.startsWith("http://localhost:76")) {
newArgsList.add(arg);
proxyTimeoutTime = 0;
} else if (arg.startsWith("http://127.0.0.1:76")) {
newArgsList.add(arg);
proxyTimeoutTime = 0;
} else if (arg.startsWith("https://localhost:76")) {
newArgsList.add(arg);
proxyTimeoutTime = 0;
} else if (arg.startsWith("https://127.0.0.1:76")) {
newArgsList.add(arg);
proxyTimeoutTime = 0;
} else if (proxyTimeoutTime > 0) {
newArgsList.add(arg);
} else if (!isAvailable(4444)) {
newArgsList.add(arg);
}
2022-09-07 02:28:23 -04:00
}
}
}
}
2022-09-11 00:03:30 -04:00
File programs = programFile();
2022-09-10 23:51:13 -04:00
File home = homeDir();
System.setProperty("i2p.dir.base", programs.getAbsolutePath());
System.setProperty("i2p.dir.config", home.getAbsolutePath());
System.setProperty("router.pid",
String.valueOf(ProcessHandle.current().pid()));
/**
* IMPORTANT: You must set user.dir to the same directory where the
* jpackage is intstalled, or when the launcher tries to re-run itself
* to start the browser, it will start in the wrong directory and fail
* to find the JVM and Runtime bundle. This broke Windows 11 installs.
*/
System.setProperty("user.dir", programs.getAbsolutePath());
logger.info("\t" + System.getProperty("user.dir"));
logger.info("\t" + System.getProperty("i2p.dir.base"));
logger.info("\t" + System.getProperty("i2p.dir.config"));
logger.info("\t" + System.getProperty("router.pid"));
2022-09-19 19:31:21 -04:00
boolean continuerunning = promptServiceStartIfAvailable("i2p");
if (!continuerunning) {
logger.severe(
"Service startup failure, please start I2P service with services.msc");
2022-09-19 19:31:21 -04:00
System.exit(2);
} else {
fixServiceConfig();
2022-09-19 19:31:21 -04:00
}
2022-09-19 20:03:57 -04:00
continuerunning = promptUserInstallStartIfAvailable();
if (!continuerunning) {
logger.severe("User-install startup required.");
2022-09-19 20:03:57 -04:00
System.exit(2);
} else {
fixServiceConfig();
2022-09-19 20:03:57 -04:00
}
2022-09-19 19:31:21 -04:00
2022-09-12 20:29:09 -04:00
// This actually does most of what we use NSIS for if NSIS hasn't
// already done it, which essentially makes this whole thing portable.
if (!copyConfigDir()) {
logger.severe("Cannot copy the configuration directory");
System.exit(1);
}
2022-09-11 02:18:32 -04:00
if (launchBrowser(privateBrowsing, usabilityMode, chromiumFirst,
proxyTimeoutTime, newArgsList)) {
System.exit(0);
}
i2pRouter = new Router(routerConfig(), System.getProperties());
if (!isInstalled("i2p")) {
if (i2pRouter.saveConfig("routerconsole.browser", null)) {
logger.info("removed routerconsole.browser config");
}
if (i2pRouter.saveConfig("routerconsole.browser",
appImageExe() + " -noproxycheck")) {
logger.info("updated routerconsole.browser config " + appImageExe());
}
}
2022-09-10 23:51:13 -04:00
logger.info("Router is configured");
Thread registrationThread = new Thread(REGISTER_UPP);
registrationThread.setName("UPP Registration");
registrationThread.setDaemon(true);
registrationThread.start();
2022-09-11 00:03:30 -04:00
setNotStarting();
i2pRouter.runRouter();
2022-09-10 23:51:13 -04:00
}
private static void fixServiceConfig() {
2022-09-20 00:54:56 -04:00
if (osName() != "windows")
return;
// If the user installed the Easy bundle before installing the
// IzPack installer, then they have a config file which contains the
// wrong update URL. Check for it, and change it back if necessary.
// closes #23
String routerconf = routerConfig();
if (routerconf != null) {
File routerconffile = new File(routerconf);
if (!routerconffile.exists()) {
return;
}
} else {
return;
}
if (isInstalled("i2p") || checkProgramFilesInstall()) {
i2pRouter = new Router(routerconf, System.getProperties());
String newsURL = i2pRouter.getConfigSetting("router.newsURL");
if (newsURL != null) {
if (newsURL.contains("http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/win/beta/news.su3")) {
logger.info(
"checked router.newsURL config, containes win/beta in a service install, invalid update type");
if (i2pRouter.saveConfig("router.newsURL", ServiceUpdaterString())) {
logger.info("updated routerconsole.browser config " +
appImageExe());
}
}
}
String backupNewsURL = i2pRouter.getConfigSetting("router.backupNewsURL");
if (backupNewsURL != null) {
if (backupNewsURL.contains("http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/win/beta/news.su3")) {
logger.info(
"checked router.backupNewsURL config, containes win/beta in a service install, invalid update type");
if (i2pRouter.saveConfig("router.backupNewsURL",
ServiceBackupUpdaterString())) {
logger.info("updated routerconsole.browser config " +
appImageExe());
}
}
}
String updateURL = i2pRouter.getConfigSetting("router.updateURL");
if (updateURL != null) {
if (updateURL.contains("http://ekm3fu6fr5pxudhwjmdiea5dovc3jdi66hjgop4c7z7dfaw7spca.b32.i2p/i2pwinupdate.su3")) {
logger.info(
"checked router.updateURL config, containes easy-intall update in a service install, invalid update type");
if (i2pRouter.saveConfig("router.updateURL",
ServiceStaticUpdaterString())) {
logger.info("updated routerconsole.browser config " +
appImageExe());
}
}
}
}
}
2022-09-10 23:51:13 -04:00
private static void setupLauncher() {
File jrehome = javaHome();
logger.info("jre home is: " + jrehome.getAbsolutePath());
File appimagehome = appImageHome();
logger.info("appimage home is: " + appimagehome.getAbsolutePath());
}
2021-04-03 16:39:26 -04:00
2022-09-11 00:03:30 -04:00
private static File programFile() {
File programs = selectProgramFile();
if (!programs.exists())
programs.mkdirs();
else if (!programs.isDirectory()) {
logger.warning(
programs +
" exists but is not a directory. Please get it out of the way");
System.exit(1);
}
2022-09-10 23:51:13 -04:00
return programs;
}
2022-09-11 00:03:30 -04:00
private static File homeDir() {
File home = selectHome();
if (!home.exists())
home.mkdirs();
else if (!home.isDirectory()) {
logger.warning(
home +
" exists but is not a directory. Please get it out of the way");
System.exit(1);
}
2022-09-10 23:51:13 -04:00
return home;
}
2022-10-01 22:00:58 -04:00
private static boolean launchBrowser(int privateBrowsing,
2022-09-10 23:51:13 -04:00
boolean usabilityMode,
boolean chromiumFirst,
int proxyTimeoutTime,
ArrayList<String> newArgsList) {
if (i2pIsRunning()) {
2022-09-10 23:51:13 -04:00
logger.info("I2P is already running, launching an I2P browser");
I2PBrowser i2pBrowser = new I2PBrowser();
i2pBrowser.usability = usabilityMode;
i2pBrowser.chromiumFirst = chromiumFirst;
i2pBrowser.firefox = !chromiumFirst;
i2pBrowser.chromium = chromiumFirst;
2022-09-11 00:03:30 -04:00
if (chromiumFirst) {
2022-09-10 23:51:13 -04:00
logger.warning("favoring Chromium instead of Firefox");
}
i2pBrowser.setProxyTimeoutTime(proxyTimeoutTime);
System.out.println("I2PBrowser");
String[] newArgs = newArgsList.toArray(new String[newArgsList.size()]);
2022-09-11 00:03:30 -04:00
setNotStarting();
i2pBrowser.launch(privateBrowsing, newArgs);
2022-09-10 23:51:13 -04:00
return true;
}
2022-09-10 23:51:13 -04:00
return false;
}
// see
// https://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java
2022-09-11 01:31:08 -04:00
private static boolean isAvailable(int portNr) {
boolean portFree;
try (var ignored = new ServerSocket(portNr)) {
portFree = true;
} catch (IOException e) {
portFree = false;
}
return portFree;
}
2022-09-04 23:56:07 -04:00
private static boolean i2pIsRunningCheck() {
// check if there's something listening on port 7657(Router Console)
if (!isAvailable(7657))
2022-09-04 23:56:07 -04:00
return true;
// check if there's something listening on port 7654(I2CP)
if (!isAvailable(7654))
return true;
if (checkPing())
2022-09-04 23:56:07 -04:00
return true;
return false;
}
2022-09-11 00:03:30 -04:00
private static void setNotStarting() {
2022-09-10 23:51:13 -04:00
logger.info("removing startup file, the application has started");
2022-09-05 01:47:16 -04:00
File home = selectHome();
2022-09-10 23:51:13 -04:00
File starting = new File(home, "starting");
if (starting.exists()) {
starting.delete();
2022-09-05 01:47:16 -04:00
}
}
2022-09-11 00:03:30 -04:00
private static void setStarting() {
2022-09-10 23:51:13 -04:00
logger.info("creating startup file, router is starting up");
2022-09-05 01:47:16 -04:00
File home = selectHome();
2022-09-10 23:51:13 -04:00
File starting = new File(home, "starting");
if (!starting.exists()) {
2022-09-07 02:28:23 -04:00
try {
2022-09-10 23:51:13 -04:00
starting.createNewFile();
2022-09-07 02:28:23 -04:00
} catch (IOException e) {
logger.info(e.toString());
}
2022-09-05 01:47:16 -04:00
}
}
2022-09-10 23:51:13 -04:00
2022-09-11 00:03:30 -04:00
private static boolean checkStarting() {
2022-09-10 23:51:13 -04:00
logger.info("checking startup file");
2022-09-05 00:41:20 -04:00
File home = selectHome();
2022-09-10 23:51:13 -04:00
File starting = new File(home, "starting");
if (starting.exists()) {
logger.info("startup file exists, I2P is already starting up");
2022-09-05 01:47:16 -04:00
return true;
}
2022-09-10 23:51:13 -04:00
logger.info("startup file does not exist but we're running now");
2022-09-11 00:03:30 -04:00
setStarting();
return false;
}
// check for the existence of router.ping file, if it's less then 2
// minutes old, exit
private static boolean checkPing() {
File home = selectHome();
2022-09-05 00:41:20 -04:00
File ping = new File(home, "router.ping");
if (ping.exists()) {
long diff = System.currentTimeMillis() - ping.lastModified();
2022-09-05 00:41:51 -04:00
if (diff > 60 * 1000) {
2022-09-05 00:41:20 -04:00
logger.info(
"router.ping exists and is more than 1 minute old, I2P does not appear to be running.");
logger.info("If I2P is running, report this as a bug.");
return false;
} else {
return true;
2022-09-05 00:41:20 -04:00
}
}
return false;
}
private static boolean i2pIsRunning() {
2022-09-11 00:03:30 -04:00
if (checkStarting())
return true;
if (checkPing())
return true;
2022-09-04 23:56:07 -04:00
if (i2pIsRunningCheck())
return true;
2022-09-07 16:19:21 -04:00
for (int i = 0; i < 10; i++) {
2022-09-04 23:56:07 -04:00
if (i2pIsRunningCheck())
return true;
2022-09-04 23:50:58 -04:00
sleep(1000);
}
return false;
}
private static final Runnable REGISTER_UPP = () -> {
RouterContext ctx;
while ((ctx = i2pRouter.getContext()) == null) {
sleep(1000);
}
// then wait for the update manager
ClientAppManager cam;
while ((cam = ctx.clientAppManager()) == null) {
sleep(1000);
}
UpdateManager um;
while ((um = (UpdateManager)cam.getRegisteredApp(UpdateManager.APP_NAME)) ==
null) {
sleep(1000);
}
WindowsUpdatePostProcessor wupp = new WindowsUpdatePostProcessor(ctx);
um.register(wupp, UpdateType.ROUTER_SIGNED_SU3, SU3File.TYPE_EXE);
um.register(wupp, UpdateType.ROUTER_DEV_SU3, SU3File.TYPE_EXE);
};
/**
* sleep for 1 second
*
* @param millis
*/
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException bad) {
bad.printStackTrace();
throw new RuntimeException(bad);
}
}
2021-04-03 16:39:26 -04:00
}