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

Reply via email to