Bug 1275507 - XPCOM API to create SB v4 update request. r=francois
authorHenry Chang <hchang@mozilla.com>
Tue, 19 Jul 2016 18:09:53 +0800
changeset 306062 29ead859749af91a4e70d10a278a0ca3fca9d2b4
parent 306061 fc1d44b2cb7b7d7c47a365bddfc23ff991505003
child 306096 e28e856b987380f55d699092f11f6997378f79a6
child 306140 0ce00a7b3b5869a7eef4d3ccf787d9e8ed0a5954
push id79765
push usercbook@mozilla.com
push dateThu, 21 Jul 2016 14:26:34 +0000
treeherdermozilla-inbound@ab54bfc55266 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfrancois
bugs1275507
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1275507 - XPCOM API to create SB v4 update request. r=francois MozReview-Commit-ID: RfM3KFe6kG
toolkit/components/url-classifier/nsIUrlClassifierUtils.idl
toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
toolkit/components/url-classifier/tests/unit/test_safebrowsing_protobuf.js
toolkit/components/url-classifier/tests/unit/test_threat_type_conversion.js
toolkit/components/url-classifier/tests/unit/xpcshell.ini
--- a/toolkit/components/url-classifier/nsIUrlClassifierUtils.idl
+++ b/toolkit/components/url-classifier/nsIUrlClassifierUtils.idl
@@ -25,9 +25,40 @@ interface nsIUrlClassifierUtils : nsISup
   /**
    * Get the protocol version for the given provider.
    *
    * @param provider String the provider name. e.g. "google"
    *
    * @returns String to indicate the protocol version. e.g. "2.2"
    */
   ACString getProtocolVersion(in ACString provider);
+
+  /**
+   * Convert threat type to list name.
+   *
+   * @param Integer to indicate threat type.
+   *
+   * @returns The list name.
+   */
+  ACString convertThreatTypeToListName(in uint32_t threatType);
+
+  /**
+   * Convert list name to threat type.
+   *
+   * @param The list name.
+   *
+   * @returns The threat type in integer.
+   */
+  uint32_t convertListNameToThreatType(in ACString listName);
+
+  /**
+   * Make update request for given lists and their states.
+   *
+   * @param aListNames An array of list name represented in string.
+   * @param aState An array of states (in string) for each list.
+   * @param aCount The array length of aList and aState.
+   *
+   * @returns A string to store request. Not null-terminated.
+   */
+  ACString makeUpdateRequestV4([array, size_is(aCount)] in string aListNames,
+                               [array, size_is(aCount)] in string aStates,
+                               in uint32_t aCount);
 };
--- a/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
@@ -6,16 +6,17 @@
 #include "nsString.h"
 #include "nsIURI.h"
 #include "nsUrlClassifierUtils.h"
 #include "nsTArray.h"
 #include "nsReadableUtils.h"
 #include "plbase64.h"
 #include "prprf.h"
 #include "nsPrintfCString.h"
+#include "safebrowsing.pb.h"
 
 #define DEFAULT_PROTOCOL_VERSION "2.2"
 
 static char int_to_hex_digit(int32_t i)
 {
   NS_ASSERTION((i >= 0) && (i <= 15), "int too big in int_to_hex_digit");
   return static_cast<char>(((i < 10) ? (i + '0') : ((i - 10) + 'A')));
 }
@@ -67,16 +68,86 @@ IsOctal(const nsACString & num)
     if (!isdigit(num[i]) || num[i] == '8' || num[i] == '9') {
       return false;
     }
   }
 
   return true;
 }
 
+/////////////////////////////////////////////////////////////////
+// SafeBrowsing V4 related utits.
+
+namespace mozilla {
+namespace safebrowsing {
+
+static PlatformType
+GetPlatformType()
+{
+#if defined(ANDROID)
+  return ANDROID_PLATFORM;
+#elif defined(XP_MACOSX)
+  return OSX_PLATFORM;
+#elif defined(XP_LINUX)
+  return LINUX_PLATFORM;
+#elif defined(XP_WIN)
+  return WINDOWS_PLATFORM;
+#else
+  #error Unrecognized platform type.
+#endif
+}
+
+typedef FetchThreatListUpdatesRequest_ListUpdateRequest ListUpdateRequest;
+typedef FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints Constraints;
+
+static void
+InitListUpdateRequest(ThreatType aThreatType,
+                      const char* aState,
+                      ListUpdateRequest* aListUpdateRequest)
+{
+  aListUpdateRequest->set_threat_type(aThreatType);
+  aListUpdateRequest->set_platform_type(GetPlatformType());
+  aListUpdateRequest->set_threat_entry_type(URL);
+
+  // Only RAW data is supported for now.
+  // TODO: Bug 1285848 Supports Rice-Golomb encoding.
+  Constraints* contraints = new Constraints();
+  contraints->add_supported_compressions(RAW);
+  aListUpdateRequest->set_allocated_constraints(contraints);
+
+  // Only set non-empty state.
+  if (aState[0] != '\0') {
+    aListUpdateRequest->set_state(aState);
+  }
+}
+
+static ClientInfo*
+CreateClientInfo()
+{
+  ClientInfo* c = new ClientInfo();
+
+  nsCOMPtr<nsIPrefBranch> prefBranch =
+    do_GetService(NS_PREFSERVICE_CONTRACTID);
+
+  nsXPIDLCString clientId;
+  nsresult rv = prefBranch->GetCharPref("browser.safebrowsing.id",
+                                        getter_Copies(clientId));
+
+  if (NS_FAILED(rv)) {
+    clientId = "Firefox"; // Use "Firefox" as fallback.
+  }
+
+  c->set_client_id(clientId.get());
+
+  return c;
+}
+
+} // end of namespace safebrowsing.
+} // end of namespace mozilla.
+
 nsUrlClassifierUtils::nsUrlClassifierUtils() : mEscapeCharmap(nullptr)
 {
 }
 
 nsresult
 nsUrlClassifierUtils::Init()
 {
   // Everything but alpha numerics, - and .
@@ -122,16 +193,55 @@ nsUrlClassifierUtils::GetKeyForURI(nsIUR
   rv = CanonicalizePath(path, temp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   _retval.Append(temp);
 
   return NS_OK;
 }
 
+// We use "goog-*-proto" as the list name for v4, where "proto" indicates
+// it's updated (as well as hash completion) via protobuf.
+static const struct {
+  const char* mListName;
+  uint32_t mThreatType;
+} THREAT_TYPE_CONV_TABLE[] = {
+  { "goog-malware-proto",  MALWARE_THREAT},            // 1
+  { "goog-phish-proto",    SOCIAL_ENGINEERING_PUBLIC}, // 2
+  { "goog-unwanted-proto", UNWANTED_SOFTWARE},         // 3
+};
+
+NS_IMETHODIMP
+nsUrlClassifierUtils::ConvertThreatTypeToListName(uint32_t aThreatType,
+                                                  nsACString& aListName)
+{
+  for (uint32_t i = 0; i < ArrayLength(THREAT_TYPE_CONV_TABLE); i++) {
+    if (aThreatType == THREAT_TYPE_CONV_TABLE[i].mThreatType) {
+      aListName = THREAT_TYPE_CONV_TABLE[i].mListName;
+      return NS_OK;
+    }
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsUrlClassifierUtils::ConvertListNameToThreatType(const nsACString& aListName,
+                                                  uint32_t* aThreatType)
+{
+  for (uint32_t i = 0; i < ArrayLength(THREAT_TYPE_CONV_TABLE); i++) {
+    if (aListName.EqualsASCII(THREAT_TYPE_CONV_TABLE[i].mListName)) {
+      *aThreatType = THREAT_TYPE_CONV_TABLE[i].mThreatType;
+      return NS_OK;
+    }
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
 NS_IMETHODIMP
 nsUrlClassifierUtils::GetProtocolVersion(const nsACString& aProvider,
                                          nsACString& aVersion)
 {
   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefBranch) {
       nsPrintfCString prefName("browser.safebrowsing.provider.%s.pver",
                                nsCString(aProvider).get());
@@ -141,16 +251,50 @@ nsUrlClassifierUtils::GetProtocolVersion
       aVersion = NS_SUCCEEDED(rv) ? version : DEFAULT_PROTOCOL_VERSION;
   } else {
       aVersion = DEFAULT_PROTOCOL_VERSION;
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsUrlClassifierUtils::MakeUpdateRequestV4(const char** aListNames,
+                                          const char** aStates,
+                                          uint32_t aCount,
+                                          nsACString &aRequest)
+{
+  using namespace mozilla::safebrowsing;
+
+  FetchThreatListUpdatesRequest r;
+  r.set_allocated_client(CreateClientInfo());
+
+  for (uint32_t i = 0; i < aCount; i++) {
+    nsCString listName(aListNames[i]);
+    uint32_t threatType;
+    nsresult rv = ConvertListNameToThreatType(listName, &threatType);
+    if (NS_FAILED(rv)) {
+      continue; // Unknown list name.
+    }
+    auto lur = r.mutable_list_update_requests()->Add();
+    InitListUpdateRequest(static_cast<ThreatType>(threatType), aStates[i], lur);
+  }
+
+  // Then serialize.
+  std::string s;
+  r.SerializeToString(&s);
+
+  nsCString out;
+  out.Assign(s.c_str(), s.size());
+
+  aRequest = out;
+
+  return NS_OK;
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // non-interface methods
 
 nsresult
 nsUrlClassifierUtils::CanonicalizeHostname(const nsACString & hostname,
                                            nsACString & _retval)
 {
   nsAutoCString unescaped;
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/unit/test_safebrowsing_protobuf.js
@@ -0,0 +1,23 @@
+function run_test() {
+  let urlUtils = Cc["@mozilla.org/url-classifier/utils;1"]
+                   .getService(Ci.nsIUrlClassifierUtils);
+
+  // No list at all.
+  let requestNoList = urlUtils.makeUpdateRequestV4([], [], 0);
+
+  // Only one valid list name.
+  let requestOneValid =
+    urlUtils.makeUpdateRequestV4(["goog-phish-proto"], ["AAAAAA"], 1);
+
+  // Only one invalid list name.
+  let requestOneInvalid =
+    urlUtils.makeUpdateRequestV4(["bad-list-name"], ["AAAAAA"], 1);
+
+  // One valid and one invalid list name.
+  let requestOneInvalidOneValid =
+    urlUtils.makeUpdateRequestV4(["goog-phish-proto", "bad-list-name"],
+                                 ["AAAAAA", "AAAAAA"], 2);
+
+  equal(requestNoList, requestOneInvalid);
+  equal(requestOneValid, requestOneInvalidOneValid);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/unit/test_threat_type_conversion.js
@@ -0,0 +1,35 @@
+function run_test() {
+  let urlUtils = Cc["@mozilla.org/url-classifier/utils;1"]
+                   .getService(Ci.nsIUrlClassifierUtils);
+
+  // Test list name to threat type conversion.
+
+  equal(urlUtils.convertListNameToThreatType("goog-malware-proto"), 1);
+  equal(urlUtils.convertListNameToThreatType("goog-phish-proto"), 2);
+  equal(urlUtils.convertListNameToThreatType("goog-unwanted-proto"), 3);
+
+  try {
+    urlUtils.convertListNameToThreatType("bad-list-name");
+    ok(false, "Bad list name should lead to exception.");
+  } catch (e) {}
+
+  try {
+    urlUtils.convertListNameToThreatType("bad-list-name");
+    ok(false, "Bad list name should lead to exception.");
+  } catch (e) {}
+
+  // Test threat type to list name conversion.
+  equal(urlUtils.convertThreatTypeToListName(1), "goog-malware-proto");
+  equal(urlUtils.convertThreatTypeToListName(2), "goog-phish-proto");
+  equal(urlUtils.convertThreatTypeToListName(3), "goog-unwanted-proto");
+
+  try {
+    urlUtils.convertThreatTypeToListName(0);
+    ok(false, "Bad threat type should lead to exception.");
+  } catch (e) {}
+
+  try {
+    urlUtils.convertThreatTypeToListName(100);
+    ok(false, "Bad threat type should lead to exception.");
+  } catch (e) {}
+}
\ No newline at end of file
--- a/toolkit/components/url-classifier/tests/unit/xpcshell.ini
+++ b/toolkit/components/url-classifier/tests/unit/xpcshell.ini
@@ -10,13 +10,15 @@ support-files =
 [test_bug1274685_unowned_list.js]
 [test_backoff.js]
 [test_dbservice.js]
 [test_hashcompleter.js]
 # Bug 752243: Profile cleanup frequently fails
 #skip-if = os == "mac" || os == "linux"
 [test_partial.js]
 [test_prefixset.js]
+[test_threat_type_conversion.js]
 [test_provider_url.js]
 [test_streamupdater.js]
 [test_digest256.js]
 [test_listmanager.js]
 [test_pref.js]
+[test_safebrowsing_protobuf.js]