2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
6 package com.threerings.getdown.launcher;
9 import java.io.FileInputStream;
10 import java.io.FileOutputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.PrintStream;
14 import java.net.Authenticator;
15 import java.net.HttpURLConnection;
16 import java.net.InetSocketAddress;
17 import java.net.PasswordAuthentication;
18 import java.net.Proxy;
20 import java.net.URLConnection;
21 import java.util.Iterator;
22 import java.util.ServiceLoader;
24 import jalview.bin.LaunchUtils;
25 import jalview.util.ChannelProperties;
27 import ca.beq.util.win32.registry.RegistryKey;
28 import ca.beq.util.win32.registry.RegistryValue;
29 import ca.beq.util.win32.registry.RootKey;
31 import com.threerings.getdown.data.Application;
32 import com.threerings.getdown.spi.ProxyAuth;
33 import com.threerings.getdown.util.Config;
34 import com.threerings.getdown.util.ConnectionUtil;
35 import com.threerings.getdown.util.LaunchUtil;
36 import com.threerings.getdown.util.StringUtil;
38 import static com.threerings.getdown.Log.log;
40 public class ProxyUtil {
42 public static boolean autoDetectProxy (Application app)
44 String host = null, port = null;
46 // check for a proxy configured via system properties
47 if (System.getProperty("https.proxyHost") != null) {
48 host = System.getProperty("https.proxyHost");
49 port = System.getProperty("https.proxyPort");
51 if (StringUtil.isBlank(host) && System.getProperty("http.proxyHost") != null) {
52 host = System.getProperty("http.proxyHost");
53 port = System.getProperty("http.proxyPort");
56 // check the Windows registry
57 if (StringUtil.isBlank(host) && LaunchUtil.isWindows()) {
59 String rhost = null, rport = null;
60 boolean enabled = false;
61 RegistryKey.initialize();
62 RegistryKey r = new RegistryKey(RootKey.HKEY_CURRENT_USER, PROXY_REGISTRY);
63 for (Iterator<?> iter = r.values(); iter.hasNext(); ) {
64 RegistryValue value = (RegistryValue)iter.next();
65 if (value.getName().equals("ProxyEnable")) {
66 enabled = value.getStringValue().equals("1");
68 if (value.getName().equals("ProxyServer")) {
69 String strval = value.getStringValue();
70 int cidx = strval.indexOf(":");
72 rport = strval.substring(cidx+1);
73 strval = strval.substring(0, cidx);
82 log.info("Detected no proxy settings in the registry.");
84 } catch (Throwable t) {
85 log.info("Failed to find proxy settings in Windows registry", "error", t);
89 // look for a proxy.txt file
90 if (StringUtil.isBlank(host)) {
91 String[] hostPort = loadProxy(app);
96 // look in jalview_properties
97 String[] hostPortAuthUser = jalviewProxyProperties(app);
98 host = hostPortAuthUser[0];
99 port = hostPortAuthUser[1];
100 boolean proxyAuth = Boolean.parseBoolean(hostPortAuthUser[2]);
101 String username = hostPortAuthUser[3];
103 if (StringUtil.isBlank(host)) {
107 // yay, we found a proxy configuration, configure it in the app
108 initProxy(app, host, port, username, null);
112 public static String[] jalviewProxyProperties(Application app) {
115 boolean proxyAuth = false;
116 String username = null;
117 File channelProps = app.getLocalPath(ChannelProperties.CHANNEL_PROPERTIES_FILENAME);
118 if (channelProps.exists()) {
120 InputStream is = new FileInputStream(channelProps);
121 ChannelProperties.loadProps(is);
122 } catch (IOException e) {
123 log.error(e.getMessage());
125 if (Boolean.parseBoolean(LaunchUtils.getUserPreference("USE_PROXY"))) {
126 host = LaunchUtils.getUserPreference("PROXY_SERVER_HTTPS");
127 port = LaunchUtils.getUserPreference("PROXY_PORT_HTTPS");
128 if (StringUtil.isBlank(host)) {
129 host = LaunchUtils.getUserPreference("PROXY_SERVER");
130 port = LaunchUtils.getUserPreference("PROXY_PORT");
132 proxyAuth = Boolean.parseBoolean(LaunchUtils.getUserPreference("PROXY_AUTH"));
134 username = LaunchUtils.getUserPreference("PROXY_AUTH_USERNAME");
138 return new String[]{ host, port, String.valueOf(proxyAuth), username };
141 public static boolean canLoadWithoutProxy (URL rurl)
143 log.info("Testing whether proxy is needed, via: " + rurl);
145 // try to make a HEAD request for this URL (use short connect and read timeouts)
146 URLConnection conn = ConnectionUtil.open(Proxy.NO_PROXY, rurl, 5, 5);
147 if (conn instanceof HttpURLConnection) {
148 HttpURLConnection hcon = (HttpURLConnection)conn;
150 hcon.setRequestMethod("HEAD");
152 // make sure we got a satisfactory response code
153 int rcode = hcon.getResponseCode();
154 if (rcode == HttpURLConnection.HTTP_PROXY_AUTH ||
155 rcode == HttpURLConnection.HTTP_FORBIDDEN) {
156 log.warning("Got an 'HTTP credentials needed' response", "code", rcode);
164 // if the appbase is not an HTTP/S URL (like file:), then we don't need a proxy
167 } catch (IOException ioe) {
168 log.info("Failed to HEAD " + rurl + ": " + ioe);
169 log.info("We probably need a proxy, but auto-detection failed.");
174 public static void configProxy (Application app, String host, String port,
175 String username, String password) {
176 // save our proxy host and port in a local file
177 saveProxy(app, host, port);
179 // save our credentials via the SPI
180 if (!StringUtil.isBlank(username) && !StringUtil.isBlank(password)) {
181 ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
182 Iterator<ProxyAuth> iterator = loader.iterator();
183 String appDir = app.getAppDir().getAbsolutePath();
184 while (iterator.hasNext()) {
185 iterator.next().saveCredentials(appDir, username, password);
189 // also configure them in the app
190 initProxy(app, host, port, username, password);
193 public static String[] loadProxy (Application app) {
194 File pfile = app.getLocalPath("proxy.txt");
195 if (pfile.exists()) {
197 Config pconf = Config.parseConfig(pfile, Config.createOpts(false));
198 return new String[] { pconf.getString("host"), pconf.getString("port") };
199 } catch (IOException ioe) {
200 log.warning("Failed to read '" + pfile + "': " + ioe);
203 return new String[] { null, null};
206 public static void saveProxy (Application app, String host, String port) {
207 File pfile = app.getLocalPath("proxy.txt");
208 try (PrintStream pout = new PrintStream(new FileOutputStream(pfile))) {
209 if (!StringUtil.isBlank(host)) {
210 pout.println("host = " + host);
212 if (!StringUtil.isBlank(port)) {
213 pout.println("port = " + port);
215 } catch (IOException ioe) {
216 log.warning("Error creating proxy file '" + pfile + "': " + ioe);
220 public static void initProxy (Application app, String host, String port,
221 String username, String password)
223 System.out.println("**** initProxy(app, '"+host+"', "+port+", '"+username+"', "+(password==null?"null":"*x"+password.length())+")");
224 // check whether we have saved proxy credentials
225 String appDir = app.getAppDir().getAbsolutePath();
226 ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
227 Iterator<ProxyAuth> iter = loader.iterator();
228 ProxyAuth.Credentials creds = iter.hasNext() ? iter.next().loadCredentials(appDir) : null;
230 username = creds.username;
231 password = creds.password;
233 boolean haveCreds = !StringUtil.isBlank(username) && !StringUtil.isBlank(password);
235 int pport = StringUtil.isBlank(port) ? 80 : Integer.valueOf(port);
236 log.info("Using proxy", "host", host, "port", pport, "haveCreds", haveCreds);
237 app.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, pport));
240 final String fuser = username;
241 final char[] fpass = password.toCharArray();
242 Authenticator.setDefault(new Authenticator() {
243 @Override protected PasswordAuthentication getPasswordAuthentication () {
244 return new PasswordAuthentication(fuser, fpass);
250 protected static final String PROXY_REGISTRY =
251 "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";