forked from mirrors/gecko-dev
		
	 0b6fe69890
			
		
	
	
		0b6fe69890
		
	
	
	
	
		
			
			This patch moves the addons-search-detection system add-on in tree and adjusts the build configuration to make it a built-in add-on (which requires changes in the `BrowserGlue.jsm` file). Summary of the changes made to the different files: - `api.js`: added license header, reformatted with Prettier, then fixed ESLint errors: use of `Services.eTLD` instead of `XPCOMUtils.defineLazyServiceGetter(...)` and defined `"searchInitialized"` on `this` instead of `global` which was unknown - `background.js`: added license header, reformatted with Prettier, removed debug logs because they were off by default anyway, fixed ESLint error: id => addonId because addonId was already defined in a parent scope - `manifest.json`: version number changed + `hidden: true` - `schema.json`: no change await addon.enable(); Depends on D129019 Differential Revision: https://phabricator.services.mozilla.com/D128908
		
			
				
	
	
		
			177 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
	
		
			5.6 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";
 | |
| 
 | |
| /* global browser */
 | |
| 
 | |
| const TELEMETRY_CATEGORY = "addonsSearchDetection";
 | |
| // methods
 | |
| const TELEMETRY_METHOD_ETLD_CHANGE = "etld_change";
 | |
| // objects
 | |
| const TELEMETRY_OBJECT_WEBREQUEST = "webrequest";
 | |
| const TELEMETRY_OBJECT_OTHER = "other";
 | |
| // values
 | |
| const TELEMETRY_VALUE_EXTENSION = "extension";
 | |
| const TELEMETRY_VALUE_SERVER = "server";
 | |
| 
 | |
| class AddonsSearchDetection {
 | |
|   constructor() {
 | |
|     // The key is an URL pattern to monitor and its corresponding value is a
 | |
|     // list of add-on IDs.
 | |
|     this.matchPatterns = {};
 | |
| 
 | |
|     browser.telemetry.registerEvents(TELEMETRY_CATEGORY, {
 | |
|       [TELEMETRY_METHOD_ETLD_CHANGE]: {
 | |
|         methods: [TELEMETRY_METHOD_ETLD_CHANGE],
 | |
|         objects: [TELEMETRY_OBJECT_WEBREQUEST, TELEMETRY_OBJECT_OTHER],
 | |
|         extra_keys: ["addonId", "addonVersion", "from", "to"],
 | |
|         record_on_release: true,
 | |
|       },
 | |
|     });
 | |
| 
 | |
|     this.onRedirectedListener = this.onRedirectedListener.bind(this);
 | |
|   }
 | |
| 
 | |
|   async getMatchPatterns() {
 | |
|     try {
 | |
|       this.matchPatterns = await browser.addonsSearchDetection.getMatchPatterns();
 | |
|     } catch (err) {
 | |
|       console.error(`failed to retrieve the list of URL patterns: ${err}`);
 | |
|       this.matchPatterns = {};
 | |
|     }
 | |
| 
 | |
|     return this.matchPatterns;
 | |
|   }
 | |
| 
 | |
|   // When the search service changes the set of engines that are enabled, we
 | |
|   // update our pattern matching in the webrequest listeners (go to the bottom
 | |
|   // of this file for the search service events we listen to).
 | |
|   async monitor() {
 | |
|     // If there is already a listener, remove it so that we can re-add one
 | |
|     // after. This is because we're using the same listener with different URL
 | |
|     // patterns (when the list of search engines changes).
 | |
|     if (
 | |
|       browser.addonsSearchDetection.onRedirected.hasListener(
 | |
|         this.onRedirectedListener
 | |
|       )
 | |
|     ) {
 | |
|       browser.addonsSearchDetection.onRedirected.removeListener(
 | |
|         this.onRedirectedListener
 | |
|       );
 | |
|     }
 | |
|     // If there is already a listener, remove it so that we can re-add one
 | |
|     // after. This is because we're using the same listener with different URL
 | |
|     // patterns (when the list of search engines changes).
 | |
|     if (browser.webRequest.onBeforeRequest.hasListener(this.noOpListener)) {
 | |
|       browser.webRequest.onBeforeRequest.removeListener(this.noOpListener);
 | |
|     }
 | |
| 
 | |
|     // Retrieve the list of URL patterns to monitor with our listener.
 | |
|     //
 | |
|     // Note: search suggestions are system principal requests, so webRequest
 | |
|     // cannot intercept them.
 | |
|     const matchPatterns = await this.getMatchPatterns();
 | |
|     const patterns = Object.keys(matchPatterns);
 | |
| 
 | |
|     if (patterns.length === 0) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     browser.webRequest.onBeforeRequest.addListener(
 | |
|       this.noOpListener,
 | |
|       { types: ["main_frame"], urls: patterns },
 | |
|       ["blocking"]
 | |
|     );
 | |
| 
 | |
|     browser.addonsSearchDetection.onRedirected.addListener(
 | |
|       this.onRedirectedListener,
 | |
|       { urls: patterns }
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   // This listener is required to force the registration of traceable channels.
 | |
|   noOpListener() {
 | |
|     // Do nothing.
 | |
|   }
 | |
| 
 | |
|   async onRedirectedListener({ addonId, firstUrl, lastUrl }) {
 | |
|     // When we do not have an add-on ID (in the request property bag), we
 | |
|     // likely detected a search server-side redirect.
 | |
|     const maybeServerSideRedirect = !addonId;
 | |
| 
 | |
|     let addonIds = [];
 | |
|     // Search server-side redirects are possible because an extension has
 | |
|     // registered a search engine, which is why we can (hopefully) retrieve the
 | |
|     // add-on ID.
 | |
|     if (maybeServerSideRedirect) {
 | |
|       addonIds = this.getAddonIdsForUrl(firstUrl);
 | |
|     } else if (addonId) {
 | |
|       addonIds = [addonId];
 | |
|     }
 | |
| 
 | |
|     if (addonIds.length === 0) {
 | |
|       // No add-on ID means there is nothing we can report.
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // This is the monitored URL that was first redirected.
 | |
|     const from = await browser.addonsSearchDetection.getPublicSuffix(firstUrl);
 | |
|     // This is the final URL after redirect(s).
 | |
|     const to = await browser.addonsSearchDetection.getPublicSuffix(lastUrl);
 | |
| 
 | |
|     if (from === to) {
 | |
|       // We do not want to report redirects to same public suffixes. However,
 | |
|       // we will report redirects from public suffixes belonging to a same
 | |
|       // entity (.e.g., `example.com` -> `example.fr`).
 | |
|       //
 | |
|       // Known limitation: if a redirect chain starts and ends with the same
 | |
|       // public suffix, we won't report any event, even if the chain contains
 | |
|       // different public suffixes in between.
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     const telemetryObject = maybeServerSideRedirect
 | |
|       ? TELEMETRY_OBJECT_OTHER
 | |
|       : TELEMETRY_OBJECT_WEBREQUEST;
 | |
|     const telemetryValue = maybeServerSideRedirect
 | |
|       ? TELEMETRY_VALUE_SERVER
 | |
|       : TELEMETRY_VALUE_EXTENSION;
 | |
| 
 | |
|     for (const id of addonIds) {
 | |
|       const addonVersion = await browser.addonsSearchDetection.getAddonVersion(
 | |
|         id
 | |
|       );
 | |
|       const extra = { addonId: id, addonVersion, from, to };
 | |
| 
 | |
|       browser.telemetry.recordEvent(
 | |
|         TELEMETRY_CATEGORY,
 | |
|         TELEMETRY_METHOD_ETLD_CHANGE,
 | |
|         telemetryObject,
 | |
|         telemetryValue,
 | |
|         extra
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   getAddonIdsForUrl(url) {
 | |
|     for (const pattern of Object.keys(this.matchPatterns)) {
 | |
|       // `getMatchPatterns()` returns the prefix plus "*".
 | |
|       const urlPrefix = pattern.slice(0, -1);
 | |
| 
 | |
|       if (url.startsWith(urlPrefix)) {
 | |
|         return this.matchPatterns[pattern];
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return [];
 | |
|   }
 | |
| }
 | |
| 
 | |
| const exp = new AddonsSearchDetection();
 | |
| exp.monitor();
 | |
| 
 | |
| browser.addonsSearchDetection.onSearchEngineModified.addListener(async () => {
 | |
|   await exp.monitor();
 | |
| });
 |