JAL-3130 adapted getdown src. attempt 2. first attempt failed due to cp'ed .git files
[jalview.git] / getdown / src / getdown / launcher / src / main / java / com / threerings / getdown / launcher / ProxyUtil.java
1 //
2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
5
6 package com.threerings.getdown.launcher;
7
8 import java.io.File;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.io.PrintStream;
12 import java.net.Authenticator;
13 import java.net.HttpURLConnection;
14 import java.net.InetSocketAddress;
15 import java.net.PasswordAuthentication;
16 import java.net.Proxy;
17 import java.net.URL;
18 import java.net.URLConnection;
19 import java.util.Iterator;
20 import java.util.ServiceLoader;
21
22 import ca.beq.util.win32.registry.RegistryKey;
23 import ca.beq.util.win32.registry.RegistryValue;
24 import ca.beq.util.win32.registry.RootKey;
25
26 import com.threerings.getdown.data.Application;
27 import com.threerings.getdown.spi.ProxyAuth;
28 import com.threerings.getdown.util.Config;
29 import com.threerings.getdown.util.ConnectionUtil;
30 import com.threerings.getdown.util.LaunchUtil;
31 import com.threerings.getdown.util.StringUtil;
32
33 import static com.threerings.getdown.Log.log;
34
35 public class ProxyUtil {
36
37     public static boolean autoDetectProxy (Application app)
38     {
39         String host = null, port = null;
40
41         // check for a proxy configured via system properties
42         if (System.getProperty("https.proxyHost") != null) {
43             host = System.getProperty("https.proxyHost");
44             port = System.getProperty("https.proxyPort");
45         }
46         if (StringUtil.isBlank(host) && System.getProperty("http.proxyHost") != null) {
47             host = System.getProperty("http.proxyHost");
48             port = System.getProperty("http.proxyPort");
49         }
50
51         // check the Windows registry
52         if (StringUtil.isBlank(host) && LaunchUtil.isWindows()) {
53             try {
54                 String rhost = null, rport = null;
55                 boolean enabled = false;
56                 RegistryKey.initialize();
57                 RegistryKey r = new RegistryKey(RootKey.HKEY_CURRENT_USER, PROXY_REGISTRY);
58                 for (Iterator<?> iter = r.values(); iter.hasNext(); ) {
59                     RegistryValue value = (RegistryValue)iter.next();
60                     if (value.getName().equals("ProxyEnable")) {
61                         enabled = value.getStringValue().equals("1");
62                     }
63                     if (value.getName().equals("ProxyServer")) {
64                         String strval = value.getStringValue();
65                         int cidx = strval.indexOf(":");
66                         if (cidx != -1) {
67                             rport = strval.substring(cidx+1);
68                             strval = strval.substring(0, cidx);
69                         }
70                         rhost = strval;
71                     }
72                 }
73                 if (enabled) {
74                     host = rhost;
75                     port = rport;
76                 } else {
77                     log.info("Detected no proxy settings in the registry.");
78                 }
79             } catch (Throwable t) {
80                 log.info("Failed to find proxy settings in Windows registry", "error", t);
81             }
82         }
83
84         // look for a proxy.txt file
85         if (StringUtil.isBlank(host)) {
86             String[] hostPort = loadProxy(app);
87             host = hostPort[0];
88             port = hostPort[1];
89         }
90
91         if (StringUtil.isBlank(host)) {
92             return false;
93         }
94
95         // yay, we found a proxy configuration, configure it in the app
96         initProxy(app, host, port, null, null);
97         return true;
98     }
99
100     public static boolean canLoadWithoutProxy (URL rurl)
101     {
102         log.info("Testing whether proxy is needed, via: " + rurl);
103         try {
104             // try to make a HEAD request for this URL (use short connect and read timeouts)
105             URLConnection conn = ConnectionUtil.open(Proxy.NO_PROXY, rurl, 5, 5);
106             if (conn instanceof HttpURLConnection) {
107                 HttpURLConnection hcon = (HttpURLConnection)conn;
108                 try {
109                     hcon.setRequestMethod("HEAD");
110                     hcon.connect();
111                     // make sure we got a satisfactory response code
112                     int rcode = hcon.getResponseCode();
113                     if (rcode == HttpURLConnection.HTTP_PROXY_AUTH ||
114                         rcode == HttpURLConnection.HTTP_FORBIDDEN) {
115                         log.warning("Got an 'HTTP credentials needed' response", "code", rcode);
116                     } else {
117                         return true;
118                     }
119                 } finally {
120                     hcon.disconnect();
121                 }
122             } else {
123                 // if the appbase is not an HTTP/S URL (like file:), then we don't need a proxy
124                 return true;
125             }
126         } catch (IOException ioe) {
127             log.info("Failed to HEAD " + rurl + ": " + ioe);
128             log.info("We probably need a proxy, but auto-detection failed.");
129         }
130         return false;
131     }
132
133     public static void configProxy (Application app, String host, String port,
134                                     String username, String password) {
135         // save our proxy host and port in a local file
136         saveProxy(app, host, port);
137
138         // save our credentials via the SPI
139         if (!StringUtil.isBlank(username) && !StringUtil.isBlank(password)) {
140             ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
141             Iterator<ProxyAuth> iterator = loader.iterator();
142             String appDir = app.getAppDir().getAbsolutePath();
143             while (iterator.hasNext()) {
144                 iterator.next().saveCredentials(appDir, username, password);
145             }
146         }
147
148         // also configure them in the app
149         initProxy(app, host, port, username, password);
150     }
151
152     public static String[] loadProxy (Application app) {
153         File pfile = app.getLocalPath("proxy.txt");
154         if (pfile.exists()) {
155             try {
156                 Config pconf = Config.parseConfig(pfile, Config.createOpts(false));
157                 return new String[] { pconf.getString("host"), pconf.getString("port") };
158             } catch (IOException ioe) {
159                 log.warning("Failed to read '" + pfile + "': " + ioe);
160             }
161         }
162         return new String[] { null, null};
163     }
164
165     public static void saveProxy (Application app, String host, String port) {
166         File pfile = app.getLocalPath("proxy.txt");
167         try (PrintStream pout = new PrintStream(new FileOutputStream(pfile))) {
168             if (!StringUtil.isBlank(host)) {
169                 pout.println("host = " + host);
170             }
171             if (!StringUtil.isBlank(port)) {
172                 pout.println("port = " + port);
173             }
174         } catch (IOException ioe) {
175             log.warning("Error creating proxy file '" + pfile + "': " + ioe);
176         }
177     }
178
179     public static void initProxy (Application app, String host, String port,
180                                   String username, String password)
181     {
182         // check whether we have saved proxy credentials
183         String appDir = app.getAppDir().getAbsolutePath();
184         ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
185         Iterator<ProxyAuth> iter = loader.iterator();
186         ProxyAuth.Credentials creds = iter.hasNext() ? iter.next().loadCredentials(appDir) : null;
187         if (creds != null) {
188             username = creds.username;
189             password = creds.password;
190         }
191         boolean haveCreds = !StringUtil.isBlank(username) && !StringUtil.isBlank(password);
192
193         int pport = StringUtil.isBlank(port) ? 80 : Integer.valueOf(port);
194         log.info("Using proxy", "host", host, "port", pport, "haveCreds", haveCreds);
195         app.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, pport));
196
197         if (haveCreds) {
198             final String fuser = username;
199             final char[] fpass = password.toCharArray();
200             Authenticator.setDefault(new Authenticator() {
201                 @Override protected PasswordAuthentication getPasswordAuthentication () {
202                     return new PasswordAuthentication(fuser, fpass);
203                 }
204             });
205         }
206     }
207
208     protected static final String PROXY_REGISTRY =
209         "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
210 }