Author: toad
Date: 2009-01-07 16:51:22 +0000 (Wed, 07 Jan 2009)
New Revision: 24955
Modified:
trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
trunk/freenet/src/freenet/clients/http/ToadletContainer.java
trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
trunk/freenet/src/freenet/support/URLEncoder.java
Log:
Make secureid code much more sensible about encoded URLs. One definitive
encoding doesn't seem feasible at present - there are two conflicting RFCs for
a start.
Modified: trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
2009-01-07 14:20:15 UTC (rev 24954)
+++ trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
2009-01-07 16:51:22 UTC (rev 24955)
@@ -38,6 +38,9 @@
import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.OOMHandler;
+import freenet.support.URLDecoder;
+import freenet.support.URLEncodedFormatException;
+import freenet.support.URLEncoder;
import freenet.support.api.BooleanCallback;
import freenet.support.api.BucketFactory;
import freenet.support.api.IntCallback;
@@ -813,8 +816,9 @@
return bf;
}
- public String generateSID(String realPath) {
+ public String generateSID(String realPath) throws
URLEncodedFormatException {
MessageDigest md = SHA256.getMessageDigest();
+ realPath = prepareForSID(realPath);
try {
md.update(realPath.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
@@ -826,6 +830,42 @@
return Base64.encode(output);
}
+ private String prepareForSID(String realPath) throws
URLEncodedFormatException {
+ StringBuffer sb = new StringBuffer(realPath.length());
+ int idx = realPath.indexOf('?');
+ String query = null;
+ if(idx > -1) {
+ query = realPath.substring(idx+1);
+ realPath = realPath.substring(0, idx);
+ }
+ String[] split = realPath.split("/");
+ boolean first = true;
+ for(String component : split) {
+ if(component.indexOf('%') > -1)
+ component = URLDecoder.decode(component, true);
+ component = URLEncoder.minimalEncode(component, "/?");
+ sb.append(component);
+ if(!first) sb.append('/');
+ first = false;
+ }
+ if(query != null) {
+ sb.append('?');
+ split = query.split("&");
+ first = true;
+ for(String component : split) {
+ if(component.indexOf('%') > -1)
+ component =
URLDecoder.decode(component, true);
+ component = URLEncoder.minimalEncode(component,
"&");
+ sb.append(component);
+ if(!first) sb.append('&');
+ first = false;
+ }
+ }
+ return sb.toString();
+ }
+
+
+
public boolean isSecureIDCheckingDisabled() {
return !enableHistoryCloaking;
}
@@ -843,11 +883,16 @@
frag = toSign.substring(hashIndex);
toSign = toSign.substring(0, hashIndex);
}
+ try {
if(orig.indexOf('?') == -1) {
return toSign + "?secureid=" + generateSID(toSign) +
frag;
} else {
return toSign + "&secureid=" + generateSID(toSign) +
frag;
}
+ } catch (URLEncodedFormatException e) {
+ Logger.error(this, "UNABLE TO ENCODE INTERNALLY
GENERATED STRING: "+orig+" because URL decode failure: "+e);
+ return orig;
+ }
}
public URI fixLink(URI uri) throws URISyntaxException {
@@ -857,11 +902,16 @@
if(uri.getFragment() != null) {
toSign = toSign.substring(0, toSign.indexOf('#'));
}
+ try {
if(uri.getQuery() == null) {
return new URI(uri.getScheme(), uri.getUserInfo(),
uri.getHost(), uri.getPort(), uri.getPath(), "secureid="+generateSID(toSign),
uri.getFragment());
} else {
return new URI(uri.getScheme(), uri.getUserInfo(),
uri.getHost(), uri.getPort(), uri.getPath(),
uri.getQuery()+"&secureid="+generateSID(toSign), uri.getFragment());
}
+ } catch (URLEncodedFormatException e) {
+ Logger.error(this, "UNABLE TO ENCODE INTERNALLY
GENERATED STRING: "+uri+" because URL decode failure: "+e);
+ return uri;
+ }
}
public synchronized void setNonce(byte[] nonce) {
Modified: trunk/freenet/src/freenet/clients/http/ToadletContainer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/ToadletContainer.java
2009-01-07 14:20:15 UTC (rev 24954)
+++ trunk/freenet/src/freenet/clients/http/ToadletContainer.java
2009-01-07 16:51:22 UTC (rev 24955)
@@ -9,6 +9,7 @@
import freenet.clients.http.PageMaker.THEME;
import freenet.support.HTMLNode;
+import freenet.support.URLEncodedFormatException;
import freenet.support.api.BucketFactory;
/** Interface for toadlet containers. Toadlets should register here. */
@@ -69,8 +70,9 @@
* URIs don't go into the browser history.
* @param realPath
* @return
+ * @throws URLEncodedFormatException
*/
- public String generateSID(String realPath);
+ public String generateSID(String realPath) throws
URLEncodedFormatException;
/**
* If true, secure-id checking is disabled.
Modified: trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
2009-01-07 14:20:15 UTC (rev 24954)
+++ trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
2009-01-07 16:51:22 UTC (rev 24955)
@@ -23,6 +23,7 @@
import freenet.support.Logger;
import freenet.support.MultiValueTable;
import freenet.support.URIPreEncoder;
+import freenet.support.URLEncodedFormatException;
import freenet.support.api.Bucket;
import freenet.support.api.BucketFactory;
import freenet.support.io.BucketTools;
@@ -93,6 +94,14 @@
}
/**
+ * Send an error message. Caller provides the HTTP code, reason string,
and a message, which
+ * will become the title and the h1'ed contents of the error page.
+ */
+ private void sendError(int code, String httpReason, String message,
boolean shouldDisconnect, MultiValueTable<String,String> mvt) throws
IOException {
+ sendHTMLError(sockOutputStream, code, httpReason,
"<html><head><title>"+message+"</title></head><body><h1>"+message+"</h1></body>",
shouldDisconnect, mvt);
+ }
+
+ /**
* Send an error message, containing full HTML from a String.
* @param os The OutputStream to send the message to.
* @param code The HTTP status code.
@@ -436,7 +445,13 @@
String queries = getQueriesNoSecureID(uri);
String realPath = path;
if(queries != null) realPath += queries;
- String expectedSecureID = ctx.container.generateSID(realPath);
+ String expectedSecureID;
+ try {
+ expectedSecureID = ctx.container.generateSID(realPath);
+ } catch (URLEncodedFormatException e1) {
+ ctx.sendError(400, "Bad Request",
l10n("invalidURICheckingSecureID"), false, null);
+ return true;
+ }
if(secureid != null && expectedSecureID.equals(secureid)) {
return false;
}
Modified: trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
===================================================================
--- trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2009-01-07
14:20:15 UTC (rev 24954)
+++ trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2009-01-07
16:51:22 UTC (rev 24955)
@@ -1280,6 +1280,7 @@
ToadletContextImpl.cannotParseContentLength=Content-length parse error:
${error}
ToadletContextImpl.cannotParseContentLengthWithError=Cannot parse the
content-length: ${error}
ToadletContextImpl.headersLineTooLong=Line too long parsing headers
+ToadletContextImpl.invalidURICheckingSecureID=Invalid URI (while checking
secureid=)
ToadletContextImpl.methodNotAllowed=HTTP Method Not Allowed
ToadletContextImpl.noContentLengthInPOST=No content-length in POST
ToadletContextImpl.noSuchToadlet=No Toadlet of that name
Modified: trunk/freenet/src/freenet/support/URLEncoder.java
===================================================================
--- trunk/freenet/src/freenet/support/URLEncoder.java 2009-01-07 14:20:15 UTC
(rev 24954)
+++ trunk/freenet/src/freenet/support/URLEncoder.java 2009-01-07 16:51:22 UTC
(rev 24955)
@@ -62,4 +62,48 @@
return encode(s, null, ascii);
}
+ /**
+ * Encode only % and those characters in the encode list.
+ * @param encode Characters that must be encoded (as well as %).
+ * @return
+ */
+ public static String minimalEncode(String URL, String force) {
+ // First check that we need to encode.
+ boolean needed = false;
+ if(URL.indexOf('%') > -1) needed = true;
+ if(!needed) {
+ for(int i=0;i<URL.length();i++) {
+ char c = URL.charAt(i);
+ if(force.indexOf(c) > -1) {
+ needed = true;
+ break;
+ }
+ }
+ }
+ if(!needed) return URL;
+ StringBuilder enc = new StringBuilder(URL.length());
+ for (int i = 0; i < URL.length(); ++i) {
+ char c = URL.charAt(i);
+ if(c != '%' && force.indexOf(c) < 0) {
+ enc.append(c);
+ } else {
+ try {
+ byte[] encoded = ("" +
c).getBytes("UTF-8");
+ for (int j = 0; j < encoded.length;
j++) {
+ byte b = encoded[j];
+ int x = b & 0xFF;
+ if (x < 16)
+ enc.append("%0");
+ else
+ enc.append('%');
+
enc.append(Integer.toHexString(x));
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new Error("Impossible: JVM
doesn't support UTF-8: " + e, e);
+ }
+ }
+ }
+ return enc.toString();
+ }
+
}
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs