diff --git a/build.xml b/build.xml index ca222a6..4c6bd59 100755 --- a/build.xml +++ b/build.xml @@ -2,7 +2,7 @@ - + @@ -20,6 +20,18 @@ + + + + + + + + + + + + diff --git a/src/java/net/i2p/i2pfirefox/I2PChromium.java b/src/java/net/i2p/i2pfirefox/I2PChromium.java new file mode 100644 index 0000000..01d9ca7 --- /dev/null +++ b/src/java/net/i2p/i2pfirefox/I2PChromium.java @@ -0,0 +1,446 @@ +package net.i2p.i2pfirefox; + +import java.io.File; +import java.io.IOException; +import java.net.Socket; +import java.util.ArrayList; + + +public class I2PChromium { + private final String[] CHROMIUM_SEARCH_PATHS = CHROMIUM_FINDER(); + private final int DEFAULT_TIMEOUT = 200; + + /* + * Construct an I2PChromium class which manages an instance of Chromium and + * an accompanying Chromium profile. This version includes Chromium variants + * and forks. + * + * @since 0.0.1 + */ + public I2PChromium() { + for (String path : CHROMIUM_SEARCH_PATHS) { + File f = new File(path); + if (f.exists()) { + System.out.println("Found Chromium at " + path); + return; + } + } + + } + + private static String[] FIND_CHROMIUM_SEARCH_PATHS_UNIX(){ + String[] path = new String[]{"/usr/bin", "/usr/local/bin", "/opt/chrome/bin","/snap/bin"}; + String[] exes = new String[]{"ungoogled-chromium", "chromium", "brave", "edge", "ungoogled-chromium", "chrome"}; + String[] exePath = new String[path.length * exes.length]; + int i = 0; + for (String s : path) { + for (String exe : exes) { + exePath[i] = s + "/" + exe; + i++; + } + } + return exePath; + } + private static String[] FIND_CHROMIUM_SEARCH_PATHS_OSX() { + String[] path = new String[]{"/Applications/Chromium.app/Contents/MacOS/", "/Applications/Waterfox.app/Contents/MacOS/", "/Applications/Librewolf.app/Contents/MacOS/"}; + String[] exes = new String[]{"ungoogled-chromium", "chromium", "brave", "edge", "ungoogled-chromium", "chrome"}; + String[] exePath = new String[path.length * exes.length]; + int i = 0; + for (String s : path) { + for (String exe : exes) { + exePath[i] = s + "/" + exe; + i++; + } + } + return exePath; + } + private static String[] FIND_CHROMIUM_SEARCH_PATHS_WINDOWS() { + String userHome = System.getProperty("user.home"); + String programFiles = System.getenv("ProgramFiles"); + String localAppData = System.getenv("LOCALAPPDATA"); + String programFiles86 = System.getenv("ProgramFiles(x86)"); + String[] path = new String[]{ + new File(localAppData, "/Google/Chrome/Application/").toString(), + new File(programFiles, "/Google/Chrome/Application/").toString(), + new File(programFiles86, "/Google/Chrome/Application/").toString(), + new File(localAppData, "/Chromium/Application/").toString(), + new File(programFiles, "/Chromium/Application/").toString(), + new File(programFiles86, "/Chromium/Application/").toString(), + new File(localAppData, "/BraveSoftware/Brave Browser/Application/").toString(), + new File(programFiles, "/BraveSoftware/Brave Browser/Application/").toString(), + new File(programFiles86, "/BraveSoftware/Brave Browser/Application/").toString(), + new File(programFiles86, "/Microsoft/Edge/Application/").toString(), + new File(programFiles, "/Microsoft/Edge/Application/").toString(), + }; + String[] exes = new String[]{"ungoogled-chromium.exe", "chromium.exe", "brave.exe", "edge.exe", "ungoogled-chromium.exe", "chrome.exe"}; + String[] exePath = new String[path.length * exes.length]; + int i = 0; + for (String s : path) { + for (String exe : exes) { + exePath[i] = s + exe; + i++; + } + } + return exePath; + } + + private static String[] FIND_ALL_CHROMIUM_SEARCH_PATHS() { + String[] Unix = FIND_CHROMIUM_SEARCH_PATHS_UNIX(); + String[] Windows = FIND_CHROMIUM_SEARCH_PATHS_WINDOWS(); + String[] Mac = FIND_CHROMIUM_SEARCH_PATHS_OSX(); + String[] exePath = new String[Unix.length + Windows.length + Mac.length]; + int i = 0; + for (String s : Unix) { + exePath[i] = s; + i++; + } + for (String s : Windows) { + exePath[i] = s; + i++; + } + for (String s : Mac) { + exePath[i] = s; + i++; + } + return exePath; + } + private static String[] FIND_CHROMIUM_SEARCH_PATHS() { + switch (getOperatingSystem()) { + case "Windows": + return FIND_CHROMIUM_SEARCH_PATHS_WINDOWS(); + case "Linux": + return FIND_CHROMIUM_SEARCH_PATHS_UNIX(); + case "Mac": + return FIND_CHROMIUM_SEARCH_PATHS_OSX(); + case "BSD": + return FIND_CHROMIUM_SEARCH_PATHS_UNIX(); + default: + return FIND_ALL_CHROMIUM_SEARCH_PATHS(); + } + } + private static String[] NEARBY_CHROMIUM_SEARCH_PATHS() { + // obtain the PLUGIN environment variable + String plugin = System.getenv("PLUGIN"); + // search the plugin directory for anything named "ungoogled-chromium", "chromium", "brave", "edge", "ungoogled-chromium", "chrome" + // up to a depth of 2 directories deep. + // list the directories in the plugin directory + if (plugin != null && !plugin.isEmpty()){ + File pluginDir = new File(plugin); + if (pluginDir.exists()) { + File[] pluginDirs = pluginDir.listFiles(); + // list the files in the plugin directory + for (File pluginDir1 : pluginDirs) { + File[] pluginFiles = pluginDir1.listFiles(); + // list the files in the plugin directory + if (pluginFiles != null){ + for (File pluginFile : pluginFiles) { + if (pluginFile.getName().equals("ungoogled-chromium") || pluginFile.getName().equals("chromium") || pluginFile.getName().equals("brave") || pluginFile.getName().equals("edge") || pluginFile.getName().equals("ungoogled-chromium") || pluginFile.getName().equals("chrome")) { + return new String[]{pluginFile.getAbsolutePath()}; + } + } + } + } + } + } + // now, do the same thing, but with user.dir instead of plugin + // list the directories in the user.dir directory + File userDir = new File(System.getProperty("user.dir")); + if (userDir.exists()) { + File[] userDirs = userDir.listFiles(); + // list the files in the user.dir directory + for (File userDir1 : userDirs) { + File[] userFiles = userDir1.listFiles(); + // list the files in the user.dir directory + if (userFiles != null){ + for (File userFile : userFiles) { + if (userFile.getName().equals("ungoogled-chromium") || userFile.getName().equals("chromium") || userFile.getName().equals("brave") || userFile.getName().equals("edge") || userFile.getName().equals("ungoogled-chromium") || userFile.getName().equals("chrome")) { + return new String[]{userFile.getAbsolutePath()}; + } + } + } + } + } + return new String[]{}; + } + private static String[] CHROMIUM_FINDER() { + String[] nearby = NEARBY_CHROMIUM_SEARCH_PATHS(); + String[] all = FIND_CHROMIUM_SEARCH_PATHS(); + + if (nearby != null && nearby.length > 0) { + return nearby; + } else if (all != null && all.length > 0) { + return all; + } else { + return new String[]{}; + } + } + private static String getOperatingSystem() { + String os = System.getProperty("os.name"); + if (os.startsWith("Windows")) { + return "Windows"; + } else if (os.contains("Linux")) { + return "Linux"; + } else if (os.contains("BSD")) { + return "BSD"; + } else if (os.contains("Mac")) { + return "Mac"; + } + return "Unknown"; + } + + /* + * Check our list of chrome paths for a valid chrome binary. + * Just an existence check for now, but should check versions + * in the future. + * + * @return a list of usable Chromiums, or an empty list if none are found. + * @since 0.0.1 + */ + public String[] onlyValidChromiums() { + String[] chromees = CHROMIUM_FINDER(); + ArrayList validChromiums = new ArrayList(); + for (String chrome : chromees) { + File chromeFile = new File(chrome); + if (chromeFile.exists()) { + validChromiums.add(chrome); + } + } + return validChromiums.toArray(new String[validChromiums.size()]); + } + + /* + * Return the best available Chromium from the list of Chromiums we have. + * + * @return the path to the best available Chromium, or null if none are found. + * @since 0.0.1 + */ + public String topChromium() { + // get the CHROMIUM environment variable + String chrome = System.getenv("CHROMIUM"); + // if it is not null and not empty + if (chrome != null && !chrome.isEmpty()) { + // check if the file exists + File chromeFile = new File(chrome); + if (chromeFile.exists()) { + // if it does, return it + return chrome; + } + } + String[] chromees = onlyValidChromiums(); + if (chromees.length > 0) { + return chromees[0]; + } else { + return ""; + } + } + + /* + * Return the best available Chromium from the list of Chromiums we have. + * if override is passed it will be validated and if it validates, it will + * be used. + * + * @param override the path to a valid Chromium binary to use. + * @return the path to the best available Chromium, or null if none are found. + * @since 0.0.1 + */ + public String topChromium(String overrideChromium) { + if (overrideChromium != null && !overrideChromium.isEmpty()) { + File chromeFile = new File(overrideChromium); + if (chromeFile.exists()) { + return overrideChromium; + } + } + return topChromium(); + } + + /* + * Build a ProcessBuilder for the top Chromium binary and + * the default profile. + * + * @return a ProcessBuilder for the top Chromium binary and + * the default profile. + * @since 0.0.1 + */ + public ProcessBuilder defaultProcessBuilder() { + return processBuilder(new String[]{}); + } + + /* + 1 --user-data-dir="$CHROMIUM_I2P" \ + 2 --proxy-server="http://127.0.0.1:4444" \ + 3 --proxy-bypass-list=127.0.0.1:7657 \ + 4 --user-data-dir=$HOME/WebApps/i2padmin \ + 5 --safebrowsing-disable-download-protection \ + 6 --disable-client-side-phishing-detection \ + 7 --disable-3d-apis \ + 8 --disable-accelerated-2d-canvas \ + 9 --disable-remote-fonts \ + 10 --disable-sync-preferences \ + 11 --disable-sync \ + 12 --disable-speech \ + 13 --disable-webgl \ + 14 --disable-reading-from-canvas \ + 15 --disable-gpu \ + 16 --disable-32-apis \ + 17 --disable-auto-reload \ + 18 --disable-background-networking \ + 19 --disable-d3d11 \ + 20 --disable-file-system \ + */ + + /* + * Build a ProcessBuilder for the top Chromium binary and + * the default profile, with a specific set of extended + * arguments. + * + * @param args the extended arguments to pass to the Chromium binary. + * @return a ProcessBuilder for the top Chromium binary and + * default profile, with a specific set of extended arguments. + * @since 0.0.1 + */ + public ProcessBuilder processBuilder(String[] args) { + String chrome = topChromium(); + if (!chrome.isEmpty()) { + String[] newArgs = new String[args.length+19]; + newArgs[0] = chrome; + newArgs[1] = "--user-data-dir="+I2PChromiumProfileBuilder.profileDirectory(); + newArgs[2] = "--proxy-server=http://127.0.0.1:4444"; + newArgs[3] = "--proxy-bypass-list=http://localhost:7657"; + newArgs[4] = "--safebrowsing-disable-download-protection"; + newArgs[5] = "--disable-client-side-phishing-detection"; + newArgs[6] = "--disable-3d-apis"; + newArgs[7] = "--disable-accelerated-2d-canvas"; + newArgs[8] = "--disable-remote-fonts"; + newArgs[9] = "--disable-sync-preferences"; + newArgs[10] = "--disable-sync"; + newArgs[11] = "--disable-speech"; + newArgs[12] = "--disable-webgl"; + newArgs[13] = "--disable-reading-from-canvas"; + newArgs[14] = "--disable-gpu"; + newArgs[15] = "--disable-auto-reload"; + newArgs[16] = "--disable-background-networking"; + newArgs[17] = "--disable-d3d11"; + newArgs[18] = "--disable-file-system"; + for (int i = 0; i < args.length; i++) { + newArgs[i+19] = args[i]; + } + return new ProcessBuilder(newArgs).directory(I2PChromiumProfileBuilder.runtimeDirectory(true)); + } else { + return new ProcessBuilder(args); + } + } + + /* + * Waits for an HTTP proxy on port 4444 to be ready. + * Returns false on timeout of 200 seconds. + * + * @return true if the proxy is ready, false if it is not. + * @since 0.0.1 + */ + public boolean waitForProxy() { + return waitForProxy(DEFAULT_TIMEOUT); + } + + /* + * Waits for an HTTP proxy on port 4444 to be ready. + * Returns false on timeout of the specified number of seconds. + * + * @param timeout the number of seconds to wait for the proxy to be ready. + * @return true if the proxy is ready, false if it is not. + * @since 0.0.1 + */ + public boolean waitForProxy(int timeout) { + return waitForProxy(timeout, 4444); + } + /* + * Waits for an HTTP proxy on the specified port to be ready. + * Returns false on timeout of the specified number of seconds. + * + * @param timeout the number of seconds to wait for the proxy to be ready. + * @param port the port to wait for the proxy to be ready on. + * @return true if the proxy is ready, false if it is not. + * @since 0.0.1 + */ + public boolean waitForProxy(int timeout, int port) { + return waitForProxy(timeout, port, "localhost"); + } + /* + * Waits for an HTTP proxy on the specified port to be ready. + * Returns false on timeout of the specified number of seconds. + * + * @param timeout the number of seconds to wait for the proxy to be ready. + * @param port the port to wait for the proxy to be ready on. + * @param host the host to wait for the proxy to be ready on. + * @return true if the proxy is ready, false if it is not. + * @since 0.0.1 + */ + public boolean waitForProxy(int timeout, int port, String host) { + for (int i = 0; i < timeout; i++) { + if (checkifPortIsOccupied(port, host)) { + return true; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return false; + } + private boolean checkifPortIsOccupied(int port, String host) { + try { + Socket socket = new Socket(host, port); + socket.close(); + return true; + } catch (IOException e) { + return false; + } + } + + + /* + * Populates a profile directory with a proxy configuration. + * Waits for an HTTP proxy on the port 4444 to be ready. + * Launches Chromium with the profile directory. + * + * @since 0.0.1 + */ + public void launch(){ + String profileDirectory = I2PChromiumProfileBuilder.profileDirectory(); + if (I2PChromiumProfileChecker.validateProfileDirectory(profileDirectory)) { + System.out.println("Valid profile directory: "+profileDirectory); + } else { + System.out.println("Invalid profile directory: "+profileDirectory+" rebuilding..."); + if (!I2PChromiumProfileBuilder.copyBaseProfiletoProfile()) { + System.out.println("Failed to rebuild profile directory: "+profileDirectory); + return; + } else { + System.out.println("Rebuilt profile directory: "+profileDirectory); + } + } + if (waitForProxy()){ + ProcessBuilder pb = this.defaultProcessBuilder(); + Process p = null; + try{ + System.out.println(pb.command()); + p = pb.start(); + }catch(Exception e){ + System.out.println("Error: "+e.getMessage()); + }finally{ + System.out.println("I2PChromium"); + try{ + System.out.println("Waiting for I2PChromium to close..."); + p.waitFor(); + }catch(Exception e){ + System.out.println("Error: "+e.getMessage()); + } + } + } + } + + public static void main(String[] args) { + System.out.println("I2PChromium"); + I2PChromium i2pChromium = new I2PChromium(); + i2pChromium.launch(); + } +} diff --git a/src/java/net/i2p/i2pfirefox/I2PChromiumProfileBuilder.java b/src/java/net/i2p/i2pfirefox/I2PChromiumProfileBuilder.java new file mode 100644 index 0000000..2a9a4e2 --- /dev/null +++ b/src/java/net/i2p/i2pfirefox/I2PChromiumProfileBuilder.java @@ -0,0 +1,259 @@ +package net.i2p.i2pfirefox; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +public class I2PChromiumProfileBuilder { + private static boolean strict; + + private static String profileDir(String file) { + File profileDir = new File(file, "i2p.chromium.profile"); + return profileDir.getAbsolutePath(); + } + + /* + * get the profile directory, creating it if necessary + * + * @return the profile directory, or null if it could not be created + */ + public static String profileDirectory() { + String pd = System.getenv("I2P_FIREFOX_PROFILE"); + if (pd != null && !pd.isEmpty()) { + File pdf = new File(pd); + if (pdf.exists() && pdf.isDirectory()) { + return pd; + } + } + String rtd = runtimeDirectory(); + return profileDir(rtd); + } + + private static String baseProfileDir(String file) { + File profileDir = new File(file, "i2p.chromium.base.profile"); + // make sure the directory exists + if (profileDir.exists()) { + return profileDir.getAbsolutePath(); + } else { + // create the directory + I2PChromiumProfileUnpacker unpacker = new I2PChromiumProfileUnpacker(); + if (!unpacker.unpackProfile(profileDir.getAbsolutePath())) { + return null; + } + return profileDir.getAbsolutePath(); + } + } + + /* + * get the base profile directory, creating it if necessary + * + * @return the base profile directory, or null if it could not be created + */ + public static String baseProfileDirectory() { + String pd = System.getenv("I2P_FIREFOX_BASE_PROFILE"); + if (pd != null && !pd.isEmpty()) { + File pdf = new File(pd); + if (pdf.exists() && pdf.isDirectory()) { + return pd; + }else{ + I2PChromiumProfileUnpacker unpacker = new I2PChromiumProfileUnpacker(); + if (!unpacker.unpackProfile(pdf.getAbsolutePath())) { + return null; + } + } + } + String rtd = runtimeDirectory(); + return baseProfileDir(rtd); + } + + /* + * get the runtime directory, creating it if create=true + * + * @param create if true, create the runtime directory if it does not exist + * @return the runtime directory, or null if it could not be created + * @since 0.0.1 + */ + public static File runtimeDirectory(boolean create) { + String rtd = runtimeDirectory(); + File rtdFile = new File(rtd); + if (create) { + if (!rtdFile.exists()) { + rtdFile.mkdir(); + } + } + return new File(rtd); + } + + /* + * get the correct runtime directory + * + * @return the runtime directory, or null if it could not be created or found + * @since 0.0.1 + */ + public static String runtimeDirectory() { + // get the I2P_FIREFOX_DIR environment variable + String rtd = System.getenv("I2P_FIREFOX_DIR"); + // if it is not null and not empty + if (rtd != null && !rtd.isEmpty()) { + // check if the file exists + File rtdFile = new File(rtd); + if (rtdFile.exists()) { + // if it does, return it + return rtd; + } + } + // obtain the PLUGIN environment variable + String plugin = System.getenv("PLUGIN"); + if (plugin != null && !plugin.isEmpty()) { + File pluginDir = new File(plugin); + if (pluginDir.exists()) { + return pluginDir.toString(); + } + } + String userDir = System.getProperty("user.dir"); + if (userDir != null && !userDir.isEmpty()) { + File userDir1 = new File(userDir); + if (userDir1.exists()) { + return userDir1.toString(); + } + } + String homeDir = System.getProperty("user.home"); + if (homeDir != null && !homeDir.isEmpty()) { + File homeDir1 = new File(homeDir+"/.i2p"); + if (homeDir1.exists()) { + return homeDir.toString(); + } + File homeDir2 = new File(homeDir+"/i2p"); + if (homeDir2.exists()) { + return homeDir2.toString(); + } + } + return ""; + } + + /* + * Copy the inert base profile directory to the runtime profile directory + * + * @since 0.0.1 + */ + public static boolean copyBaseProfiletoProfile() { + String baseProfile = baseProfileDirectory(); + String profile = profileDirectory(); + System.out.println("Copying base profile to profile directory: " + baseProfile + " -> " + profile); + if (baseProfile.isEmpty() || profile.isEmpty()) { + return false; + } + File baseProfileDir = new File(baseProfile); + File profileDir = new File(profile); + + try { + System.out.println("Copying base profile to profile directory"); + copyDirectory(baseProfileDir, profileDir); + } catch (Exception e) { + System.out.println("Error copying base profile to profile"+e); + return false; + } + System.out.println("Copied base profile to profile directory"); + // if user.js does not exist yet, make an empty one. + //if (!touch(profileDir.toString(), "user.js")) { + //return false; + //} + // if extensions does not exist yet, make an empty one. + //if (!mkExtensionsDir(profileDir.toString())){ + //return false; + //} + + + return copyStrictOptions(); + } + private static void copyDirectory(File sourceDirectory, File destinationDirectory) throws IOException { + destinationDirectory = new File(destinationDirectory.toString().replace("i2p.chromium.base.profile", "")); + if (!destinationDirectory.exists()) { + destinationDirectory.mkdir(); + } + for (String f : sourceDirectory.list()) { + copyDirectoryCompatibityMode(new File(sourceDirectory, f), new File(destinationDirectory, f)); + } + } + + public static void copyDirectoryCompatibityMode(File source, File destination) throws IOException { + if (source.isDirectory()) { + copyDirectory(source, destination); + } else { + copyFile(source, destination); + } + } + + private static void copyFile(File sourceFile, File destinationFile) throws IOException { + try (InputStream in = new FileInputStream(sourceFile); + OutputStream out = new FileOutputStream(destinationFile)) { + byte[] buf = new byte[1024]; + int length; + while ((length = in.read(buf)) > 0) { + out.write(buf, 0, length); + } + } + } + + /* + * Copy the strict options from the base profile to the profile + * + * @return true if successful, false otherwise + * @since 0.0.1 + */ + public static boolean copyStrictOptions() { + if (!strict){ + return true; + } + String baseProfile = baseProfileDirectory(); + String profile = profileDirectory(); + if (baseProfile.isEmpty() || profile.isEmpty()) { + return false; + } + File baseProfileDir = new File(baseProfile); + File profileDir = new File(profile); + if (!baseProfileDir.exists() || !profileDir.exists()) { + return false; + } + File baseOverrides = new File(baseProfile, "strict-overrides.js"); + File userOverrides = new File(baseProfile, "user-overrides.js"); + if (!baseOverrides.exists()) { + return false; + } + try { + Files.copy(baseOverrides.toPath(), userOverrides.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + System.out.println("Error copying base profile to profile"+e); + return false; + } + // if user-overrides.js does not exist yet, make an empty one. + //if (!touch(profileDir.toString(), "user-overrides.js")) { + //return false; + //} + return true; + } + + /* + * Construct a new Profile Builder + * + * @since 0.0.1 + */ + public I2PChromiumProfileBuilder() { + I2PChromiumProfileBuilder.strict = false; + } + + /* + * Construct a new Profile Builder + * @param strict if true, the strict overrides will be copied to the profile + * + * @since 0.0.1 + */ + public I2PChromiumProfileBuilder(boolean strict) { + I2PChromiumProfileBuilder.strict = strict; + } +} diff --git a/src/java/net/i2p/i2pfirefox/I2PChromiumProfileChecker.java b/src/java/net/i2p/i2pfirefox/I2PChromiumProfileChecker.java new file mode 100644 index 0000000..092ca17 --- /dev/null +++ b/src/java/net/i2p/i2pfirefox/I2PChromiumProfileChecker.java @@ -0,0 +1,84 @@ +package net.i2p.i2pfirefox; + +import java.io.File; + +public class I2PChromiumProfileChecker { + public static void main(String[] args) { + String profileDirectory = I2PChromiumProfileBuilder.profileDirectory(); + if (profileDirectory == null) { + System.out.println("No profile directory found"); + return; + } + System.out.println("Profile directory: " + profileDirectory); + boolean ok = validateProfileDirectory(profileDirectory); + if (ok) { + System.out.println("Profile directory is valid"); + } else { + System.out.println("Profile directory is invalid"); + } + } + public static boolean validateProfileDirectory(String profileDirectory) { + File profileDir = new File(profileDirectory); + if (!profileDir.exists()) { + System.out.println("Profile directory does not exist"); + return false; + } + if (!profileDir.isDirectory()) { + System.out.println("Profile directory is not a directory"); + return false; + } + if (!profileDir.canRead()) { + System.out.println("Profile directory is not readable"); + return false; + } + if (!profileDir.canWrite()) { + System.out.println("Profile directory is not writable"); + return false; + } + if (!validateExtensionDirectory(profileDir+"/extensions")){ + System.out.println("extensions directory is invalid"); + return false; + } + return true; + } + public static boolean validateFile(String file) { + File f = new File(file); + if (!f.exists()) { + System.out.println("User JavaScript file does not exist"); + return false; + } + if (!f.isFile()) { + System.out.println("User JavaScript file is not a file"); + return false; + } + if (!f.canRead()) { + System.out.println("User JavaScript file is not readable"); + return false; + } + if (!f.canWrite()) { + System.out.println("User JavaScript file is not writable"); + return false; + } + return true; + } + public static boolean validateExtensionDirectory(String extensionDirectory) { + File extensionDir = new File(extensionDirectory); + if (!extensionDir.exists()) { + System.out.println("Extension directory does not exist"); + return false; + } + if (!extensionDir.isDirectory()) { + System.out.println("Extension directory is not a directory"); + return false; + } + if (!extensionDir.canRead()) { + System.out.println("Extension directory is not readable"); + return false; + } + if (!extensionDir.canWrite()) { + System.out.println("Extension directory is not writable"); + return false; + } + return true; + } +} diff --git a/src/java/net/i2p/i2pfirefox/I2PChromiumProfileUnpacker.java b/src/java/net/i2p/i2pfirefox/I2PChromiumProfileUnpacker.java new file mode 100644 index 0000000..df53883 --- /dev/null +++ b/src/java/net/i2p/i2pfirefox/I2PChromiumProfileUnpacker.java @@ -0,0 +1,70 @@ +package net.i2p.i2pfirefox; + +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class I2PChromiumProfileUnpacker { + + public static void main(String[] args) { + String profileDirectory = I2PChromiumProfileBuilder.profileDirectory(); + if (profileDirectory == null) { + System.out.println("No profile directory found"); + return; + } + + } + + /* + * unpack the profile directory + * + * @return true if the profile directory was successfully unpacked + * @since 0.0.1 + */ + public boolean unpackProfile(String profileDirectory) { + System.out.println("Unpacking base profile to " + profileDirectory); + try { + final InputStream resources = this.getClass().getClassLoader().getResourceAsStream("i2p.chromium.base.profile.zip"); + if (resources == null) { + System.out.println("Could not find resources"); + return false; + } + System.out.println(resources.toString()); + // InputStream corresponds to a zip file. Unzip it. + //Files.copy(r, new File(profileDirectory).toPath(), StandardCopyOption.REPLACE_EXISTING); + ZipInputStream zis = new ZipInputStream(resources); + ZipEntry entry; + // while there are entries I process them + while ((entry = zis.getNextEntry()) != null) + { + System.out.println("entry: " + entry.getName() + ", " + entry.getSize()); + // consume all the data from this entry + if (entry.isDirectory()) { + System.out.println("Creating directory: " + entry.getName()); + File dir = new File(profileDirectory + "/" + entry.getName()); + dir.mkdirs(); + } else { + System.out.println("Creating file: " + entry.getName()); + File file = new File(profileDirectory + "/" + entry.getName()); + file.createNewFile(); + Files.copy(zis, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + while (zis.available() > 0) + zis.read(); + // I could close the entry, but getNextEntry does it automatically + // zis.closeEntry() + } + // loop through the Enumeration + + } catch (Exception e) { + System.out.println("Error copying profile files: " + e.getMessage()); + return false; + } + return true; + } + + +} diff --git a/src/java/net/i2p/i2pfirefox/I2PFirefox.java b/src/java/net/i2p/i2pfirefox/I2PFirefox.java index 0f53a26..b615411 100644 --- a/src/java/net/i2p/i2pfirefox/I2PFirefox.java +++ b/src/java/net/i2p/i2pfirefox/I2PFirefox.java @@ -55,8 +55,20 @@ public class I2PFirefox { } private static String[] FIND_FIREFOX_SEARCH_PATHS_WINDOWS() { String userHome = System.getProperty("user.home"); - String[] tbPath = new String[]{userHome + "/OneDrive/Desktop/Tor Browser/Browser/", userHome + "/Desktop/Tor Browser/Browser/"}; - String[] path = new String[]{"C:/Program Files/Mozilla Firefox/", "C:/Program Files (x86)/Mozilla Firefox/", "C:/Program Files/Waterfox/", "C:/Program Files (x86)/Waterfox/", "C:/Program Files/Librewolf/", tbPath[0], tbPath[1]}; + String programFiles = System.getenv("ProgramFiles"); + //String localAppData = System.getenv("LOCALAPPDATA"); + //Is there some way Mozilla does adminless installs to LocalAppData? Don't know for sure. + String programFiles86 = System.getenv("ProgramFiles(x86)"); + + String[] tbPath = new String[]{new File(userHome, "/OneDrive/Desktop/Tor Browser/Browser/").toString(), new File(userHome, "/Desktop/Tor Browser/Browser/").toString()}; + + String[] path = new String[]{ + new File(programFiles, "Mozilla Firefox/").toString(), + new File(programFiles86, "Mozilla Firefox/").toString(), + new File(programFiles, "Waterfox/").toString(), + new File(programFiles86, "Waterfox/").toString(), + new File(programFiles, "Librewolf/").toString(), + tbPath[0], tbPath[1]}; String[] exes = new String[]{"firefox.exe", "firefox-bin.exe", "firefox-esr.exe", "waterfox.exe", "waterfox-bin.exe", "librewolf.exe"}; String[] exePath = new String[path.length * exes.length]; int i = 0;