diff options
Diffstat (limited to 'src/main/java/com/btr/proxy/search/browser/firefox')
5 files changed, 486 insertions, 0 deletions
diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProfileSource.java b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProfileSource.java new file mode 100644 index 0000000..8517074 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProfileSource.java @@ -0,0 +1,23 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.File; +import java.io.IOException; + +/***************************************************************************** + * A profile source for Firefox profiles. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +interface FirefoxProfileSource { + + /************************************************************************* + * Gets a profile folder found on the current system. + * If multiple profile folders are available the "default" profile is chosen. + * @return a profile folder. + * @throws IOException on error. + ************************************************************************/ + + public File getProfileFolder() throws IOException; + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java new file mode 100644 index 0000000..30c3be1 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java @@ -0,0 +1,267 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.IOException; +import java.net.ProxySelector; +import java.util.Properties; + +import com.btr.proxy.search.ProxySearchStrategy; +import com.btr.proxy.search.desktop.DesktopProxySearchStrategy; +import com.btr.proxy.search.wpad.WpadProxySearchStrategy; +import com.btr.proxy.selector.direct.NoProxySelector; +import com.btr.proxy.selector.fixed.FixedProxySelector; +import com.btr.proxy.selector.fixed.FixedSocksSelector; +import com.btr.proxy.selector.misc.ProtocolDispatchSelector; +import com.btr.proxy.selector.whitelist.ProxyBypassListSelector; +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; +import com.btr.proxy.util.PlatformUtil; +import com.btr.proxy.util.PlatformUtil.Platform; +import com.btr.proxy.util.ProxyException; +import com.btr.proxy.util.ProxyUtil; + +/***************************************************************************** + * Loads the Firefox3 proxy settings from the users Firefox3 settings. + * This will load the file <i>prefs.js</i> that is located in the + * <p> + * <i>.mozilla/firefox/(profile)/</i> folder. + * </p> + * + * See <a href="https://developer.mozilla.org/En/Mozilla_Networking_Preferences">Mozilla_Networking_Preferences</a> + * for an explanation of the proxy settings. + * <p> + * The following settings are extracted from + * this file: + * </p> + * Some generic settings:<br/> + * <ul> + * <li><i>network.proxy.type</i> -> n/a = use system settings, 0 = direct, 1 = Fixed proxy settings, 2 = proxy script (PAC), 3 = also direct , 4 = auto detect (WPAD)</li> + * <li><i>network.proxy.share_proxy_settings</i> -> true = use same proxy for all protocols</li> + * <li><i>network.proxy.no_proxies_on</i> -> a comma separated ignore list. </li> + * <li><i>network.proxy.autoconfig_url</i> -> a URL to an proxy configuration script</li> + * </ul> + * Host names and ports per protocol are stored in the following settings: + * <ul> + * <li><i>network.proxy.http</i></li> + * <li><i>network.proxy.http_port</i></li> + * <li><i>network.proxy.ssl</i></li> + * <li><i>network.proxy.ssl_port</i></li> + * <li><i>network.proxy.ftp</i></li> + * <li><i>network.proxy.ftp_port</i></li> + * <li><i>network.proxy.gopher</i></li> + * <li><i>network.proxy.gopher_port</i></li> + * <li><i>network.proxy.socks</i></li> + * <li><i>network.proxy.socks_port</i></li> + * <li><i>network.proxy.socks_version</i> -> 4 or 5</li> + * </u> + * <p> + * Note that if there are more than one profile the first profile found will be used. + * </p> + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class FirefoxProxySearchStrategy implements ProxySearchStrategy { + + private FirefoxProfileSource profileScanner; + private FirefoxSettingParser settingsParser; + + /************************************************************************* + * ProxySelector + * @see java.net.ProxySelector#ProxySelector() + ************************************************************************/ + + public FirefoxProxySearchStrategy() { + super(); + if (PlatformUtil.getCurrentPlattform() == Platform.WIN) { + this.profileScanner = new WinFirefoxProfileSource(); + } else { + this.profileScanner = new LinuxFirefoxProfileSource(); + } + this.settingsParser = new FirefoxSettingParser(); + } + + /************************************************************************* + * Loads the proxy settings and initializes a proxy selector for the firefox + * proxy settings. + * @return a configured ProxySelector, null if none is found. + * @throws ProxyException on file reading error. + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + Logger.log(getClass(), LogLevel.TRACE, "Detecting Firefox settings."); + + Properties settings = readSettings(); + + ProxySelector result = null; + int type = Integer.parseInt(settings.getProperty("network.proxy.type", "-1")); + switch (type) { + case -1: // Use system settings + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses system settings"); + result = new DesktopProxySearchStrategy().getProxySelector(); + break; + case 0: // Use no proxy + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses no proxy"); + result = NoProxySelector.getInstance(); + break; + case 1: // Fixed settings + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses manual settings"); + result = setupFixedProxySelector(settings); + break; + case 2: // PAC Script + String pacScriptUrl = settings.getProperty("network.proxy.autoconfig_url", ""); + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses script (PAC) {0}", pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + break; + case 3: // Backward compatibility to netscape. + Logger.log(getClass(), LogLevel.TRACE, "Netscape compability mode -> uses no proxy"); + result = NoProxySelector.getInstance(); + break; + case 4: // WPAD auto config + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses automatic detection (WPAD)"); + result = new WpadProxySearchStrategy().getProxySelector(); + break; + default: + break; + } + + // Wrap in white list filter. + String noProxyList = settings.getProperty("network.proxy.no_proxies_on", null); + if (result != null && noProxyList != null && noProxyList.trim().length() > 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses proxy bypass list for: {0}", noProxyList); + result = new ProxyBypassListSelector(noProxyList, result); + } + + return result; + } + + /************************************************************************* + * Reads the settings file and stores all settings in a Properties map. + * @return the parsed settings. + * @throws ProxyException on read error. + ************************************************************************/ + + public Properties readSettings() throws ProxyException { + try { + Properties settings = this.settingsParser.parseSettings(this.profileScanner); + return settings; + } catch (IOException e) { + Logger.log(getClass(), LogLevel.ERROR, "Error parsing settings", e); + throw new ProxyException(e); + } + } + + /************************************************************************* + * Parse the fixed proxy settings and build an ProxySelector for this a + * chained configuration. + * @param settings the proxy settings to evaluate. + ************************************************************************/ + + private ProxySelector setupFixedProxySelector(Properties settings) { + ProtocolDispatchSelector ps = new ProtocolDispatchSelector(); + installHttpProxy(ps, settings); + if (isProxyShared(settings)) { + installSharedProxy(ps); + } else { + installFtpProxy(ps, settings); + installSecureProxy(ps, settings); + installSocksProxy(ps, settings); + } + return ps; + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installFtpProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + installSelectorForProtocol(ps, settings, "ftp"); + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installHttpProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + installSelectorForProtocol(ps, settings, "http"); + } + + /************************************************************************* + * @param settings + * @return + ************************************************************************/ + + private boolean isProxyShared(Properties settings) { + return Boolean.TRUE.toString().equals(settings.getProperty("network.proxy.share_proxy_settings", "false").toLowerCase()); + } + + /************************************************************************* + * @param ps + ************************************************************************/ + + private void installSharedProxy(ProtocolDispatchSelector ps) { + ProxySelector httpProxy = ps.getSelector("http"); + if (httpProxy != null) { + ps.setFallbackSelector(httpProxy); + } + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installSocksProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + String proxyHost = settings.getProperty("network.proxy.socks", null); + int proxyPort = Integer.parseInt(settings.getProperty("network.proxy.socks_port", "0")); + if (proxyHost != null && proxyPort != 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox socks proxy is {0}:{1}", proxyHost, proxyPort); + ps.setSelector("socks", new FixedSocksSelector(proxyHost, proxyPort)); + } + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installSecureProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + String proxyHost = settings.getProperty("network.proxy.ssl", null); + int proxyPort = Integer.parseInt(settings.getProperty("network.proxy.ssl_port", "0")); + if (proxyHost != null && proxyPort != 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox secure proxy is {0}:{1}", proxyHost, proxyPort); + ps.setSelector("https", new FixedProxySelector(proxyHost, proxyPort)); + ps.setSelector("sftp", new FixedProxySelector(proxyHost, proxyPort)); + } + } + + /************************************************************************* + * Installs a proxy selector for the given protocol when settings are + * available. + * @param ps a ProtocolDispatchSelector to configure. + * @param settings to read the config from. + * @param protocol to configure. + * @throws NumberFormatException + ************************************************************************/ + + private void installSelectorForProtocol(ProtocolDispatchSelector ps, + Properties settings, String protocol) throws NumberFormatException { + + String proxyHost = settings.getProperty("network.proxy."+protocol, null); + int proxyPort = Integer.parseInt(settings.getProperty("network.proxy."+protocol+"_port", "0")); + if (proxyHost != null && proxyPort != 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox "+protocol+" proxy is {0}:{1}", proxyHost, proxyPort); + ps.setSelector(protocol, new FixedProxySelector(proxyHost, proxyPort)); + } + } + + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java new file mode 100644 index 0000000..b793299 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java @@ -0,0 +1,79 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Properties; + +/***************************************************************************** + * Parser for the Firefox settings file. + * Will extract all relevant proxy settings form the configuration file. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +class FirefoxSettingParser { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public FirefoxSettingParser() { + super(); + } + + /************************************************************************* + * Parse the settings file and extract all network.proxy.* settings from it. + * @param source of the Firefox profiles. + * @return the parsed properties. + * @throws IOException on read error. + ************************************************************************/ + + public Properties parseSettings(FirefoxProfileSource source) throws IOException { + // Search settings folder + File profileFolder = source.getProfileFolder(); + + // Read settings from file + File settingsFile = new File(profileFolder, "prefs.js"); + + BufferedReader fin = new BufferedReader( + new InputStreamReader( + new FileInputStream(settingsFile))); + + Properties result = new Properties(); + try { + String line = fin.readLine(); + while (line != null) { + line = line.trim(); + if (line.startsWith("user_pref(\"network.proxy")) { + line = line.substring(10, line.length()-2); + int index = line.indexOf(","); + String key = line.substring(0, index).trim(); + if (key.startsWith("\"")) { + key = key.substring(1); + } + if (key.endsWith("\"")) { + key = key.substring(0, key.length()-1); + } + String value = line.substring(index+1).trim(); + if (value.startsWith("\"")) { + value = value.substring(1); + } + if (value.endsWith("\"")) { + value = value.substring(0, value.length()-1); + } + result.put(key, value); + } + line = fin.readLine(); + } + } finally { + fin.close(); + } + + return result; + } + + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java b/src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java new file mode 100644 index 0000000..38b1553 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java @@ -0,0 +1,46 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.File; + +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; + +/***************************************************************************** + * Searches for Firefox profile on an Linux / Unix base system. + * This will scan the <i>.mozilla</i> folder in the users home directory to find the + * profiles. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +class LinuxFirefoxProfileSource implements FirefoxProfileSource { + + /************************************************************************* + * Get profile folder for the Linux Firefox profile + ************************************************************************/ + + public File getProfileFolder() { + File userDir = new File(System.getProperty("user.home")); + File cfgDir = new File(userDir, ".mozilla"+File.separator+"firefox"+File.separator); + if (!cfgDir.exists()) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox settings folder not found!"); + return null; + } + File[] profiles = cfgDir.listFiles(); + if (profiles == null || profiles.length == 0) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox settings folder not found!"); + return null; + } + for (File p : profiles) { + if (p.getName().endsWith(".default")) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox settings folder is {0}", p); + return p; + } + } + + // Fall back -> take the first one found. + Logger.log(getClass(), LogLevel.TRACE, "Firefox settings folder is {0}", profiles[0]); + return profiles[0]; + } + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java b/src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java new file mode 100644 index 0000000..9189585 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java @@ -0,0 +1,71 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.File; +import java.io.IOException; + +import com.btr.proxy.search.desktop.win.Win32ProxyUtils; +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; + +/***************************************************************************** + * Finds the Firefox profile on Windows platforms. + * On Windows the profiles are located in the users appdata directory under: + * <p> + * <i>Mozilla\Firefox\Profiles\</i> + * </p> + * The location of the appdata folder is read from the windows registry. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +class WinFirefoxProfileSource implements FirefoxProfileSource { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public WinFirefoxProfileSource() { + super(); + } + + /************************************************************************* + * Reads the current location of the app data folder from the registry. + * @return a path to the folder. + ************************************************************************/ + + private String getAppFolder() { + return new Win32ProxyUtils().readUserHomedir(); + } + + /************************************************************************* + * Get profile folder for the Windows Firefox profile + * @throws IOException on error. + ************************************************************************/ + + public File getProfileFolder() throws IOException { + + File appDataDir = new File(getAppFolder()); + File cfgDir = new File(appDataDir, "Mozilla"+File.separator+"Firefox"+File.separator+"Profiles"); + + if (!cfgDir.exists()) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox windows settings folder not found."); + return null; + } + File[] profiles = cfgDir.listFiles(); + if (profiles == null || profiles.length == 0) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox windows settings folder not found."); + return null; + } + for (File p : profiles) { + if (p.getName().endsWith(".default")) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox windows settings folder is {0}.", p); + return p; + } + } + + // Fall back -> take the first one found. + Logger.log(getClass(), LogLevel.TRACE, "Firefox windows settings folder is {0}.", profiles[0]); + return profiles[0]; + } + +} |