// // Getdown - application installer, patcher and launcher // Copyright (C) 2004-2018 Getdown authors // https://github.com/threerings/getdown/blob/master/LICENSE package com.threerings.getdown.launcher; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.net.Authenticator; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.PasswordAuthentication; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; import java.util.Iterator; import java.util.ServiceLoader; import jalview.util.LaunchUtils; import ca.beq.util.win32.registry.RegistryKey; import ca.beq.util.win32.registry.RegistryValue; import ca.beq.util.win32.registry.RootKey; import com.threerings.getdown.data.Application; import com.threerings.getdown.spi.ProxyAuth; import com.threerings.getdown.util.Config; import com.threerings.getdown.util.ConnectionUtil; import com.threerings.getdown.util.LaunchUtil; import com.threerings.getdown.util.StringUtil; import static com.threerings.getdown.Log.log; public class ProxyUtil { public static boolean autoDetectProxy (Application app) { String host = null, port = null; // check for a proxy configured via system properties if (System.getProperty("https.proxyHost") != null) { host = System.getProperty("https.proxyHost"); port = System.getProperty("https.proxyPort"); } if (StringUtil.isBlank(host) && System.getProperty("http.proxyHost") != null) { host = System.getProperty("http.proxyHost"); port = System.getProperty("http.proxyPort"); } // check the Windows registry if (StringUtil.isBlank(host) && LaunchUtil.isWindows()) { try { String rhost = null, rport = null; boolean enabled = false; RegistryKey.initialize(); RegistryKey r = new RegistryKey(RootKey.HKEY_CURRENT_USER, PROXY_REGISTRY); for (Iterator iter = r.values(); iter.hasNext(); ) { RegistryValue value = (RegistryValue)iter.next(); if (value.getName().equals("ProxyEnable")) { enabled = value.getStringValue().equals("1"); } if (value.getName().equals("ProxyServer")) { String strval = value.getStringValue(); int cidx = strval.indexOf(":"); if (cidx != -1) { rport = strval.substring(cidx+1); strval = strval.substring(0, cidx); } rhost = strval; } } if (enabled) { host = rhost; port = rport; } else { log.info("Detected no proxy settings in the registry."); } } catch (Throwable t) { log.info("Failed to find proxy settings in Windows registry", "error", t); } } // look for a proxy.txt file if (StringUtil.isBlank(host)) { String[] hostPort = loadProxy(app); host = hostPort[0]; port = hostPort[1]; } // look in jalview_properties String[] hostPortAuthUser = jalviewProxyProperties(app); host = hostPortAuthUser[0]; port = hostPortAuthUser[1]; boolean proxyAuth = Boolean.parseBoolean(hostPortAuthUser[2]); String username = hostPortAuthUser[3]; if (StringUtil.isBlank(host)) { return false; } // yay, we found a proxy configuration, configure it in the app initProxy(app, host, port, username, null); return true; } public static String[] jalviewProxyProperties(Application app) { String host = null; String port = null; boolean proxyAuth = false; String username = null; LaunchUtils.loadChannelProps(app.getAppDir()); if (LaunchUtils.getBooleanUserPreference("USE_PROXY")) { host = LaunchUtils.getUserPreference("PROXY_SERVER_HTTPS"); port = LaunchUtils.getUserPreference("PROXY_PORT_HTTPS"); if (StringUtil.isBlank(host)) { host = LaunchUtils.getUserPreference("PROXY_SERVER"); port = LaunchUtils.getUserPreference("PROXY_PORT"); } proxyAuth = LaunchUtils.getBooleanUserPreference("PROXY_AUTH"); if (proxyAuth) { username = LaunchUtils.getUserPreference("PROXY_AUTH_USERNAME"); } } return new String[]{ host, port, String.valueOf(proxyAuth), username }; } public static boolean canLoadWithoutProxy (URL rurl) { log.info("Testing whether proxy is needed, via: " + rurl); try { // try to make a HEAD request for this URL (use short connect and read timeouts) URLConnection conn = ConnectionUtil.open(Proxy.NO_PROXY, rurl, 5, 5); if (conn instanceof HttpURLConnection) { HttpURLConnection hcon = (HttpURLConnection)conn; try { hcon.setRequestMethod("HEAD"); hcon.connect(); // make sure we got a satisfactory response code int rcode = hcon.getResponseCode(); if (rcode == HttpURLConnection.HTTP_PROXY_AUTH || rcode == HttpURLConnection.HTTP_FORBIDDEN) { log.warning("Got an 'HTTP credentials needed' response", "code", rcode); } else { return true; } } finally { hcon.disconnect(); } } else { // if the appbase is not an HTTP/S URL (like file:), then we don't need a proxy return true; } } catch (IOException ioe) { log.info("Failed to HEAD " + rurl + ": " + ioe); log.info("We probably need a proxy, but auto-detection failed."); } return false; } public static void configProxy (Application app, String host, String port, String username, String password) { // save our proxy host and port in a local file saveProxy(app, host, port); // save our credentials via the SPI if (!StringUtil.isBlank(username) && !StringUtil.isBlank(password)) { ServiceLoader loader = ServiceLoader.load(ProxyAuth.class); Iterator iterator = loader.iterator(); String appDir = app.getAppDir().getAbsolutePath(); while (iterator.hasNext()) { iterator.next().saveCredentials(appDir, username, password); } } // also configure them in the app initProxy(app, host, port, username, password); } public static String[] loadProxy (Application app) { File pfile = app.getLocalPath("proxy.txt"); if (pfile.exists()) { try { Config pconf = Config.parseConfig(pfile, Config.createOpts(false)); return new String[] { pconf.getString("host"), pconf.getString("port") }; } catch (IOException ioe) { log.warning("Failed to read '" + pfile + "': " + ioe); } } return new String[] { null, null}; } public static void saveProxy (Application app, String host, String port) { File pfile = app.getLocalPath("proxy.txt"); try (PrintStream pout = new PrintStream(new FileOutputStream(pfile))) { if (!StringUtil.isBlank(host)) { pout.println("host = " + host); } if (!StringUtil.isBlank(port)) { pout.println("port = " + port); } } catch (IOException ioe) { log.warning("Error creating proxy file '" + pfile + "': " + ioe); } } public static void initProxy (Application app, String host, String port, String username, String password) { System.out.println("**** initProxy(app, '"+host+"', "+port+", '"+username+"', "+(password==null?"null":"*x"+password.length())+")"); // check whether we have saved proxy credentials String appDir = app.getAppDir().getAbsolutePath(); ServiceLoader loader = ServiceLoader.load(ProxyAuth.class); Iterator iter = loader.iterator(); ProxyAuth.Credentials creds = iter.hasNext() ? iter.next().loadCredentials(appDir) : null; if (creds != null) { username = creds.username; password = creds.password; } boolean haveCreds = !StringUtil.isBlank(username) && !StringUtil.isBlank(password); int pport = StringUtil.isBlank(port) ? 80 : Integer.valueOf(port); log.info("Using proxy", "host", host, "port", pport, "haveCreds", haveCreds); app.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, pport)); if (haveCreds) { final String fuser = username; final char[] fpass = password.toCharArray(); Authenticator.setDefault(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication () { return new PasswordAuthentication(fuser, fpass); } }); } } protected static final String PROXY_REGISTRY = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; }