- Convert HTTP and CONNECT proxies to MD5 authentication

- Allow multiple users
  - Migrate passwords on first save
This commit is contained in:
zzz
2012-10-16 19:17:06 +00:00
parent 613dd77d2c
commit a9e18620b9
6 changed files with 154 additions and 93 deletions

View File

@@ -58,7 +58,7 @@ import net.i2p.util.PortMapper;
*/ */
public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable { public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable {
private static final String AUTH_REALM = "I2P SSL Proxy"; public static final String AUTH_REALM = "I2P SSL Proxy";
private final static byte[] ERR_DESTINATION_UNKNOWN = private final static byte[] ERR_DESTINATION_UNKNOWN =
("HTTP/1.1 503 Service Unavailable\r\n"+ ("HTTP/1.1 503 Service Unavailable\r\n"+
@@ -277,14 +277,15 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
} }
// Authorization // Authorization
if (!authorize(s, requestId, method, authorization)) { AuthResult result = authorize(s, requestId, method, authorization);
if (result != AuthResult.AUTH_GOOD) {
if (_log.shouldLog(Log.WARN)) { if (_log.shouldLog(Log.WARN)) {
if (authorization != null) if (authorization != null)
_log.warn(getPrefix(requestId) + "Auth failed, sending 407 again"); _log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
else else
_log.warn(getPrefix(requestId) + "Auth required, sending 407"); _log.warn(getPrefix(requestId) + "Auth required, sending 407");
} }
out.write(getAuthError(false).getBytes()); out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
s.close(); s.close();
return; return;
} }

View File

@@ -77,7 +77,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
*/ */
private final String _proxyNonce; private final String _proxyNonce;
private static final String AUTH_REALM = "I2P HTTP Proxy"; public static final String AUTH_REALM = "I2P HTTP Proxy";
/** /**
* These are backups if the xxx.ht error page is missing. * These are backups if the xxx.ht error page is missing.
@@ -846,7 +846,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
} }
// Authorization // Authorization
if(!authorize(s, requestId, method, authorization)) { AuthResult result = authorize(s, requestId, method, authorization);
if (result != AuthResult.AUTH_GOOD) {
if(_log.shouldLog(Log.WARN)) { if(_log.shouldLog(Log.WARN)) {
if(authorization != null) { if(authorization != null) {
_log.warn(getPrefix(requestId) + "Auth failed, sending 407 again"); _log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
@@ -854,7 +855,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_log.warn(getPrefix(requestId) + "Auth required, sending 407"); _log.warn(getPrefix(requestId) + "Auth required, sending 407");
} }
} }
out.write(getAuthError(false).getBytes()); out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
writeFooter(out); writeFooter(out);
s.close(); s.close();
return; return;

View File

@@ -122,9 +122,16 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
/** passwords for specific outproxies may be added with outproxyUsername.fooproxy.i2p=user and outproxyPassword.fooproxy.i2p=pw */ /** passwords for specific outproxies may be added with outproxyUsername.fooproxy.i2p=user and outproxyPassword.fooproxy.i2p=pw */
public static final String PROP_OUTPROXY_USER_PREFIX = PROP_OUTPROXY_USER + '.'; public static final String PROP_OUTPROXY_USER_PREFIX = PROP_OUTPROXY_USER + '.';
public static final String PROP_OUTPROXY_PW_PREFIX = PROP_OUTPROXY_PW + '.'; public static final String PROP_OUTPROXY_PW_PREFIX = PROP_OUTPROXY_PW + '.';
/** new style MD5 auth */
public static final String PROP_PROXY_DIGEST_PREFIX = "proxy.auth.";
public static final String PROP_PROXY_DIGEST_SUFFIX = ".md5";
public static final String BASIC_AUTH = "basic";
public static final String DIGEST_AUTH = "digest";
protected abstract String getRealm(); protected abstract String getRealm();
protected enum AuthResult {AUTH_BAD_REQ, AUTH_BAD, AUTH_STALE, AUTH_GOOD}
/** /**
* @since 0.9.4 * @since 0.9.4
*/ */
@@ -144,81 +151,77 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* @param authorization may be null, the full auth line e.g. "Basic lskjlksjf" * @param authorization may be null, the full auth line e.g. "Basic lskjlksjf"
* @return success * @return success
*/ */
protected boolean authorize(Socket s, long requestId, String method, String authorization) { protected AuthResult authorize(Socket s, long requestId, String method, String authorization) {
String authRequired = getTunnel().getClientOptions().getProperty(PROP_AUTH); String authRequired = getTunnel().getClientOptions().getProperty(PROP_AUTH);
if (authRequired == null) if (authRequired == null)
return true; return AuthResult.AUTH_GOOD;
authRequired = authRequired.toLowerCase(Locale.US); authRequired = authRequired.toLowerCase(Locale.US);
if (authRequired.equals("false")) if (authRequired.equals("false"))
return true; return AuthResult.AUTH_GOOD;
if (s instanceof InternalSocket) { if (s instanceof InternalSocket) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Internal access, no auth required"); _log.info(getPrefix(requestId) + "Internal access, no auth required");
return true; return AuthResult.AUTH_GOOD;
} }
if (authorization == null) if (authorization == null)
return false; return AuthResult.AUTH_BAD;
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Auth: " + authorization); _log.info(getPrefix(requestId) + "Auth: " + authorization);
String authLC = authorization.toLowerCase(Locale.US); String authLC = authorization.toLowerCase(Locale.US);
if (authRequired.equals("true") || authRequired.equals("basic")) { if (authRequired.equals("true") || authRequired.equals(BASIC_AUTH)) {
if (!authLC.startsWith("basic ")) if (!authLC.startsWith("basic "))
return false; return AuthResult.AUTH_BAD;
authorization = authorization.substring(6); authorization = authorization.substring(6);
// hmm safeDecode(foo, true) to use standard alphabet is private in Base64 // hmm safeDecode(foo, true) to use standard alphabet is private in Base64
byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "=")); byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "="));
if (decoded != null) { if (decoded != null) {
// We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ? // We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ?
try { try {
String dec = new String(decoded, "UTF-8"); String dec = new String(decoded, "UTF-8");
String[] parts = dec.split(":"); String[] parts = dec.split(":");
String user = parts[0]; String user = parts[0];
String pw = parts[1]; String pw = parts[1];
// first try pw for that user // first try pw for that user
String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user); String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user);
if (configPW == null) { if (configPW == null) {
// if not, look at default user and pw // if not, look at default user and pw
String configUser = getTunnel().getClientOptions().getProperty(PROP_USER); String configUser = getTunnel().getClientOptions().getProperty(PROP_USER);
if (user.equals(configUser)) if (user.equals(configUser))
configPW = getTunnel().getClientOptions().getProperty(PROP_PW); configPW = getTunnel().getClientOptions().getProperty(PROP_PW);
}
if (configPW != null) {
if (pw.equals(configPW)) {
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Good auth - user: " + user + " pw: " + pw);
return true;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth, pw mismatch - user: " + user + " pw: " + pw + " expected: " + configPW);
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth, no stored pw for user: " + user + " pw: " + pw);
}
} catch (UnsupportedEncodingException uee) {
_log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee);
} catch (ArrayIndexOutOfBoundsException aioobe) {
// no ':' in response
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe);
} }
} else { if (configPW != null) {
if (pw.equals(configPW)) {
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Good auth - user: " + user + " pw: " + pw);
return AuthResult.AUTH_GOOD;
}
}
_log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
} catch (UnsupportedEncodingException uee) {
_log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee);
} catch (ArrayIndexOutOfBoundsException aioobe) {
// no ':' in response
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization); _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe);
return AuthResult.AUTH_BAD_REQ;
} }
return AuthResult.AUTH_BAD;
return false; } else {
} else if (authRequired.equals("digest")) { if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization);
return AuthResult.AUTH_BAD_REQ;
}
} else if (authRequired.equals(DIGEST_AUTH)) {
if (!authLC.startsWith("digest ")) if (!authLC.startsWith("digest "))
return false; return AuthResult.AUTH_BAD;
authorization = authorization.substring(7); authorization = authorization.substring(7);
Map<String, String> args = parseArgs(authorization); Map<String, String> args = parseArgs(authorization);
AuthResult rv = validateDigest(method, args); AuthResult rv = validateDigest(method, args);
return rv == AuthResult.AUTH_GOOD; return rv;
} else { } else {
_log.error("Unknown proxy authorization type configured: " + authRequired); _log.error("Unknown proxy authorization type configured: " + authRequired);
return true; return AuthResult.AUTH_BAD_REQ;
} }
} }
@@ -250,10 +253,10 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
return check; return check;
} }
// get H(A1) == stored password // get H(A1) == stored password
String ha1 = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user); String ha1 = getTunnel().getClientOptions().getProperty(PROP_PROXY_DIGEST_PREFIX + user +
PROP_PROXY_DIGEST_SUFFIX);
if (ha1 == null) { if (ha1 == null) {
if (_log.shouldLog(Log.INFO)) _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
_log.info("Bad digest auth - no stored pw for user: " + user);
return AuthResult.AUTH_BAD; return AuthResult.AUTH_BAD;
} }
// get H(A2) // get H(A2)
@@ -263,8 +266,9 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
String kd = ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2; String kd = ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2;
String hkd = PasswordManager.md5Hex(kd); String hkd = PasswordManager.md5Hex(kd);
if (!response.equals(hkd)) { if (!response.equals(hkd)) {
_log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Bad digest auth - user: " + user); _log.info("Bad digest auth: " + DataHelper.toString(args));
return AuthResult.AUTH_BAD; return AuthResult.AUTH_BAD;
} }
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
@@ -288,8 +292,6 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
return Base64.encode(n); return Base64.encode(n);
} }
protected enum AuthResult {AUTH_BAD_REQ, AUTH_BAD, AUTH_STALE, AUTH_GOOD}
/** /**
* Verify the Base 64 of 24 bytes: (now, md5 of (now, proxy nonce)) * Verify the Base 64 of 24 bytes: (now, md5 of (now, proxy nonce))
* @since 0.9.4 * @since 0.9.4

View File

@@ -221,19 +221,7 @@ public class EditBean extends IndexBean {
/** all proxy auth @since 0.8.2 */ /** all proxy auth @since 0.8.2 */
public boolean getProxyAuth(int tunnel) { public boolean getProxyAuth(int tunnel) {
return getBooleanProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH) && return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH, "false") != "false";
getProxyUsername(tunnel).length() > 0 &&
getProxyPassword(tunnel).length() > 0;
}
public String getProxyUsername(int tunnel) {
return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_USER, "");
}
public String getProxyPassword(int tunnel) {
if (getProxyUsername(tunnel).length() <= 0)
return "";
return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_PW, "");
} }
public boolean getOutproxyAuth(int tunnel) { public boolean getOutproxyAuth(int tunnel) {
@@ -354,10 +342,17 @@ public class EditBean extends IndexBean {
if (opts == null) return ""; if (opts == null) return "";
StringBuilder buf = new StringBuilder(64); StringBuilder buf = new StringBuilder(64);
int i = 0; int i = 0;
boolean isMD5Proxy = "httpclient".equals(tun.getType()) ||
"connectclient".equals(tun.getType());
for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) { for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) {
String key = (String)iter.next(); String key = (String)iter.next();
if (_noShowSet.contains(key)) if (_noShowSet.contains(key))
continue; continue;
// leave in for HTTP and Connect so it can get migrated to MD5
// hide for SOCKS until migrated to MD5
if ((!isMD5Proxy) &&
_nonProxyNoShowSet.contains(key))
continue;
String val = opts.getProperty(key); String val = opts.getProperty(key);
if (i != 0) buf.append(' '); if (i != 0) buf.append(' ');
buf.append(key).append('=').append(val); buf.append(key).append('=').append(val);

View File

@@ -27,6 +27,7 @@ import net.i2p.data.Certificate;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.data.PrivateKeyFile; import net.i2p.data.PrivateKeyFile;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.i2ptunnel.I2PTunnelConnectClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPClient; import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase; import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
import net.i2p.i2ptunnel.I2PTunnelIRCClient; import net.i2p.i2ptunnel.I2PTunnelIRCClient;
@@ -36,6 +37,7 @@ import net.i2p.util.Addresses;
import net.i2p.util.ConcurrentHashSet; import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.FileUtil; import net.i2p.util.FileUtil;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.PasswordManager;
/** /**
* Simple accessor for exposing tunnel info, but also an ugly form handler * Simple accessor for exposing tunnel info, but also an ugly form handler
@@ -83,6 +85,8 @@ public class IndexBean {
private int _hashCashValue; private int _hashCashValue;
private int _certType; private int _certType;
private String _certSigner; private String _certSigner;
private String _newProxyUser;
private String _newProxyPW;
public static final int RUNNING = 1; public static final int RUNNING = 1;
public static final int STARTING = 2; public static final int STARTING = 2;
@@ -224,9 +228,9 @@ public class IndexBean {
private String start() { private String start() {
if (_tunnel < 0) return "Invalid tunnel"; if (_tunnel < 0) return "Invalid tunnel";
List controllers = _group.getControllers(); List<TunnelController> controllers = _group.getControllers();
if (_tunnel >= controllers.size()) return "Invalid tunnel"; if (_tunnel >= controllers.size()) return "Invalid tunnel";
TunnelController controller = (TunnelController)controllers.get(_tunnel); TunnelController controller = controllers.get(_tunnel);
controller.startTunnelBackground(); controller.startTunnelBackground();
// give the messages a chance to make it to the window // give the messages a chance to make it to the window
try { Thread.sleep(1000); } catch (InterruptedException ie) {} try { Thread.sleep(1000); } catch (InterruptedException ie) {}
@@ -237,9 +241,9 @@ public class IndexBean {
private String stop() { private String stop() {
if (_tunnel < 0) return "Invalid tunnel"; if (_tunnel < 0) return "Invalid tunnel";
List controllers = _group.getControllers(); List<TunnelController> controllers = _group.getControllers();
if (_tunnel >= controllers.size()) return "Invalid tunnel"; if (_tunnel >= controllers.size()) return "Invalid tunnel";
TunnelController controller = (TunnelController)controllers.get(_tunnel); TunnelController controller = controllers.get(_tunnel);
controller.stopTunnel(); controller.stopTunnel();
// give the messages a chance to make it to the window // give the messages a chance to make it to the window
try { Thread.sleep(1000); } catch (InterruptedException ie) {} try { Thread.sleep(1000); } catch (InterruptedException ie) {}
@@ -268,10 +272,10 @@ public class IndexBean {
// if the current tunnel is shared, and of supported type // if the current tunnel is shared, and of supported type
if (Boolean.parseBoolean(cur.getSharedClient()) && isClient(cur.getType())) { if (Boolean.parseBoolean(cur.getSharedClient()) && isClient(cur.getType())) {
// all clients use the same I2CP session, and as such, use the same I2CP options // all clients use the same I2CP session, and as such, use the same I2CP options
List controllers = _group.getControllers(); List<TunnelController> controllers = _group.getControllers();
for (int i = 0; i < controllers.size(); i++) { for (int i = 0; i < controllers.size(); i++) {
TunnelController c = (TunnelController)controllers.get(i); TunnelController c = controllers.get(i);
// Current tunnel modified by user, skip // Current tunnel modified by user, skip
if (c == cur) continue; if (c == cur) continue;
@@ -804,21 +808,22 @@ public class IndexBean {
/** all proxy auth @since 0.8.2 */ /** all proxy auth @since 0.8.2 */
public void setProxyAuth(String s) { public void setProxyAuth(String s) {
_booleanOptions.add(I2PTunnelHTTPClientBase.PROP_AUTH); if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
} }
public void setProxyUsername(String s) { public void setProxyUsername(String s) {
if (s != null) if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_USER, s.trim()); _newProxyUser = s.trim();
} }
public void setProxyPassword(String s) { public void setProxyPassword(String s) {
if (s != null) if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_PW, s.trim()); _newProxyPW = s.trim();
} }
public void setOutproxyAuth(String s) { public void setOutproxyAuth(String s) {
_booleanOptions.add(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH); _otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
} }
public void setOutproxyUsername(String s) { public void setOutproxyUsername(String s) {
@@ -1040,6 +1045,45 @@ public class IndexBean {
config.setProperty("proxyList", _proxyList); config.setProperty("proxyList", _proxyList);
} }
// Proxy auth including migration to MD5
if ("httpclient".equals(_type) || "connectclient".equals(_type)) {
// Migrate even if auth is disabled
// go get the old from custom options that updateConfigGeneric() put in there
String puser = "option." + I2PTunnelHTTPClientBase.PROP_USER;
String user = config.getProperty(puser);
String ppw = "option." + I2PTunnelHTTPClientBase.PROP_PW;
String pw = config.getProperty(ppw);
if (user != null && pw != null && user.length() > 0 && pw.length() > 0) {
String pmd5 = "option." + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
user + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
if (config.getProperty(pmd5) == null) {
// not in there, migrate
String realm = _type.equals("httpclient") ? I2PTunnelHTTPClient.AUTH_REALM
: I2PTunnelConnectClient.AUTH_REALM;
String hex = PasswordManager.md5Hex(realm, user, pw);
if (hex != null) {
config.setProperty(pmd5, hex);
config.remove(puser);
config.remove(ppw);
}
}
}
// New user/password
String auth = _otherOptions.get(I2PTunnelHTTPClientBase.PROP_AUTH);
if (auth != null && !auth.equals("false")) {
if (_newProxyUser != null && _newProxyPW != null &&
_newProxyUser.length() > 0 && _newProxyPW.length() > 0) {
String pmd5 = "option." + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
_newProxyUser + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
String realm = _type.equals("httpclient") ? I2PTunnelHTTPClient.AUTH_REALM
: I2PTunnelConnectClient.AUTH_REALM;
String hex = PasswordManager.md5Hex(realm, _newProxyUser, _newProxyPW);
if (hex != null)
config.setProperty(pmd5, hex);
}
}
}
if ("ircclient".equals(_type) || "client".equals(_type) || "streamrclient".equals(_type)) { if ("ircclient".equals(_type) || "client".equals(_type) || "streamrclient".equals(_type)) {
if (_targetDestination != null) if (_targetDestination != null)
config.setProperty("targetDestination", _targetDestination); config.setProperty("targetDestination", _targetDestination);
@@ -1084,15 +1128,16 @@ public class IndexBean {
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen" "i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen"
}; };
private static final String _booleanProxyOpts[] = { private static final String _booleanProxyOpts[] = {
I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH
}; };
private static final String _booleanServerOpts[] = { private static final String _booleanServerOpts[] = {
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST "i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST
}; };
private static final String _otherClientOpts[] = { private static final String _otherClientOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime", "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
"proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword", "outproxyUsername", "outproxyPassword",
I2PTunnelHTTPClient.PROP_JUMP_SERVERS I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
I2PTunnelHTTPClientBase.PROP_AUTH
}; };
private static final String _otherServerOpts[] = { private static final String _otherServerOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList", "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
@@ -1101,7 +1146,17 @@ public class IndexBean {
PROP_MAX_STREAMS PROP_MAX_STREAMS
}; };
/**
* do NOT add these to noShoOpts, we must leave them in for HTTPClient and ConnectCLient
* so they will get migrated to MD5
* TODO migrate socks to MD5
*/
private static final String _otherProxyOpts[] = {
"proxyUsername", "proxyPassword"
};
protected static final Set _noShowSet = new HashSet(64); protected static final Set _noShowSet = new HashSet(64);
protected static final Set _nonProxyNoShowSet = new HashSet(4);
static { static {
_noShowSet.addAll(Arrays.asList(_noShowOpts)); _noShowSet.addAll(Arrays.asList(_noShowOpts));
_noShowSet.addAll(Arrays.asList(_booleanClientOpts)); _noShowSet.addAll(Arrays.asList(_booleanClientOpts));
@@ -1109,6 +1164,7 @@ public class IndexBean {
_noShowSet.addAll(Arrays.asList(_booleanServerOpts)); _noShowSet.addAll(Arrays.asList(_booleanServerOpts));
_noShowSet.addAll(Arrays.asList(_otherClientOpts)); _noShowSet.addAll(Arrays.asList(_otherClientOpts));
_noShowSet.addAll(Arrays.asList(_otherServerOpts)); _noShowSet.addAll(Arrays.asList(_otherServerOpts));
_nonProxyNoShowSet.addAll(Arrays.asList(_otherProxyOpts));
} }
private void updateConfigGeneric(Properties config) { private void updateConfigGeneric(Properties config) {
@@ -1139,6 +1195,12 @@ public class IndexBean {
String key = pair.substring(0, eq); String key = pair.substring(0, eq);
if (_noShowSet.contains(key)) if (_noShowSet.contains(key))
continue; continue;
// leave in for HTTP and Connect so it can get migrated to MD5
// hide for SOCKS until migrated to MD5
if ((!"httpclient".equals(_type)) &&
(! "connectclient".equals(_type)) &&
_nonProxyNoShowSet.contains(key))
continue;
String val = pair.substring(eq+1); String val = pair.substring(eq+1);
config.setProperty("option." + key, val); config.setProperty("option." + key, val);
} }
@@ -1190,9 +1252,9 @@ public class IndexBean {
protected TunnelController getController(int tunnel) { protected TunnelController getController(int tunnel) {
if (tunnel < 0) return null; if (tunnel < 0) return null;
if (_group == null) return null; if (_group == null) return null;
List controllers = _group.getControllers(); List<TunnelController> controllers = _group.getControllers();
if (controllers.size() > tunnel) if (controllers.size() > tunnel)
return (TunnelController)controllers.get(tunnel); return controllers.get(tunnel);
else else
return null; return null;
} }

View File

@@ -435,13 +435,13 @@
<label> <label>
<%=intl._("Username")%>: <%=intl._("Username")%>:
</label> </label>
<input type="text" id="clientPort" name="proxyUsername" title="Set username for this service" value="<%=editBean.getProxyUsername(curTunnel)%>" class="freetext" /> <input type="text" id="clientPort" name="proxyUsername" title="Set username for this service" value="" class="freetext" />
</div> </div>
<div id="portField" class="rowItem"> <div id="portField" class="rowItem">
<label> <label>
<%=intl._("Password")%>: <%=intl._("Password")%>:
</label> </label>
<input type="password" id="clientPort" name="proxyPassword" title="Set password for this service" value="<%=editBean.getProxyPassword(curTunnel)%>" class="freetext" /> <input type="password" id="clientPort" name="proxyPassword" title="Set password for this service" value="" class="freetext" />
</div> </div>
<div class="subdivider"> <div class="subdivider">
<hr /> <hr />