forked from I2P_Developers/i2p.i2p
Proxy: Decode IDN hostnames in error pages
This commit is contained in:
@@ -1428,16 +1428,20 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.8.7 */
|
||||
/**
|
||||
* @param destination the hostname
|
||||
* @since 0.8.7
|
||||
*/
|
||||
private void writeHelperSaveForm(OutputStream outs, String destination, String ahelperKey,
|
||||
String targetRequest, String referer) throws IOException {
|
||||
if(outs == null)
|
||||
return;
|
||||
String idn = decodeIDNHost(destination);
|
||||
Writer out = new BufferedWriter(new OutputStreamWriter(outs, "UTF-8"));
|
||||
String header = getErrorPage("ahelper-new", ERR_AHELPER_NEW);
|
||||
out.write(header);
|
||||
out.write("<table id=\"proxyNewHost\">\n<tr><td align=\"right\">" + _t("Host") +
|
||||
"</td><td>" + destination + "</td></tr>\n");
|
||||
"</td><td>" + idn + "</td></tr>\n");
|
||||
try {
|
||||
String b32 = Base32.encode(SHA256Generator.getInstance().calculateHash(Base64.decode(ahelperKey)).getData());
|
||||
out.write("<tr><td align=\"right\">" + _t("Base32") + "</td>" +
|
||||
@@ -1450,7 +1454,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
|
||||
// FIXME if there is a query remaining it is lost
|
||||
"<form method=\"GET\" action=\"" + targetRequest + "\">\n" +
|
||||
"<h4>" + _t("Continue to {0} without saving", destination) + "</h4>\n<p>" +
|
||||
"<h4>" + _t("Continue to {0} without saving", idn) + "</h4>\n<p>" +
|
||||
_t("You can browse to the site without saving it to the address book. The address will be remembered until you restart your I2P router.") +
|
||||
"</p>\n<div class=\"formaction\"><button type=\"submit\" class=\"go\">" + _t("Continue without saving") + "</button></div>" + "\n</form>\n" +
|
||||
|
||||
@@ -1459,7 +1463,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
"<input type=\"hidden\" name=\"dest\" value=\"" + ahelperKey + "\">\n" +
|
||||
"<input type=\"hidden\" name=\"nonce\" value=\"" + _proxyNonce + "\">\n" +
|
||||
|
||||
"<h4>" + _t("Save {0} to router address book and continue to website", destination) + "</h4>\n<p>" +
|
||||
"<h4>" + _t("Save {0} to router address book and continue to website", idn) + "</h4>\n<p>" +
|
||||
_t("This address will be saved to your Router address book where your subscription-based addresses are stored."));
|
||||
if(_context.namingService().getName().equals("BlockfileNamingService")) {
|
||||
out.write(" " + _t("If you want to keep track of sites you have added manually, add to your Local or Private address book instead."));
|
||||
@@ -1472,12 +1476,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
if(_context.namingService().getName().equals("BlockfileNamingService")) {
|
||||
// only blockfile supports multiple books
|
||||
|
||||
out.write("<h4>" + _t("Save {0} to local address book and continue to website", destination) + "</h4>\n<p>" +
|
||||
out.write("<h4>" + _t("Save {0} to local address book and continue to website", idn) + "</h4>\n<p>" +
|
||||
_t("This address will be saved to your Local address book. Select this option for addresses you wish to keep separate from the main router address book, but don't mind publishing.") +
|
||||
"</p>\n<div class=\"formaction\"><button type=\"submit\" class=\"accept\" name=\"local\" value=\"local\">" +
|
||||
label + "</button></div>\n");
|
||||
|
||||
out.write("<h4>" + _t("Save {0} to private address book and continue to website", destination) + "</h4>\n<p>" +
|
||||
out.write("<h4>" + _t("Save {0} to private address book and continue to website", idn) + "</h4>\n<p>" +
|
||||
_t("This address will be saved to your Private address book, ensuring it is never published.") +
|
||||
"</p>\n<div class=\"formaction\"><button type=\"submit\" class=\"accept\" name=\"private\" value=\"private\">" +
|
||||
label + "</button></div>\n");
|
||||
|
@@ -15,6 +15,7 @@ import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.IDN;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
@@ -144,6 +145,19 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
||||
// very simple, remember last-failed only
|
||||
private String _lastFailedSSLProxy;
|
||||
|
||||
/** available as of Java 6 and Android API 9 */
|
||||
private static final boolean _haveIDN;
|
||||
static {
|
||||
boolean h;
|
||||
try {
|
||||
Class.forName("java.net.IDN", false, ClassLoader.getSystemClassLoader());
|
||||
h = true;
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
h = false;
|
||||
}
|
||||
_haveIDN = h;
|
||||
}
|
||||
|
||||
protected String getPrefix(long requestId) {
|
||||
return "HTTPClient[" + _clientId + '/' + requestId + "]: ";
|
||||
}
|
||||
@@ -929,7 +943,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
||||
out.write(uri);
|
||||
out.write("\">");
|
||||
// Long URLs are handled in CSS
|
||||
out.write(uri);
|
||||
out.write(decodeIDNURI(uri));
|
||||
out.write("</a>");
|
||||
if (usingWWWProxy) {
|
||||
out.write("<br><br><b>");
|
||||
@@ -996,6 +1010,45 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
||||
writeFooter(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the host part of a URI for display.
|
||||
* Returns original string on any error.
|
||||
*
|
||||
* @since 0.9.50
|
||||
*/
|
||||
private static String decodeIDNURI(String uri) {
|
||||
if (!_haveIDN)
|
||||
return uri;
|
||||
if (!uri.contains("xn--"))
|
||||
return uri;
|
||||
try {
|
||||
URI u = new URI(uri);
|
||||
String h = u.getHost();
|
||||
String hu = IDN.toUnicode(h);
|
||||
if (hu == null || h.equals(hu))
|
||||
return uri;
|
||||
int idx = uri.indexOf(h);
|
||||
if (idx < 0)
|
||||
return uri;
|
||||
return uri.substring(0, idx) + hu + uri.substring(idx + h.length(), uri.length());
|
||||
} catch(URISyntaxException use) {}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a hostname for display.
|
||||
* Returns original string on any error.
|
||||
*
|
||||
* @since 0.9.50
|
||||
*/
|
||||
public static String decodeIDNHost(String host) {
|
||||
if (!_haveIDN)
|
||||
return host;
|
||||
if (!host.contains("xn--"))
|
||||
return host;
|
||||
return IDN.toUnicode(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes.
|
||||
*
|
||||
|
@@ -365,6 +365,7 @@ public abstract class LocalHTTPServer {
|
||||
|
||||
PortMapper pm = I2PAppContext.getGlobalContext().portMapper();
|
||||
String conURL = pm.getConsoleURL();
|
||||
String idn = I2PTunnelHTTPClientBase.decodeIDNHost(host);
|
||||
out.write(("HTTP/1.1 200 OK\r\n"+
|
||||
"Content-Type: text/html; charset=UTF-8\r\n"+
|
||||
"Referrer-Policy: no-referrer\r\n"+
|
||||
@@ -372,7 +373,7 @@ public abstract class LocalHTTPServer {
|
||||
"Proxy-Connection: close\r\n"+
|
||||
"\r\n"+
|
||||
"<html><head>"+
|
||||
"<title>" + _t("Redirecting to {0}", host) + "</title>\n" +
|
||||
"<title>" + _t("Redirecting to {0}", idn) + "</title>\n" +
|
||||
"<link rel=\"shortcut icon\" href=\"http://proxy.i2p/themes/console/images/favicon.ico\" >\n" +
|
||||
"<link href=\"http://proxy.i2p/themes/console/default/console.css\" rel=\"stylesheet\" type=\"text/css\" >\n" +
|
||||
"<meta http-equiv=\"Refresh\" content=\"1; url=" + url + "\">\n" +
|
||||
@@ -386,8 +387,8 @@ public abstract class LocalHTTPServer {
|
||||
"<div class=warning id=warning>\n" +
|
||||
"<h3>" +
|
||||
(success ?
|
||||
_t("Saved {0} to the {1} address book, redirecting now.", host, tbook) :
|
||||
_t("Failed to save {0} to the {1} address book, redirecting now.", host, tbook)) +
|
||||
_t("Saved {0} to the {1} address book, redirecting now.", idn, tbook) :
|
||||
_t("Failed to save {0} to the {1} address book, redirecting now.", idn, tbook)) +
|
||||
"</h3>\n<p><a href=\"" + url + "\">" +
|
||||
_t("Click here if you are not redirected automatically.") +
|
||||
"</a></p></div>").getBytes("UTF-8"));
|
||||
@@ -399,6 +400,7 @@ public abstract class LocalHTTPServer {
|
||||
private static void writeB32RedirectPage(OutputStream out, String host, String url) throws IOException {
|
||||
PortMapper pm = I2PAppContext.getGlobalContext().portMapper();
|
||||
String conURL = pm.getConsoleURL();
|
||||
String idn = I2PTunnelHTTPClientBase.decodeIDNHost(host);
|
||||
out.write(("HTTP/1.1 200 OK\r\n"+
|
||||
"Content-Type: text/html; charset=UTF-8\r\n"+
|
||||
"Referrer-Policy: no-referrer\r\n"+
|
||||
@@ -406,7 +408,7 @@ public abstract class LocalHTTPServer {
|
||||
"Proxy-Connection: close\r\n"+
|
||||
"\r\n"+
|
||||
"<html><head>"+
|
||||
"<title>" + _t("Redirecting to {0}", host) + "</title>\n" +
|
||||
"<title>" + _t("Redirecting to {0}", idn) + "</title>\n" +
|
||||
"<link rel=\"shortcut icon\" href=\"http://proxy.i2p/themes/console/images/favicon.ico\" >\n" +
|
||||
"<link href=\"http://proxy.i2p/themes/console/default/console.css\" rel=\"stylesheet\" type=\"text/css\" >\n" +
|
||||
"<meta http-equiv=\"Refresh\" content=\"1; url=" + url + "\">\n" +
|
||||
@@ -419,7 +421,7 @@ public abstract class LocalHTTPServer {
|
||||
out.write(("</div>" +
|
||||
"<div class=warning id=warning>\n" +
|
||||
"<h3>" +
|
||||
_t("Saved the authentication for {0}, redirecting now.", host) +
|
||||
_t("Saved the authentication for {0}, redirecting now.", idn) +
|
||||
"</h3>\n<p><a href=\"" + url + "\">" +
|
||||
_t("Click here if you are not redirected automatically.") +
|
||||
"</a></p></div>").getBytes("UTF-8"));
|
||||
|
Reference in New Issue
Block a user