forked from mirrors/gecko-dev
		
	 a181785400
			
		
	
	
		a181785400
		
	
	
	
	
		
			
			Depends on D135989 Differential Revision: https://phabricator.services.mozilla.com/D135990
		
			
				
	
	
		
			370 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* 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.import(
 | |
|   "resource://services-settings/remote-settings.js"
 | |
| );
 | |
| const { SBRS_UPDATE_MINIMUM_DELAY } = ChromeUtils.import(
 | |
|   "resource://gre/modules/UrlClassifierRemoteSettingsService.jsm"
 | |
| );
 | |
| 
 | |
| 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,
 | |
|   },
 | |
|   // 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_task(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
 | |
|   );
 | |
| });
 |