Bug 1224528 - Provide a mechanism to populate the OneCRL kinto collection with initial records r=rnewman draft
authorMark Goodwin <mgoodwin@mozilla.com>
Fri, 19 Feb 2016 12:30:33 +0000
changeset 362959 955977030bbe3c31331aed900e1d7619f5ef0755
parent 356103 2045bc8c9e90a7ca0b8c6447ddecd812a71b29e1
child 362960 67db60dfdbdeb49dd2d7b1ad76679d831911c7ab
child 362979 d2e949c6eaf4f7181d9e8f2921b986ccf8a232a9
child 362981 69291bf413f05af6ddc103ba8f74f78b124ae5fc
push id17069
push usermleplatre@mozilla.com
push dateTue, 03 May 2016 16:31:17 +0000
reviewersrnewman
bugs1224528
milestone49.0a1
Bug 1224528 - Provide a mechanism to populate the OneCRL kinto collection with initial records r=rnewman This makes use of the kinto.js loadDump feature to populate the OneCRL collection with initial data from application defaults. This also includes a modified moz-kinto-client.js because there was an issue with the loadDump implementation in the FirefoxStorage adapter that caused breakage with empty collections. MozReview-Commit-ID: HilHc9Z9gzr
browser/app/collections/certificates.json
browser/app/collections/moz.build
browser/app/moz.build
services/common/KintoBlocklist.js
services/common/tests/unit/test_kintoCertBlocklist.js
new file mode 100644
--- /dev/null
+++ b/browser/app/collections/certificates.json
@@ -0,0 +1,1 @@
+{"data":[{"issuerName":"MDcxJDAiBgNVBAMTG1JDUyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEPMA0GA1UEChMGSFQgc3Js","serialNumber":"AN9bfYOvlR1t","id":"63e5ccb8-1798-3b9f-48f5-12b5ca13054e","last_modified":1447863870100},{"issuerName":"MFkxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKjAoBgNVBAMTIVN0YWF0IGRlciBOZWRlcmxhbmRlbiBPdmVyaGVpZCBDQQ","serialNumber":"ATFpsA==","id":"dabafde9-df4a-ddba-2548-748da04cc02c","last_modified":1447863870001},{"issuerName":"MIGQMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDE2MDQGA1UEAxMtQ09NT0RPIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB","serialNumber":"UoRGnb96CUDTxIqVry6LBg==","id":"c960b86c-5c04-e455-e069-04555910f581","last_modified":1447863869813},{"issuerName":"MGcxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpGcmF1bmhvZmVyMSEwHwYDVQQLExhGcmF1bmhvZmVyIENvcnBvcmF0ZSBQS0kxIDAeBgNVBAMTF0ZyYXVuaG9mZXIgUm9vdCBDQSAyMDA3","serialNumber":"YR3YYQAAAAAABA==","id":"22294c18-1096-e6fe-5a79-31e1ef4aef85","last_modified":1447863869907},{"issuerName":"MFkxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKjAoBgNVBAMTIVN0YWF0IGRlciBOZWRlcmxhbmRlbiBPdmVyaGVpZCBDQQ","serialNumber":"ATFEdg==","id":"c2bfc807-893a-1f73-5b41-d2510f71097c","last_modified":1447863870054},{"issuerName":"MEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHjAcBgNVBAMTFXRoYXd0ZSBFViBTU0wgQ0EgLSBHMw==","serialNumber":"CrTHPEE6AZSfI3jysin2bA==","id":"78cf8900-fdea-4ce5-f8fb-b78710617718","last_modified":1447863870147},{"issuerName":"MIGQMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDE2MDQGA1UEAxMtQ09NT0RPIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB","serialNumber":"D9UltDPl4XVfSSqQOvdiwQ==","id":"a81803c3-3c06-1549-bbe3-4b7d4c739f25","last_modified":1447863869721},{"issuerName":"MDIxCzAJBgNVBAYTAkNOMQ4wDAYDVQQKEwVDTk5JQzETMBEGA1UEAxMKQ05OSUMgUk9PVA==","serialNumber":"STMAjg==","id":"85547569-b7f8-9f18-1641-ff7f056ef16a","last_modified":1447863869767},{"issuerName":"MHExCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNEZXV0c2NoZSBUZWxla29tIEFHMR8wHQYDVQQLExZULVRlbGVTZWMgVHJ1c3QgQ2VudGVyMSMwIQYDVQQDExpEZXV0c2NoZSBUZWxla29tIFJvb3QgQ0EgMg==","serialNumber":"ARQ=","id":"63bfea69-bb25-911f-3f89-d54fe63a2e2f","last_modified":1447863869861},{"issuerName":"MGExCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xMjAwBgNVBAMMKVN0YWF0IGRlciBOZWRlcmxhbmRlbiBPcmdhbmlzYXRpZSBDQSAtIEcy","serialNumber":"ATE0vw==","id":"decad8c9-204a-a0af-030f-04cbf4410b70","last_modified":1447863869955}]}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/app/collections/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FINAL_TARGET_FILES.defaults.collections.blocklists += ['certificates.json']
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIRS += ['profile/extensions']
+DIRS += ['collections', 'profile/extensions']
 
 if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_ASAN']:
     GeckoProgram(CONFIG['MOZ_APP_NAME'])
 else:
     GeckoProgram(CONFIG['MOZ_APP_NAME'], msvcrt='static')
 
 JS_PREFERENCE_PP_FILES += [
     'profile/firefox.js',
--- a/services/common/KintoBlocklist.js
+++ b/services/common/KintoBlocklist.js
@@ -15,16 +15,19 @@ this.EXPORTED_SYMBOLS = ["AddonBlocklist
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 const { Task } = Cu.import("resource://gre/modules/Task.jsm");
 const { OS } = Cu.import("resource://gre/modules/osfile.jsm");
 
 const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
 
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+  "resource://gre/modules/FileUtils.jsm");
+
 const PREF_KINTO_BASE                    = "services.kinto.base";
 const PREF_KINTO_BUCKET                  = "services.kinto.bucket";
 const PREF_KINTO_ONECRL_COLLECTION       = "services.kinto.onecrl.collection";
 const PREF_KINTO_ONECRL_CHECKED_SECONDS  = "services.kinto.onecrl.checked";
 const PREF_KINTO_ADDONS_COLLECTION       = "services.kinto.addons.collection";
 const PREF_KINTO_ADDONS_CHECKED_SECONDS  = "services.kinto.addons.checked";
 const PREF_KINTO_PLUGINS_COLLECTION      = "services.kinto.plugins.collection";
 const PREF_KINTO_PLUGINS_CHECKED_SECONDS = "services.kinto.plugins.checked";
@@ -79,16 +82,32 @@ class BlocklistClient {
     let db = kintoClient();
     let collection = db.collection(this.collectionName);
 
     return Task.spawn((function* syncCollection() {
       try {
         yield collection.db.open();
 
         let collectionLastModified = yield collection.db.getLastModified();
+
+        // if there is no data currently in the collection, attempt to import
+        // initial data from the application defaults
+        if (!collectionLastModified) {
+          const collectionFile = FileUtils.getFile("CurProcD",
+            ["defaults", "collections", "blocklists", `${collectionName}.json`]);
+          if (collectionFile.exists()) {
+            const fileURI = Services.io.newFileURI(collectionFile);
+            const response = yield fetch(fileURI.spec);
+            if (response.ok) {
+              const initialData = yield response.json()
+              yield blocklist.db.loadDump(initialData.data);
+            }
+          }
+        }
+
         // If the data is up to date, there's no need to sync. We still need
         // to record the fact that a check happened.
         if (lastModified <= collectionLastModified) {
           this.updateLastCheck(serverTime);
           return;
         }
         // Fetch changes from server.
         yield collection.sync();
--- a/services/common/tests/unit/test_kintoCertBlocklist.js
+++ b/services/common/tests/unit/test_kintoCertBlocklist.js
@@ -71,16 +71,36 @@ add_task(function* test_something(){
   // Test an empty db populates
   let result = yield OneCRLBlocklistClient.maybeSync(2000, Date.now());
 
   // Open the collection, verify it's been populated:
   // Our test data has a single record; it should be in the local collection
   let collection = do_get_kinto_collection("certificates");
   yield collection.db.open();
   let list = yield collection.list();
+  // We know there will be initial values; just not how many.
+  do_check_neq(list.data.length, 0);
+  yield collection.db.close();
+
+  // clear the collection, save a non-zero lastModified so we don't do
+  // import of initial data when we sync again.
+  collection = do_get_kinto_collection("certificates");
+  yield collection.db.open();
+  yield collection.clear();
+  // a lastModified value of 1000 means we get a remote collection with a
+  // single record
+  yield collection.db.saveLastModified(1000);
+  yield collection.db.close();
+  yield OneCRLClient.maybeSync(2000, Date.now());
+
+  // Open the collection, verify it's been updated:
+  // Our test data now has two records; both should be in the local collection
+  collection = do_get_kinto_collection("certificates");
+  yield collection.db.open();
+  list = yield collection.list();
   do_check_eq(list.data.length, 1);
   yield collection.db.close();
 
   // Test the db is updated when we call again with a later lastModified value
   result = yield OneCRLBlocklistClient.maybeSync(4000, Date.now());
 
   // Open the collection, verify it's been updated:
   // Our test data now has two records; both should be in the local collection