Added support for proxy auth.

This also makes the use of a Proxy instance explicit in the Getdown code,
rather than trying to thread things through the proxy-related system
properties.

It introduces a ProxyAuth SPI which allows an app installation to save proxy
credentials in whatever way it deems fit. Otherwise the credentials are unsaved
and the user effectively has to enter them every time Getdown attempts to
access the internet.

This is obviously a terrible design, but there's no good (cross-platform) way
to securely store a username and password. So anyone using this feature is
likely going to need to provide an implementation of ProxyAuth that does
whatever auth storage they deem appropriate.

Adapted from PR from @ThomasG-AI, thanks!
This commit is contained in:
Michael Bayne
2019-01-15 12:02:10 -08:00
parent dc768515d5
commit ae129fad6f
16 changed files with 409 additions and 214 deletions
@@ -8,6 +8,7 @@ package com.threerings.getdown.data;
import java.io.*;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
@@ -231,6 +232,11 @@ public class Application
}
}
/** The proxy that should be used to do HTTP downloads. This must be configured prior to using
* the application instance. Yes this is a public mutable field, no I'm not going to create a
* getter and setter just to pretend like that's not the case. */
public Proxy proxy = Proxy.NO_PROXY;
/**
* Creates an application instance which records the location of the <code>getdown.txt</code>
* configuration file from the supplied application directory.
@@ -1208,7 +1214,7 @@ public class Application
}
if (_latest != null) {
try (InputStream in = ConnectionUtil.open(_latest, 0, 0).getInputStream();
try (InputStream in = ConnectionUtil.open(proxy, _latest, 0, 0).getInputStream();
InputStreamReader reader = new InputStreamReader(in, UTF_8);
BufferedReader bin = new BufferedReader(reader)) {
for (String[] pair : Config.parsePairs(bin, Config.createOpts(false))) {
@@ -1592,7 +1598,7 @@ public class Application
log.info("Attempting to refetch '" + path + "' from '" + targetURL + "'.");
// stream the URL into our temporary file
URLConnection uconn = ConnectionUtil.open(targetURL, 0, 0);
URLConnection uconn = ConnectionUtil.open(proxy, targetURL, 0, 0);
// we have to tell Java not to use caches here, otherwise it will cache any request for
// same URL for the lifetime of this JVM (based on the URL string, not the URL object);
// if the getdown.txt file, for example, changes in the meanwhile, we would never hear
@@ -10,6 +10,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
@@ -25,9 +26,14 @@ import static com.threerings.getdown.Log.log;
*/
public class HTTPDownloader extends Downloader
{
public HTTPDownloader (Proxy proxy)
{
_proxy = proxy;
}
@Override protected long checkSize (Resource rsrc) throws IOException
{
URLConnection conn = ConnectionUtil.open(rsrc.getRemote(), 0, 0);
URLConnection conn = ConnectionUtil.open(_proxy, rsrc.getRemote(), 0, 0);
try {
// if we're accessing our data via HTTP, we only need a HEAD request
if (conn instanceof HttpURLConnection) {
@@ -54,7 +60,7 @@ public class HTTPDownloader extends Downloader
// system property
if (true) {
// download the resource from the specified URL
URLConnection conn = ConnectionUtil.open(rsrc.getRemote(), 0, 0);
URLConnection conn = ConnectionUtil.open(_proxy, rsrc.getRemote(), 0, 0);
conn.connect();
// make sure we got a satisfactory response code
@@ -65,7 +71,6 @@ public class HTTPDownloader extends Downloader
hcon.getResponseCode());
}
}
long actualSize = conn.getContentLength();
log.info("Downloading resource", "url", rsrc.getRemote(), "size", actualSize);
long currentSize = 0L;
@@ -105,4 +110,6 @@ public class HTTPDownloader extends Downloader
}
}
}
protected final Proxy _proxy;
}
@@ -0,0 +1,32 @@
//
// Getdown - application installer, patcher and launcher
// Copyright (C) 2004-2018 Getdown authors
// https://github.com/threerings/getdown/blob/master/LICENSE
package com.threerings.getdown.spi;
/**
* A service provider interface that handles the storage of proxy credentials.
*/
public interface ProxyAuth
{
/** Credentials for a proxy server. */
public static class Credentials {
public final String username;
public final String password;
public Credentials (String username, String password) {
this.username = username;
this.password = password;
}
}
/**
* Loads the credentials for the app installed in {@code appDir}.
*/
public Credentials loadCredentials (String appDir);
/**
* Encrypts and saves the credentials for the app installed in {@code appDir}.
*/
public void saveCredentials (String appDir, String username, String password);
}
@@ -7,11 +7,12 @@ package com.threerings.getdown.util;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import com.threerings.getdown.data.SysProps;
import com.threerings.getdown.util.Base64;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -19,6 +20,7 @@ public class ConnectionUtil
{
/**
* Opens a connection to a URL, setting the authentication header if user info is present.
* @param proxy the proxy via which to perform HTTP connections.
* @param url the URL to which to open a connection.
* @param connectTimeout if {@code > 0} then a timeout, in seconds, to use when opening the
* connection. If {@code 0} is supplied, the connection timeout specified via system properties
@@ -27,10 +29,10 @@ public class ConnectionUtil
* the connection. If {@code 0} is supplied, the read timeout specified via system properties
* will be used instead.
*/
public static URLConnection open (URL url, int connectTimeout, int readTimeout)
public static URLConnection open (Proxy proxy, URL url, int connectTimeout, int readTimeout)
throws IOException
{
URLConnection conn = url.openConnection();
URLConnection conn = url.openConnection(proxy);
// configure a connect timeout, if requested
int ctimeout = connectTimeout > 0 ? connectTimeout : SysProps.connectTimeout();
@@ -63,9 +65,9 @@ public class ConnectionUtil
* present. Throws a class cast exception if the connection returned is not the right type. See
* {@link #open} for parameter documentation.
*/
public static HttpURLConnection openHttp (URL url, int connectTimeout, int readTimeout)
throws IOException
public static HttpURLConnection openHttp (
Proxy proxy, URL url, int connectTimeout, int readTimeout) throws IOException
{
return (HttpURLConnection)open(url, connectTimeout, readTimeout);
return (HttpURLConnection)open(proxy, url, connectTimeout, readTimeout);
}
}
@@ -13,6 +13,16 @@ import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
@@ -20,29 +30,9 @@ import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import ca.beq.util.win32.registry.RegistryKey;
import ca.beq.util.win32.registry.RegistryValue;
import ca.beq.util.win32.registry.RootKey;
import com.samskivert.swing.util.SwingUtil;
import com.threerings.getdown.data.Application.UpdateInterface.Step;
import com.threerings.getdown.data.*;
import com.threerings.getdown.data.Application.UpdateInterface.Step;
import com.threerings.getdown.net.Downloader;
import com.threerings.getdown.net.HTTPDownloader;
import com.threerings.getdown.tools.Patcher;
@@ -186,24 +176,12 @@ public abstract class Getdown extends Thread
/**
* Configures our proxy settings (called by {@link ProxyPanel}) and fires up the launcher.
*/
public void configureProxy (String host, String port)
public void configProxy (String host, String port, String username, String password)
{
log.info("User configured proxy", "host", host, "port", port);
// if we're provided with valid values, create a proxy.txt file
if (!StringUtil.isBlank(host)) {
File pfile = _app.getLocalPath("proxy.txt");
try (PrintStream pout = new PrintStream(new FileOutputStream(pfile))) {
pout.println("host = " + host);
if (!StringUtil.isBlank(port)) {
pout.println("port = " + port);
}
} catch (IOException ioe) {
log.warning("Error creating proxy file '" + pfile + "': " + ioe);
}
// also configure them in the JVM
setProxyProperties(host, port);
ProxyUtil.configProxy(_app, host, port, username, password);
}
// clear out our UI
@@ -214,67 +192,11 @@ public abstract class Getdown extends Thread
new Thread(this).start();
}
/**
* Reads and/or autodetects our proxy settings.
*
* @return true if we should proceed with running the launcher, false if we need to wait for
* the user to enter proxy settings.
*/
protected boolean detectProxy ()
{
// we may already have a proxy configured
if (System.getProperty("http.proxyHost") != null ||
System.getProperty("https.proxyHost") != null) {
protected boolean detectProxy () {
if (ProxyUtil.autoDetectProxy(_app)) {
return true;
}
// look in the Vinders registry
if (LaunchUtil.isWindows()) {
try {
String host = null, port = 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) {
port = strval.substring(cidx+1);
strval = strval.substring(0, cidx);
}
host = strval;
}
}
if (enabled) {
setProxyProperties(host, port);
return true;
} 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);
}
}
// otherwise look for and read our proxy.txt file
File pfile = _app.getLocalPath("proxy.txt");
if (pfile.exists()) {
try {
Config pconf = Config.parseConfig(pfile, Config.createOpts(false));
setProxyProperties(pconf.getString("host"), pconf.getString("port"));
return true;
} catch (IOException ioe) {
log.warning("Failed to read '" + pfile + "': " + ioe);
}
}
// otherwise see if we actually need a proxy; first we have to initialize our application
// to get some sort of interface configuration and the appbase URL
log.info("Checking whether we need to use a proxy...");
@@ -284,59 +206,15 @@ public abstract class Getdown extends Thread
// no worries
}
updateStatus("m.detecting_proxy");
URL rurl = _app.getConfigResource().getRemote();
try {
// try to make a HEAD request for this URL (use short connect and read timeouts)
URLConnection conn = ConnectionUtil.open(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
if (hcon.getResponseCode() != HttpURLConnection.HTTP_OK) {
log.warning("Got a non-200 response but assuming we're OK because we got " +
"something...", "url", rurl, "rsp", hcon.getResponseCode());
}
} finally {
hcon.disconnect();
}
}
// we got through, so we appear not to require a proxy; make a blank proxy config and
// get on gettin' down
log.info("No proxy appears to be needed.");
try {
pfile.createNewFile();
} catch (IOException ioe) {
log.warning("Failed to create blank proxy file '" + pfile + "': " + ioe);
}
return true;
} catch (IOException ioe) {
log.info("Failed to HEAD " + rurl + ": " + ioe);
log.info("We probably need a proxy, but auto-detection failed.");
if (!ProxyUtil.canLoadWithoutProxy(_app.getConfigResource().getRemote())) {
return false;
}
// let the caller know that we need a proxy but can't detect it
return false;
}
/**
* Configures the JVM proxy system properties.
*/
protected void setProxyProperties (String host, String port)
{
if (!StringUtil.isBlank(host)) {
System.setProperty("http.proxyHost", host);
System.setProperty("https.proxyHost", host);
if (!StringUtil.isBlank(port)) {
System.setProperty("http.proxyPort", port);
System.setProperty("https.proxyPort", port);
}
log.info("Using proxy", "host", host, "port", port);
}
// we got through, so we appear not to require a proxy; make a blank proxy config so that
// we don't go through this whole detection process again next time
log.info("No proxy appears to be needed.");
ProxyUtil.saveProxy(_app, null, null);
return true;
}
protected void readConfig (boolean preloads) throws IOException {
@@ -374,10 +252,6 @@ public abstract class Getdown extends Thread
*/
protected void getdown ()
{
log.info("---------------- Proxy Info -----------------");
log.info("-- Proxy Host: " + System.getProperty("http.proxyHost"));
log.info("-- Proxy Port: " + System.getProperty("http.proxyPort"));
log.info("---------------------------------------------");
try {
// first parses our application deployment file
@@ -723,7 +597,7 @@ public abstract class Getdown extends Thread
// create our user interface
createInterfaceAsync(false);
Downloader dl = new HTTPDownloader() {
Downloader dl = new HTTPDownloader(_app.proxy) {
@Override protected void resolvingDownloads () {
updateStatus("m.resolving");
}
@@ -1113,7 +987,7 @@ public abstract class Getdown extends Thread
@Override
public void run () {
try {
HttpURLConnection ucon = ConnectionUtil.openHttp(_url, 0, 0);
HttpURLConnection ucon = ConnectionUtil.openHttp(_app.proxy, _url, 0, 0);
// if we have a tracking cookie configured, configure the request with it
if (_app.getTrackingCookieName() != null &&
@@ -1182,6 +1056,4 @@ public abstract class Getdown extends Thread
protected static final int MAX_LOOPS = 5;
protected static final long FALLBACK_CHECK_TIME = 1000L;
protected static final String PROXY_REGISTRY =
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
}
@@ -7,22 +7,25 @@ package com.threerings.getdown.launcher;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import com.samskivert.swing.GroupLayout;
import com.samskivert.swing.Spacer;
import com.samskivert.swing.VGroupLayout;
import com.threerings.getdown.util.MessageUtil;
import static com.threerings.getdown.Log.log;
@@ -30,8 +33,7 @@ import static com.threerings.getdown.Log.log;
* Displays an interface with which the user can configure their proxy
* settings.
*/
public final class ProxyPanel extends JPanel
implements ActionListener
public final class ProxyPanel extends JPanel implements ActionListener
{
public ProxyPanel (Getdown getdown, ResourceBundle msgs)
{
@@ -40,21 +42,50 @@ public final class ProxyPanel extends JPanel
setLayout(new VGroupLayout());
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
add(new JLabel(get("m.configure_proxy")));
add(new SaneLabelField(get("m.configure_proxy")));
add(new Spacer(5, 5));
JPanel row = new JPanel(new BorderLayout(5, 5));
row.add(new JLabel(get("m.proxy_host")), BorderLayout.WEST);
JPanel row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_host")), BorderLayout.WEST);
row.add(_host = new SaneTextField());
add(row);
row = new JPanel(new BorderLayout(5, 5));
row.add(new JLabel(get("m.proxy_port")), BorderLayout.WEST);
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_port")), BorderLayout.WEST);
row.add(_port = new SaneTextField());
add(row);
add(new Spacer(5, 5));
add(new JLabel(get("m.proxy_extra")));
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_auth_required")), BorderLayout.WEST);
_useAuth = new JCheckBox();
row.add(_useAuth);
add(row);
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_username")), BorderLayout.WEST);
_username = new SaneTextField();
_username.setEnabled(false);
row.add(_username);
add(row);
row = new JPanel(new GridLayout());
row.add(new SaneLabelField(get("m.proxy_password")), BorderLayout.WEST);
_password = new SanePasswordField();
_password.setEnabled(false);
row.add(_password);
add(row);
_useAuth.addItemListener(new ItemListener() {
@Override public void itemStateChanged (ItemEvent event) {
boolean selected = (event.getStateChange() == ItemEvent.SELECTED);
_username.setEnabled(selected);
_password.setEnabled(selected);
}
});
add(new Spacer(5, 5));
row = GroupLayout.makeButtonBox(GroupLayout.CENTER);
JButton button;
@@ -79,7 +110,7 @@ public final class ProxyPanel extends JPanel
// documentation inherited
@Override
public void addNotify ()
public void addNotify ()
{
super.addNotify();
_host.requestFocusInWindow();
@@ -93,17 +124,23 @@ public final class ProxyPanel extends JPanel
// or the JLabel will claim a bogus height thinking it can lay its
// text out all on one line which will booch the whole UI's
// preferred size
return new Dimension(500, 350);
return new Dimension(500, 320);
}
// documentation inherited from interface
@Override
public void actionPerformed (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals("ok")) {
// communicate this info back to getdown
_getdown.configureProxy(_host.getText(), _port.getText());
String user = null, pass = null;
if (_useAuth.isSelected()) {
user = _username.getText();
// we have to keep the proxy password around for every HTTP request, so having it
// in a char[] that gets zeroed out after use is not viable for this use case
pass = new String(_password.getPassword());
}
_getdown.configProxy(_host.getText(), _port.getText(), user, pass);
} else {
// they canceled, we're outta here
System.exit(0);
@@ -126,19 +163,34 @@ public final class ProxyPanel extends JPanel
}
}
protected static class SaneTextField extends JTextField
{
@Override
public Dimension getPreferredSize () {
Dimension d = super.getPreferredSize();
d.width = Math.max(d.width, 150);
return d;
protected static class SaneLabelField extends JLabel {
public SaneLabelField(String message) { super(message); }
@Override public Dimension getPreferredSize () {
return clampWidth(super.getPreferredSize(), 200);
}
}
protected static class SaneTextField extends JTextField {
@Override public Dimension getPreferredSize () {
return clampWidth(super.getPreferredSize(), 150);
}
}
protected static class SanePasswordField extends JPasswordField {
@Override public Dimension getPreferredSize () {
return clampWidth(super.getPreferredSize(), 150);
}
}
protected static Dimension clampWidth (Dimension dim, int minWidth) {
dim.width = Math.max(dim.width, minWidth);
return dim;
}
protected Getdown _getdown;
protected ResourceBundle _msgs;
protected JTextField _host;
protected JTextField _port;
protected JCheckBox _useAuth;
protected JTextField _username;
protected JPasswordField _password;
}
@@ -0,0 +1,210 @@
//
// 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.FileOutputStream;
import java.io.IOException;
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 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];
}
if (StringUtil.isBlank(host)) {
return false;
}
// yay, we found a proxy configuration, configure it in the app
initProxy(app, host, port, null, null);
return true;
}
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<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
Iterator<ProxyAuth> 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)
{
// check whether we have saved proxy credentials
String appDir = app.getAppDir().getAbsolutePath();
ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
Iterator<ProxyAuth> 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";
}
@@ -11,15 +11,11 @@ m.abort_cancel = Continue installation
m.detecting_proxy = Trying to auto-detect proxy settings
m.configure_proxy = <html>We were unable to connect to our servers to download data. \
<ul><li> If Windows Firewall or Norton Internet Security was instructed \
to block <code>javaw.exe</code> we cannot download the data. You will need \
to allow <code>javaw.exe</code> to access the internet. You can try \
running the app again, but you may need to clear javaw.exe from your \
firewall configuration ( Start -> Control Panel -> Windows Firewall ).</ul> \
<p> Your computer may access the Internet through a proxy and we were \
unable to automatically detect your proxy settings. If you know your \
proxy settings, you can enter them below.</html>
m.configure_proxy = <html>We were unable to connect to the application server to download data. \
<p> Please make sure that no virus scanner or firewall is blocking network communicaton with \
the server. \
<p> Your computer may access the Internet through a proxy and we were unable to automatically \
detect your proxy settings. If you know your proxy settings, you can enter them below.</html>
m.proxy_extra = <html>If you are sure that you don't use a proxy then \
perhaps there is a temporary Internet outage that is preventing us from \
@@ -28,6 +24,9 @@ m.proxy_extra = <html>If you are sure that you don't use a proxy then \
m.proxy_host = Proxy IP
m.proxy_port = Proxy port
m.proxy_username = Username
m.proxy_password = Password
m.proxy_auth_required = Authentication required
m.proxy_ok = OK
m.proxy_cancel = Cancel
@@ -13,27 +13,21 @@ m.abort_cancel = Installation fortsetzen
m.detecting_proxy = Versuche Proxy-Einstellungen automatisch zu ermitteln
m.configure_proxy = <html>Es war nicht m\u00f6glich, eine Verbindung zu unserem \
Server herzustellen, um die Anwendungsdaten herunterzuladen. \
<ul><li> Falls Windows Firewall oder Norton Internet Security angewiesen \
wurden, <code>javaw.exe</code> zu blockieren, kann die Anwendung nicht \
heruntergeladen werden. Du musst <code>javaw.exe</code> erlauben, \
Verbindung zum Internet herzustellen. Du kannst nochmals versuchen, die \
Anwendung zu starten, aber eventuell musst du javaw.exe aus der \
Firewall-Konfiguration entfernen (Start -> Systemsteuerung -> Windows \
Firewall). </ul> \
<p> Eventuell ist der Computer durch einen Proxy mit dem Internet \
verbunden. Es war uns nicht m\u00f6glich, die Proxy-Einstellungen automatisch \
zu ermitteln. Falls bekannt, k\u00f6nnen diese unten eingetragen \
werden.</html>
m.configure_proxy = <html>Es konnte keine Verbindung zum Applikations-Server aufgebaut werden. \
<p>Bitte kontrollieren Sie die Proxyeinstellungen und stellen Sie sicher, dass keine lokal oder \
im Netzwerk betriebene Sicherheitsanwendung (Virenscanner, Firewall, etc.) die Kommunikation \
mit dem Server blockiert.<br> \
Wenn kein Proxy verwendet werden soll, l\u00f6schen Sie bitte alle Eintr\u00e4ge in den unten \
stehenden Feldern und klicken sie auf OK.</html>
m.proxy_extra = <html>Falls kein Proxy verwendet wird, liegt \
m\u00f6glicherweise eine St\u00f6rung in der Internetverbindung zu unserem Server \
vor. In diesem Fall bitte abbrechen und sp\u00e4ter noch einmal \
versuchen.</html>
m.proxy_extra = <html>Sollten Sie keine Proxyeinstellungen gesetzt haben wenden Sie sich bitte \
an Ihren Administrator.</html>
m.proxy_host = Proxy IP
m.proxy_port = Proxy port
m.proxy_host = Proxy-Adresse
m.proxy_port = Proxy-Port
m.proxy_username = Benutzername
m.proxy_password = Passwort
m.proxy_auth_required = Authentisierung erforderlich
m.proxy_ok = OK
m.proxy_cancel = Abbrechen
@@ -29,6 +29,9 @@ m.proxy_extra = <html>Si est\u00e1s seguro de que no tienes un proxy entonces \
m.proxy_host = IP proxy
m.proxy_port = Puerto proxy
m.proxy_username = Nombre de usuario
m.proxy_password = Contrase\u00f1a
m.proxy_auth_required = Autenticacion requerida
m.proxy_ok = OK
m.proxy_cancel = Cancelar
@@ -27,6 +27,9 @@ m.proxy_extra =<html>Si vous \u00eates certain de ne pas utiliser de proxy, il e
m.proxy_host = Proxy IP
m.proxy_port = Proxy port
m.proxy_username = Nom d'utilisateur
m.proxy_password = Mot de passe
m.proxy_auth_required = Identification requise
m.proxy_ok = OK
m.proxy_cancel = Annuler
@@ -28,6 +28,9 @@ m.proxy_extra = <html>Se sei sicuro di non usare proxy \
m.proxy_host = IP Proxy
m.proxy_port = Porta Proxy
m.proxy_username = Nome utente
m.proxy_password = Parola d'ordine
m.proxy_auth_required = Autenticazione richiesta
m.proxy_ok = OK
m.proxy_cancel = Annulla
@@ -28,7 +28,10 @@ m.proxy_extra = <html>\u30d7\u30ed\u30ad\u30b7\u3092\u4f7f\u7528\u3057\u3066\u30
\u5f8c\u307b\u3069\u6539\u3081\u3066\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002</html>
m.proxy_host = \u30d7\u30ed\u30ad\u30b7IP
m.proxy_port = \u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8
m.proxy_port = \u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8
m.proxy_username = Username
m.proxy_password = Password
m.proxy_auth_required = Authentication required
m.proxy_ok = OK
m.proxy_cancel = \u30ad\u30e3\u30f3\u30bb\u30eb
@@ -24,6 +24,9 @@ m.proxy_extra = \uC790\uB3D9 \uD504\uB85D\uC2DC\uB97C \uC124\uC815\uC744 \uC2DC\
m.proxy_host = \uD504\uB85D\uC2DC IP
m.proxy_port = \uD504\uB85D\uC2DC \uD3EC\uD2B8
m.proxy_username = Username
m.proxy_password = Password
m.proxy_auth_required = Authentication required
m.proxy_ok = OK
m.proxy_cancel = \uCDE8\uC18C
@@ -31,6 +31,9 @@ m.proxy_extra = <html>Se voc\u00EA tem certeza que n\u00E3o usa um proxy, ent\u0
m.proxy_host = IP do Proxy
m.proxy_port = Porta do Proxy
m.proxy_username = Nome de usu\u00e1rio
m.proxy_password = Senha
m.proxy_auth_required = Autentifica\u00e7\u00e3o requerida
m.proxy_ok = OK
m.proxy_cancel = Cancelar
@@ -16,6 +16,9 @@ m.proxy_extra = <html>\u5982\u679c\u60a8\u786e\u5b9a\u60a8\u6ca1\u6709\u4f7f\u75
m.proxy_host = \u4ee3\u7406\u670d\u52a1\u5668\u7684IP\u5730\u5740
m.proxy_port = \u4ee3\u7406\u670d\u52a1\u5668\u7684\u7aef\u53e3\u53f7
m.proxy_username = Username
m.proxy_password = Password
m.proxy_auth_required = Authentication required
m.proxy_ok = \u786e\u5b9a
m.proxy_cancel = \u53d6\u6d88