Bug 1322308 - Allow WebExtensions to read the overriden homepage and newTab values, r=mixedpuppy

This introduces browser.browserSettings.homepageOverride and browser.browserSettings.newTabPageOverride
which will return the values of the overridden home page and the overridden new tab page.

These browserSettings are read-only.

MozReview-Commit-ID: A9vJP2QIaoA

--HG--
rename : browser/components/extensions/test/browser/browser_ext_url_overrides_home.js => browser/components/extensions/test/browser/browser_ext_chrome_settings_overrides_home.js
extra : rebase_source : 7c3fc91a5ca489b909a8b60d5b4a882180a0276e
This commit is contained in:
Bob Silverberg 2017-07-17 14:16:02 -04:00
Родитель 8ae9f03df3
Коммит e98081a6dd
7 изменённых файлов: 235 добавлений и 57 удалений

Просмотреть файл

@ -52,6 +52,7 @@ skip-if = (os == 'win' && !debug) # bug 1352668
[browser_ext_browsingData_localStorage.js]
[browser_ext_browsingData_pluginData.js]
[browser_ext_browsingData_serviceWorkers.js]
[browser_ext_chrome_settings_overrides_home.js]
[browser_ext_commands_execute_browser_action.js]
[browser_ext_commands_execute_page_action.js]
[browser_ext_commands_execute_sidebar_action.js]
@ -156,7 +157,6 @@ skip-if = debug || asan # Bug 1354681
[browser_ext_themes_icons.js]
[browser_ext_themes_validation.js]
[browser_ext_url_overrides_newtab.js]
[browser_ext_url_overrides_home.js]
[browser_ext_user_events.js]
[browser_ext_webRequest.js]
[browser_ext_webNavigation_frameId0.js]

Просмотреть файл

@ -13,33 +13,69 @@ const HOME_URI_2 = "http://example.com/";
const HOME_URI_3 = "http://example.org/";
const HOME_URI_4 = "http://example.net/";
const CONTROLLABLE = "controllable_by_this_extension";
const CONTROLLED_BY_THIS = "controlled_by_this_extension";
const CONTROLLED_BY_OTHER = "controlled_by_other_extensions";
add_task(async function test_multiple_extensions_overriding_home_page() {
let defaultHomePage = Preferences.get("browser.startup.homepage");
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_settings_overrides": {}},
useAddonManager: "temporary",
});
function background() {
browser.test.onMessage.addListener(async msg => {
switch (msg) {
case "checkHomepage":
let homepage = await browser.browserSettings.homepageOverride.get({});
browser.test.sendMessage("homepage", homepage);
break;
case "trySet":
await browser.browserSettings.homepageOverride.set({value: "foo"});
browser.test.sendMessage("homepageSet");
break;
case "tryClear":
await browser.browserSettings.homepageOverride.clear({});
browser.test.sendMessage("homepageCleared");
break;
}
});
}
let ext2 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_settings_overrides": {homepage: HOME_URI_2}},
let extObj = {
manifest: {
"chrome_settings_overrides": {},
permissions: ["browserSettings"],
},
useAddonManager: "temporary",
});
background,
};
let ext3 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_settings_overrides": {homepage: HOME_URI_3}},
useAddonManager: "temporary",
});
let ext1 = ExtensionTestUtils.loadExtension(extObj);
let ext4 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_settings_overrides": {homepage: HOME_URI_4}},
useAddonManager: "temporary",
});
extObj.manifest.chrome_settings_overrides = {homepage: HOME_URI_2};
let ext2 = ExtensionTestUtils.loadExtension(extObj);
extObj.manifest.chrome_settings_overrides = {homepage: HOME_URI_3};
let ext3 = ExtensionTestUtils.loadExtension(extObj);
extObj.manifest.chrome_settings_overrides = {homepage: HOME_URI_4};
let ext4 = ExtensionTestUtils.loadExtension(extObj);
extObj.manifest.chrome_settings_overrides = {};
let ext5 = ExtensionTestUtils.loadExtension(extObj);
async function checkHomepageOverride(ext, expectedValue, expectedLevelOfControl) {
ext.sendMessage("checkHomepage");
let homepage = await ext.awaitMessage("homepage");
is(homepage.value, expectedValue,
`homepageOverride setting returns the expected value: ${expectedValue}.`);
is(homepage.levelOfControl, expectedLevelOfControl,
`homepageOverride setting returns the expected levelOfControl: ${expectedLevelOfControl}.`);
}
await ext1.startup();
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
"Home url should be the default");
await checkHomepageOverride(ext1, null, CONTROLLABLE);
// Because we are expecting the pref to change when we start or unload, we
// need to wait on a pref change. This is because the pref management is
@ -51,9 +87,22 @@ add_task(async function test_multiple_extensions_overriding_home_page() {
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
"Home url should be overridden by the second extension.");
await checkHomepageOverride(ext1, HOME_URI_2, CONTROLLED_BY_OTHER);
// Verify that calling set and clear do nothing.
ext2.sendMessage("trySet");
await ext2.awaitMessage("homepageSet");
await checkHomepageOverride(ext1, HOME_URI_2, CONTROLLED_BY_OTHER);
ext2.sendMessage("tryClear");
await ext2.awaitMessage("homepageCleared");
await checkHomepageOverride(ext1, HOME_URI_2, CONTROLLED_BY_OTHER);
// Because we are unloading an earlier extension, browser.startup.homepage won't change
await ext1.unload();
await checkHomepageOverride(ext2, HOME_URI_2, CONTROLLED_BY_THIS);
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
"Home url should be overridden by the second extension.");
@ -64,12 +113,16 @@ add_task(async function test_multiple_extensions_overriding_home_page() {
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_3),
"Home url should be overridden by the third extension.");
await checkHomepageOverride(ext3, HOME_URI_3, CONTROLLED_BY_THIS);
// Because we are unloading an earlier extension, browser.startup.homepage won't change
await ext2.unload();
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_3),
"Home url should be overridden by the third extension.");
await checkHomepageOverride(ext3, HOME_URI_3, CONTROLLED_BY_THIS);
prefPromise = promisePrefChangeObserved("browser.startup.homepage");
await ext4.startup();
await prefPromise;
@ -77,6 +130,7 @@ add_task(async function test_multiple_extensions_overriding_home_page() {
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_4),
"Home url should be overridden by the third extension.");
await checkHomepageOverride(ext3, HOME_URI_4, CONTROLLED_BY_OTHER);
prefPromise = promisePrefChangeObserved("browser.startup.homepage");
await ext4.unload();
@ -85,12 +139,18 @@ add_task(async function test_multiple_extensions_overriding_home_page() {
ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_3),
"Home url should be overridden by the third extension.");
await checkHomepageOverride(ext3, HOME_URI_3, CONTROLLED_BY_THIS);
prefPromise = promisePrefChangeObserved("browser.startup.homepage");
await ext3.unload();
await prefPromise;
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
"Home url should be reset to default");
await ext5.startup();
await checkHomepageOverride(ext5, null, CONTROLLABLE);
await ext5.unload();
});
const HOME_URI_1 = "http://example.com/";

Просмотреть файл

@ -37,44 +37,92 @@ function awaitEvent(eventName) {
}
add_task(async function test_multiple_extensions_overriding_newtab_page() {
const NEWTAB_URI_1 = "webext-newtab-1.html";
const NEWTAB_URI_2 = "webext-newtab-2.html";
const NEWTAB_URI_2 = "webext-newtab-1.html";
const NEWTAB_URI_3 = "webext-newtab-2.html";
const EXT_2_ID = "ext2@tests.mozilla.org";
const EXT_3_ID = "ext3@tests.mozilla.org";
const CONTROLLABLE = "controllable_by_this_extension";
const CONTROLLED_BY_THIS = "controlled_by_this_extension";
const CONTROLLED_BY_OTHER = "controlled_by_other_extensions";
function background() {
browser.test.onMessage.addListener(async msg => {
switch (msg) {
case "checkNewTabPage":
let newTabPage = await browser.browserSettings.newTabPageOverride.get({});
browser.test.sendMessage("newTabPage", newTabPage);
break;
case "trySet":
await browser.browserSettings.newTabPageOverride.set({value: "foo"});
browser.test.sendMessage("newTabPageSet");
break;
case "tryClear":
await browser.browserSettings.newTabPageOverride.clear({});
browser.test.sendMessage("newTabPageCleared");
break;
}
});
}
async function checkNewTabPageOverride(ext, expectedValue, expectedLevelOfControl) {
ext.sendMessage("checkNewTabPage");
let newTabPage = await ext.awaitMessage("newTabPage");
if (expectedValue) {
ok(newTabPage.value.endsWith(expectedValue),
`newTabPageOverride setting returns the expected value ending with: ${expectedValue}.`);
} else {
equal(newTabPage.value, expectedValue,
`newTabPageOverride setting returns the expected value: ${expectedValue}.`);
}
equal(newTabPage.levelOfControl, expectedLevelOfControl,
`newTabPageOverride setting returns the expected levelOfControl: ${expectedLevelOfControl}.`);
}
let extObj = {
manifest: {
"chrome_url_overrides": {},
permissions: ["browserSettings"],
},
useAddonManager: "temporary",
background,
};
let ext1 = ExtensionTestUtils.loadExtension(extObj);
extObj.manifest.chrome_url_overrides = {newtab: NEWTAB_URI_2};
extObj.manifest.applications = {gecko: {id: EXT_2_ID}};
let ext2 = ExtensionTestUtils.loadExtension(extObj);
extObj.manifest.chrome_url_overrides = {newtab: NEWTAB_URI_3};
extObj.manifest.applications.gecko.id = EXT_3_ID;
let ext3 = ExtensionTestUtils.loadExtension(extObj);
equal(aboutNewTabService.newTabURL, "about:newtab",
"Default newtab url is about:newtab");
await promiseStartupManager();
let ext1 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {}},
useAddonManager: "temporary",
});
let ext2 = ExtensionTestUtils.loadExtension({
manifest: {
"chrome_url_overrides": {newtab: NEWTAB_URI_1},
applications: {
gecko: {
id: EXT_2_ID,
},
},
},
useAddonManager: "temporary",
});
let ext3 = ExtensionTestUtils.loadExtension({
manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI_2}},
useAddonManager: "temporary",
});
await ext1.startup();
equal(aboutNewTabService.newTabURL, "about:newtab",
"Default newtab url is still about:newtab");
await checkNewTabPageOverride(ext1, null, CONTROLLABLE);
await ext2.startup();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
"Newtab url is overriden by the second extension.");
await checkNewTabPageOverride(ext1, NEWTAB_URI_2, CONTROLLED_BY_OTHER);
// Verify that calling set and clear do nothing.
ext2.sendMessage("trySet");
await ext2.awaitMessage("newTabPageSet");
await checkNewTabPageOverride(ext1, NEWTAB_URI_2, CONTROLLED_BY_OTHER);
ext2.sendMessage("tryClear");
await ext2.awaitMessage("newTabPageCleared");
await checkNewTabPageOverride(ext1, NEWTAB_URI_2, CONTROLLED_BY_OTHER);
// Disable the second extension.
let addon = await AddonManager.getAddonByID(EXT_2_ID);
@ -83,39 +131,46 @@ add_task(async function test_multiple_extensions_overriding_newtab_page() {
await disabledPromise;
equal(aboutNewTabService.newTabURL, "about:newtab",
"Newtab url is about:newtab after second extension is disabled.");
await checkNewTabPageOverride(ext1, null, CONTROLLABLE);
// Re-enable the second extension.
let enabledPromise = awaitEvent("ready");
addon.userDisabled = false;
await enabledPromise;
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
"Newtab url is overriden by the second extension.");
await checkNewTabPageOverride(ext2, NEWTAB_URI_2, CONTROLLED_BY_THIS);
await ext1.unload();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
"Newtab url is still overriden by the second extension.");
await checkNewTabPageOverride(ext2, NEWTAB_URI_2, CONTROLLED_BY_THIS);
await ext3.startup();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_3),
"Newtab url is overriden by the third extension.");
await checkNewTabPageOverride(ext2, NEWTAB_URI_3, CONTROLLED_BY_OTHER);
// Disable the second extension.
disabledPromise = awaitEvent("shutdown");
addon.userDisabled = true;
await disabledPromise;
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_3),
"Newtab url is still overriden by the third extension.");
await checkNewTabPageOverride(ext3, NEWTAB_URI_3, CONTROLLED_BY_THIS);
// Re-enable the second extension.
enabledPromise = awaitEvent("ready");
addon.userDisabled = false;
await enabledPromise;
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_3),
"Newtab url is still overriden by the third extension.");
await checkNewTabPageOverride(ext3, NEWTAB_URI_3, CONTROLLED_BY_THIS);
await ext3.unload();
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
"Newtab url reverts to being overriden by the second extension.");
await checkNewTabPageOverride(ext2, NEWTAB_URI_2, CONTROLLED_BY_THIS);
await ext2.unload();
equal(aboutNewTabService.newTabURL, "about:newtab",

Просмотреть файл

@ -296,6 +296,19 @@ this.ExtensionPreferencesManager = {
await Promise.all(removePromises);
},
/**
* Return the currently active value for a setting.
*
* @param {string} name
* The unique id of the setting.
*
* @returns {Object} The current setting object.
*/
async getSetting(name) {
await ExtensionSettingsStore.initialize();
return ExtensionSettingsStore.getSetting(STORE_TYPE, name);
},
/**
* Return the levelOfControl for a setting / extension combo.
* This queries the levelOfControl from the ExtensionSettingsStore and also
@ -305,17 +318,24 @@ this.ExtensionPreferencesManager = {
* The extension for which levelOfControl is being requested.
* @param {string} name
* The unique id of the setting.
* @param {string} storeType
* The name of the store in ExtensionSettingsStore.
* Defaults to STORE_TYPE.
*
* @returns {Promise}
* Resolves to the level of control of the extension over the setting.
*/
async getLevelOfControl(extension, name) {
for (let prefName of settingsMap.get(name).prefNames) {
if (Preferences.locked(prefName)) {
return "not_controllable";
async getLevelOfControl(extension, name, storeType = STORE_TYPE) {
// This could be called for a setting that isn't defined to the PreferencesManager,
// in which case we simply defer to the SettingsStore.
if (storeType === STORE_TYPE) {
for (let prefName of settingsMap.get(name).prefNames) {
if (Preferences.locked(prefName)) {
return "not_controllable";
}
}
}
await ExtensionSettingsStore.initialize();
return ExtensionSettingsStore.getLevelOfControl(extension, STORE_TYPE, name);
return ExtensionSettingsStore.getLevelOfControl(extension, storeType, name);
},
};

Просмотреть файл

@ -2,28 +2,38 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/ExtensionPreferencesManager.jsm");
const getSettingsAPI = (extension, name, callback) => {
const HOMEPAGE_OVERRIDE_SETTING = "homepage_override";
const URL_STORE_TYPE = "url_overrides";
const NEW_TAB_OVERRIDE_SETTING = "newTabURL";
const getSettingsAPI = (extension, name, callback, storeType, readOnly = false) => {
return {
async get(details) {
return {
levelOfControl: details.incognito ?
"not_controllable" :
await ExtensionPreferencesManager.getLevelOfControl(
extension, name),
extension, name, storeType),
value: await callback(),
};
},
set(details) {
return ExtensionPreferencesManager.setSetting(
extension, name, details.value);
if (!readOnly) {
return ExtensionPreferencesManager.setSetting(
extension, name, details.value);
}
},
clear(details) {
return ExtensionPreferencesManager.removeSetting(extension, name);
if (!readOnly) {
return ExtensionPreferencesManager.removeSetting(extension, name);
}
},
};
};
@ -73,6 +83,25 @@ this.browserSettings = class extends ExtensionAPI {
return Preferences.get("browser.cache.disk.enable") &&
Preferences.get("browser.cache.memory.enable");
}),
homepageOverride: getSettingsAPI(extension,
HOMEPAGE_OVERRIDE_SETTING,
async () => {
let homepageSetting = await ExtensionPreferencesManager.getSetting(HOMEPAGE_OVERRIDE_SETTING);
if (homepageSetting) {
return homepageSetting.value;
}
return null;
}, undefined, true),
newTabPageOverride: getSettingsAPI(extension,
NEW_TAB_OVERRIDE_SETTING,
async () => {
await ExtensionSettingsStore.initialize();
let newTabPageSetting = ExtensionSettingsStore.getSetting(URL_STORE_TYPE, NEW_TAB_OVERRIDE_SETTING);
if (newTabPageSetting) {
return newTabPageSetting.value;
}
return null;
}, URL_STORE_TYPE, true),
},
};
}

Просмотреть файл

@ -29,6 +29,14 @@
"cacheEnabled": {
"$ref": "types.Setting",
"description": "Enables or disables the browser cache."
},
"homepageOverride": {
"$ref": "types.Setting",
"description": "Returns the value of the overridden home page. Read-only."
},
"newTabPageOverride": {
"$ref": "types.Setting",
"description": "Returns the value of the overridden new tab page. Read-only."
}
}
}

Просмотреть файл

@ -119,6 +119,9 @@ add_task(async function test_preference_manager() {
"controlled_by_this_extension",
"getLevelOfControl returns correct levelOfControl when a pref has been set.");
let checkSetting = await ExtensionPreferencesManager.getSetting(setting);
equal(checkSetting.value, newValue1, "getSetting returns the expected value.");
let newValue2 = "newValue2";
prefsChanged = await ExtensionPreferencesManager.setSetting(extensions[0], setting, newValue2);
ok(!prefsChanged, "setSetting returns false when the pref(s) have not been set.");
@ -166,6 +169,9 @@ add_task(async function test_preference_manager() {
equal(Preferences.get(settingObj.prefNames[i]), settingObj.initalValues[i],
"removeSetting sets the pref(s) to the initial value(s) when removing the last extension.");
}
checkSetting = await ExtensionPreferencesManager.getSetting(setting);
equal(checkSetting, null, "getSetting returns null when nothing has been set.");
}
// Tests for unsetAll.