mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 20:55:39 +00:00
Bug 1338525 - Add schema validation for webextension themes r=mikedeboer,mossop
MozReview-Commit-ID: 3QjDrTeMKH0 --HG-- extra : rebase_source : e487b3a12d3645de5f846305ae7b99532d15dcc5
This commit is contained in:
parent
1ff3ed4ad5
commit
bb56bb5645
@ -85,6 +85,7 @@ const {
|
||||
LocaleData,
|
||||
StartupCache,
|
||||
getUniqueId,
|
||||
validateThemeManifest,
|
||||
} = ExtensionUtils;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "console", ExtensionUtils.getConsole);
|
||||
@ -429,6 +430,17 @@ this.ExtensionData = class {
|
||||
preprocessors: {},
|
||||
};
|
||||
|
||||
if (this.manifest.theme) {
|
||||
let invalidProps = validateThemeManifest(Object.getOwnPropertyNames(this.manifest));
|
||||
|
||||
if (invalidProps.length) {
|
||||
let message = `Themes defined in the manifest may only contain static resources. ` +
|
||||
`If you would like to use additional properties, please use the "theme" permission instead. ` +
|
||||
`(the invalid properties found are: ${invalidProps})`;
|
||||
this.manifestError(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.localeData) {
|
||||
context.preprocessors.localize = (value, context) => this.localize(value);
|
||||
}
|
||||
|
@ -861,11 +861,28 @@ function watchExtensionProxyContextLoad({extension, viewType, browser}, onExtens
|
||||
};
|
||||
}
|
||||
|
||||
// Used to cache the list of WebExtensionManifest properties defined in the BASE_SCHEMA.
|
||||
let gBaseManifestProperties = null;
|
||||
|
||||
const ExtensionParent = {
|
||||
GlobalManager,
|
||||
HiddenExtensionPage,
|
||||
ParentAPIManager,
|
||||
apiManager,
|
||||
get baseManifestProperties() {
|
||||
if (gBaseManifestProperties) {
|
||||
return gBaseManifestProperties;
|
||||
}
|
||||
|
||||
let types = Schemas.schemaJSON.get(BASE_SCHEMA)[0].types;
|
||||
let manifest = types.find(type => type.id === "WebExtensionManifest");
|
||||
if (!manifest) {
|
||||
throw new Error("Unable to find base manifest properties");
|
||||
}
|
||||
|
||||
gBaseManifestProperties = Object.getOwnPropertyNames(manifest.properties);
|
||||
return gBaseManifestProperties;
|
||||
},
|
||||
promiseExtensionViewLoaded,
|
||||
watchExtensionProxyContextLoad,
|
||||
};
|
||||
|
@ -61,6 +61,39 @@ function getUniqueId() {
|
||||
return `${nextId++}-${uniqueProcessID}`;
|
||||
}
|
||||
|
||||
// The list of properties that themes are allowed to contain.
|
||||
XPCOMUtils.defineLazyGetter(this, "gAllowedThemeProperties", () => {
|
||||
Cu.import("resource://gre/modules/ExtensionParent.jsm");
|
||||
let propertiesInBaseManifest = ExtensionParent.baseManifestProperties;
|
||||
|
||||
// The properties found in the base manifest contain all of the properties that
|
||||
// themes are allowed to have. However, the list also contains several properties
|
||||
// that aren't allowed, so we need to filter them out first before the list can
|
||||
// be used to validate themes.
|
||||
return propertiesInBaseManifest.filter(prop => {
|
||||
const propertiesToRemove = ["background", "content_scripts", "permissions"];
|
||||
return !propertiesToRemove.includes(prop);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Validates a theme to ensure it only contains static resources.
|
||||
*
|
||||
* @param {Array<string> manifestProperties} The list of top-level keys found in the
|
||||
* the extension's manifest.
|
||||
* @returns {Array<string>} A list of invalid properties or an empty list
|
||||
* if none are found.
|
||||
*/
|
||||
function validateThemeManifest(manifestProperties) {
|
||||
let invalidProps = [];
|
||||
for (let propName of manifestProperties) {
|
||||
if (propName != "theme" && !gAllowedThemeProperties.includes(propName)) {
|
||||
invalidProps.push(propName);
|
||||
}
|
||||
}
|
||||
return invalidProps;
|
||||
}
|
||||
|
||||
let StartupCache = {
|
||||
DB_NAME: "ExtensionStartupCache",
|
||||
|
||||
@ -1314,6 +1347,7 @@ this.ExtensionUtils = {
|
||||
runSafeSyncWithoutClone,
|
||||
runSafeWithoutClone,
|
||||
stylesheetMap,
|
||||
validateThemeManifest,
|
||||
DefaultMap,
|
||||
DefaultWeakMap,
|
||||
EventEmitter,
|
||||
|
@ -7,6 +7,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gThemesEnabled", () => {
|
||||
return Preferences.get("extensions.webextensions.themes.enabled");
|
||||
});
|
||||
|
||||
// WeakMap[Extension -> Theme]
|
||||
let themeMap = new WeakMap();
|
||||
|
||||
@ -154,7 +158,7 @@ class Theme {
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extensions.on("manifest_theme", (type, directive, extension, manifest) => {
|
||||
if (!Preferences.get("extensions.webextensions.themes.enabled")) {
|
||||
if (!gThemesEnabled) {
|
||||
// Return early if themes are disabled.
|
||||
return;
|
||||
}
|
||||
@ -181,11 +185,18 @@ extensions.registerSchemaAPI("theme", "addon_parent", context => {
|
||||
return {
|
||||
theme: {
|
||||
update(details) {
|
||||
if (!gThemesEnabled) {
|
||||
// Return early if themes are disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
let theme = themeMap.get(extension);
|
||||
|
||||
// We won't have a theme if theme's aren't enabled.
|
||||
// Themes which use `update` cannot have a theme defined
|
||||
// in the manifest. Therefore, we need to initialize the
|
||||
// theme the first time `update` is called.
|
||||
if (!theme) {
|
||||
return;
|
||||
themeMap.set(extension, new Theme(extension.baseURI));
|
||||
}
|
||||
|
||||
theme.load(details);
|
||||
|
@ -6,6 +6,15 @@
|
||||
{
|
||||
"namespace": "manifest",
|
||||
"types": [
|
||||
{
|
||||
"$extend": "Permission",
|
||||
"choices": [{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"theme"
|
||||
]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id": "ThemeType",
|
||||
"type": "object",
|
||||
@ -202,7 +211,7 @@
|
||||
{
|
||||
"namespace": "theme",
|
||||
"description": "The theme API allows customizing of visual elements of the browser.",
|
||||
"permissions": ["manifest:theme"],
|
||||
"permissions": ["theme"],
|
||||
"functions": [
|
||||
{
|
||||
"name": "update",
|
||||
|
@ -40,15 +40,7 @@ add_task(function* setup() {
|
||||
add_task(function* test_dynamic_theme_updates() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": BACKGROUND_1,
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
},
|
||||
},
|
||||
permissions: ["theme"],
|
||||
},
|
||||
background() {
|
||||
browser.test.onMessage.addListener((msg, details) => {
|
||||
@ -64,6 +56,18 @@ add_task(function* test_dynamic_theme_updates() {
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
extension.sendMessage("update-theme", {
|
||||
"images": {
|
||||
"headerURL": BACKGROUND_1,
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.awaitMessage("theme-updated");
|
||||
|
||||
validateTheme(BACKGROUND_1, ACCENT_COLOR_1, TEXT_COLOR_1);
|
||||
|
||||
extension.sendMessage("update-theme", {
|
||||
|
Loading…
Reference in New Issue
Block a user