Bug 1918386 - browser.search.get() should be returning data URIs for application provided search engines. a=diannaS

Original Revision: https://phabricator.services.mozilla.com/D222264

Differential Revision: https://phabricator.services.mozilla.com/D222466
This commit is contained in:
Mark Banner 2024-09-19 00:19:34 +00:00
parent 718f786f39
commit 0ad3c9da9b
2 changed files with 86 additions and 8 deletions

View file

@ -41,14 +41,18 @@ this.search = class extends ExtensionAPI {
return Promise.all(
visibleEngines.map(async engine => {
let favIconUrl = await engine.getIconURL();
// Convert moz-extension:-URLs to data:-URLs to make sure that
// Convert blob:-URLs to data:-URLs since they can't be shared
// across processes. blob:-URLs originate from application provided
// search engines.
// Also convert moz-extension:-URLs to data:-URLs to make sure that
// extensions can see icons from other extensions, even if they
// are not web-accessible.
// Also prevents leakage of extension UUIDs to other extensions..
if (
favIconUrl &&
favIconUrl.startsWith("moz-extension:") &&
!favIconUrl.startsWith(context.extension.baseURL)
(favIconUrl.startsWith("blob:") ||
(favIconUrl.startsWith("moz-extension:") &&
!favIconUrl.startsWith(context.extension.baseURL)))
) {
favIconUrl = await ExtensionUtils.makeDataURI(favIconUrl);
}

View file

@ -8,9 +8,19 @@ const { AddonTestUtils } = ChromeUtils.importESModule(
const { XPCShellContentUtils } = ChromeUtils.importESModule(
"resource://testing-common/XPCShellContentUtils.sys.mjs"
);
const { SearchTestUtils } = ChromeUtils.importESModule(
"resource://testing-common/SearchTestUtils.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
"resource://testing-common/Sinon.sys.mjs"
);
const { AppProvidedSearchEngine } = ChromeUtils.importESModule(
"resource://gre/modules/AppProvidedSearchEngine.sys.mjs"
);
AddonTestUtils.initMochitest(this);
XPCShellContentUtils.initMochitest(this);
SearchTestUtils.init(this);
// Base64-encoded "Fake icon data".
const FAKE_ICON_DATA = "RmFrZSBpY29uIGRhdGE=";
@ -18,11 +28,40 @@ const FAKE_ICON_DATA = "RmFrZSBpY29uIGRhdGE=";
// Base64-encoded "HTTP icon data".
const HTTP_ICON_DATA = "SFRUUCBpY29uIGRhdGE=";
const HTTP_ICON_URL = "http://example.org/ico.png";
const server = XPCShellContentUtils.createHttpServer({
hosts: ["example.org"],
});
server.registerPathHandler("/ico.png", (request, response) => {
response.write(atob(HTTP_ICON_DATA));
const IMAGE_DATA_URI =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC";
add_setup(async () => {
const server = XPCShellContentUtils.createHttpServer({
hosts: ["example.org"],
});
server.registerPathHandler("/ico.png", (request, response) => {
response.write(atob(HTTP_ICON_DATA));
});
await SearchTestUtils.updateRemoteSettingsConfig([
{ identifier: "appEngineWithIcon" },
]);
let createdBlobURLs = [];
sinon
.stub(AppProvidedSearchEngine.prototype, "getIconURL")
.callsFake(async () => {
let response = await fetch(IMAGE_DATA_URI);
let blobURL = URL.createObjectURL(await response.blob());
createdBlobURLs.push(blobURL);
return blobURL;
});
registerCleanupFunction(async () => {
sinon.restore();
for (let blobURL of createdBlobURLs) {
URL.revokeObjectURL(blobURL);
}
});
});
async function promiseEngineIconLoaded(engineName) {
@ -182,3 +221,38 @@ add_task(async function test_search_favicon() {
await searchExtWithBadIcon.unload();
await searchExtWithHttpIcon.unload();
});
add_task(async function test_app_provided_return_data_uris() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["search"],
},
files: {
"myFavicon.png": imageBuffer,
},
useAddonManager: "temporary",
async background() {
let engines = await browser.search.get();
browser.test.sendMessage(
"appEngine",
engines.find(engine => engine.name == "appEngineWithIcon")
);
},
});
await extension.startup();
await AddonTestUtils.waitForSearchProviderStartup(extension);
Assert.deepEqual(
await extension.awaitMessage("appEngine"),
{
name: "appEngineWithIcon",
isDefault: true,
alias: undefined,
favIconUrl: IMAGE_DATA_URI,
},
"browser.search.get result for app provided engine should have a data URL for the icon"
);
await extension.unload();
});