const ANNOTATION_TABLE_NAME = "mochitest1-track-simple"; const ANNOTATION_TABLE_PREF = "urlclassifier.trackingAnnotationTable"; const ANNOTATION_ENTITYLIST_TABLE_NAME = "mochitest1-trackwhite-simple"; const ANNOTATION_ENTITYLIST_TABLE_PREF = "urlclassifier.trackingAnnotationWhitelistTable"; const TRACKING_TABLE_NAME = "mochitest2-track-simple"; const TRACKING_TABLE_PREF = "urlclassifier.trackingTable"; const ENTITYLIST_TABLE_NAME = "mochitest2-trackwhite-simple"; const ENTITYLIST_TABLE_PREF = "urlclassifier.trackingWhitelistTable"; const SOCIAL_ANNOTATION_TABLE_NAME = "mochitest3-track-simple"; const SOCIAL_ANNOTATION_TABLE_PREF = "urlclassifier.features.socialtracking.annotate.blacklistTables"; const SOCIAL_TRACKING_TABLE_NAME = "mochitest4-track-simple"; const SOCIAL_TRACKING_TABLE_PREF = "urlclassifier.features.socialtracking.blacklistTables"; const EMAIL_TRACKING_TABLE_NAME = "mochitest5-track-simple"; const EMAIL_TRACKING_TABLE_PREF = "urlclassifier.features.emailtracking.blocklistTables"; let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); export var UrlClassifierTestUtils = { addTestTrackers() { // Add some URLs to the tracking databases let annotationURL1 = "tracking.example.org/"; // only for annotations let annotationURL2 = "itisatracker.org/"; let annotationURL3 = "trackertest.org/"; let annotationURL4 = "another-tracking.example.net/"; let annotationURL5 = "tlsresumptiontest.example.org/"; let annotationEntitylistedURL = "itisatrap.org/?resource=example.org"; let trackingURL1 = "tracking.example.com/"; // only for TP let trackingURL2 = "itisatracker.org/"; let trackingURL3 = "trackertest.org/"; let entitylistedURL = "itisatrap.org/?resource=itisatracker.org"; let socialTrackingURL = "social-tracking.example.org/"; let emailTrackingURL = "email-tracking.example.org/"; let annotationUpdate = "n:1000\ni:" + ANNOTATION_TABLE_NAME + "\nad:5\n" + "a:1:32:" + annotationURL1.length + "\n" + annotationURL1 + "\n" + "a:2:32:" + annotationURL2.length + "\n" + annotationURL2 + "\n" + "a:3:32:" + annotationURL3.length + "\n" + annotationURL3 + "\n" + "a:4:32:" + annotationURL4.length + "\n" + annotationURL4 + "\n" + "a:5:32:" + annotationURL5.length + "\n" + annotationURL5 + "\n"; let socialAnnotationUpdate = "n:1000\ni:" + SOCIAL_ANNOTATION_TABLE_NAME + "\nad:1\n" + "a:1:32:" + socialTrackingURL.length + "\n" + socialTrackingURL + "\n"; let annotationEntitylistUpdate = "n:1000\ni:" + ANNOTATION_ENTITYLIST_TABLE_NAME + "\nad:1\n" + "a:1:32:" + annotationEntitylistedURL.length + "\n" + annotationEntitylistedURL + "\n"; let trackingUpdate = "n:1000\ni:" + TRACKING_TABLE_NAME + "\nad:3\n" + "a:1:32:" + trackingURL1.length + "\n" + trackingURL1 + "\n" + "a:2:32:" + trackingURL2.length + "\n" + trackingURL2 + "\n" + "a:3:32:" + trackingURL3.length + "\n" + trackingURL3 + "\n"; let socialTrackingUpdate = "n:1000\ni:" + SOCIAL_TRACKING_TABLE_NAME + "\nad:1\n" + "a:1:32:" + socialTrackingURL.length + "\n" + socialTrackingURL + "\n"; let emailTrackingUpdate = "n:1000\ni:" + EMAIL_TRACKING_TABLE_NAME + "\nad:1\n" + "a:1:32:" + emailTrackingURL.length + "\n" + emailTrackingURL + "\n"; let entitylistUpdate = "n:1000\ni:" + ENTITYLIST_TABLE_NAME + "\nad:1\n" + "a:1:32:" + entitylistedURL.length + "\n" + entitylistedURL + "\n"; var tables = [ { pref: ANNOTATION_TABLE_PREF, name: ANNOTATION_TABLE_NAME, update: annotationUpdate, }, { pref: SOCIAL_ANNOTATION_TABLE_PREF, name: SOCIAL_ANNOTATION_TABLE_NAME, update: socialAnnotationUpdate, }, { pref: ANNOTATION_ENTITYLIST_TABLE_PREF, name: ANNOTATION_ENTITYLIST_TABLE_NAME, update: annotationEntitylistUpdate, }, { pref: TRACKING_TABLE_PREF, name: TRACKING_TABLE_NAME, update: trackingUpdate, }, { pref: SOCIAL_TRACKING_TABLE_PREF, name: SOCIAL_TRACKING_TABLE_NAME, update: socialTrackingUpdate, }, { pref: EMAIL_TRACKING_TABLE_PREF, name: EMAIL_TRACKING_TABLE_NAME, update: emailTrackingUpdate, }, { pref: ENTITYLIST_TABLE_PREF, name: ENTITYLIST_TABLE_NAME, update: entitylistUpdate, }, ]; let tableIndex = 0; let doOneUpdate = () => { if (tableIndex == tables.length) { return Promise.resolve(); } return this.useTestDatabase(tables[tableIndex]).then( () => { tableIndex++; return doOneUpdate(); }, aErrMsg => { dump("Rejected: " + aErrMsg + ". Retry later.\n"); return new Promise(resolve => { timer.initWithCallback(resolve, 100, Ci.nsITimer.TYPE_ONE_SHOT); }).then(doOneUpdate); } ); }; return doOneUpdate(); }, cleanupTestTrackers() { Services.prefs.clearUserPref(ANNOTATION_TABLE_PREF); Services.prefs.clearUserPref(SOCIAL_ANNOTATION_TABLE_PREF); Services.prefs.clearUserPref(ANNOTATION_ENTITYLIST_TABLE_PREF); Services.prefs.clearUserPref(TRACKING_TABLE_PREF); Services.prefs.clearUserPref(SOCIAL_TRACKING_TABLE_PREF); Services.prefs.clearUserPref(EMAIL_TRACKING_TABLE_PREF); Services.prefs.clearUserPref(ENTITYLIST_TABLE_PREF); }, /** * Add some entries to a test tracking protection database, and resets * back to the default database after the test ends. * * @return {Promise} */ useTestDatabase(table) { Services.prefs.setCharPref(table.pref, table.name); return new Promise((resolve, reject) => { let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"].getService( Ci.nsIUrlClassifierDBService ); let listener = { QueryInterface: iid => { if ( iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIUrlClassifierUpdateObserver) ) { return listener; } throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); }, updateUrlRequested: url => {}, streamFinished: status => {}, updateError: errorCode => { reject("Got updateError when updating " + table.name); }, updateSuccess: requestedTimeout => { resolve(); }, }; try { dbService.beginUpdate(listener, table.name, ""); dbService.beginStream("", ""); dbService.updateStream(table.update); dbService.finishStream(); dbService.finishUpdate(); } catch (e) { reject("Failed to update with dbService: " + table.name); } }); }, /** * Handle the next "urlclassifier-before-block-channel" event. * @param {Object} options * @param {String} [options.filterOrigin] - Only handle event for channels * with matching origin. * @param {function} [options.onBeforeBlockChannel] - Optional callback for * the event. Called before acting on the channel. * @param {("allow"|"replace")} [options.action] - Whether to allow or replace * the channel. * @returns {Promise} - Resolves once event has been handled. */ handleBeforeBlockChannel({ filterOrigin = null, onBeforeBlockChannel, action, }) { if (action && action != "allow" && action != "replace") { throw new Error("Invalid action " + action); } let channelClassifierService = Cc[ "@mozilla.org/url-classifier/channel-classifier-service;1" ].getService(Ci.nsIChannelClassifierService); let resolver; let promise = new Promise(resolve => { resolver = resolve; }); let observer = { observe(subject, topic) { if (topic != "urlclassifier-before-block-channel") { return; } let channel = subject.QueryInterface(Ci.nsIUrlClassifierBlockedChannel); if (filterOrigin) { let { url } = channel; let { origin } = new URL(url); if (filterOrigin != origin) { return; } } if (onBeforeBlockChannel) { onBeforeBlockChannel(channel); } if (action) { channel[action](); } channelClassifierService.removeListener(observer); resolver(); }, }; channelClassifierService.addListener(observer); return promise; }, };