[tor-commits] [onionoo/master] Support quoted qualified search terms.

karsten at torproject.org karsten at torproject.org
Mon Oct 30 16:03:30 UTC 2017


commit 75981fe7d03091c78f901e1589288be4a27ce56c
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Thu Oct 19 14:46:28 2017 +0200

    Support quoted qualified search terms.
    
    With this patch, the "search" parameter does not only accept unquoted
    qualified search terms like `search=contact:John Doe` where "John"
    would be looked up in the contact line and "Doe" in the nickname or
    base64-encoded fingerprint. It also accepts quoted qualified search
    terms like `search=contact:"John Doe"` where "John Doe" would be
    looked up in the contact line. It further accepts escaped double
    quotes (\") within quoted qualified search terms.
    
    Implements #21366.
---
 CHANGELOG.md                                       |  8 ++++-
 .../torproject/onionoo/server/ResourceServlet.java | 38 ++++++++++++++++++++--
 .../onionoo/server/ResourceServletTest.java        | 36 +++++++++++++++++++-
 3 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca17fa7..74f29b7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,10 @@
-# Changes in version 4.2-1.6.1 - 2017-10-2?
+# Changes in version 4.3-1.7.0 - 2017-1?-??
+
+ * Medium changes
+   - Support quoted qualified search terms.
+
+
+# Changes in version 4.2-1.6.1 - 2017-10-26
 
  * Medium changes
    - Fix two NullPointerExceptions caused by accessing optional parts
diff --git a/src/main/java/org/torproject/onionoo/server/ResourceServlet.java b/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
index 31244c2..2fff913 100644
--- a/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
+++ b/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
@@ -3,6 +3,8 @@
 
 package org.torproject.onionoo.server;
 
+import org.apache.commons.lang3.StringUtils;
+
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -169,6 +171,12 @@ public class ResourceServlet extends HttpServlet {
           }
           if (!parameterMap.containsKey(parameterKey)) {
             String parameterValue = parts[1];
+            if (parameterValue.startsWith("\"")
+                && parameterValue.endsWith("\"")) {
+              parameterValue = parameterValue
+                  .substring(1, parameterValue.length() - 1)
+                  .replaceAll("\\\\\"", "\"");
+            }
             parameterMap.put(parameterKey, parameterValue);
           }
         } else {
@@ -388,7 +396,7 @@ public class ResourceServlet extends HttpServlet {
       + "^[0-9a-zA-Z+/]{1,27}$|" /* Base64 fingerprint. */
       + "^[0-9a-zA-Z\\.]{1,19}$|" /* Nickname or IPv4 address. */
       + ipv6AddressPatternString + "|" /* IPv6 address. */
-      + "^[a-zA-Z_]+:\\p{Graph}+$" /* Qualified search term. */);
+      + "^[a-zA-Z_]+:\"?[\\p{Graph} ]+\"?$"); /* Qualified search term. */
 
   protected static String[] parseSearchParameters(String queryString) {
     Matcher searchQueryStringMatcher = searchQueryStringPattern.matcher(
@@ -398,15 +406,39 @@ public class ResourceServlet extends HttpServlet {
       return null;
     }
     String parameter = searchQueryStringMatcher.group(1);
-    String[] searchParameters =
+    String[] spaceSeparatedParts =
         parameter.replaceAll("%20", " ").split(" ");
+    List<String> searchParameters = new ArrayList<>();
+    StringBuilder doubleQuotedSearchTerm = null;
+    for (String spaceSeparatedPart : spaceSeparatedParts) {
+      if ((StringUtils.countMatches(spaceSeparatedPart, '"')
+          - StringUtils.countMatches(spaceSeparatedPart, "\\\"")) % 2 == 0) {
+        if (null == doubleQuotedSearchTerm) {
+          searchParameters.add(spaceSeparatedPart);
+        } else {
+          doubleQuotedSearchTerm.append(' ').append(spaceSeparatedPart);
+        }
+      } else {
+        if (null == doubleQuotedSearchTerm) {
+          doubleQuotedSearchTerm = new StringBuilder(spaceSeparatedPart);
+        } else {
+          doubleQuotedSearchTerm.append(' ').append(spaceSeparatedPart);
+          searchParameters.add(doubleQuotedSearchTerm.toString());
+          doubleQuotedSearchTerm = null;
+        }
+      }
+    }
+    if (null != doubleQuotedSearchTerm) {
+      /* Opening double quote is not followed by closing double quote. */
+      return null;
+    }
     for (String searchParameter : searchParameters) {
       if (!searchParameterPattern.matcher(searchParameter).matches()) {
         /* Illegal search term. */
         return null;
       }
     }
-    return searchParameters;
+    return searchParameters.toArray(new String[0]);
   }
 
   private static Pattern fingerprintParameterPattern =
diff --git a/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java b/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
index 303cf21..1588f8a 100644
--- a/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
+++ b/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
@@ -169,7 +169,7 @@ public class ResourceServletTest {
         new TreeSet<>(Arrays.asList(new String[] { "Fast",
             "Running", "Unnamed", "V2Dir", "Valid" })), 63L, "a1",
         DateTimeHelper.parse("2013-04-16 18:00:00"), "AS6830",
-        "1024D/51E2A1C7 steven j. murdoch "
+        "1024d/51e2a1c7 \"steven j. murdoch\" "
         + "<tor+steven.murdoch at cl.cam.ac.uk> <fb-token:5sr_k_zs2wm=>",
         new TreeSet<String>(), new TreeSet<String>(), "0.2.3.25");
     this.relays.put("0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B",
@@ -933,6 +933,40 @@ public class ResourceServletTest {
   }
 
   @Test(timeout = 100)
+  public void testSearchDoubleQuotedEmailAddress() {
+    this.assertSummaryDocument(
+        "/summary?search=contact:\"klaus dot zufall at gmx dot de\"", 1,
+        new String[] { "TorkaZ" }, 0, null);
+  }
+
+  @Test(timeout = 100)
+  public void testSearchDoubleQuotedContactAndNickname() {
+    this.assertSummaryDocument(
+        "/summary?search=contact:\"dot de\" TorkaZ", 1,
+        new String[] { "TorkaZ" }, 0, null);
+  }
+
+  @Test(timeout = 100)
+  public void testSearchMissingEndingDoubleQuote() {
+    this.assertErrorStatusCode(
+        "/summary?search=contact:\"klaus dot zufall at gmx dot de", 400);
+  }
+
+  @Test(timeout = 100)
+  public void testSearchEvenNumberOfDoubleQuotes() {
+    this.assertSummaryDocument(
+        "/summary?search=contact:\"\"\" \"\"\"", 0,
+        null, 0, null);
+  }
+
+  @Test(timeout = 100)
+  public void testSearchContactEscapedDoubleQuotes() {
+    this.assertSummaryDocument(
+        "/summary?search=contact:\"1024D/51E2A1C7 \\\"Steven J. Murdoch\\\"\"",
+        1, new String[] { "TimMayTribute" }, 0, null);
+  }
+
+  @Test(timeout = 100)
   public void testLookupFingerprint() {
     this.assertSummaryDocument(
         "/summary?lookup=000C5F55BD4814B917CC474BD537F1A3B33CCE2A", 1,





More information about the tor-commits mailing list