From 448b3cfbd87ec0f60e50ba14225ca8d22c3afbda Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Wed, 10 Feb 2010 13:37:48 -0800 Subject: [PATCH] Bug 544753: Add-ons manager is blank when a custom persona has been created by an older version of the personas extension. r=dao --- .../extensions/LightweightThemeManager.jsm | 82 +++++++++++------- .../mozapps/extensions/content/extensions.js | 5 +- .../test/unit/test_LightweightThemeManager.js | 86 +++++++++++++++++++ 3 files changed, 141 insertions(+), 32 deletions(-) diff --git a/toolkit/mozapps/extensions/LightweightThemeManager.jsm b/toolkit/mozapps/extensions/LightweightThemeManager.jsm index 1c90bd0e0940..f083de1945fd 100644 --- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm +++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm @@ -109,6 +109,8 @@ var LightweightThemeManager = { }, set currentTheme (aData) { + aData = _sanitizeTheme(aData); + let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); cancel.data = false; _observerService.notifyObservers(cancel, "lightweight-theme-change-requested", @@ -190,39 +192,10 @@ var LightweightThemeManager = { parseTheme: function (aString, aBaseURI) { try { - var data = JSON.parse(aString); + return _sanitizeTheme(JSON.parse(aString), aBaseURI); } catch (e) { return null; } - - if (!data || typeof data != "object") - return null; - - for (let prop in data) { - if (typeof data[prop] == "string" && - (data[prop] = data[prop].trim()) && - (MANDATORY.indexOf(prop) > -1 || OPTIONAL.indexOf(prop) > -1)) { - if (!/URL$/.test(prop)) - continue; - - try { - data[prop] = _makeURI(data[prop], _makeURI(aBaseURI)).spec; - if (/^https:/.test(data[prop])) - continue; - if (prop != "updateURL" && /^http:/.test(data[prop])) - continue; - } catch (e) {} - } - - delete data[prop]; - } - - for (let i = 0; i < MANDATORY.length; i++) { - if (!(MANDATORY[i] in data)) - return null; - } - - return data; }, updateCurrentTheme: function () { @@ -264,8 +237,55 @@ var LightweightThemeManager = { } }; +function _sanitizeTheme(aData, aBaseURI) { + if (!aData || typeof aData != "object") + return null; + + function sanitizeProperty(prop) { + if (!(prop in aData)) + return null; + if (typeof aData[prop] != "string") + return null; + let val = aData[prop].trim(); + if (!val) + return null; + + if (!/URL$/.test(prop)) + return val; + + try { + val = _makeURI(val, aBaseURI ? _makeURI(aBaseURI) : null).spec; + if (/^https:/.test(val)) + return val; + if (prop != "updateURL" && /^http:/.test(val)) + return val; + return null; + } + catch (e) { + return null; + } + } + + let result = {}; + for (let i = 0; i < MANDATORY.length; i++) { + let val = sanitizeProperty(MANDATORY[i]); + if (!val) + throw Components.results.NS_ERROR_INVALID_ARG; + result[MANDATORY[i]] = val; + } + + for (let i = 0; i < OPTIONAL.length; i++) { + let val = sanitizeProperty(OPTIONAL[i]); + if (!val) + continue; + result[OPTIONAL[i]] = val; + } + + return result; +} + function _usedThemesExceptId(aId) - LightweightThemeManager.usedThemes.filter(function (t) t.id != aId); + LightweightThemeManager.usedThemes.filter(function (t) "id" in t && t.id != aId); function _version(aThemeData) aThemeData.version || ""; diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index eb1aae4b05ed..7f60d992adbf 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -920,11 +920,14 @@ function rebuildLWThemeDS() { for (var i = 0; i < themes.length; i++) { var theme = themes[i]; + if (!("id" in theme)) + continue; + var themeNode = gRDF.GetResource(PREFIX_LWTHEME_URI + theme.id); rootctr.AppendElement(themeNode); gLWThemeDS.Assert(themeNode, gRDF.GetResource(PREFIX_NS_EM + "name"), - gRDF.GetLiteral(theme.name), + gRDF.GetLiteral(theme.name || ""), true); gLWThemeDS.Assert(themeNode, gRDF.GetResource(PREFIX_NS_EM + "addonID"), diff --git a/toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js b/toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js index 31137e8c3868..edfc6fe60664 100644 --- a/toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js +++ b/toolkit/mozapps/extensions/test/unit/test_LightweightThemeManager.js @@ -1,3 +1,6 @@ +const Cc = Components.classes; +const Ci = Components.interfaces; + const MANDATORY = ["id", "name", "headerURL"]; const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL", "previewURL", "author", "description", "homepageURL", @@ -247,4 +250,87 @@ function run_test() { }, function (after, prop) { do_check_eq(typeof after[prop], "undefined"); }); + + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + data = dummy(); + delete data.name; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with no name"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + data.headerURL = "foo"; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with a bad headerURL"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + data.headerURL = "ftp://lwtest.invalid/test.png"; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with a bad headerURL"); + } + catch (e) { + // Expected exception + } + + data = dummy(); + delete data.id; + try { + ltm.currentTheme = data; + do_throw("Should have rejected a theme with no ID"); + } + catch (e) { + // Expected exception + } + + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + // Force the theme into the prefs anyway + let prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch); + let themes = [data]; + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes)); + do_check_eq(ltm.usedThemes.length, 1); + + // This should silently drop the bad theme. + ltm.currentTheme = dummy(); + do_check_eq(ltm.usedThemes.length, 1); + ltm.forgetUsedTheme(ltm.currentTheme.id); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + // Add one broken and some working. + themes = [data, dummy("x1"), dummy("x2")]; + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes)); + do_check_eq(ltm.usedThemes.length, 3); + + // Switching to an existing theme should drop the bad theme. + ltm.currentTheme = ltm.getUsedTheme("x1"); + do_check_eq(ltm.usedThemes.length, 2); + ltm.forgetUsedTheme("x1"); + ltm.forgetUsedTheme("x2"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); + + prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify(themes)); + do_check_eq(ltm.usedThemes.length, 3); + + // Forgetting an existing theme should drop the bad theme. + ltm.forgetUsedTheme("x1"); + do_check_eq(ltm.usedThemes.length, 1); + ltm.forgetUsedTheme("x2"); + do_check_eq(ltm.usedThemes.length, 0); + do_check_eq(ltm.currentTheme, null); }