author | Mathieu Leplatre <mathieu@mozilla.com> |
Mon, 06 Feb 2017 10:35:26 +0100 | |
changeset 340996 | dd195a6fabaf558c0089488af184265041ffc34b |
parent 340995 | ed583f4e5054748738c92e466fd8d2650c8d0888 |
child 340997 | f0f5fdf96c80ed8ef55c7c8152976cd8c41a072a |
push id | 86615 |
push user | kwierso@gmail.com |
push date | Tue, 07 Feb 2017 01:52:08 +0000 |
treeherder | mozilla-inbound@f0453084d86e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mgoodwin |
bugs | 1331629 |
milestone | 54.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
|
--- a/services/common/blocklist-clients.js +++ b/services/common/blocklist-clients.js @@ -63,64 +63,53 @@ function mergeChanges(collection, localR return Object.values(records) // Filter out deleted records. .filter((record) => record.deleted != true) // Sort list by record id. .sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0); } -function fetchCollectionMetadata(collection) { - const client = new KintoHttpClient(collection.api.remote); +function fetchCollectionMetadata(remote, collection) { + const client = new KintoHttpClient(remote); return client.bucket(collection.bucket).collection(collection.name).getData() .then(result => { return result.signature; }); } -function fetchRemoteCollection(collection) { - const client = new KintoHttpClient(collection.api.remote); +function fetchRemoteCollection(remote, collection) { + const client = new KintoHttpClient(remote); return client.bucket(collection.bucket) .collection(collection.name) .listRecords({sort: "id"}); } -/** - * Helper to instantiate a Kinto client based on preferences for remote server - * URL and bucket name. It uses the `FirefoxAdapter` which relies on SQLite to - * persist the local DB. - */ -function kintoClient(connection, bucket) { - const remote = Services.prefs.getCharPref(PREF_SETTINGS_SERVER); - - const config = { - remote, - bucket, - adapter: FirefoxAdapter, - adapterOptions: {sqliteHandle: connection}, - }; - - return new Kinto(config); -} - class BlocklistClient { constructor(collectionName, lastCheckTimePref, processCallback, bucketName, signerName) { this.collectionName = collectionName; this.lastCheckTimePref = lastCheckTimePref; this.processCallback = processCallback; this.bucketName = bucketName; this.signerName = signerName; + + this._kinto = new Kinto({ + bucket: bucketName, + adapter: FirefoxAdapter, + }); } - validateCollectionSignature(payload, collection, ignoreLocal) { + validateCollectionSignature(remote, payload, collection, options = {}) { + const {ignoreLocal} = options; + return Task.spawn((function* () { // this is a content-signature field from an autograph response. - const {x5u, signature} = yield fetchCollectionMetadata(collection); + const {x5u, signature} = yield fetchCollectionMetadata(remote, collection); const certChain = yield fetch(x5u).then((res) => res.text()); const verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"] .createInstance(Ci.nsIContentSignatureVerifier); let toSerialize; if (ignoreLocal) { toSerialize = { @@ -152,57 +141,63 @@ class BlocklistClient { * Synchronize from Kinto server, if necessary. * * @param {int} lastModified the lastModified date (on the server) for the remote collection. * @param {Date} serverTime the current date return by the server. * @return {Promise} which rejects on sync or process failure. */ maybeSync(lastModified, serverTime) { - const opts = {}; - const enforceCollectionSigning = + const remote = Services.prefs.getCharPref(PREF_SETTINGS_SERVER); + let enforceCollectionSigning = Services.prefs.getBoolPref(PREF_BLOCKLIST_ENFORCE_SIGNING); // if there is a signerName and collection signing is enforced, add a // hook for incoming changes that validates the signature + let hooks; if (this.signerName && enforceCollectionSigning) { - opts.hooks = { - "incoming-changes": [this.validateCollectionSignature.bind(this)] + hooks = { + "incoming-changes": [(payload, collection) => { + return this.validateCollectionSignature(remote, payload, collection); + }] } } - return Task.spawn((function* syncCollection() { - let connection; + let sqliteHandle; try { - connection = yield FirefoxAdapter.openConnection({path: KINTO_STORAGE_PATH}); - const db = kintoClient(connection, this.bucketName); - const collection = db.collection(this.collectionName, opts); + // Synchronize remote data into a local Sqlite DB. + sqliteHandle = yield FirefoxAdapter.openConnection({path: KINTO_STORAGE_PATH}); + const options = { + hooks, + adapterOptions: {sqliteHandle}, + }; + const collection = this._kinto.collection(this.collectionName, options); const collectionLastModified = yield collection.db.getLastModified(); // 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. try { - const {ok} = yield collection.sync(); + const {ok} = yield collection.sync({remote}); if (!ok) { throw new Error("Sync failed"); } } catch (e) { if (e.message == INVALID_SIGNATURE) { // if sync fails with a signature error, it's likely that our // local data has been modified in some way. // We will attempt to fix this by retrieving the whole // remote collection. - const payload = yield fetchRemoteCollection(collection); - yield this.validateCollectionSignature(payload, collection, true); + const payload = yield fetchRemoteCollection(remote, collection); + yield this.validateCollectionSignature(remote, payload, collection, {ignoreLocal: true}); // if the signature is good (we haven't thrown), and the remote // last_modified is newer than the local last_modified, replace the // local data const localLastModified = yield collection.db.getLastModified(); if (payload.last_modified >= localLastModified) { yield collection.clear(); yield collection.loadDump(payload.data); } @@ -213,17 +208,17 @@ class BlocklistClient { // Read local collection of records. const {data} = yield collection.list(); yield this.processCallback(data); // Track last update. this.updateLastCheck(serverTime); } finally { - yield connection.close(); + yield sqliteHandle.close(); } }).bind(this)); } /** * Save last time server was checked in users prefs. * * @param {Date} serverTime the current date return by server.