--- a/services/common/blocklist-clients.js
+++ b/services/common/blocklist-clients.js
@@ -20,25 +20,16 @@ const { Task } = Cu.import("resource://g
const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
Cu.importGlobalProperties(["fetch"]);
const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js", {});
const { KintoHttpClient } = Cu.import("resource://services-common/kinto-http-client.js", {});
const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js", {});
const { CanonicalJSON } = Components.utils.import("resource://gre/modules/CanonicalJSON.jsm", {});
-const SERVICES_SETTINGS_SYNC_SIG_FAIL = 3;
-const SERVICES_SETTINGS_SYNC_RETRY_SIG_FAIL = 4;
-const SERVICES_SETTINGS_SYNC_ONECRL_FAIL = 5;
-const SERVICES_SETTINGS_SYNC_ONECRL_ENTRY = 6;
-const SERVICES_SETTINGS_SYNC_ADDONS_FAIL = 7;
-const SERVICES_SETTINGS_SYNC_GFX_FAIL = 8;
-const SERVICES_SETTINGS_SYNC_PLUGINS_FAIL = 9;
-const SERVICES_SETTINGS_SYNC_PINNING_FAIL = 10;
-
const PREF_SETTINGS_SERVER = "services.settings.server";
const PREF_BLOCKLIST_BUCKET = "services.blocklist.bucket";
const PREF_BLOCKLIST_ONECRL_COLLECTION = "services.blocklist.onecrl.collection";
const PREF_BLOCKLIST_ONECRL_CHECKED_SECONDS = "services.blocklist.onecrl.checked";
const PREF_BLOCKLIST_ADDONS_COLLECTION = "services.blocklist.addons.collection";
const PREF_BLOCKLIST_ADDONS_CHECKED_SECONDS = "services.blocklist.addons.checked";
const PREF_BLOCKLIST_PLUGINS_COLLECTION = "services.blocklist.plugins.collection";
const PREF_BLOCKLIST_PLUGINS_CHECKED_SECONDS = "services.blocklist.plugins.checked";
@@ -47,16 +38,26 @@ const PREF_BLOCKLIST_PINNING_BUCKET
const PREF_BLOCKLIST_PINNING_COLLECTION = "services.blocklist.pinning.collection";
const PREF_BLOCKLIST_PINNING_CHECKED_SECONDS = "services.blocklist.pinning.checked";
const PREF_BLOCKLIST_GFX_COLLECTION = "services.blocklist.gfx.collection";
const PREF_BLOCKLIST_GFX_CHECKED_SECONDS = "services.blocklist.gfx.checked";
const PREF_BLOCKLIST_ENFORCE_SIGNING = "services.blocklist.signing.enforced";
const INVALID_SIGNATURE = "Invalid content/signature";
+// Telemetry report results.
+const SERVICE_SETTINGS_UPDATE_UP_TO_DATE = -1;
+const SERVICE_SETTINGS_UPDATE_SUCCESS = 0;
+const SERVICE_SETTINGS_UPDATE_UNKNOWN_FAILURE = 1;
+const SERVICE_SETTINGS_UPDATE_SYNC_FAILURE = 2;
+const SERVICE_SETTINGS_UPDATE_CONFLICT_FAILURE = 3;
+const SERVICE_SETTINGS_UPDATE_SIGNATURE_FAILURE = 4;
+const SERVICE_SETTINGS_UPDATE_SIGNATURE_RETRY_FAILURE = 5;
+const SERVICE_SETTINGS_UPDATE_APPLICATION_FAILURE = 6;
+
// FIXME: this was the default path in earlier versions of
// FirefoxAdapter, so for backwards compatibility we maintain this
// filename, even though it isn't descriptive of who is using it.
this.KINTO_STORAGE_PATH = "kinto.sqlite";
this.FILENAME_ADDONS_JSON = "blocklist-addons.json";
this.FILENAME_GFX_JSON = "blocklist-gfx.json";
this.FILENAME_PLUGINS_JSON = "blocklist-plugins.json";
@@ -108,23 +109,27 @@ function kintoClient(connection, bucket)
};
return new Kinto(config);
}
class BlocklistClient {
- constructor(collectionName, lastCheckTimePref, processCallback, bucketName, signerName, failureBucket) {
+ constructor(collectionName, lastCheckTimePref, processCallback, bucketName, signerName) {
this.collectionName = collectionName;
this.lastCheckTimePref = lastCheckTimePref;
this.processCallback = processCallback;
this.bucketName = bucketName;
this.signerName = signerName;
- this.failureBucket = failureBucket;
+ }
+
+ get histogramId() {
+ const identifier = `${this.bucketName.toUpperCase()}_${this.collectionName.toUpperCase()}`;
+ return `SERVICE_SETTINGS_UPDATE_${identifier}_RESULT`;
}
validateCollectionSignature(payload, collection, ignoreLocal) {
return Task.spawn((function* () {
// this is a content-signature field from an autograph response.
const {x5u, signature} = yield fetchCollectionMetadata(collection);
const certChain = yield fetch(x5u).then((res) => res.text());
@@ -149,19 +154,16 @@ class BlocklistClient {
const serialized = CanonicalJSON.stringify(toSerialize);
if (verifier.verifyContentSignature(serialized, "p384ecdsa=" + signature,
certChain,
this.signerName)) {
// In case the hash is valid, apply the changes locally.
return payload;
}
- Services.telemetry
- .getHistogramById("SERVICES_SETTINGS_SUCCESS")
- .add(SERVICES_SETTINGS_SYNC_SIG_FAIL);
throw new Error(INVALID_SIGNATURE);
}).bind(this));
}
/**
* Synchronize from Kinto server, if necessary.
*
* @param {int} lastModified the lastModified date (on the server) for
@@ -180,75 +182,101 @@ class BlocklistClient {
opts.hooks = {
"incoming-changes": [this.validateCollectionSignature.bind(this)]
}
}
return Task.spawn((function* syncCollection() {
let connection;
+ let reportStatus;
try {
connection = yield FirefoxAdapter.openConnection({path: KINTO_STORAGE_PATH});
const db = kintoClient(connection, this.bucketName);
const collection = db.collection(this.collectionName, opts);
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);
+ reportStatus = SERVICE_SETTINGS_UPDATE_UP_TO_DATE;
return;
}
// Fetch changes from server.
try {
const {ok} = yield collection.sync();
if (!ok) {
+ // Some synchronization conflicts occured.
+ reportStatus = SERVICE_SETTINGS_UPDATE_CONFLICT_FAILURE;
throw new Error("Sync failed");
}
} catch (e) {
if (e.message == INVALID_SIGNATURE) {
+ // Signature verification failed during synchronzation.
+ reportStatus = SERVICE_SETTINGS_UPDATE_SIGNATURE_FAILURE;
// 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);
try {
yield this.validateCollectionSignature(payload, collection, true);
} catch (e) {
- Services.telemetry
- .getHistogramById("SERVICES_SETTINGS_SUCCESS")
- .add(SERVICES_SETTINGS_SYNC_RETRY_SIG_FAIL);
+ reportStatus = SERVICE_SETTINGS_UPDATE_SIGNATURE_RETRY_FAILURE;
throw(e);
}
// 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);
}
} else {
+ // The sync has thrown, it can be a network or local database error.
+ reportStatus = SERVICE_SETTINGS_UPDATE_SYNC_FAILURE;
throw e;
}
}
// Read local collection of records.
const {data} = yield collection.list();
- yield this.processCallback(data);
+ // Handle the obtained records (ie. apply locally).
+ try {
+ yield this.processCallback(data);
+ } catch (e) {
+ reportStatus = SERVICE_SETTINGS_UPDATE_APPLICATION_FAILURE;
+ throw e;
+ }
// Track last update.
this.updateLastCheck(serverTime);
} catch(e) {
- Services.telemetry
- .getHistogramById("SERVICES_SETTINGS_SUCCESS")
- .add(this.failureBucket);
+ // No specific error was tracked, mark it as unknown.
+ if (!reportStatus) {
+ reportStatus = SERVICE_SETTINGS_UPDATE_UNKNOWN_FAILURE;
+ }
throw e;
} finally {
- yield connection.close();
+ if (connection) {
+ yield connection.close();
+ }
+ // No error was reported, this is a success!
+ if (!reportStatus) {
+ reportStatus = SERVICE_SETTINGS_UPDATE_SUCCESS;
+ }
+ // Report status to Telemetry.
+ // XXX: TODO: check that histogram exists (e.g. QA using preview bucket)
+ if (reportStatus >= 0) {
+ Services.telemetry
+ .getHistogramById(this.histogramId)
+ .add(reportStatus);
+ }
}
}).bind(this));
}
/**
* Save last time server was checked in users prefs.
*
* @param {Date} serverTime the current date return by server.
@@ -352,47 +380,42 @@ function* updateJSONBlocklist(filename,
}
}
this.OneCRLBlocklistClient = new BlocklistClient(
Services.prefs.getCharPref(PREF_BLOCKLIST_ONECRL_COLLECTION),
PREF_BLOCKLIST_ONECRL_CHECKED_SECONDS,
updateCertBlocklist,
Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
- "onecrl.content-signature.mozilla.org",
- SERVICES_SETTINGS_SYNC_ONECRL_FAIL
+ "onecrl.content-signature.mozilla.org"
);
this.AddonBlocklistClient = new BlocklistClient(
Services.prefs.getCharPref(PREF_BLOCKLIST_ADDONS_COLLECTION),
PREF_BLOCKLIST_ADDONS_CHECKED_SECONDS,
updateJSONBlocklist.bind(undefined, FILENAME_ADDONS_JSON),
Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
- undefined,
- SERVICES_SETTINGS_SYNC_ADDONS_FAIL
+ undefined
);
this.GfxBlocklistClient = new BlocklistClient(
Services.prefs.getCharPref(PREF_BLOCKLIST_GFX_COLLECTION),
PREF_BLOCKLIST_GFX_CHECKED_SECONDS,
updateJSONBlocklist.bind(undefined, FILENAME_GFX_JSON),
Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
- undefined,
- SERVICES_SETTINGS_SYNC_GFX_FAIL
+ undefined
);
this.PluginBlocklistClient = new BlocklistClient(
Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_COLLECTION),
PREF_BLOCKLIST_PLUGINS_CHECKED_SECONDS,
updateJSONBlocklist.bind(undefined, FILENAME_PLUGINS_JSON),
Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET),
- undefined,
- SERVICES_SETTINGS_SYNC_PLUGINS_FAIL
+ undefined
);
this.PinningPreloadClient = new BlocklistClient(
Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_COLLECTION),
PREF_BLOCKLIST_PINNING_CHECKED_SECONDS,
updatePinningList,
Services.prefs.getCharPref(PREF_BLOCKLIST_PINNING_BUCKET),
- "pinning-preload.content-signature.mozilla.org",
- SERVICES_SETTINGS_SYNC_PINNING_FAIL
+ "pinning-preload.content-signature.mozilla.org"
);
--- a/services/common/blocklist-updater.js
+++ b/services/common/blocklist-updater.js
@@ -12,17 +12,18 @@ Cu.importGlobalProperties(["fetch"]);
const BlocklistClients = Cu.import("resource://services-common/blocklist-clients.js", {});
const PREF_SETTINGS_SERVER = "services.settings.server";
const PREF_BLOCKLIST_CHANGES_PATH = "services.blocklist.changes.path";
const PREF_BLOCKLIST_LAST_UPDATE = "services.blocklist.last_update_seconds";
const PREF_BLOCKLIST_LAST_ETAG = "services.blocklist.last_etag";
const PREF_BLOCKLIST_CLOCK_SKEW_SECONDS = "services.blocklist.clock_skew_seconds";
-// Telemetry report result.
+// Telemetry report results.
+const TELEMETRY_HISTOGRAM = "SERVICE_SETTINGS_POLLING_RESULT";
const SERVICE_SETTINGS_POLLING_SUCCESS = 0;
const SERVICE_SETTINGS_POLLING_NETWORK_FAILURE = 1;
const SERVICE_SETTINGS_POLLING_SERVER_FAILURE = 2;
const gBlocklistClients = {
[BlocklistClients.OneCRLBlocklistClient.collectionName]: BlocklistClients.OneCRLBlocklistClient,
[BlocklistClients.AddonBlocklistClient.collectionName]: BlocklistClients.AddonBlocklistClient,
[BlocklistClients.GfxBlocklistClient.collectionName]: BlocklistClients.GfxBlocklistClient,
@@ -96,17 +97,17 @@ this.checkVersions = function() {
} catch (e) {
pollError = e;
}
// Report polling status to Telemetry.
const report = pollResult ? SERVICE_SETTINGS_POLLING_SUCCESS
: /Server/.test(pollError.message) ? SERVICE_SETTINGS_POLLING_SERVER_FAILURE
: SERVICE_SETTINGS_POLLING_NETWORK_FAILURE;
Services.telemetry
- .getHistogramById("SERVICE_SETTINGS_POLLING_RESULT")
+ .getHistogramById(TELEMETRY_HISTOGRAM)
.add(report);
if (pollError) {
// No need to go further.
throw new Error(`Polling for changes failed: ${pollError.message}.`);
}
const {serverTimeMillis, versionInfo, currentEtag} = pollResult;
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -1,12 +1,18 @@
const { Constructor: CC } = Components;
const KEY_PROFILEDIR = "ProfD";
+const SERVICE_SETTINGS_UPDATE_SUCCESS = 0;
+const SERVICE_SETTINGS_UPDATE_UNKNOWN_FAILURE = 1;
+const SERVICE_SETTINGS_UPDATE_SYNC_FAILURE = 2;
+const SERVICE_SETTINGS_UPDATE_APPLICATION_FAILURE = 6;
+
+
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/Timer.jsm");
const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
const { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js", {});
const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js", {});
@@ -194,29 +200,109 @@ add_task(function* test_sends_reload_mes
add_task(clear_state);
add_task(function* test_do_nothing_when_blocklist_is_up_to_date() {
for (let {client, filename} of gBlocklistClients) {
yield client.maybeSync(2000, Date.now() - 1000);
const profFile = FileUtils.getFile(KEY_PROFILEDIR, [filename]);
const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000;
const serverTime = Date.now();
+ const startHistogram = getHistogramSnapshot(client.histogramId);
yield client.maybeSync(3000, serverTime);
// File was not updated.
equal(fileLastModified, profFile.lastModifiedTime);
// Server time was updated.
const after = Services.prefs.getIntPref(client.lastCheckTimePref);
equal(after, Math.round(serverTime / 1000));
+ // No Telemetry was sent.
+ const endHistogram = getHistogramSnapshot(client.histogramId);
+ const expectedIncrements = getDefaultIncrements(startHistogram);
+ checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
+ }
+});
+add_task(clear_state);
+
+add_task(function* test_telemetry_if_sync_succeeds() {
+ // We test each client because Telemetry requires preleminary declarations.
+ for (let {client} of gBlocklistClients) {
+ const serverTime = Date.now();
+ const startHistogram = getHistogramSnapshot(client.histogramId);
+
+ yield client.maybeSync(2000, serverTime);
+
+ const endHistogram = getHistogramSnapshot(client.histogramId);
+ const expectedIncrements = getDefaultIncrements(startHistogram);
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_SUCCESS] = 1;
+ checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
}
});
add_task(clear_state);
+add_task(function* test_telemetry_reports_if_application_fails() {
+ const {client} = gBlocklistClients[0];
+ const serverTime = Date.now();
+ const startHistogram = getHistogramSnapshot(client.histogramId);
+ const backup = client.processCallback;
+ client.processCallback = () => {throw new Error("boom");}
+ try {
+ yield client.maybeSync(2000, serverTime);
+ } catch (e) {}
+
+ client.processCallback = backup;
+
+ const endHistogram = getHistogramSnapshot(client.histogramId);
+ const expectedIncrements = getDefaultIncrements(startHistogram);
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_APPLICATION_FAILURE] = 1;
+ checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
+});
+add_task(clear_state);
+
+add_task(function* test_telemetry_reports_if_sync_fails() {
+ const {client} = gBlocklistClients[0];
+ const serverTime = Date.now();
+
+ const sqliteHandle = yield FirefoxAdapter.openConnection({path: kintoFilename});
+ const collection = kintoCollection(client.collectionName, sqliteHandle);
+ yield collection.db.saveLastModified(9999);
+ yield sqliteHandle.close();
+
+ const startHistogram = getHistogramSnapshot(client.histogramId);
+
+ try {
+ yield client.maybeSync(10000, serverTime);
+ } catch (e) {}
+
+ const endHistogram = getHistogramSnapshot(client.histogramId);
+ const expectedIncrements = getDefaultIncrements(startHistogram);
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_SYNC_FAILURE] = 1;
+ checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
+});
+add_task(clear_state);
+
+add_task(function* test_telemetry_reports_unknown_errors() {
+ const {client} = gBlocklistClients[0];
+ const serverTime = Date.now();
+ const backup = FirefoxAdapter.openConnection;
+ FirefoxAdapter.openConnection = () => {throw new Error("Internal")};
+ const startHistogram = getHistogramSnapshot(client.histogramId);
+
+ try {
+ yield client.maybeSync(2000, serverTime);
+ } catch (e) {}
+
+ FirefoxAdapter.openConnection = backup;
+ const endHistogram = getHistogramSnapshot(client.histogramId);
+ const expectedIncrements = getDefaultIncrements(startHistogram);
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_UNKNOWN_FAILURE] = 1;
+ checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
+});
+add_task(clear_state);
// get a response for a given request from sample data
function getSampleResponse(req, port) {
const responses = {
"OPTIONS": {
"sampleHeaders": [
"Access-Control-Allow-Headers: Content-Length,Expires,Backoff,Retry-After,Last-Modified,Total-Records,ETag,Pragma,Cache-Control,authorization,content-type,if-none-match,Alert,Next-Page",
"Access-Control-Allow-Methods: GET,HEAD,OPTIONS,POST,DELETE,OPTIONS",
@@ -394,14 +480,28 @@ function getSampleResponse(req, port) {
"blockID": "g200",
"feature": "WEBGL_MSAA",
"devices": [],
"id": "c3a15ba9-e0e2-421f-e399-c995e5b8d14e",
"last_modified": 3500,
"os": "Darwin 11",
"featureStatus": "BLOCKED_DEVICE"
}]})
+ },
+ "GET:/v1/buckets/blocklists/collections/addons/records?_sort=-last_modified&_since=9999": {
+ "sampleHeaders": [
+ "Access-Control-Allow-Origin: *",
+ "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
+ "Content-Type: application/json; charset=UTF-8",
+ "Server: waitress",
+ ],
+ "status": {status: 503, statusText: "Service Unavailable"},
+ "responseBody": JSON.stringify({
+ code: 503,
+ errno: 999,
+ error: "Service Unavailable",
+ })
}
};
return responses[`${req.method}:${req.path}?${req.queryString}`] ||
responses[req.method];
}
--- a/services/common/tests/unit/test_blocklist_signatures.js
+++ b/services/common/tests/unit/test_blocklist_signatures.js
@@ -11,19 +11,21 @@ const { OneCRLBlocklistClient } = Cu.imp
let server;
const PREF_BLOCKLIST_BUCKET = "services.blocklist.bucket";
const PREF_BLOCKLIST_ENFORCE_SIGNING = "services.blocklist.signing.enforced";
const PREF_BLOCKLIST_ONECRL_COLLECTION = "services.blocklist.onecrl.collection";
const PREF_SETTINGS_SERVER = "services.settings.server";
const PREF_SIGNATURE_ROOT = "security.content.signature.root_hash";
-const SERVICES_SETTINGS_SYNC_SIG_FAIL = 3;
-const SERVICES_SETTINGS_SYNC_RETRY_SIG_FAIL = 4;
-const SERVICES_SETTINGS_SYNC_ONECRL_FAIL = 5;
+// Telemetry reports.
+const histogramId = OneCRLBlocklistClient.histogramId;
+const SERVICE_SETTINGS_UPDATE_SUCCESS = 0;
+const SERVICE_SETTINGS_UPDATE_SIGNATURE_FAILURE = 4;
+const SERVICE_SETTINGS_UPDATE_SIGNATURE_RETRY_FAILURE = 5;
const kintoFilename = "kinto.sqlite";
const CERT_DIR = "test_blocklist_signatures/";
const CHAIN_FILES =
["collection_signing_ee.pem",
"collection_signing_int.pem",
"collection_signing_root.pem"];
@@ -291,27 +293,27 @@ add_task(function* test_check_signatures
[RESPONSE_EMPTY_INITIAL],
"GET:/v1/buckets/blocklists/collections/certificates?":
[RESPONSE_META_EMPTY_SIG]
};
// .. and use this map to register handlers for each path
registerHandlers(emptyCollectionResponses);
- let startHistogram = getHistogramSnapshot("SERVICES_SETTINGS_SUCCESS");
+ let startHistogram = getHistogramSnapshot(histogramId);
// With all of this set up, we attempt a sync. This will resolve if all is
// well and throw if something goes wrong.
yield OneCRLBlocklistClient.maybeSync(1000, startTime);
- let endHistogram = getHistogramSnapshot("SERVICES_SETTINGS_SUCCESS");
+ let endHistogram = getHistogramSnapshot(histogramId);
- // ensure that none of the services_settings_success histogram counts are
- // affected when a succesful sync occurs
+ // ensure that a success histogram is tracked when a succesful sync occurs.
let expectedIncrements = getDefaultIncrements(startHistogram);
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_SUCCESS] = 1;
checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
// Check that some additions (2 records) to the collection have a valid
// signature.
// This response adds two entries (RECORD1 and RECORD2) to the collection
const RESPONSE_TWO_ADDED = {
comment: "RESPONSE_TWO_ADDED",
@@ -440,25 +442,28 @@ add_task(function* test_check_signatures
[RESPONSE_COMPLETE_INITIAL],
// The next request is for the full collection sorted by id. This will be
// checked against the valid signature - so the sync should succeed.
"GET:/v1/buckets/blocklists/collections/certificates/records?_sort=id":
[RESPONSE_COMPLETE_INITIAL_SORTED_BY_ID]
};
registerHandlers(badSigGoodSigResponses);
+
+ startHistogram = getHistogramSnapshot(histogramId);
+
yield OneCRLBlocklistClient.maybeSync(5000, startTime);
- endHistogram = getHistogramSnapshot("SERVICES_SETTINGS_SUCCESS");
+ endHistogram = getHistogramSnapshot(histogramId);
// ensure that the failure count is incremented for a succesful sync with an
// (initial) bad signature - only SERVICES_SETTINGS_SYNC_SIG_FAIL should
// increment.
expectedIncrements = getDefaultIncrements(startHistogram);
- expectedIncrements[SERVICES_SETTINGS_SYNC_SIG_FAIL] = 1;
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_SIGNATURE_FAILURE] = 1;
checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
const badSigGoodOldResponses = {
// In this test, we deliberately serve a bad signature initially. The
// subsequent sitnature returned is a valid one for the three item
// collection.
"GET:/v1/buckets/blocklists/collections/certificates?":
[RESPONSE_META_BAD_SIG, RESPONSE_META_EMPTY_SIG],
@@ -490,30 +495,29 @@ add_task(function* test_check_signatures
"GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=4000":
[RESPONSE_EMPTY_NO_UPDATE],
// The next request is for the full collection sorted by id. This will be
// checked against the valid signature - so the sync should succeed.
"GET:/v1/buckets/blocklists/collections/certificates/records?_sort=id":
[RESPONSE_COMPLETE_INITIAL_SORTED_BY_ID]
};
- startHistogram = getHistogramSnapshot("SERVICES_SETTINGS_SUCCESS");
+ startHistogram = getHistogramSnapshot(histogramId);
registerHandlers(allBadSigResponses);
try {
yield OneCRLBlocklistClient.maybeSync(6000, startTime);
do_throw("Sync should fail (the signature is intentionally bad)");
} catch (e) {
yield checkRecordCount(2);
}
// Ensure that the failure is reflected in the accumulated telemetry:
- endHistogram = getHistogramSnapshot("SERVICES_SETTINGS_SUCCESS");
- expectedIncrements[SERVICES_SETTINGS_SYNC_SIG_FAIL] = 2;
- expectedIncrements[SERVICES_SETTINGS_SYNC_RETRY_SIG_FAIL] = 1;
- expectedIncrements[SERVICES_SETTINGS_SYNC_ONECRL_FAIL] = 1;
+ endHistogram = getHistogramSnapshot(histogramId);
+ expectedIncrements = getDefaultIncrements(startHistogram);
+ expectedIncrements[SERVICE_SETTINGS_UPDATE_SIGNATURE_RETRY_FAILURE] = 1;
checkHistogramIncrements(startHistogram, endHistogram, expectedIncrements);
});
function run_test() {
// ensure signatures are enforced
Services.prefs.setBoolPref(PREF_BLOCKLIST_ENFORCE_SIGNING, true);
// get a signature verifier to ensure nsNSSComponent is initialized
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8889,17 +8889,57 @@
"description": "Intercepted fetch sending back same Request object. File bugs in Core::DOM in case of a Telemetry regression."
},
"SERVICE_SETTINGS_POLLING_RESULT": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 5,
"alert_emails": ["seceng-telemetry@mozilla.com"],
"bug_numbers": [1254099],
- "description": "Services settings polling result information (0=Success, 1=Network error, 2=Server response error"
+ "description": "Services settings polling result information (0=Success, 1=Network error, 2=Server response error)"
+ },
+ "SERVICE_SETTINGS_UPDATE_BLOCKLISTS_ADDONS_RESULT": {
+ "expires_in_version": "never",
+ "kind": "enumerated",
+ "n_values": 20,
+ "alert_emails": ["seceng-telemetry@mozilla.com"],
+ "bug_numbers": [1254099],
+ "description": "Update of addons blocklist from settings server result (0=Success, 1=Unknown failure, 2=Synchronization failure, 3=Conflict error, 4=Signature verification failure, 5=Signature recovery failure, 6=Application failure)"
+ },
+ "SERVICE_SETTINGS_UPDATE_BLOCKLISTS_CERTIFICATES_RESULT": {
+ "expires_in_version": "never",
+ "kind": "enumerated",
+ "n_values": 20,
+ "alert_emails": ["seceng-telemetry@mozilla.com"],
+ "bug_numbers": [1254099],
+ "description": "Update of OneCRL blocklist from settings server result (0=Success, 1=Unknown failure, 2=Synchronization failure, 3=Conflict error, 4=Signature verification failure, 5=Signature recovery failure, 6=Application failure)"
+ },
+ "SERVICE_SETTINGS_UPDATE_BLOCKLISTS_GFX_RESULT": {
+ "expires_in_version": "never",
+ "kind": "enumerated",
+ "n_values": 20,
+ "alert_emails": ["seceng-telemetry@mozilla.com"],
+ "bug_numbers": [1254099],
+ "description": "Update of GFX blocklist from settings server result (0=Success, 1=Unknown failure, 2=Synchronization failure, 3=Conflict error, 4=Signature verification failure, 5=Signature recovery failure, 6=Application failure)"
+ },
+ "SERVICE_SETTINGS_UPDATE_BLOCKLISTS_PLUGINS_RESULT": {
+ "expires_in_version": "never",
+ "kind": "enumerated",
+ "n_values": 20,
+ "alert_emails": ["seceng-telemetry@mozilla.com"],
+ "bug_numbers": [1254099],
+ "description": "Update of plugins blocklist from settings server result (0=Success, 1=Unknown failure, 2=Synchronization failure, 3=Conflict error, 4=Signature verification failure, 5=Signature recovery failure, 6=Application failure)"
+ },
+ "SERVICE_SETTINGS_UPDATE_PINNING_PINS_RESULT": {
+ "expires_in_version": "never",
+ "kind": "enumerated",
+ "n_values": 20,
+ "alert_emails": ["seceng-telemetry@mozilla.com"],
+ "bug_numbers": [1254099],
+ "description": "Update of certicates pinning from settings server result (0=Success, 1=Unknown failure, 2=Synchronization failure, 3=Conflict error, 4=Signature verification failure, 5=Signature recovery failure, 6=Application failure)"
},
"E10S_STATUS": {
"alert_emails": ["firefox-dev@mozilla.org"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 12,
"releaseChannelCollection": "opt-out",
"bug_numbers": [1241294],
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -620,25 +620,17 @@ Blocklist.prototype = {
if (!this._isBlocklistLoaded())
this._loadBlocklist();
// If kinto update is enabled, do the kinto update
if (gPref.getBoolPref(PREF_BLOCKLIST_UPDATE_ENABLED)) {
const updater =
Components.utils.import("resource://services-common/blocklist-updater.js",
{});
- updater.checkVersions().then(() => {
- Services.telemetry
- .getHistogramById("SERVICES_SETTINGS_SUCCESS")
- .add(SERVICES_SETTINGS_SYNC_OK);
- }).catch(() => {
- Services.telemetry
- .getHistogramById("SERVICES_SETTINGS_SUCCESS")
- .add(SERVICES_SETTINGS_SYNC_FAILED);
- });
+ updater.checkVersions();
}
},
onXMLLoad: Task.async(function*(aEvent) {
let request = aEvent.target;
try {
gCertUtils.checkCert(request.channel);
} catch (e) {