[tor-commits] [onionoo/master] Add "recommended_version" parameter.

karsten at torproject.org karsten at torproject.org
Mon Nov 27 09:20:58 UTC 2017


commit 11e5bbd80c24bb6c11ab3450d208517d4d145780
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Sat Nov 18 20:43:59 2017 +0100

    Add "recommended_version" parameter.
    
    Add a "recommended_version" parameter to return only relays and
    bridges running a Tor software version that is recommended or not
    recommended by the directory authorities.
    
    Implements #23544.
---
 CHANGELOG.md                                       |  3 ++
 .../org/torproject/onionoo/docs/DocumentStore.java |  4 ++-
 .../torproject/onionoo/docs/SummaryDocument.java   | 16 +++++++++-
 .../org/torproject/onionoo/server/NodeIndex.java   | 22 +++++++++++++
 .../org/torproject/onionoo/server/NodeIndexer.java | 21 +++++++++++++
 .../torproject/onionoo/server/RequestHandler.java  | 20 ++++++++++++
 .../torproject/onionoo/server/ResourceServlet.java | 19 ++++++++++--
 .../onionoo/writer/SummaryDocumentWriter.java      |  3 +-
 .../onionoo/docs/SummaryDocumentTest.java          |  2 +-
 .../onionoo/server/ResourceServletTest.java        | 36 ++++++++++++++++++----
 .../server/SummaryDocumentComparatorTest.java      |  2 +-
 11 files changed, 134 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a84259..8acdc0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,9 @@
    - Add a "recommended_version" field to bridge details documents
      based on whether the directory authorities recommend the bridge's
      version.
+   - Add a "recommended_version" parameter to return only relays and
+     bridges running a Tor software version that is recommended or not
+     recommended by the directory authorities.
 
 
 # Changes in version 4.3-1.7.1 - 2017-11-17
diff --git a/src/main/java/org/torproject/onionoo/docs/DocumentStore.java b/src/main/java/org/torproject/onionoo/docs/DocumentStore.java
index 57d4165..23f11c7 100644
--- a/src/main/java/org/torproject/onionoo/docs/DocumentStore.java
+++ b/src/main/java/org/torproject/onionoo/docs/DocumentStore.java
@@ -440,10 +440,12 @@ public class DocumentStore {
     long consensusWeight = -1L;
     long firstSeenMillis = -1L;
     String hostName = null;
+    Boolean recommendedVersion = null;
     SummaryDocument summaryDocument = new SummaryDocument(isRelay,
         nickname, fingerprint, addresses, lastSeenMillis, running,
         relayFlags, consensusWeight, countryCode, firstSeenMillis,
-        asNumber, contact, family, family, version, hostName);
+        asNumber, contact, family, family, version, hostName,
+        recommendedVersion);
     return summaryDocument;
   }
 
diff --git a/src/main/java/org/torproject/onionoo/docs/SummaryDocument.java b/src/main/java/org/torproject/onionoo/docs/SummaryDocument.java
index cca5ab9..11f6070 100644
--- a/src/main/java/org/torproject/onionoo/docs/SummaryDocument.java
+++ b/src/main/java/org/torproject/onionoo/docs/SummaryDocument.java
@@ -322,6 +322,18 @@ public class SummaryDocument extends Document {
     return this.hostName;
   }
 
+  @Expose
+  @SerializedName("rv")
+  private Boolean recommendedVersion;
+
+  public void setRecommendedVersion(Boolean recommendedVersion) {
+    this.recommendedVersion = recommendedVersion;
+  }
+
+  public Boolean getRecommendedVersion() {
+    return this.recommendedVersion;
+  }
+
   /* The familyFingerprints parameter can go away after September 8, 2015.
    * See above. */
   /** Instantiates a summary document with all given properties. */
@@ -330,7 +342,8 @@ public class SummaryDocument extends Document {
       boolean running, SortedSet<String> relayFlags, long consensusWeight,
       String countryCode, long firstSeenMillis, String asNumber,
       String contact, SortedSet<String> familyFingerprints,
-      SortedSet<String> effectiveFamily, String version, String hostName) {
+      SortedSet<String> effectiveFamily, String version, String hostName,
+      Boolean recommendedVersion) {
     this.setRelay(isRelay);
     this.setNickname(nickname);
     this.setFingerprint(fingerprint);
@@ -347,6 +360,7 @@ public class SummaryDocument extends Document {
     this.setEffectiveFamily(effectiveFamily);
     this.setVersion(version);
     this.setHostName(hostName);
+    this.setRecommendedVersion(recommendedVersion);
   }
 }
 
diff --git a/src/main/java/org/torproject/onionoo/server/NodeIndex.java b/src/main/java/org/torproject/onionoo/server/NodeIndex.java
index c41dd7a..8ab22a4 100644
--- a/src/main/java/org/torproject/onionoo/server/NodeIndex.java
+++ b/src/main/java/org/torproject/onionoo/server/NodeIndex.java
@@ -199,5 +199,27 @@ class NodeIndex {
   public Map<String, Set<String>> getRelaysByHostName() {
     return this.relaysByHostName;
   }
+
+  private Map<Boolean, Set<String>> relaysByRecommendedVersion;
+
+  public void setRelaysByRecommendedVersion(
+      Map<Boolean, Set<String>> relaysByRecommendedVersion) {
+    this.relaysByRecommendedVersion = relaysByRecommendedVersion;
+  }
+
+  public Map<Boolean, Set<String>> getRelaysByRecommendedVersion() {
+    return this.relaysByRecommendedVersion;
+  }
+
+  private Map<Boolean, Set<String>> bridgesByRecommendedVersion;
+
+  public void setBridgesByRecommendedVersion(
+      Map<Boolean, Set<String>> bridgesByRecommendedVersion) {
+    this.bridgesByRecommendedVersion = bridgesByRecommendedVersion;
+  }
+
+  public Map<Boolean, Set<String>> getBridgesByRecommendedVersion() {
+    return this.bridgesByRecommendedVersion;
+  }
 }
 
diff --git a/src/main/java/org/torproject/onionoo/server/NodeIndexer.java b/src/main/java/org/torproject/onionoo/server/NodeIndexer.java
index 585d33f..815a02e 100644
--- a/src/main/java/org/torproject/onionoo/server/NodeIndexer.java
+++ b/src/main/java/org/torproject/onionoo/server/NodeIndexer.java
@@ -156,6 +156,12 @@ public class NodeIndexer implements ServletContextListener, Runnable {
     Map<String, Set<String>> newRelaysByVersion = new HashMap<>();
     Map<String, Set<String>> newBridgesByVersion = new HashMap<>();
     Map<String, Set<String>> newRelaysByHostName = new HashMap<>();
+    Map<Boolean, Set<String>> newRelaysByRecommendedVersion = new HashMap<>();
+    newRelaysByRecommendedVersion.put(true, new HashSet<>());
+    newRelaysByRecommendedVersion.put(false, new HashSet<>());
+    Map<Boolean, Set<String>> newBridgesByRecommendedVersion = new HashMap<>();
+    newBridgesByRecommendedVersion.put(true, new HashSet<>());
+    newBridgesByRecommendedVersion.put(false, new HashSet<>());
     SortedMap<Integer, Set<String>> newRelaysByFirstSeenDays = new TreeMap<>();
     SortedMap<Integer, Set<String>> newBridgesByFirstSeenDays = new TreeMap<>();
     SortedMap<Integer, Set<String>> newRelaysByLastSeenDays = new TreeMap<>();
@@ -269,6 +275,12 @@ public class NodeIndexer implements ServletContextListener, Runnable {
         newRelaysByHostName.get(hostNameLowerCase).add(fingerprint);
         newRelaysByHostName.get(hostNameLowerCase).add(hashedFingerprint);
       }
+      Boolean recommendedVersion = entry.getRecommendedVersion();
+      if (null != recommendedVersion) {
+        newRelaysByRecommendedVersion.get(recommendedVersion).add(fingerprint);
+        newRelaysByRecommendedVersion.get(recommendedVersion).add(
+            hashedFingerprint);
+      }
     }
     /* This loop can go away once all Onionoo services had their hourly
      * updater write effective families to summary documents at least
@@ -332,6 +344,13 @@ public class NodeIndexer implements ServletContextListener, Runnable {
         newBridgesByVersion.get(version).add(hashedFingerprint);
         newBridgesByVersion.get(version).add(hashedHashedFingerprint);
       }
+      Boolean recommendedVersion = entry.getRecommendedVersion();
+      if (null != recommendedVersion) {
+        newBridgesByRecommendedVersion.get(recommendedVersion).add(
+            hashedFingerprint);
+        newBridgesByRecommendedVersion.get(recommendedVersion).add(
+            hashedHashedFingerprint);
+      }
     }
     NodeIndex newNodeIndex = new NodeIndex();
     newNodeIndex.setRelayFingerprintSummaryLines(
@@ -353,6 +372,8 @@ public class NodeIndexer implements ServletContextListener, Runnable {
     newNodeIndex.setRelaysByVersion(newRelaysByVersion);
     newNodeIndex.setBridgesByVersion(newBridgesByVersion);
     newNodeIndex.setRelaysByHostName(newRelaysByHostName);
+    newNodeIndex.setRelaysByRecommendedVersion(newRelaysByRecommendedVersion);
+    newNodeIndex.setBridgesByRecommendedVersion(newBridgesByRecommendedVersion);
     synchronized (this) {
       this.lastIndexed = updateStatusMillis;
       this.latestNodeIndex = newNodeIndex;
diff --git a/src/main/java/org/torproject/onionoo/server/RequestHandler.java b/src/main/java/org/torproject/onionoo/server/RequestHandler.java
index 067a738..c81051e 100644
--- a/src/main/java/org/torproject/onionoo/server/RequestHandler.java
+++ b/src/main/java/org/torproject/onionoo/server/RequestHandler.java
@@ -103,6 +103,12 @@ public class RequestHandler {
     this.hostName = hostName;
   }
 
+  private Boolean recommendedVersion;
+
+  public void setRecommendedVersion(Boolean recommendedVersion) {
+    this.recommendedVersion = recommendedVersion;
+  }
+
   private String[] order;
 
   public void setOrder(String[] order) {
@@ -172,6 +178,7 @@ public class RequestHandler {
     this.filterByFamily();
     this.filterByVersion();
     this.filterByHostName();
+    this.filterByRecommendedVersion();
     this.order();
     this.offset();
     this.limit();
@@ -570,6 +577,19 @@ public class RequestHandler {
     this.filteredBridges.clear();
   }
 
+  private void filterByRecommendedVersion() {
+    if (null == this.recommendedVersion) {
+      /* Not filtering by recommended version. */
+      return;
+    }
+    Set<String> keepRelays = this.nodeIndex.getRelaysByRecommendedVersion()
+        .get(this.recommendedVersion);
+    this.filteredRelays.keySet().retainAll(keepRelays);
+    Set<String> keepBridges = this.nodeIndex.getBridgesByRecommendedVersion()
+        .get(this.recommendedVersion);
+    this.filteredBridges.keySet().retainAll(keepBridges);
+  }
+
   private void order() {
     List<SummaryDocument> uniqueRelays = new ArrayList<>();
     List<SummaryDocument> uniqueBridges = new ArrayList<>();
diff --git a/src/main/java/org/torproject/onionoo/server/ResourceServlet.java b/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
index f1521e2..3449407 100644
--- a/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
+++ b/src/main/java/org/torproject/onionoo/server/ResourceServlet.java
@@ -66,9 +66,10 @@ public class ResourceServlet extends HttpServlet {
   private static final long CACHE_INTERVAL = 5L * 60L * 1000L;
 
   private static Set<String> knownParameters = new HashSet<>(
-      Arrays.asList(("type,running,search,lookup,fingerprint,country,as,"
-          + "flag,first_seen_days,last_seen_days,contact,order,limit,"
-          + "offset,fields,family,version,host_name").split(",")));
+      Arrays.asList("type", "running", "search", "lookup", "fingerprint",
+          "country", "as", "flag", "first_seen_days", "last_seen_days",
+          "contact", "order", "limit", "offset", "fields", "family", "version",
+          "host_name", "recommended_version"));
 
   private static Set<String> illegalSearchQualifiers =
       new HashSet<>(Arrays.asList(("search,fingerprint,order,limit,"
@@ -301,6 +302,18 @@ public class ResourceServlet extends HttpServlet {
       }
       rh.setHostName(hostNameParameter);
     }
+    if (parameterMap.containsKey("recommended_version")) {
+      String recommendedVersionParameterValue =
+          parameterMap.get("recommended_version").toLowerCase();
+      boolean recommendedVersionRequested = true;
+      if (recommendedVersionParameterValue.equals("false")) {
+        recommendedVersionRequested = false;
+      } else if (!recommendedVersionParameterValue.equals("true")) {
+        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+        return;
+      }
+      rh.setRecommendedVersion(recommendedVersionRequested);
+    }
     if (parameterMap.containsKey("order")) {
       String[] order = this.parseOrderParameter(parameterMap.get("order"));
       if (order == null) {
diff --git a/src/main/java/org/torproject/onionoo/writer/SummaryDocumentWriter.java b/src/main/java/org/torproject/onionoo/writer/SummaryDocumentWriter.java
index faf54fa..a412eec 100644
--- a/src/main/java/org/torproject/onionoo/writer/SummaryDocumentWriter.java
+++ b/src/main/java/org/torproject/onionoo/writer/SummaryDocumentWriter.java
@@ -93,11 +93,12 @@ public class SummaryDocumentWriter implements DocumentWriter {
       String nickname = nodeStatus.getNickname();
       String version = nodeStatus.getVersion();
       String hostName = nodeStatus.getHostName();
+      Boolean recommendedVersion = nodeStatus.getRecommendedVersion();
       SummaryDocument summaryDocument = new SummaryDocument(isRelay,
           nickname, fingerprint, addresses, lastSeenMillis, running,
           relayFlags, consensusWeight, countryCode, firstSeenMillis,
           asNumber, contact, declaredFamily, effectiveFamily, version,
-          hostName);
+          hostName, recommendedVersion);
       if (this.documentStore.store(summaryDocument, fingerprint)) {
         this.writtenDocuments++;
       }
diff --git a/src/test/java/org/torproject/onionoo/docs/SummaryDocumentTest.java b/src/test/java/org/torproject/onionoo/docs/SummaryDocumentTest.java
index 8c45ed2..ce13ccc 100644
--- a/src/test/java/org/torproject/onionoo/docs/SummaryDocumentTest.java
+++ b/src/test/java/org/torproject/onionoo/docs/SummaryDocumentTest.java
@@ -27,7 +27,7 @@ public class SummaryDocumentTest {
             "0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B" })),
         new TreeSet<>(Arrays.asList(
         new String[] { "001C13B3A55A71B977CA65EC85539D79C653A3FC" })), null,
-        null);
+        null, true);
   }
 
   @Test()
diff --git a/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java b/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
index d763988..dee5139 100644
--- a/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
+++ b/src/test/java/org/torproject/onionoo/server/ResourceServletTest.java
@@ -144,7 +144,7 @@ public class ResourceServletTest {
             "0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B" })),
         new TreeSet<>(Arrays.asList(
         new String[] { "001C13B3A55A71B977CA65EC85539D79C653A3FC" })),
-        "0.2.3.25", "ppp-62-216-201-221.dynamic.mnet-online.de");
+        "0.2.3.25", "ppp-62-216-201-221.dynamic.mnet-online.de", true);
     this.relays.put("000C5F55BD4814B917CC474BD537F1A3B33CCE2A",
         relayTorkaZ);
     org.torproject.onionoo.docs.SummaryDocument relayFerrari458 =
@@ -159,7 +159,7 @@ public class ResourceServletTest {
             "000C5F55BD4814B917CC474BD537F1A3B33CCE2A" })),
         new TreeSet<>(Arrays.asList(new String[] {
             "000C5F55BD4814B917CC474BD537F1A3B33CCE2A" })), null,
-            "c-68-38-171-200.hsd1.in.comcast.net");
+            "c-68-38-171-200.hsd1.in.comcast.net", null);
     this.relays.put("001C13B3A55A71B977CA65EC85539D79C653A3FC",
         relayFerrari458);
     org.torproject.onionoo.docs.SummaryDocument relayTimMayTribute =
@@ -172,7 +172,8 @@ public class ResourceServletTest {
         DateTimeHelper.parse("2013-04-16 18:00:00"), "AS6830",
         "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.24-rc-dev", null);
+        new TreeSet<String>(), new TreeSet<String>(), "0.2.3.24-rc-dev", null,
+        false);
     this.relays.put("0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B",
         relayTimMayTribute);
     this.bridges = new TreeMap<>();
@@ -183,7 +184,7 @@ public class ResourceServletTest {
         DateTimeHelper.parse("2013-04-21 18:07:03"), false,
         new TreeSet<>(Arrays.asList(new String[] { "Valid" })), -1L,
         null, DateTimeHelper.parse("2013-04-20 15:37:04"), null, null,
-        null, null, "0.2.2.39", null);
+        null, null, "0.2.2.39", null, true);
     this.bridges.put("0000831B236DFF73D409AD17B40E2A728A53994F",
         bridgeec2bridgercc7f31fe);
     org.torproject.onionoo.docs.SummaryDocument bridgeUnnamed =
@@ -193,7 +194,7 @@ public class ResourceServletTest {
         DateTimeHelper.parse("2013-04-20 17:37:04"), false,
         new TreeSet<>(Arrays.asList(new String[] { "Valid" })), -1L,
         null, DateTimeHelper.parse("2013-04-14 07:07:05"), null, null,
-        null, null, null, null);
+        null, null, null, null, null);
     this.bridges.put("0002D9BDBBC230BD9C78FF502A16E0033EF87E0C",
         bridgeUnnamed);
     org.torproject.onionoo.docs.SummaryDocument bridgegummy =
@@ -204,7 +205,7 @@ public class ResourceServletTest {
         new TreeSet<>(Arrays.asList(new String[] { "Running",
             "Valid" })), -1L, null,
         DateTimeHelper.parse("2013-01-16 21:07:04"), null, null, null,
-        null, "0.2.4.4-alpha-dev", null);
+        null, "0.2.4.4-alpha-dev", null, false);
     this.bridges.put("1FEDE50ED8DBA1DD9F9165F78C8131E4A44AB756",
         bridgegummy);
   }
@@ -1695,5 +1696,28 @@ public class ResourceServletTest {
   public void testHostNameUmlaut() {
     this.assertErrorStatusCode("/summary?host_name=äöü", 400);
   }
+
+  @Test
+  public void testRecommendedVersionTrue() {
+    this.assertSummaryDocument("/summary?recommended_version=true", 1,
+        new String[] { "TorkaZ" }, 1, new String[] { "ec2bridgercc7f31fe" });
+  }
+
+  @Test
+  public void testRecommendedVersionFalse() {
+    this.assertSummaryDocument("/summary?recommended_version=false", 1,
+        new String[] { "TimMayTribute" }, 1, new String[] { "gummy" });
+  }
+
+  @Test
+  public void testRecommendedVersionTrueCapitalized() {
+    this.assertSummaryDocument("/summary?recommended_version=TRUE", 1,
+        new String[] { "TorkaZ" }, 1,new String[] { "ec2bridgercc7f31fe" });
+  }
+
+  @Test
+  public void testRecommendedVersionNull() {
+    this.assertErrorStatusCode("/summary?recommended_version=null", 400);
+  }
 }
 
diff --git a/src/test/java/org/torproject/onionoo/server/SummaryDocumentComparatorTest.java b/src/test/java/org/torproject/onionoo/server/SummaryDocumentComparatorTest.java
index 38d94fa..6820372 100644
--- a/src/test/java/org/torproject/onionoo/server/SummaryDocumentComparatorTest.java
+++ b/src/test/java/org/torproject/onionoo/server/SummaryDocumentComparatorTest.java
@@ -41,7 +41,7 @@ public class SummaryDocumentComparatorTest {
             "0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B" })),
         new TreeSet<>(Arrays.asList(
         new String[] { "001C13B3A55A71B977CA65EC85539D79C653A3FC" })), null,
-        null);
+        null, null);
   }
 
   /** Some values for running all comparison types. */



More information about the tor-commits mailing list