summaryrefslogtreecommitdiffstats
path: root/services/common/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'services/common/tests/unit')
-rw-r--r--services/common/tests/unit/test_blocklist_certificates.js224
-rw-r--r--services/common/tests/unit/test_blocklist_clients.js412
-rw-r--r--services/common/tests/unit/test_blocklist_signatures.js510
-rw-r--r--services/common/tests/unit/test_blocklist_updater.js173
-rw-r--r--services/common/tests/unit/test_kinto.js412
-rw-r--r--services/common/tests/unit/xpcshell.ini8
6 files changed, 0 insertions, 1739 deletions
diff --git a/services/common/tests/unit/test_blocklist_certificates.js b/services/common/tests/unit/test_blocklist_certificates.js
deleted file mode 100644
index e85970321..000000000
--- a/services/common/tests/unit/test_blocklist_certificates.js
+++ /dev/null
@@ -1,224 +0,0 @@
-const { Constructor: CC } = Components;
-
-Cu.import("resource://testing-common/httpd.js");
-
-const { OneCRLBlocklistClient } = Cu.import("resource://services-common/blocklist-clients.js");
-const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
-
-const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-
-let server;
-
-// set up what we need to make storage adapters
-const Kinto = loadKinto();
-const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
-const kintoFilename = "kinto.sqlite";
-
-let kintoClient;
-
-function do_get_kinto_collection(collectionName) {
- if (!kintoClient) {
- let config = {
- // Set the remote to be some server that will cause test failure when
- // hit since we should never hit the server directly, only via maybeSync()
- remote: "https://firefox.settings.services.mozilla.com/v1/",
- // Set up the adapter and bucket as normal
- adapter: FirefoxAdapter,
- bucket: "blocklists"
- };
- kintoClient = new Kinto(config);
- }
- return kintoClient.collection(collectionName);
-}
-
-// Some simple tests to demonstrate that the logic inside maybeSync works
-// correctly and that simple kinto operations are working as expected. There
-// are more tests for core Kinto.js (and its storage adapter) in the
-// xpcshell tests under /services/common
-add_task(function* test_something(){
- const configPath = "/v1/";
- const recordsPath = "/v1/buckets/blocklists/collections/certificates/records";
-
- Services.prefs.setCharPref("services.settings.server",
- `http://localhost:${server.identity.primaryPort}/v1`);
-
- // register a handler
- function handleResponse (request, response) {
- try {
- const sample = getSampleResponse(request, server.identity.primaryPort);
- if (!sample) {
- do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
- }
-
- response.setStatusLine(null, sample.status.status,
- sample.status.statusText);
- // send the headers
- for (let headerLine of sample.sampleHeaders) {
- let headerElements = headerLine.split(':');
- response.setHeader(headerElements[0], headerElements[1].trimLeft());
- }
- response.setHeader("Date", (new Date()).toUTCString());
-
- response.write(sample.responseBody);
- } catch (e) {
- do_print(e);
- }
- }
- server.registerPathHandler(configPath, handleResponse);
- server.registerPathHandler(recordsPath, handleResponse);
-
- // 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();
- 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
- collection = do_get_kinto_collection("certificates");
- yield collection.db.open();
- list = yield collection.list();
- do_check_eq(list.data.length, 3);
- yield collection.db.close();
-
- // Try to maybeSync with the current lastModified value - no connection
- // should be attempted.
- // Clear the kinto base pref so any connections will cause a test failure
- Services.prefs.clearUserPref("services.settings.server");
- yield OneCRLBlocklistClient.maybeSync(4000, Date.now());
-
- // Try again with a lastModified value at some point in the past
- yield OneCRLBlocklistClient.maybeSync(3000, Date.now());
-
- // Check the OneCRL check time pref is modified, even if the collection
- // hasn't changed
- Services.prefs.setIntPref("services.blocklist.onecrl.checked", 0);
- yield OneCRLBlocklistClient.maybeSync(3000, Date.now());
- let newValue = Services.prefs.getIntPref("services.blocklist.onecrl.checked");
- do_check_neq(newValue, 0);
-
- // Check that a sync completes even when there's bad data in the
- // collection. This will throw on fail, so just calling maybeSync is an
- // acceptible test.
- Services.prefs.setCharPref("services.settings.server",
- `http://localhost:${server.identity.primaryPort}/v1`);
- yield OneCRLBlocklistClient.maybeSync(5000, Date.now());
-});
-
-function run_test() {
- // Ensure that signature verification is disabled to prevent interference
- // with basic certificate sync tests
- Services.prefs.setBoolPref("services.blocklist.signing.enforced", false);
-
- // Set up an HTTP Server
- server = new HttpServer();
- server.start(-1);
-
- run_next_test();
-
- do_register_cleanup(function() {
- server.stop(() => { });
- });
-}
-
-// 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",
- "Access-Control-Allow-Origin: *",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress"
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": "null"
- },
- "GET:/v1/?": {
- "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: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"settings":{"batch_max_requests":25}, "url":`http://localhost:${port}/v1/`, "documentation":"https://kinto.readthedocs.org/", "version":"1.5.1", "commit":"cbc6f58", "hello":"kinto"})
- },
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"3000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "issuerName": "MEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHjAcBgNVBAMTFXRoYXd0ZSBFViBTU0wgQ0EgLSBHMw==",
- "serialNumber":"CrTHPEE6AZSfI3jysin2bA==",
- "id":"78cf8900-fdea-4ce5-f8fb-b78710617718",
- "last_modified":3000
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=3000": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"4000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "issuerName":"MFkxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKjAoBgNVBAMTIVN0YWF0IGRlciBOZWRlcmxhbmRlbiBPdmVyaGVpZCBDQQ",
- "serialNumber":"ATFpsA==",
- "id":"dabafde9-df4a-ddba-2548-748da04cc02c",
- "last_modified":4000
- },{
- "subject":"MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5",
- "pubKeyHash":"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=",
- "id":"dabafde9-df4a-ddba-2548-748da04cc02d",
- "last_modified":4000
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=4000": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"5000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "issuerName":"not a base64 encoded issuer",
- "serialNumber":"not a base64 encoded serial",
- "id":"dabafde9-df4a-ddba-2548-748da04cc02e",
- "last_modified":5000
- },{
- "subject":"not a base64 encoded subject",
- "pubKeyHash":"not a base64 encoded pubKeyHash",
- "id":"dabafde9-df4a-ddba-2548-748da04cc02f",
- "last_modified":5000
- },{
- "subject":"MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5",
- "pubKeyHash":"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=",
- "id":"dabafde9-df4a-ddba-2548-748da04cc02g",
- "last_modified":5000
- }]})
- }
- };
- return responses[`${req.method}:${req.path}?${req.queryString}`] ||
- responses[req.method];
-
-}
diff --git a/services/common/tests/unit/test_blocklist_clients.js b/services/common/tests/unit/test_blocklist_clients.js
deleted file mode 100644
index 121fac926..000000000
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ /dev/null
@@ -1,412 +0,0 @@
-const { Constructor: CC } = Components;
-
-const KEY_PROFILEDIR = "ProfD";
-
-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 { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
-const BlocklistClients = Cu.import("resource://services-common/blocklist-clients.js");
-
-const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-
-const gBlocklistClients = [
- {client: BlocklistClients.AddonBlocklistClient, filename: BlocklistClients.FILENAME_ADDONS_JSON, testData: ["i808","i720", "i539"]},
- {client: BlocklistClients.PluginBlocklistClient, filename: BlocklistClients.FILENAME_PLUGINS_JSON, testData: ["p1044","p32","p28"]},
- {client: BlocklistClients.GfxBlocklistClient, filename: BlocklistClients.FILENAME_GFX_JSON, testData: ["g204","g200","g36"]},
-];
-
-
-let server;
-let kintoClient;
-
-function kintoCollection(collectionName) {
- if (!kintoClient) {
- const Kinto = loadKinto();
- const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
- const config = {
- // Set the remote to be some server that will cause test failure when
- // hit since we should never hit the server directly, only via maybeSync()
- remote: "https://firefox.settings.services.mozilla.com/v1/",
- adapter: FirefoxAdapter,
- bucket: "blocklists"
- };
- kintoClient = new Kinto(config);
- }
- return kintoClient.collection(collectionName);
-}
-
-function* readJSON(filepath) {
- const binaryData = yield OS.File.read(filepath);
- const textData = (new TextDecoder()).decode(binaryData);
- return Promise.resolve(JSON.parse(textData));
-}
-
-function* clear_state() {
- for (let {client} of gBlocklistClients) {
- // Remove last server times.
- Services.prefs.clearUserPref(client.lastCheckTimePref);
-
- // Clear local DB.
- const collection = kintoCollection(client.collectionName);
- try {
- yield collection.db.open();
- yield collection.clear();
- } finally {
- yield collection.db.close();
- }
- }
-
- // Remove profile data.
- for (let {filename} of gBlocklistClients) {
- const blocklist = FileUtils.getFile(KEY_PROFILEDIR, [filename]);
- if (blocklist.exists()) {
- blocklist.remove(true);
- }
- }
-}
-
-
-function run_test() {
- // Set up an HTTP Server
- server = new HttpServer();
- server.start(-1);
-
- // Point the blocklist clients to use this local HTTP server.
- Services.prefs.setCharPref("services.settings.server",
- `http://localhost:${server.identity.primaryPort}/v1`);
-
- // Setup server fake responses.
- function handleResponse(request, response) {
- try {
- const sample = getSampleResponse(request, server.identity.primaryPort);
- if (!sample) {
- do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
- }
-
- response.setStatusLine(null, sample.status.status,
- sample.status.statusText);
- // send the headers
- for (let headerLine of sample.sampleHeaders) {
- let headerElements = headerLine.split(':');
- response.setHeader(headerElements[0], headerElements[1].trimLeft());
- }
- response.setHeader("Date", (new Date()).toUTCString());
-
- response.write(sample.responseBody);
- response.finish();
- } catch (e) {
- do_print(e);
- }
- }
- const configPath = "/v1/";
- const addonsRecordsPath = "/v1/buckets/blocklists/collections/addons/records";
- const gfxRecordsPath = "/v1/buckets/blocklists/collections/gfx/records";
- const pluginsRecordsPath = "/v1/buckets/blocklists/collections/plugins/records";
- server.registerPathHandler(configPath, handleResponse);
- server.registerPathHandler(addonsRecordsPath, handleResponse);
- server.registerPathHandler(gfxRecordsPath, handleResponse);
- server.registerPathHandler(pluginsRecordsPath, handleResponse);
-
-
- run_next_test();
-
- do_register_cleanup(function() {
- server.stop(() => { });
- });
-}
-
-add_task(function* test_records_obtained_from_server_are_stored_in_db(){
- for (let {client} of gBlocklistClients) {
- // Test an empty db populates
- let result = yield client.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 = kintoCollection(client.collectionName);
- yield collection.db.open();
- let list = yield collection.list();
- equal(list.data.length, 1);
- yield collection.db.close();
- }
-});
-add_task(clear_state);
-
-add_task(function* test_list_is_written_to_file_in_profile(){
- for (let {client, filename, testData} of gBlocklistClients) {
- const profFile = FileUtils.getFile(KEY_PROFILEDIR, [filename]);
- strictEqual(profFile.exists(), false);
-
- let result = yield client.maybeSync(2000, Date.now());
-
- strictEqual(profFile.exists(), true);
- const content = yield readJSON(profFile.path);
- equal(content.data[0].blockID, testData[testData.length - 1]);
- }
-});
-add_task(clear_state);
-
-add_task(function* test_current_server_time_is_saved_in_pref(){
- for (let {client} of gBlocklistClients) {
- const before = Services.prefs.getIntPref(client.lastCheckTimePref);
- const serverTime = Date.now();
- yield client.maybeSync(2000, serverTime);
- const after = Services.prefs.getIntPref(client.lastCheckTimePref);
- equal(after, Math.round(serverTime / 1000));
- }
-});
-add_task(clear_state);
-
-add_task(function* test_update_json_file_when_addons_has_changes(){
- for (let {client, filename, testData} of gBlocklistClients) {
- yield client.maybeSync(2000, Date.now() - 1000);
- const before = Services.prefs.getIntPref(client.lastCheckTimePref);
- const profFile = FileUtils.getFile(KEY_PROFILEDIR, [filename]);
- const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000;
- const serverTime = Date.now();
-
- yield client.maybeSync(3001, serverTime);
-
- // File was updated.
- notEqual(fileLastModified, profFile.lastModifiedTime);
- const content = yield readJSON(profFile.path);
- deepEqual(content.data.map((r) => r.blockID), testData);
- // Server time was updated.
- const after = Services.prefs.getIntPref(client.lastCheckTimePref);
- equal(after, Math.round(serverTime / 1000));
- }
-});
-add_task(clear_state);
-
-add_task(function* test_sends_reload_message_when_blocklist_has_changes(){
- for (let {client, filename} of gBlocklistClients) {
- let received = yield new Promise((resolve, reject) => {
- Services.ppmm.addMessageListener("Blocklist:reload-from-disk", {
- receiveMessage(aMsg) { resolve(aMsg) }
- });
-
- client.maybeSync(2000, Date.now() - 1000);
- });
-
- equal(received.data.filename, filename);
- }
-});
-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 before = Services.prefs.getIntPref(client.lastCheckTimePref);
- const profFile = FileUtils.getFile(KEY_PROFILEDIR, [filename]);
- const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000;
- const serverTime = Date.now();
-
- 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));
- }
-});
-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",
- "Access-Control-Allow-Origin: *",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress"
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": "null"
- },
- "GET:/v1/?": {
- "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: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"settings":{"batch_max_requests":25}, "url":`http://localhost:${port}/v1/`, "documentation":"https://kinto.readthedocs.org/", "version":"1.5.1", "commit":"cbc6f58", "hello":"kinto"})
- },
- "GET:/v1/buckets/blocklists/collections/addons/records?_sort=-last_modified": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"3000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "prefs": [],
- "blockID": "i539",
- "last_modified": 3000,
- "versionRange": [{
- "targetApplication": [],
- "maxVersion": "*",
- "minVersion": "0",
- "severity": "1"
- }],
- "guid": "ScorpionSaver@jetpack",
- "id": "9d500963-d80e-3a91-6e74-66f3811b99cc"
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/plugins/records?_sort=-last_modified": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"3000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "matchFilename": "NPFFAddOn.dll",
- "blockID": "p28",
- "id": "7b1e0b3c-e390-a817-11b6-a6887f65f56e",
- "last_modified": 3000,
- "versionRange": []
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/gfx/records?_sort=-last_modified": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"3000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "driverVersionComparator": "LESS_THAN_OR_EQUAL",
- "driverVersion": "8.17.12.5896",
- "vendor": "0x10de",
- "blockID": "g36",
- "feature": "DIRECT3D_9_LAYERS",
- "devices": ["0x0a6c"],
- "featureStatus": "BLOCKED_DRIVER_VERSION",
- "last_modified": 3000,
- "os": "WINNT 6.1",
- "id": "3f947f16-37c2-4e96-d356-78b26363729b"
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/addons/records?_sort=-last_modified&_since=3000": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"4000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "prefs": [],
- "blockID": "i808",
- "last_modified": 4000,
- "versionRange": [{
- "targetApplication": [],
- "maxVersion": "*",
- "minVersion": "0",
- "severity": "3"
- }],
- "guid": "{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}",
- "id": "9ccfac91-e463-c30c-f0bd-14143794a8dd"
- }, {
- "prefs": ["browser.startup.homepage"],
- "blockID": "i720",
- "last_modified": 3500,
- "versionRange": [{
- "targetApplication": [],
- "maxVersion": "*",
- "minVersion": "0",
- "severity": "1"
- }],
- "guid": "FXqG@xeeR.net",
- "id": "cf9b3129-a97e-dbd7-9525-a8575ac03c25"
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/plugins/records?_sort=-last_modified&_since=3000": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"4000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "infoURL": "https://get.adobe.com/flashplayer/",
- "blockID": "p1044",
- "matchFilename": "libflashplayer\\.so",
- "last_modified": 4000,
- "versionRange": [{
- "targetApplication": [],
- "minVersion": "11.2.202.509",
- "maxVersion": "11.2.202.539",
- "severity": "0",
- "vulnerabilityStatus": "1"
- }],
- "os": "Linux",
- "id": "aabad965-e556-ffe7-4191-074f5dee3df3"
- }, {
- "matchFilename": "npViewpoint.dll",
- "blockID": "p32",
- "id": "1f48af42-c508-b8ef-b8d5-609d48e4f6c9",
- "last_modified": 3500,
- "versionRange": [{
- "targetApplication": [{
- "minVersion": "3.0",
- "guid": "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
- "maxVersion": "*"
- }]
- }]
- }]})
- },
- "GET:/v1/buckets/blocklists/collections/gfx/records?_sort=-last_modified&_since=3000": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"4000\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{
- "vendor": "0x8086",
- "blockID": "g204",
- "feature": "WEBGL_MSAA",
- "devices": [],
- "id": "c96bca82-e6bd-044d-14c4-9c1d67e9283a",
- "last_modified": 4000,
- "os": "Darwin 10",
- "featureStatus": "BLOCKED_DEVICE"
- }, {
- "vendor": "0x10de",
- "blockID": "g200",
- "feature": "WEBGL_MSAA",
- "devices": [],
- "id": "c3a15ba9-e0e2-421f-e399-c995e5b8d14e",
- "last_modified": 3500,
- "os": "Darwin 11",
- "featureStatus": "BLOCKED_DEVICE"
- }]})
- }
- };
- return responses[`${req.method}:${req.path}?${req.queryString}`] ||
- responses[req.method];
-
-}
diff --git a/services/common/tests/unit/test_blocklist_signatures.js b/services/common/tests/unit/test_blocklist_signatures.js
deleted file mode 100644
index b2ee1019a..000000000
--- a/services/common/tests/unit/test_blocklist_signatures.js
+++ /dev/null
@@ -1,510 +0,0 @@
-"use strict";
-
-Cu.import("resource://services-common/blocklist-updater.js");
-Cu.import("resource://testing-common/httpd.js");
-
-const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
-const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
-const { OneCRLBlocklistClient } = Cu.import("resource://services-common/blocklist-clients.js");
-
-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 CERT_DIR = "test_blocklist_signatures/";
-const CHAIN_FILES =
- ["collection_signing_ee.pem",
- "collection_signing_int.pem",
- "collection_signing_root.pem"];
-
-function getFileData(file) {
- const stream = Cc["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Ci.nsIFileInputStream);
- stream.init(file, -1, 0, 0);
- const data = NetUtil.readInputStreamToString(stream, stream.available());
- stream.close();
- return data;
-}
-
-function setRoot() {
- const filename = CERT_DIR + CHAIN_FILES[0];
-
- const certFile = do_get_file(filename, false);
- const b64cert = getFileData(certFile)
- .replace(/-----BEGIN CERTIFICATE-----/, "")
- .replace(/-----END CERTIFICATE-----/, "")
- .replace(/[\r\n]/g, "");
- const certdb = Cc["@mozilla.org/security/x509certdb;1"]
- .getService(Ci.nsIX509CertDB);
- const cert = certdb.constructX509FromBase64(b64cert);
- Services.prefs.setCharPref(PREF_SIGNATURE_ROOT, cert.sha256Fingerprint);
-}
-
-function getCertChain() {
- const chain = [];
- for (let file of CHAIN_FILES) {
- chain.push(getFileData(do_get_file(CERT_DIR + file)));
- }
- return chain.join("\n");
-}
-
-function* checkRecordCount(count) {
- // open the collection manually
- const base = Services.prefs.getCharPref(PREF_SETTINGS_SERVER);
- const bucket = Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET);
- const collectionName =
- Services.prefs.getCharPref(PREF_BLOCKLIST_ONECRL_COLLECTION);
-
- const Kinto = loadKinto();
-
- const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
-
- const config = {
- remote: base,
- bucket: bucket,
- adapter: FirefoxAdapter,
- };
-
- const db = new Kinto(config);
- const collection = db.collection(collectionName);
-
- yield collection.db.open();
-
- // Check we have the expected number of records
- let records = yield collection.list();
- do_check_eq(count, records.data.length);
-
- // Close the collection so the test can exit cleanly
- yield collection.db.close();
-}
-
-// Check to ensure maybeSync is called with correct values when a changes
-// document contains information on when a collection was last modified
-add_task(function* test_check_signatures(){
- const port = server.identity.primaryPort;
-
- // a response to give the client when the cert chain is expected
- function makeMetaResponseBody(lastModified, signature) {
- return {
- data: {
- id: "certificates",
- last_modified: lastModified,
- signature: {
- x5u: `http://localhost:${port}/test_blocklist_signatures/test_cert_chain.pem`,
- public_key: "fake",
- "content-signature": `x5u=http://localhost:${port}/test_blocklist_signatures/test_cert_chain.pem;p384ecdsa=${signature}`,
- signature_encoding: "rs_base64url",
- signature: signature,
- hash_algorithm: "sha384",
- ref: "1yryrnmzou5rf31ou80znpnq8n"
- }
- }
- };
- }
-
- function makeMetaResponse(eTag, body, comment) {
- return {
- comment: comment,
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- `ETag: \"${eTag}\"`
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify(body)
- };
- }
-
- function registerHandlers(responses){
- function handleResponse (serverTimeMillis, request, response) {
- const key = `${request.method}:${request.path}?${request.queryString}`;
- const available = responses[key];
- const sampled = available.length > 1 ? available.shift() : available[0];
-
- if (!sampled) {
- do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
- }
-
- response.setStatusLine(null, sampled.status.status,
- sampled.status.statusText);
- // send the headers
- for (let headerLine of sampled.sampleHeaders) {
- let headerElements = headerLine.split(':');
- response.setHeader(headerElements[0], headerElements[1].trimLeft());
- }
-
- // set the server date
- response.setHeader("Date", (new Date(serverTimeMillis)).toUTCString());
-
- response.write(sampled.responseBody);
- }
-
- for (let key of Object.keys(responses)) {
- const keyParts = key.split(":");
- const method = keyParts[0];
- const valueParts = keyParts[1].split("?");
- const path = valueParts[0];
-
- server.registerPathHandler(path, handleResponse.bind(null, 2000));
- }
- }
-
- // First, perform a signature verification with known data and signature
- // to ensure things are working correctly
- let verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
- .createInstance(Ci.nsIContentSignatureVerifier);
-
- const emptyData = '[]';
- const emptySignature = "p384ecdsa=zbugm2FDitsHwk5-IWsas1PpWwY29f0Fg5ZHeqD8fzep7AVl2vfcaHA7LdmCZ28qZLOioGKvco3qT117Q4-HlqFTJM7COHzxGyU2MMJ0ZTnhJrPOC1fP3cVQjU1PTWi9";
- const name = "onecrl.content-signature.mozilla.org";
- ok(verifier.verifyContentSignature(emptyData, emptySignature,
- getCertChain(), name));
-
- verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
- .createInstance(Ci.nsIContentSignatureVerifier);
-
- const collectionData = '[{"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1155145","created":"2016-01-18T14:43:37Z","name":"GlobalSign certs","who":".","why":"."},"enabled":true,"id":"97fbf7c4-3ef2-f54f-0029-1ba6540c63ea","issuerName":"MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==","last_modified":2000,"serialNumber":"BAAAAAABA/A35EU="},{"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1155145","created":"2016-01-18T14:48:11Z","name":"GlobalSign certs","who":".","why":"."},"enabled":true,"id":"e3bd531e-1ee4-7407-27ce-6fdc9cecbbdc","issuerName":"MIGBMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTElMCMGA1UECxMcUHJpbWFyeSBPYmplY3QgUHVibGlzaGluZyBDQTEwMC4GA1UEAxMnR2xvYmFsU2lnbiBQcmltYXJ5IE9iamVjdCBQdWJsaXNoaW5nIENB","last_modified":3000,"serialNumber":"BAAAAAABI54PryQ="}]';
- const collectionSignature = "p384ecdsa=f4pA2tYM5jQgWY6YUmhUwQiBLj6QO5sHLD_5MqLePz95qv-7cNCuQoZnPQwxoptDtW8hcWH3kLb0quR7SB-r82gkpR9POVofsnWJRA-ETb0BcIz6VvI3pDT49ZLlNg3p";
-
- ok(verifier.verifyContentSignature(collectionData, collectionSignature, getCertChain(), name));
-
- // set up prefs so the kinto updater talks to the test server
- Services.prefs.setCharPref(PREF_SETTINGS_SERVER,
- `http://localhost:${server.identity.primaryPort}/v1`);
-
- // Set up some data we need for our test
- let startTime = Date.now();
-
- // These are records we'll use in the test collections
- const RECORD1 = {
- details: {
- bug: "https://bugzilla.mozilla.org/show_bug.cgi?id=1155145",
- created: "2016-01-18T14:43:37Z",
- name: "GlobalSign certs",
- who: ".",
- why: "."
- },
- enabled: true,
- id: "97fbf7c4-3ef2-f54f-0029-1ba6540c63ea",
- issuerName: "MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==",
- last_modified: 2000,
- serialNumber: "BAAAAAABA/A35EU="
- };
-
- const RECORD2 = {
- details: {
- bug: "https://bugzilla.mozilla.org/show_bug.cgi?id=1155145",
- created: "2016-01-18T14:48:11Z",
- name: "GlobalSign certs",
- who: ".",
- why: "."
- },
- enabled: true,
- id: "e3bd531e-1ee4-7407-27ce-6fdc9cecbbdc",
- issuerName: "MIGBMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTElMCMGA1UECxMcUHJpbWFyeSBPYmplY3QgUHVibGlzaGluZyBDQTEwMC4GA1UEAxMnR2xvYmFsU2lnbiBQcmltYXJ5IE9iamVjdCBQdWJsaXNoaW5nIENB",
- last_modified: 3000,
- serialNumber: "BAAAAAABI54PryQ="
- };
-
- const RECORD3 = {
- details: {
- bug: "https://bugzilla.mozilla.org/show_bug.cgi?id=1155145",
- created: "2016-01-18T14:48:11Z",
- name: "GlobalSign certs",
- who: ".",
- why: "."
- },
- enabled: true,
- id: "c7c49b69-a4ab-418e-92a9-e1961459aa7f",
- issuerName: "MIGBMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTElMCMGA1UECxMcUHJpbWFyeSBPYmplY3QgUHVibGlzaGluZyBDQTEwMC4GA1UEAxMnR2xvYmFsU2lnbiBQcmltYXJ5IE9iamVjdCBQdWJsaXNoaW5nIENB",
- last_modified: 4000,
- serialNumber: "BAAAAAABI54PryQ="
- };
-
- const RECORD1_DELETION = {
- deleted: true,
- enabled: true,
- id: "97fbf7c4-3ef2-f54f-0029-1ba6540c63ea",
- last_modified: 3500,
- };
-
- // Check that a signature on an empty collection is OK
- // We need to set up paths on the HTTP server to return specific data from
- // specific paths for each test. Here we prepare data for each response.
-
- // A cert chain response (this the cert chain that contains the signing
- // cert, the root and any intermediates in between). This is used in each
- // sync.
- const RESPONSE_CERT_CHAIN = {
- comment: "RESPONSE_CERT_CHAIN",
- sampleHeaders: [
- "Content-Type: text/plain; charset=UTF-8"
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: getCertChain()
- };
-
- // A server settings response. This is used in each sync.
- const RESPONSE_SERVER_SETTINGS = {
- comment: "RESPONSE_SERVER_SETTINGS",
- 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: 200, statusText: "OK"},
- responseBody: JSON.stringify({"settings":{"batch_max_requests":25}, "url":`http://localhost:${port}/v1/`, "documentation":"https://kinto.readthedocs.org/", "version":"1.5.1", "commit":"cbc6f58", "hello":"kinto"})
- };
-
- // This is the initial, empty state of the collection. This is only used
- // for the first sync.
- const RESPONSE_EMPTY_INITIAL = {
- comment: "RESPONSE_EMPTY_INITIAL",
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"1000\""
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify({"data": []})
- };
-
- const RESPONSE_BODY_META_EMPTY_SIG = makeMetaResponseBody(1000,
- "vxuAg5rDCB-1pul4a91vqSBQRXJG_j7WOYUTswxRSMltdYmbhLRH8R8brQ9YKuNDF56F-w6pn4HWxb076qgKPwgcEBtUeZAO_RtaHXRkRUUgVzAr86yQL4-aJTbv3D6u");
-
- // The collection metadata containing the signature for the empty
- // collection.
- const RESPONSE_META_EMPTY_SIG =
- makeMetaResponse(1000, RESPONSE_BODY_META_EMPTY_SIG,
- "RESPONSE_META_EMPTY_SIG");
-
- // Here, we map request method and path to the available responses
- const emptyCollectionResponses = {
- "GET:/test_blocklist_signatures/test_cert_chain.pem?":[RESPONSE_CERT_CHAIN],
- "GET:/v1/?": [RESPONSE_SERVER_SETTINGS],
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified":
- [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);
-
- // 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);
-
- // 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",
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"3000\""
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify({"data": [RECORD2, RECORD1]})
- };
-
- const RESPONSE_BODY_META_TWO_ITEMS_SIG = makeMetaResponseBody(3000,
- "dwhJeypadNIyzGj3QdI0KMRTPnHhFPF_j73mNrsPAHKMW46S2Ftf4BzsPMvPMB8h0TjDus13wo_R4l432DHe7tYyMIWXY0PBeMcoe5BREhFIxMxTsh9eGVXBD1e3UwRy");
-
- // A signature response for the collection containg RECORD1 and RECORD2
- const RESPONSE_META_TWO_ITEMS_SIG =
- makeMetaResponse(3000, RESPONSE_BODY_META_TWO_ITEMS_SIG,
- "RESPONSE_META_TWO_ITEMS_SIG");
-
- const twoItemsResponses = {
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=1000":
- [RESPONSE_TWO_ADDED],
- "GET:/v1/buckets/blocklists/collections/certificates?":
- [RESPONSE_META_TWO_ITEMS_SIG]
- };
- registerHandlers(twoItemsResponses);
- yield OneCRLBlocklistClient.maybeSync(3000, startTime);
-
- // Check the collection with one addition and one removal has a valid
- // signature
-
- // Remove RECORD1, add RECORD3
- const RESPONSE_ONE_ADDED_ONE_REMOVED = {
- comment: "RESPONSE_ONE_ADDED_ONE_REMOVED ",
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"4000\""
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify({"data": [RECORD3, RECORD1_DELETION]})
- };
-
- const RESPONSE_BODY_META_THREE_ITEMS_SIG = makeMetaResponseBody(4000,
- "MIEmNghKnkz12UodAAIc3q_Y4a3IJJ7GhHF4JYNYmm8avAGyPM9fYU7NzVo94pzjotG7vmtiYuHyIX2rTHTbT587w0LdRWxipgFd_PC1mHiwUyjFYNqBBG-kifYk7kEw");
-
- // signature response for the collection containing RECORD2 and RECORD3
- const RESPONSE_META_THREE_ITEMS_SIG =
- makeMetaResponse(4000, RESPONSE_BODY_META_THREE_ITEMS_SIG,
- "RESPONSE_META_THREE_ITEMS_SIG");
-
- const oneAddedOneRemovedResponses = {
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=3000":
- [RESPONSE_ONE_ADDED_ONE_REMOVED],
- "GET:/v1/buckets/blocklists/collections/certificates?":
- [RESPONSE_META_THREE_ITEMS_SIG]
- };
- registerHandlers(oneAddedOneRemovedResponses);
- yield OneCRLBlocklistClient.maybeSync(4000, startTime);
-
- // Check the signature is still valid with no operation (no changes)
-
- // Leave the collection unchanged
- const RESPONSE_EMPTY_NO_UPDATE = {
- comment: "RESPONSE_EMPTY_NO_UPDATE ",
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"4000\""
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify({"data": []})
- };
-
- const noOpResponses = {
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=4000":
- [RESPONSE_EMPTY_NO_UPDATE],
- "GET:/v1/buckets/blocklists/collections/certificates?":
- [RESPONSE_META_THREE_ITEMS_SIG]
- };
- registerHandlers(noOpResponses);
- yield OneCRLBlocklistClient.maybeSync(4100, startTime);
-
- // Check the collection is reset when the signature is invalid
-
- // Prepare a (deliberately) bad signature to check the collection state is
- // reset if something is inconsistent
- const RESPONSE_COMPLETE_INITIAL = {
- comment: "RESPONSE_COMPLETE_INITIAL ",
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"4000\""
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify({"data": [RECORD2, RECORD3]})
- };
-
- const RESPONSE_COMPLETE_INITIAL_SORTED_BY_ID = {
- comment: "RESPONSE_COMPLETE_INITIAL ",
- sampleHeaders: [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"4000\""
- ],
- status: {status: 200, statusText: "OK"},
- responseBody: JSON.stringify({"data": [RECORD3, RECORD2]})
- };
-
- const RESPONSE_BODY_META_BAD_SIG = makeMetaResponseBody(4000,
- "aW52YWxpZCBzaWduYXR1cmUK");
-
- const RESPONSE_META_BAD_SIG =
- makeMetaResponse(4000, RESPONSE_BODY_META_BAD_SIG, "RESPONSE_META_BAD_SIG");
-
- const badSigGoodSigResponses = {
- // In this test, we deliberately serve a bad signature initially. The
- // subsequent signature returned is a valid one for the three item
- // collection.
- "GET:/v1/buckets/blocklists/collections/certificates?":
- [RESPONSE_META_BAD_SIG, RESPONSE_META_THREE_ITEMS_SIG],
- // The first collection state is the three item collection (since
- // there's a sync with no updates) - but, since the signature is wrong,
- // another request will be made...
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified&_since=4000":
- [RESPONSE_EMPTY_NO_UPDATE],
- // The next request is for the full collection. This will be checked
- // against the valid signature - so the sync should succeed.
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=-last_modified":
- [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);
- yield OneCRLBlocklistClient.maybeSync(5000, startTime);
-
- 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],
- // The first collection state is the current state (since there's no update
- // - but, since the signature is wrong, another request will be made)
- "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 and last_modified times will be
- // compared. Sync should fail, even though the signature is good,
- // because the local collection is newer.
- "GET:/v1/buckets/blocklists/collections/certificates/records?_sort=id":
- [RESPONSE_EMPTY_INITIAL],
- };
-
- // ensure our collection hasn't been replaced with an older, empty one
- yield checkRecordCount(2);
-
- registerHandlers(badSigGoodOldResponses);
- yield OneCRLBlocklistClient.maybeSync(5000, startTime);
-
- const allBadSigResponses = {
- // In this test, we deliberately serve only a bad signature.
- "GET:/v1/buckets/blocklists/collections/certificates?":
- [RESPONSE_META_BAD_SIG],
- // The first collection state is the three item collection (since
- // there's a sync with no updates) - but, since the signature is wrong,
- // another request will be made...
- "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]
- };
-
- registerHandlers(allBadSigResponses);
- try {
- yield OneCRLBlocklistClient.maybeSync(6000, startTime);
- do_throw("Sync should fail (the signature is intentionally bad)");
- } catch (e) {
- yield checkRecordCount(2);
- }
-});
-
-function run_test() {
- // ensure signatures are enforced
- Services.prefs.setBoolPref(PREF_BLOCKLIST_ENFORCE_SIGNING, true);
-
- // get a signature verifier to ensure nsNSSComponent is initialized
- Cc["@mozilla.org/security/contentsignatureverifier;1"]
- .createInstance(Ci.nsIContentSignatureVerifier);
-
- // set the content signing root to our test root
- setRoot();
-
- // Set up an HTTP Server
- server = new HttpServer();
- server.start(-1);
-
- run_next_test();
-
- do_register_cleanup(function() {
- server.stop(function() { });
- });
-}
-
-
diff --git a/services/common/tests/unit/test_blocklist_updater.js b/services/common/tests/unit/test_blocklist_updater.js
deleted file mode 100644
index 1b71c194a..000000000
--- a/services/common/tests/unit/test_blocklist_updater.js
+++ /dev/null
@@ -1,173 +0,0 @@
-Cu.import("resource://testing-common/httpd.js");
-
-var server;
-
-const PREF_SETTINGS_SERVER = "services.settings.server";
-const PREF_LAST_UPDATE = "services.blocklist.last_update_seconds";
-const PREF_LAST_ETAG = "services.blocklist.last_etag";
-const PREF_CLOCK_SKEW_SECONDS = "services.blocklist.clock_skew_seconds";
-
-// Check to ensure maybeSync is called with correct values when a changes
-// document contains information on when a collection was last modified
-add_task(function* test_check_maybeSync(){
- const changesPath = "/v1/buckets/monitor/collections/changes/records";
-
- // register a handler
- function handleResponse (serverTimeMillis, request, response) {
- try {
- const sampled = getSampleResponse(request, server.identity.primaryPort);
- if (!sampled) {
- do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
- }
-
- response.setStatusLine(null, sampled.status.status,
- sampled.status.statusText);
- // send the headers
- for (let headerLine of sampled.sampleHeaders) {
- let headerElements = headerLine.split(':');
- response.setHeader(headerElements[0], headerElements[1].trimLeft());
- }
-
- // set the server date
- response.setHeader("Date", (new Date(serverTimeMillis)).toUTCString());
-
- response.write(sampled.responseBody);
- } catch (e) {
- dump(`${e}\n`);
- }
- }
-
- server.registerPathHandler(changesPath, handleResponse.bind(null, 2000));
-
- // set up prefs so the kinto updater talks to the test server
- Services.prefs.setCharPref(PREF_SETTINGS_SERVER,
- `http://localhost:${server.identity.primaryPort}/v1`);
-
- // set some initial values so we can check these are updated appropriately
- Services.prefs.setIntPref(PREF_LAST_UPDATE, 0);
- Services.prefs.setIntPref(PREF_CLOCK_SKEW_SECONDS, 0);
- Services.prefs.clearUserPref(PREF_LAST_ETAG);
-
-
- let startTime = Date.now();
-
- let updater = Cu.import("resource://services-common/blocklist-updater.js");
-
- let syncPromise = new Promise(function(resolve, reject) {
- // add a test kinto client that will respond to lastModified information
- // for a collection called 'test-collection'
- updater.addTestBlocklistClient("test-collection", {
- maybeSync(lastModified, serverTime) {
- do_check_eq(lastModified, 1000);
- do_check_eq(serverTime, 2000);
- resolve();
- }
- });
- updater.checkVersions();
- });
-
- // ensure we get the maybeSync call
- yield syncPromise;
-
- // check the last_update is updated
- do_check_eq(Services.prefs.getIntPref(PREF_LAST_UPDATE), 2);
-
- // How does the clock difference look?
- let endTime = Date.now();
- let clockDifference = Services.prefs.getIntPref(PREF_CLOCK_SKEW_SECONDS);
- // we previously set the serverTime to 2 (seconds past epoch)
- do_check_true(clockDifference <= endTime / 1000
- && clockDifference >= Math.floor(startTime / 1000) - 2);
- // Last timestamp was saved. An ETag header value is a quoted string.
- let lastEtag = Services.prefs.getCharPref(PREF_LAST_ETAG);
- do_check_eq(lastEtag, "\"1100\"");
-
- // Simulate a poll with up-to-date collection.
- Services.prefs.setIntPref(PREF_LAST_UPDATE, 0);
- // If server has no change, a 304 is received, maybeSync() is not called.
- updater.addTestBlocklistClient("test-collection", {
- maybeSync: () => {throw new Error("Should not be called");}
- });
- yield updater.checkVersions();
- // Last update is overwritten
- do_check_eq(Services.prefs.getIntPref(PREF_LAST_UPDATE), 2);
-
-
- // Simulate a server error.
- function simulateErrorResponse (request, response) {
- response.setHeader("Date", (new Date(3000)).toUTCString());
- response.setHeader("Content-Type", "application/json; charset=UTF-8");
- response.write(JSON.stringify({
- code: 503,
- errno: 999,
- error: "Service Unavailable",
- }));
- response.setStatusLine(null, 503, "Service Unavailable");
- }
- server.registerPathHandler(changesPath, simulateErrorResponse);
- // checkVersions() fails with adequate error.
- let error;
- try {
- yield updater.checkVersions();
- } catch (e) {
- error = e;
- }
- do_check_eq(error.message, "Polling for changes failed.");
- // When an error occurs, last update was not overwritten (see Date header above).
- do_check_eq(Services.prefs.getIntPref(PREF_LAST_UPDATE), 2);
-
- // check negative clock skew times
-
- // set to a time in the future
- server.registerPathHandler(changesPath, handleResponse.bind(null, Date.now() + 10000));
-
- yield updater.checkVersions();
-
- clockDifference = Services.prefs.getIntPref(PREF_CLOCK_SKEW_SECONDS);
- // we previously set the serverTime to Date.now() + 10000 ms past epoch
- do_check_true(clockDifference <= 0 && clockDifference >= -10);
-});
-
-function run_test() {
- // Set up an HTTP Server
- server = new HttpServer();
- server.start(-1);
-
- run_next_test();
-
- do_register_cleanup(function() {
- server.stop(function() { });
- });
-}
-
-// get a response for a given request from sample data
-function getSampleResponse(req, port) {
- const responses = {
- "GET:/v1/buckets/monitor/collections/changes/records?": {
- "sampleHeaders": [
- "Content-Type: application/json; charset=UTF-8",
- "ETag: \"1100\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data": [{
- "host": "localhost",
- "last_modified": 1100,
- "bucket": "blocklists:aurora",
- "id": "330a0c5f-fadf-ff0b-40c8-4eb0d924ff6a",
- "collection": "test-collection"
- }, {
- "host": "localhost",
- "last_modified": 1000,
- "bucket": "blocklists",
- "id": "254cbb9e-6888-4d9f-8e60-58b74faa8778",
- "collection": "test-collection"
- }]})
- }
- };
-
- if (req.hasHeader("if-none-match") && req.getHeader("if-none-match", "") == "\"1100\"")
- return {sampleHeaders: [], status: {status: 304, statusText: "Not Modified"}, responseBody: ""};
-
- return responses[`${req.method}:${req.path}?${req.queryString}`] ||
- responses[req.method];
-}
diff --git a/services/common/tests/unit/test_kinto.js b/services/common/tests/unit/test_kinto.js
deleted file mode 100644
index 9c5ce58d9..000000000
--- a/services/common/tests/unit/test_kinto.js
+++ /dev/null
@@ -1,412 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://services-common/kinto-offline-client.js");
-Cu.import("resource://testing-common/httpd.js");
-
-const BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-
-var server;
-
-// set up what we need to make storage adapters
-const Kinto = loadKinto();
-const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
-const kintoFilename = "kinto.sqlite";
-
-let kintoClient;
-
-function do_get_kinto_collection() {
- if (!kintoClient) {
- let config = {
- remote:`http://localhost:${server.identity.primaryPort}/v1/`,
- headers: {Authorization: "Basic " + btoa("user:pass")},
- adapter: FirefoxAdapter
- };
- kintoClient = new Kinto(config);
- }
- return kintoClient.collection("test_collection");
-}
-
-function* clear_collection() {
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- yield collection.clear();
- } finally {
- yield collection.db.close();
- }
-}
-
-// test some operations on a local collection
-add_task(function* test_kinto_add_get() {
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
-
- let newRecord = { foo: "bar" };
- // check a record is created
- let createResult = yield collection.create(newRecord);
- do_check_eq(createResult.data.foo, newRecord.foo);
- // check getting the record gets the same info
- let getResult = yield collection.get(createResult.data.id);
- deepEqual(createResult.data, getResult.data);
- // check what happens if we create the same item again (it should throw
- // since you can't create with id)
- try {
- yield collection.create(createResult.data);
- do_throw("Creation of a record with an id should fail");
- } catch (err) { }
- // try a few creates without waiting for the first few to resolve
- let promises = [];
- promises.push(collection.create(newRecord));
- promises.push(collection.create(newRecord));
- promises.push(collection.create(newRecord));
- yield collection.create(newRecord);
- yield Promise.all(promises);
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-// test some operations on multiple connections
-add_task(function* test_kinto_add_get() {
- const collection1 = do_get_kinto_collection();
- const collection2 = kintoClient.collection("test_collection_2");
-
- try {
- yield collection1.db.open();
- yield collection2.db.open();
-
- let newRecord = { foo: "bar" };
-
- // perform several write operations alternately without waiting for promises
- // to resolve
- let promises = [];
- for (let i = 0; i < 10; i++) {
- promises.push(collection1.create(newRecord));
- promises.push(collection2.create(newRecord));
- }
-
- // ensure subsequent operations still work
- yield Promise.all([collection1.create(newRecord),
- collection2.create(newRecord)]);
- yield Promise.all(promises);
- } finally {
- yield collection1.db.close();
- yield collection2.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_kinto_update() {
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const newRecord = { foo: "bar" };
- // check a record is created
- let createResult = yield collection.create(newRecord);
- do_check_eq(createResult.data.foo, newRecord.foo);
- do_check_eq(createResult.data._status, "created");
- // check we can update this OK
- let copiedRecord = Object.assign(createResult.data, {});
- deepEqual(createResult.data, copiedRecord);
- copiedRecord.foo = "wibble";
- let updateResult = yield collection.update(copiedRecord);
- // check the field was updated
- do_check_eq(updateResult.data.foo, copiedRecord.foo);
- // check the status is still "created", since we haven't synced
- // the record
- do_check_eq(updateResult.data._status, "created");
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_kinto_clear() {
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
-
- // create an expected number of records
- const expected = 10;
- const newRecord = { foo: "bar" };
- for (let i = 0; i < expected; i++) {
- yield collection.create(newRecord);
- }
- // check the collection contains the correct number
- let list = yield collection.list();
- do_check_eq(list.data.length, expected);
- // clear the collection and check again - should be 0
- yield collection.clear();
- list = yield collection.list();
- do_check_eq(list.data.length, 0);
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_kinto_delete(){
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const newRecord = { foo: "bar" };
- // check a record is created
- let createResult = yield collection.create(newRecord);
- do_check_eq(createResult.data.foo, newRecord.foo);
- // check getting the record gets the same info
- let getResult = yield collection.get(createResult.data.id);
- deepEqual(createResult.data, getResult.data);
- // delete that record
- let deleteResult = yield collection.delete(createResult.data.id);
- // check the ID is set on the result
- do_check_eq(getResult.data.id, deleteResult.data.id);
- // and check that get no longer returns the record
- try {
- getResult = yield collection.get(createResult.data.id);
- do_throw("there should not be a result");
- } catch (e) { }
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(function* test_kinto_list(){
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const expected = 10;
- const created = [];
- for (let i = 0; i < expected; i++) {
- let newRecord = { foo: "test " + i };
- let createResult = yield collection.create(newRecord);
- created.push(createResult.data);
- }
- // check the collection contains the correct number
- let list = yield collection.list();
- do_check_eq(list.data.length, expected);
-
- // check that all created records exist in the retrieved list
- for (let createdRecord of created) {
- let found = false;
- for (let retrievedRecord of list.data) {
- if (createdRecord.id == retrievedRecord.id) {
- deepEqual(createdRecord, retrievedRecord);
- found = true;
- }
- }
- do_check_true(found);
- }
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_loadDump_ignores_already_imported_records(){
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const record = {id: "41b71c13-17e9-4ee3-9268-6a41abf9730f", title: "foo", last_modified: 1457896541};
- yield collection.loadDump([record]);
- let impactedRecords = yield collection.loadDump([record]);
- do_check_eq(impactedRecords.length, 0);
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_loadDump_should_overwrite_old_records(){
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const record = {id: "41b71c13-17e9-4ee3-9268-6a41abf9730f", title: "foo", last_modified: 1457896541};
- yield collection.loadDump([record]);
- const updated = Object.assign({}, record, {last_modified: 1457896543});
- let impactedRecords = yield collection.loadDump([updated]);
- do_check_eq(impactedRecords.length, 1);
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_loadDump_should_not_overwrite_unsynced_records(){
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const recordId = "41b71c13-17e9-4ee3-9268-6a41abf9730f";
- yield collection.create({id: recordId, title: "foo"}, {useRecordId: true});
- const record = {id: recordId, title: "bar", last_modified: 1457896541};
- let impactedRecords = yield collection.loadDump([record]);
- do_check_eq(impactedRecords.length, 0);
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-add_task(function* test_loadDump_should_not_overwrite_records_without_last_modified(){
- const collection = do_get_kinto_collection();
- try {
- yield collection.db.open();
- const recordId = "41b71c13-17e9-4ee3-9268-6a41abf9730f";
- yield collection.create({id: recordId, title: "foo"}, {synced: true});
- const record = {id: recordId, title: "bar", last_modified: 1457896541};
- let impactedRecords = yield collection.loadDump([record]);
- do_check_eq(impactedRecords.length, 0);
- } finally {
- yield collection.db.close();
- }
-});
-
-add_task(clear_collection);
-
-// Now do some sanity checks against a server - we're not looking to test
-// core kinto.js functionality here (there is excellent test coverage in
-// kinto.js), more making sure things are basically working as expected.
-add_task(function* test_kinto_sync(){
- const configPath = "/v1/";
- const recordsPath = "/v1/buckets/default/collections/test_collection/records";
- // register a handler
- function handleResponse (request, response) {
- try {
- const sampled = getSampleResponse(request, server.identity.primaryPort);
- if (!sampled) {
- do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
- }
-
- response.setStatusLine(null, sampled.status.status,
- sampled.status.statusText);
- // send the headers
- for (let headerLine of sampled.sampleHeaders) {
- let headerElements = headerLine.split(':');
- response.setHeader(headerElements[0], headerElements[1].trimLeft());
- }
- response.setHeader("Date", (new Date()).toUTCString());
-
- response.write(sampled.responseBody);
- } catch (e) {
- dump(`${e}\n`);
- }
- }
- server.registerPathHandler(configPath, handleResponse);
- server.registerPathHandler(recordsPath, handleResponse);
-
- // create an empty collection, sync to populate
- const collection = do_get_kinto_collection();
- try {
- let result;
-
- yield collection.db.open();
- result = yield collection.sync();
- do_check_true(result.ok);
-
- // our test data has a single record; it should be in the local collection
- let list = yield collection.list();
- do_check_eq(list.data.length, 1);
-
- // now sync again; we should now have 2 records
- result = yield collection.sync();
- do_check_true(result.ok);
- list = yield collection.list();
- do_check_eq(list.data.length, 2);
-
- // sync again; the second records should have been modified
- const before = list.data[0].title;
- result = yield collection.sync();
- do_check_true(result.ok);
- list = yield collection.list();
- const after = list.data[0].title;
- do_check_neq(before, after);
- } finally {
- yield collection.db.close();
- }
-});
-
-function run_test() {
- // Set up an HTTP Server
- server = new HttpServer();
- server.start(-1);
-
- run_next_test();
-
- do_register_cleanup(function() {
- server.stop(function() { });
- });
-}
-
-// 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",
- "Access-Control-Allow-Origin: *",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress"
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": "null"
- },
- "GET:/v1/?": {
- "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: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"settings":{"batch_max_requests":25}, "url":`http://localhost:${port}/v1/`, "documentation":"https://kinto.readthedocs.org/", "version":"1.5.1", "commit":"cbc6f58", "hello":"kinto"})
- },
- "GET:/v1/buckets/default/collections/test_collection/records?_sort=-last_modified": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"1445606341071\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{"last_modified":1445606341071, "done":false, "id":"68db8313-686e-4fff-835e-07d78ad6f2af", "title":"New test"}]})
- },
- "GET:/v1/buckets/default/collections/test_collection/records?_sort=-last_modified&_since=1445606341071": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"1445607941223\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{"last_modified":1445607941223, "done":false, "id":"901967b0-f729-4b30-8d8d-499cba7f4b1d", "title":"Another new test"}]})
- },
- "GET:/v1/buckets/default/collections/test_collection/records?_sort=-last_modified&_since=1445607941223": {
- "sampleHeaders": [
- "Access-Control-Allow-Origin: *",
- "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
- "Content-Type: application/json; charset=UTF-8",
- "Server: waitress",
- "Etag: \"1445607541265\""
- ],
- "status": {status: 200, statusText: "OK"},
- "responseBody": JSON.stringify({"data":[{"last_modified":1445607541265, "done":false, "id":"901967b0-f729-4b30-8d8d-499cba7f4b1d", "title":"Modified title"}]})
- }
- };
- return responses[`${req.method}:${req.path}?${req.queryString}`] ||
- responses[req.method];
-
-}
diff --git a/services/common/tests/unit/xpcshell.ini b/services/common/tests/unit/xpcshell.ini
index dbec09519..f1185c2c0 100644
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -9,14 +9,6 @@ support-files =
# Test load modules first so syntax failures are caught early.
[test_load_modules.js]
-[test_blocklist_certificates.js]
-[test_blocklist_clients.js]
-[test_blocklist_updater.js]
-
-[test_kinto.js]
-[test_blocklist_signatures.js]
-[test_storage_adapter.js]
-
[test_utils_atob.js]
[test_utils_convert_string.js]
[test_utils_dateprefs.js]