mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1912086 - Fix application provided search handling in the search-detection add-on. r=robwu
Differential Revision: https://phabricator.services.mozilla.com/D218773
This commit is contained in:
parent
67b36870e4
commit
9c45f12d2e
@ -16,6 +16,8 @@ const lazy = {};
|
||||
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
AddonSearchEngine: "resource://gre/modules/AddonSearchEngine.sys.mjs",
|
||||
AppProvidedSearchEngine:
|
||||
"resource://gre/modules/AppProvidedSearchEngine.sys.mjs",
|
||||
});
|
||||
|
||||
// eslint-disable-next-line mozilla/reject-importGlobalProperties
|
||||
@ -46,41 +48,43 @@ this.addonsSearchDetection = class extends ExtensionAPI {
|
||||
|
||||
try {
|
||||
await Services.search.promiseInitialized;
|
||||
const visibleEngines = await Services.search.getEngines();
|
||||
const engines = await Services.search.getEngines();
|
||||
|
||||
visibleEngines.forEach(engine => {
|
||||
if (!(engine instanceof lazy.AddonSearchEngine)) {
|
||||
return;
|
||||
}
|
||||
const { _extensionID, _urls } = engine.wrappedJSObject;
|
||||
|
||||
if (!_extensionID) {
|
||||
// OpenSearch engines don't have an extension ID.
|
||||
return;
|
||||
for (let engine of engines) {
|
||||
if (
|
||||
!(engine instanceof lazy.AddonSearchEngine) &&
|
||||
!(engine instanceof lazy.AppProvidedSearchEngine)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_urls
|
||||
// We only want to collect "search URLs" (and not "suggestion"
|
||||
// ones for instance). See `URL_TYPE` in `SearchUtils.sys.mjs`.
|
||||
.filter(({ type }) => type === "text/html")
|
||||
.forEach(({ template }) => {
|
||||
// If this is changed, double check the code in the background
|
||||
// script because `webRequestCancelledHandler` splits patterns
|
||||
// on `*` to retrieve URL prefixes.
|
||||
const pattern = template.split("?")[0] + "*";
|
||||
// The search term isn't used, but avoids a warning of an empty
|
||||
// term.
|
||||
let submission = engine.getSubmission("searchTerm");
|
||||
if (submission) {
|
||||
// If this is changed, double check the code in the background
|
||||
// script because `getAddonIdsForUrl` truncates the last
|
||||
// character.
|
||||
const pattern =
|
||||
submission.uri.prePath + submission.uri.filePath + "*";
|
||||
|
||||
// Multiple search engines could register URL templates that
|
||||
// would become the same URL pattern as defined above so we
|
||||
// store a list of extension IDs per URL pattern.
|
||||
if (!patterns[pattern]) {
|
||||
patterns[pattern] = [];
|
||||
}
|
||||
// Multiple search engines could register URL templates that
|
||||
// would become the same URL pattern as defined above so we
|
||||
// store a list of extension IDs per URL pattern.
|
||||
if (!patterns[pattern]) {
|
||||
patterns[pattern] = [];
|
||||
}
|
||||
|
||||
if (!patterns[pattern].includes(_extensionID)) {
|
||||
patterns[pattern].push(_extensionID);
|
||||
}
|
||||
});
|
||||
});
|
||||
// We don't store ids for application provided search engines
|
||||
// because we don't need to report them. However, we do ensure
|
||||
// the pattern is recorded (above), so that we check for
|
||||
// redirects against those.
|
||||
const _extensionID = engine.wrappedJSObject._extensionID;
|
||||
if (_extensionID && !patterns[pattern].includes(_extensionID)) {
|
||||
patterns[pattern].push(_extensionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
@ -6,12 +6,14 @@
|
||||
const { AddonTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/AddonTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
const { SearchTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/SearchTestUtils.sys.mjs"
|
||||
);
|
||||
const { TelemetryTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/TelemetryTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
AddonTestUtils.initMochitest(this);
|
||||
SearchTestUtils.init(this);
|
||||
|
||||
const TELEMETRY_EVENTS_FILTERS = {
|
||||
category: "addonsSearchDetection",
|
||||
@ -25,6 +27,7 @@ async function testClientSideRedirect({
|
||||
background,
|
||||
permissions,
|
||||
telemetryExpected = false,
|
||||
redirectingAppProvidedEngine = false,
|
||||
}) {
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
@ -51,7 +54,9 @@ async function testClientSideRedirect({
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "https://example.com/search?q=babar",
|
||||
url: redirectingAppProvidedEngine
|
||||
? "https://example.org/default?q=babar"
|
||||
: "https://example.com/search?q=babar",
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
@ -67,7 +72,9 @@ async function testClientSideRedirect({
|
||||
extra: {
|
||||
addonId,
|
||||
addonVersion,
|
||||
from: "example.com",
|
||||
from: redirectingAppProvidedEngine
|
||||
? "example.org"
|
||||
: "example.com",
|
||||
to: "mochi.test",
|
||||
},
|
||||
},
|
||||
@ -81,38 +88,28 @@ async function testClientSideRedirect({
|
||||
add_setup(async function () {
|
||||
const searchEngineName = "test search engine";
|
||||
|
||||
let searchEngine;
|
||||
|
||||
// This cleanup function has to be registered before the one registered
|
||||
// internally by loadExtension, otherwise it is going to trigger a test
|
||||
// failure (because it will be called too late).
|
||||
registerCleanupFunction(async () => {
|
||||
await searchEngine.unload();
|
||||
ok(
|
||||
!Services.search.getEngineByName(searchEngineName),
|
||||
"test search engine unregistered"
|
||||
);
|
||||
});
|
||||
|
||||
searchEngine = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
chrome_settings_overrides: {
|
||||
search_provider: {
|
||||
name: searchEngineName,
|
||||
keyword: "test",
|
||||
search_url: "https://example.com/?q={searchTerms}",
|
||||
await SearchTestUtils.updateRemoteSettingsConfig([
|
||||
{
|
||||
identifier: "default",
|
||||
base: {
|
||||
urls: {
|
||||
search: {
|
||||
base: "https://example.org/default",
|
||||
searchTermParamName: "q",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// NOTE: the search extension needs to be installed through the
|
||||
// AddonManager to be correctly unregistered when it is uninstalled.
|
||||
useAddonManager: "temporary",
|
||||
]);
|
||||
|
||||
await SearchTestUtils.installSearchExtension({
|
||||
name: searchEngineName,
|
||||
keyword: "test",
|
||||
search_url: "https://example.com/?q={searchTerms}",
|
||||
});
|
||||
|
||||
await searchEngine.startup();
|
||||
await AddonTestUtils.waitForSearchProviderStartup(searchEngine);
|
||||
ok(
|
||||
Services.search.getEngineByName(searchEngineName),
|
||||
Assert.ok(
|
||||
!!Services.search.getEngineByName(searchEngineName),
|
||||
"test search engine registered"
|
||||
);
|
||||
});
|
||||
@ -137,6 +134,27 @@ add_task(function test_onBeforeRequest() {
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_onBeforeRequest_appProvidedEngine() {
|
||||
return testClientSideRedirect({
|
||||
background() {
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
() => {
|
||||
return {
|
||||
redirectUrl: "http://mochi.test:8888/",
|
||||
};
|
||||
},
|
||||
{ urls: ["*://example.org/*"] },
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
permissions: ["webRequest", "webRequestBlocking", "*://example.org/*"],
|
||||
redirectingAppProvidedEngine: true,
|
||||
telemetryExpected: true,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_onBeforeRequest_url_not_monitored() {
|
||||
// Here, we load an extension that does a client-side redirect. Because this
|
||||
// extension does not listen to the URL of the search engine registered
|
||||
@ -180,6 +198,27 @@ add_task(function test_onHeadersReceived() {
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_onHeadersReceived_appProvidedEngine() {
|
||||
return testClientSideRedirect({
|
||||
background() {
|
||||
browser.webRequest.onHeadersReceived.addListener(
|
||||
() => {
|
||||
return {
|
||||
redirectUrl: "http://mochi.test:8888/",
|
||||
};
|
||||
},
|
||||
{ urls: ["*://example.org/*"], types: ["main_frame"] },
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
permissions: ["webRequest", "webRequestBlocking", "*://example.org/*"],
|
||||
redirectingAppProvidedEngine: true,
|
||||
telemetryExpected: true,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_onHeadersReceived_url_not_monitored() {
|
||||
// Here, we load an extension that does a client-side redirect. Because this
|
||||
// extension does not listen to the URL of the search engine registered
|
||||
|
Loading…
Reference in New Issue
Block a user