summaryrefslogtreecommitdiffstats
path: root/toolkit/components/url-classifier/tests/unit/test_rsListService.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/url-classifier/tests/unit/test_rsListService.js')
-rw-r--r--toolkit/components/url-classifier/tests/unit/test_rsListService.js424
1 files changed, 424 insertions, 0 deletions
diff --git a/toolkit/components/url-classifier/tests/unit/test_rsListService.js b/toolkit/components/url-classifier/tests/unit/test_rsListService.js
new file mode 100644
index 0000000000..cd70f92885
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/unit/test_rsListService.js
@@ -0,0 +1,424 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* Unit tests for the nsIUrlClassifierRemoteSettingsService implementation. */
+
+const { RemoteSettings } = ChromeUtils.importESModule(
+ "resource://services-settings/remote-settings.sys.mjs"
+);
+const { SBRS_UPDATE_MINIMUM_DELAY } = ChromeUtils.importESModule(
+ "resource://gre/modules/UrlClassifierRemoteSettingsService.sys.mjs"
+);
+
+const COLLECTION_NAME = "tracking-protection-lists";
+
+const REMOTE_SETTINGS_DATA = [
+ {
+ Name: "content-fingerprinting-track-digest256",
+ attachment: {
+ hash: "96a4a850a1a475001148fa8a3a5efea58951f7176d3624ad7614fbf32732ee48",
+ size: 948,
+ filename: "content-fingerprinting-track-digest256",
+ location:
+ "main-workspace/tracking-protection-lists/content-fingerprinting-track-digest256",
+ mimetype: "text/plain",
+ },
+ id: "content-fingerprinting-track-digest256",
+ Version: 1597417364,
+ },
+ {
+ Name: "mozplugin-block-digest256",
+ attachment: {
+ hash: "dd2b800c7e4bad17e1c79f3e530c0b94e0a039adf4566f30bc3c285a547fa4fc",
+ size: 3029,
+ filename: "mozplugin-block-digest256",
+ location:
+ "main-workspace/tracking-protection-lists/mozplugin-block-digest256",
+ mimetype: "text/plain",
+ },
+ id: "mozplugin-block-digest256",
+ Version: 1575583456,
+ },
+ {
+ Name: "google-trackwhite-digest256",
+ attachment: {
+ hash: "1cd6d9353e97d66ac737a9716cd3a33416d6a4884dd12dcd1d65266e4c81dfad",
+ size: 1470328,
+ filename: "google-trackwhite-digest256",
+ location:
+ "main-workspace/tracking-protection-lists/google-trackwhite-digest256",
+ mimetype: "text/plain",
+ },
+ id: "google-trackwhite-digest256",
+ Version: 1575583456,
+ },
+ // Entry with non-exist attachment
+ {
+ Name: "social-track-digest256",
+ attachment: {
+ location: "main-workspace/tracking-protection-lists/not-exist",
+ },
+ id: "social-track-digest256",
+ Version: 1111111111,
+ },
+ // Entry with corrupted attachment
+ {
+ Name: "analytic-track-digest256",
+ attachment: {
+ hash: "644a0662bcf7313570ee68490e3805f5cc7a0503c097f040525c28dc5bfe4c97",
+ size: 58,
+ filename: "invalid.chunk",
+ location: "main-workspace/tracking-protection-lists/invalid.chunk",
+ mimetype: "text/plain",
+ },
+ id: "analytic-track-digest256",
+ Version: 1111111111,
+ },
+];
+
+let gListService = Cc["@mozilla.org/url-classifier/list-service;1"].getService(
+ Ci.nsIUrlClassifierRemoteSettingsService
+);
+let gDbService = Cc["@mozilla.org/url-classifier/dbservice;1"].getService(
+ Ci.nsIUrlClassifierDBService
+);
+
+class UpdateEvent extends EventTarget {}
+function waitForEvent(element, eventName) {
+ return new Promise(function (resolve) {
+ element.addEventListener(eventName, e => resolve(e.detail), { once: true });
+ });
+}
+
+function buildPayload(tables) {
+ let payload = ``;
+ for (let table of tables) {
+ payload += table[0];
+ if (table[1] != null) {
+ payload += `;a:${table[1]}`;
+ }
+ payload += `\n`;
+ }
+ return payload;
+}
+
+let server;
+add_setup(async function init() {
+ Services.prefs.setCharPref(
+ "browser.safebrowsing.provider.mozilla.updateURL",
+ `moz-sbrs://tracking-protection-list`
+ );
+ // Setup HTTP server for remote setting
+ server = new HttpServer();
+ server.start(-1);
+ registerCleanupFunction(() => server.stop(() => {}));
+
+ server.registerDirectory(
+ "/cdn/main-workspace/tracking-protection-lists/",
+ do_get_file("data")
+ );
+
+ server.registerPathHandler("/v1/", (request, response) => {
+ response.write(
+ JSON.stringify({
+ capabilities: {
+ attachments: {
+ base_url: `http://localhost:${server.identity.primaryPort}/cdn/`,
+ },
+ },
+ })
+ );
+ response.setHeader("Content-Type", "application/json; charset=UTF-8");
+ response.setStatusLine(null, 200, "OK");
+ });
+
+ Services.prefs.setCharPref(
+ "services.settings.server",
+ `http://localhost:${server.identity.primaryPort}/v1`
+ );
+
+ // Setup remote setting initial data
+ let db = await RemoteSettings(COLLECTION_NAME).db;
+ await db.importChanges({}, 42, REMOTE_SETTINGS_DATA);
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(
+ "browser.safebrowsing.provider.mozilla.updateURL"
+ );
+ Services.prefs.clearUserPref("services.settings.server");
+ });
+});
+
+// Test updates from RemoteSettings when there is no local data
+add_task(async function test_empty_update() {
+ let updateEvent = new UpdateEvent();
+ let promise = waitForEvent(updateEvent, "update");
+
+ const TEST_TABLES = [
+ ["mozplugin-block-digest256", null], // empty
+ ["content-fingerprinting-track-digest256", null], // empty
+ ];
+
+ gListService.fetchList(buildPayload(TEST_TABLES), {
+ // nsIStreamListener observer
+ onStartRequest(request) {},
+ onDataAvailable(aRequest, aStream, aOffset, aCount) {
+ let stream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ stream.init(aStream);
+ let event = new CustomEvent("update", {
+ detail: stream.readBytes(aCount),
+ });
+ updateEvent.dispatchEvent(event);
+ },
+ onStopRequest(request, status) {},
+ });
+
+ let expected = "n:" + SBRS_UPDATE_MINIMUM_DELAY + "\n";
+ for (const table of TEST_TABLES) {
+ expected += `i:${table[0]}\n` + readFileToString(`data/${table[0]}`);
+ }
+
+ Assert.equal(
+ await promise,
+ expected,
+ "Receive expected data from onDataAvailable"
+ );
+ gListService.clear();
+});
+
+// Test updates from RemoteSettings when we have an empty table,
+// a table with an older version, and a table which is up-to-date.
+add_task(async function test_update() {
+ let updateEvent = new UpdateEvent();
+ let promise = waitForEvent(updateEvent, "update");
+
+ const TEST_TABLES = [
+ ["mozplugin-block-digest256", 1575583456], // up-to-date
+ ["content-fingerprinting-track-digest256", 1575583456 - 1], // older version
+ ];
+
+ gListService.fetchList(buildPayload(TEST_TABLES), {
+ // observer
+ // nsIStreamListener observer
+ onStartRequest(request) {},
+ onDataAvailable(aRequest, aStream, aOffset, aCount) {
+ let stream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ stream.init(aStream);
+ let event = new CustomEvent("update", {
+ detail: stream.readBytes(aCount),
+ });
+ updateEvent.dispatchEvent(event);
+ },
+ onStopRequest(request, status) {},
+ });
+
+ // Build request with no version
+ let expected = "n:" + SBRS_UPDATE_MINIMUM_DELAY + "\n";
+ for (const table of TEST_TABLES) {
+ if (["content-fingerprinting-track-digest256"].includes(table[0])) {
+ expected += `i:${table[0]}\n` + readFileToString(`data/${table[0]}`);
+ }
+ }
+
+ Assert.equal(
+ await promise,
+ expected,
+ "Receive expected data from onDataAvailable"
+ );
+ gListService.clear();
+});
+
+// Test updates from RemoteSettings service when all tables are up-to-date.
+add_task(async function test_no_update() {
+ let updateEvent = new UpdateEvent();
+ let promise = waitForEvent(updateEvent, "update");
+
+ const TEST_TABLES = [
+ ["mozplugin-block-digest256", 1575583456], // up-to-date
+ ["content-fingerprinting-track-digest256", 1597417364], // up-to-date
+ ];
+
+ gListService.fetchList(buildPayload(TEST_TABLES), {
+ // nsIStreamListener observer
+ onStartRequest(request) {},
+ onDataAvailable(aRequest, aStream, aOffset, aCount) {
+ let stream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ stream.init(aStream);
+ let event = new CustomEvent("update", {
+ detail: stream.readBytes(aCount),
+ });
+ updateEvent.dispatchEvent(event);
+ },
+ onStopRequest(request, status) {},
+ });
+
+ // No data is expected
+ let expected = "n:" + SBRS_UPDATE_MINIMUM_DELAY + "\n";
+
+ Assert.equal(
+ await promise,
+ expected,
+ "Receive expected data from onDataAvailable"
+ );
+ gListService.clear();
+});
+
+add_test(function test_update() {
+ let streamUpdater = Cc[
+ "@mozilla.org/url-classifier/streamupdater;1"
+ ].getService(Ci.nsIUrlClassifierStreamUpdater);
+
+ // Download some updates, and don't continue until the downloads are done.
+ function updateSuccess(aEvent) {
+ Assert.equal(SBRS_UPDATE_MINIMUM_DELAY, aEvent);
+ info("All data processed");
+ run_next_test();
+ }
+ // Just throw if we ever get an update or download error.
+ function handleError(aEvent) {
+ do_throw("We didn't download or update correctly: " + aEvent);
+ }
+
+ streamUpdater.downloadUpdates(
+ "content-fingerprinting-track-digest256",
+ "content-fingerprinting-track-digest256;\n",
+ true,
+ "moz-sbrs://remote-setting",
+ updateSuccess,
+ handleError,
+ handleError
+ );
+});
+
+add_test(function test_url_not_denylisted() {
+ let uri = Services.io.newURI("http://example.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ gDbService.lookup(
+ principal,
+ "content-fingerprinting-track-digest256",
+ function handleEvent(aEvent) {
+ // This URI is not on any lists.
+ Assert.equal("", aEvent);
+ run_next_test();
+ }
+ );
+});
+
+add_test(function test_url_denylisted() {
+ let uri = Services.io.newURI("https://www.foresee.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ gDbService.lookup(
+ principal,
+ "content-fingerprinting-track-digest256",
+ function handleEvent(aEvent) {
+ Assert.equal("content-fingerprinting-track-digest256", aEvent);
+ run_next_test();
+ }
+ );
+});
+
+add_test(function test_update_download_error() {
+ let streamUpdater = Cc[
+ "@mozilla.org/url-classifier/streamupdater;1"
+ ].getService(Ci.nsIUrlClassifierStreamUpdater);
+
+ // Download some updates, and don't continue until the downloads are done.
+ function updateSuccessOrError(aEvent) {
+ do_throw("Should be downbload error");
+ }
+ // Just throw if we ever get an update or download error.
+ function downloadError(aEvent) {
+ run_next_test();
+ }
+
+ streamUpdater.downloadUpdates(
+ "social-track-digest256",
+ "social-track-digest256;\n",
+ true,
+ "moz-sbrs://remote-setting",
+ updateSuccessOrError,
+ updateSuccessOrError,
+ downloadError
+ );
+});
+
+add_test(function test_update_update_error() {
+ let streamUpdater = Cc[
+ "@mozilla.org/url-classifier/streamupdater;1"
+ ].getService(Ci.nsIUrlClassifierStreamUpdater);
+
+ // Download some updates, and don't continue until the downloads are done.
+ function updateSuccessOrDownloadError(aEvent) {
+ do_throw("Should be update error");
+ }
+ // Just throw if we ever get an update or download error.
+ function updateError(aEvent) {
+ run_next_test();
+ }
+
+ streamUpdater.downloadUpdates(
+ "analytic-track-digest256",
+ "analytic-track-digest256;\n",
+ true,
+ "moz-sbrs://remote-setting",
+ updateSuccessOrDownloadError,
+ updateError,
+ updateSuccessOrDownloadError
+ );
+});
+
+add_task(async function test_update_large_file() {
+ let updateEvent = new UpdateEvent();
+ let promise = waitForEvent(updateEvent, "update");
+
+ const TEST_TABLES = [
+ ["google-trackwhite-digest256", 1575583456 - 1], // up-to-date
+ ];
+
+ gListService.fetchList(buildPayload(TEST_TABLES), {
+ // observer
+ // nsIStreamListener observer
+ onStartRequest(request) {},
+ onDataAvailable(aRequest, aStream, aOffset, aCount) {
+ let stream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ stream.init(aStream);
+ let event = new CustomEvent("update", {
+ detail: stream.readBytes(aCount),
+ });
+ updateEvent.dispatchEvent(event);
+ },
+ onStopRequest(request, status) {},
+ });
+
+ // Build request with no version
+ let expected = "n:" + SBRS_UPDATE_MINIMUM_DELAY + "\n";
+ for (const table of TEST_TABLES) {
+ if (["google-trackwhite-digest256"].includes(table[0])) {
+ expected += `i:${table[0]}\n` + readFileToString(`data/${table[0]}`);
+ }
+ }
+
+ Assert.equal(
+ await promise,
+ expected,
+ "Receive expected data from onDataAvailable"
+ );
+ gListService.clear();
+});