From a9e18620b92b2f6ea5d2e4fa1d338c6a912ef934 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Tue, 16 Oct 2012 19:17:06 +0000 Subject: [PATCH] - Convert HTTP and CONNECT proxies to MD5 authentication - Allow multiple users - Migrate passwords on first save --- .../i2p/i2ptunnel/I2PTunnelConnectClient.java | 7 +- .../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 7 +- .../i2ptunnel/I2PTunnelHTTPClientBase.java | 114 +++++++++--------- .../src/net/i2p/i2ptunnel/web/EditBean.java | 21 ++-- .../src/net/i2p/i2ptunnel/web/IndexBean.java | 92 +++++++++++--- apps/i2ptunnel/jsp/editClient.jsp | 4 +- 6 files changed, 153 insertions(+), 92 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index fde47077fc..142aaf49bb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -58,7 +58,7 @@ import net.i2p.util.PortMapper; */ 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 = ("HTTP/1.1 503 Service Unavailable\r\n"+ @@ -277,14 +277,15 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R } // 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 (authorization != null) _log.warn(getPrefix(requestId) + "Auth failed, sending 407 again"); else _log.warn(getPrefix(requestId) + "Auth required, sending 407"); } - out.write(getAuthError(false).getBytes()); + out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes()); s.close(); return; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 594e64c3a5..518e7dcdcb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -77,7 +77,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn */ 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. @@ -846,7 +846,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn } // 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(authorization != null) { _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"); } } - out.write(getAuthError(false).getBytes()); + out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes()); writeFooter(out); s.close(); return; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java index 4b53e03996..1a88969141 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java @@ -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 */ public static final String PROP_OUTPROXY_USER_PREFIX = PROP_OUTPROXY_USER + '.'; 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 enum AuthResult {AUTH_BAD_REQ, AUTH_BAD, AUTH_STALE, AUTH_GOOD} + /** * @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" * @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); if (authRequired == null) - return true; + return AuthResult.AUTH_GOOD; authRequired = authRequired.toLowerCase(Locale.US); if (authRequired.equals("false")) - return true; + return AuthResult.AUTH_GOOD; if (s instanceof InternalSocket) { if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "Internal access, no auth required"); - return true; + return AuthResult.AUTH_GOOD; } if (authorization == null) - return false; + return AuthResult.AUTH_BAD; if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "Auth: " + authorization); 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 ")) - return false; + return AuthResult.AUTH_BAD; authorization = authorization.substring(6); - // hmm safeDecode(foo, true) to use standard alphabet is private in Base64 - byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "=")); - if (decoded != null) { - // We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ? - try { - String dec = new String(decoded, "UTF-8"); - String[] parts = dec.split(":"); - String user = parts[0]; - String pw = parts[1]; - // first try pw for that user - String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user); - if (configPW == null) { - // if not, look at default user and pw - String configUser = getTunnel().getClientOptions().getProperty(PROP_USER); - if (user.equals(configUser)) - 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); + // hmm safeDecode(foo, true) to use standard alphabet is private in Base64 + byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "=")); + if (decoded != null) { + // We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ? + try { + String dec = new String(decoded, "UTF-8"); + String[] parts = dec.split(":"); + String user = parts[0]; + String pw = parts[1]; + // first try pw for that user + String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user); + if (configPW == null) { + // if not, look at default user and pw + String configUser = getTunnel().getClientOptions().getProperty(PROP_USER); + if (user.equals(configUser)) + 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 AuthResult.AUTH_GOOD; } - } 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 { + _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)) - _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization); + _log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe); + return AuthResult.AUTH_BAD_REQ; } - - return false; - } else if (authRequired.equals("digest")) { + return AuthResult.AUTH_BAD; + } else { + 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 ")) - return false; + return AuthResult.AUTH_BAD; authorization = authorization.substring(7); Map<String, String> args = parseArgs(authorization); AuthResult rv = validateDigest(method, args); - return rv == AuthResult.AUTH_GOOD; + return rv; } else { _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; } // 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 (_log.shouldLog(Log.INFO)) - _log.info("Bad digest auth - no stored pw for user: " + user); + _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user); return AuthResult.AUTH_BAD; } // get H(A2) @@ -263,8 +266,9 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem String kd = ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2; String hkd = PasswordManager.md5Hex(kd); if (!response.equals(hkd)) { + _log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user); if (_log.shouldLog(Log.INFO)) - _log.info("Bad digest auth - user: " + user); + _log.info("Bad digest auth: " + DataHelper.toString(args)); return AuthResult.AUTH_BAD; } if (_log.shouldLog(Log.INFO)) @@ -288,8 +292,6 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem 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)) * @since 0.9.4 diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java index a0c38616e8..33e4f3fffd 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java @@ -221,19 +221,7 @@ public class EditBean extends IndexBean { /** all proxy auth @since 0.8.2 */ public boolean getProxyAuth(int tunnel) { - return getBooleanProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH) && - 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, ""); + return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH, "false") != "false"; } public boolean getOutproxyAuth(int tunnel) { @@ -354,10 +342,17 @@ public class EditBean extends IndexBean { if (opts == null) return ""; StringBuilder buf = new StringBuilder(64); int i = 0; + boolean isMD5Proxy = "httpclient".equals(tun.getType()) || + "connectclient".equals(tun.getType()); for (Iterator iter = opts.keySet().iterator(); iter.hasNext(); ) { String key = (String)iter.next(); if (_noShowSet.contains(key)) 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); if (i != 0) buf.append(' '); buf.append(key).append('=').append(val); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index 363c9a60b1..0ef169a421 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -27,6 +27,7 @@ import net.i2p.data.Certificate; import net.i2p.data.Destination; import net.i2p.data.PrivateKeyFile; import net.i2p.data.SessionKey; +import net.i2p.i2ptunnel.I2PTunnelConnectClient; import net.i2p.i2ptunnel.I2PTunnelHTTPClient; import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase; import net.i2p.i2ptunnel.I2PTunnelIRCClient; @@ -36,6 +37,7 @@ import net.i2p.util.Addresses; import net.i2p.util.ConcurrentHashSet; import net.i2p.util.FileUtil; import net.i2p.util.Log; +import net.i2p.util.PasswordManager; /** * Simple accessor for exposing tunnel info, but also an ugly form handler @@ -83,6 +85,8 @@ public class IndexBean { private int _hashCashValue; private int _certType; private String _certSigner; + private String _newProxyUser; + private String _newProxyPW; public static final int RUNNING = 1; public static final int STARTING = 2; @@ -224,9 +228,9 @@ public class IndexBean { private String start() { if (_tunnel < 0) return "Invalid tunnel"; - List controllers = _group.getControllers(); + List<TunnelController> controllers = _group.getControllers(); if (_tunnel >= controllers.size()) return "Invalid tunnel"; - TunnelController controller = (TunnelController)controllers.get(_tunnel); + TunnelController controller = controllers.get(_tunnel); controller.startTunnelBackground(); // give the messages a chance to make it to the window try { Thread.sleep(1000); } catch (InterruptedException ie) {} @@ -237,9 +241,9 @@ public class IndexBean { private String stop() { if (_tunnel < 0) return "Invalid tunnel"; - List controllers = _group.getControllers(); + List<TunnelController> controllers = _group.getControllers(); if (_tunnel >= controllers.size()) return "Invalid tunnel"; - TunnelController controller = (TunnelController)controllers.get(_tunnel); + TunnelController controller = controllers.get(_tunnel); controller.stopTunnel(); // give the messages a chance to make it to the window 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 (Boolean.parseBoolean(cur.getSharedClient()) && isClient(cur.getType())) { // 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++) { - TunnelController c = (TunnelController)controllers.get(i); + TunnelController c = controllers.get(i); // Current tunnel modified by user, skip if (c == cur) continue; @@ -804,21 +808,22 @@ public class IndexBean { /** all proxy auth @since 0.8.2 */ 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) { if (s != null) - _otherOptions.put(I2PTunnelHTTPClientBase.PROP_USER, s.trim()); + _newProxyUser = s.trim(); } public void setProxyPassword(String s) { if (s != null) - _otherOptions.put(I2PTunnelHTTPClientBase.PROP_PW, s.trim()); + _newProxyPW = s.trim(); } 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) { @@ -1040,6 +1045,45 @@ public class IndexBean { 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 (_targetDestination != null) config.setProperty("targetDestination", _targetDestination); @@ -1084,15 +1128,16 @@ public class IndexBean { "i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen" }; private static final String _booleanProxyOpts[] = { - I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH + I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH }; private static final String _booleanServerOpts[] = { "i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST }; private static final String _otherClientOpts[] = { "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime", - "proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword", - I2PTunnelHTTPClient.PROP_JUMP_SERVERS + "outproxyUsername", "outproxyPassword", + I2PTunnelHTTPClient.PROP_JUMP_SERVERS, + I2PTunnelHTTPClientBase.PROP_AUTH }; private static final String _otherServerOpts[] = { "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList", @@ -1101,7 +1146,17 @@ public class IndexBean { 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 _nonProxyNoShowSet = new HashSet(4); static { _noShowSet.addAll(Arrays.asList(_noShowOpts)); _noShowSet.addAll(Arrays.asList(_booleanClientOpts)); @@ -1109,6 +1164,7 @@ public class IndexBean { _noShowSet.addAll(Arrays.asList(_booleanServerOpts)); _noShowSet.addAll(Arrays.asList(_otherClientOpts)); _noShowSet.addAll(Arrays.asList(_otherServerOpts)); + _nonProxyNoShowSet.addAll(Arrays.asList(_otherProxyOpts)); } private void updateConfigGeneric(Properties config) { @@ -1139,6 +1195,12 @@ public class IndexBean { String key = pair.substring(0, eq); if (_noShowSet.contains(key)) 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); config.setProperty("option." + key, val); } @@ -1190,9 +1252,9 @@ public class IndexBean { protected TunnelController getController(int tunnel) { if (tunnel < 0) return null; if (_group == null) return null; - List controllers = _group.getControllers(); + List<TunnelController> controllers = _group.getControllers(); if (controllers.size() > tunnel) - return (TunnelController)controllers.get(tunnel); + return controllers.get(tunnel); else return null; } diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp index d2ca8f7ad3..bd147880be 100644 --- a/apps/i2ptunnel/jsp/editClient.jsp +++ b/apps/i2ptunnel/jsp/editClient.jsp @@ -435,13 +435,13 @@ <label> <%=intl._("Username")%>: </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 id="portField" class="rowItem"> <label> <%=intl._("Password")%>: </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 class="subdivider"> <hr /> -- GitLab