--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -458,17 +458,17 @@ appUpdater.prototype =
}
}
},
/**
* See XPIProvider.jsm
*/
onUpdateAvailable: function(aAddon, aInstall) {
- if (!Services.blocklist.isAddonBlocklisted(aAddon.id, aInstall.version,
+ if (!Services.blocklist.isAddonBlocklisted(aAddon,
this.update.appVersion,
this.update.platformVersion)) {
// Compatibility or new version updates mean the same thing here.
this.onCompatibilityUpdateAvailable(aAddon);
}
},
/**
--- a/browser/base/content/test/social/browser_blocklist.js
+++ b/browser/base/content/test/social/browser_blocklist.js
@@ -31,20 +31,20 @@ function test() {
resetBlocklist(finish); //restore to original pref
});
}
var tests = {
testSimpleBlocklist: function(next) {
// this really just tests adding and clearing our blocklist for later tests
setAndUpdateBlocklist(blocklistURL, function() {
- ok(Services.blocklist.isAddonBlocklisted("test1.example.com@services.mozilla.org", "0", "0", "0"), "blocking 'blocked'");
- ok(!Services.blocklist.isAddonBlocklisted("example.com@services.mozilla.org", "0", "0", "0"), "not blocking 'good'");
+ ok(Services.blocklist.isAddonBlocklisted(SocialService.createWrapper(manifest_bad)), "blocking 'blocked'");
+ ok(!Services.blocklist.isAddonBlocklisted(SocialService.createWrapper(manifest)), "not blocking 'good'");
resetBlocklist(function() {
- ok(!Services.blocklist.isAddonBlocklisted("test1.example.com@services.mozilla.org", "0", "0", "0"), "blocklist cleared");
+ ok(!Services.blocklist.isAddonBlocklisted(SocialService.createWrapper(manifest_bad)), "blocklist cleared");
next();
});
});
},
testAddingNonBlockedProvider: function(next) {
function finish(isgood) {
ok(isgood, "adding non-blocked provider ok");
Services.prefs.clearUserPref("social.manifest.good");
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -2084,35 +2084,83 @@ let CustomizableUIInternal = {
}
return true;
}
};
Object.freeze(CustomizableUIInternal);
this.CustomizableUI = {
+ /**
+ * Constant reference to the ID of the menu panel.
+ */
get AREA_PANEL() "PanelUI-contents",
+ /**
+ * Constant reference to the ID of the navigation toolbar.
+ */
get AREA_NAVBAR() "nav-bar",
+ /**
+ * Constant reference to the ID of the menubar's toolbar.
+ */
get AREA_MENUBAR() "toolbar-menubar",
+ /**
+ * Constant reference to the ID of the tabstrip toolbar.
+ */
get AREA_TABSTRIP() "TabsToolbar",
+ /**
+ * Constant reference to the ID of the bookmarks toolbar.
+ */
get AREA_BOOKMARKS() "PersonalToolbar",
+ /**
+ * Constant reference to the ID of the addon-bar toolbar shim.
+ * Do not use, this will be removed as soon as reasonably possible.
+ * @deprecated
+ */
get AREA_ADDONBAR() "addon-bar",
-
+ /**
+ * Constant indicating the area is a menu panel.
+ */
+ get TYPE_MENU_PANEL() "menu-panel",
+ /**
+ * Constant indicating the area is a toolbar.
+ */
+ get TYPE_TOOLBAR() "toolbar",
+
+ /**
+ * Constant indicating a XUL-type provider.
+ */
get PROVIDER_XUL() "xul",
+ /**
+ * Constant indicating an API-type provider.
+ */
get PROVIDER_API() "api",
+ /**
+ * Constant indicating dynamic (special) widgets: spring, spacer, and separator.
+ */
get PROVIDER_SPECIAL() "special",
+ /**
+ * Constant indicating the widget is built-in
+ */
get SOURCE_BUILTIN() "builtin",
+ /**
+ * Constant indicating the widget is externally provided
+ * (e.g. by add-ons or other items not part of the builtin widget set).
+ */
get SOURCE_EXTERNAL() "external",
get TYPE_BUTTON() "button",
- get TYPE_MENU_PANEL() "menu-panel",
- get TYPE_TOOLBAR() "toolbar",
-
+
+ /**
+ * The class used to distinguish items that span the entire menu panel.
+ */
get WIDE_PANEL_CLASS() "panel-wide-item",
+ /**
+ * The (constant) number of columns in the menu panel.
+ */
get PANEL_COLUMN_COUNT() 3,
/**
* Add a listener object that will get fired for various events regarding
* customization.
*
* @param aListener the listener object to add
*
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -113,106 +113,106 @@
command="addWatchExpressionCommand"/>
<menuseparator/>
<menuitem id="cMenu_copy"/>
<menuseparator/>
<menuitem id="cMenu_selectAll"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findFile"
label="&debuggerUI.searchFile;"
- accesskey="&debuggerUI.searchFile.key;"
+ accesskey="&debuggerUI.searchFile.accesskey;"
key="fileSearchKey"
command="fileSearchCommand"/>
<menuitem id="se-dbg-cMenu-findGlobal"
label="&debuggerUI.searchGlobal;"
- accesskey="&debuggerUI.searchGlobal.key;"
+ accesskey="&debuggerUI.searchGlobal.accesskey;"
key="globalSearchKey"
command="globalSearchCommand"/>
<menuitem id="se-dbg-cMenu-findFunction"
label="&debuggerUI.searchFunction;"
- accesskey="&debuggerUI.searchFunction.key;"
+ accesskey="&debuggerUI.searchFunction.accesskey;"
key="functionSearchKey"
command="functionSearchCommand"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findToken"
label="&debuggerUI.searchToken;"
- accesskey="&debuggerUI.searchToken.key;"
+ accesskey="&debuggerUI.searchToken.accesskey;"
key="tokenSearchKey"
command="tokenSearchCommand"/>
<menuitem id="se-dbg-cMenu-findLine"
label="&debuggerUI.searchGoToLine;"
- accesskey="&debuggerUI.searchGoToLine.key;"
+ accesskey="&debuggerUI.searchGoToLine.accesskey;"
key="lineSearchKey"
command="lineSearchCommand"/>
<menuseparator/>
<menuitem id="se-dbg-cMenu-findVariable"
label="&debuggerUI.searchVariable;"
- accesskey="&debuggerUI.searchVariable.key;"
+ accesskey="&debuggerUI.searchVariable.accesskey;"
key="variableSearchKey"
command="variableSearchCommand"/>
<menuitem id="se-dbg-cMenu-focusVariables"
label="&debuggerUI.focusVariables;"
- accesskey="&debuggerUI.focusVariables.key;"
+ accesskey="&debuggerUI.focusVariables.accesskey;"
key="variablesFocusKey"
command="variablesFocusCommand"/>
<menuitem id="se-dbg-cMenu-prettyPrint"
label="&debuggerUI.sources.prettyPrint;"
command="prettyPrintCommand"/>
</menupopup>
<menupopup id="debuggerWatchExpressionsContextMenu">
<menuitem id="add-watch-expression"
label="&debuggerUI.addWatch;"
- accesskey="&debuggerUI.addWatch.key;"
+ accesskey="&debuggerUI.addWatch.accesskey;"
key="addWatchExpressionKey"
command="addWatchExpressionCommand"/>
<menuitem id="removeAll-watch-expression"
label="&debuggerUI.removeAllWatch;"
- accesskey="&debuggerUI.removeAllWatch.key;"
+ accesskey="&debuggerUI.removeAllWatch.accesskey;"
key="removeAllWatchExpressionsKey"
command="removeAllWatchExpressionsCommand"/>
</menupopup>
<menupopup id="debuggerPrefsContextMenu"
position="before_end"
onpopupshowing="DebuggerView.Options._onPopupShowing()"
onpopuphiding="DebuggerView.Options._onPopupHiding()"
onpopuphidden="DebuggerView.Options._onPopupHidden()">
<menuitem id="auto-pretty-print"
type="checkbox"
label="&debuggerUI.autoPrettyPrint;"
accesskey="&debuggerUI.autoPrettyPrint.key;"
command="toggleAutoPrettyPrint"/>
<menuitem id="pause-on-exceptions"
type="checkbox"
label="&debuggerUI.pauseExceptions;"
- accesskey="&debuggerUI.pauseExceptions.key;"
+ accesskey="&debuggerUI.pauseExceptions.accesskey;"
command="togglePauseOnExceptions"/>
<menuitem id="ignore-caught-exceptions"
type="checkbox"
label="&debuggerUI.ignoreCaughtExceptions;"
- accesskey="&debuggerUI.ignoreCaughtExceptions.key;"
+ accesskey="&debuggerUI.ignoreCaughtExceptions.accesskey;"
command="toggleIgnoreCaughtExceptions"/>
<menuitem id="show-panes-on-startup"
type="checkbox"
label="&debuggerUI.showPanesOnInit;"
- accesskey="&debuggerUI.showPanesOnInit.key;"
+ accesskey="&debuggerUI.showPanesOnInit.accesskey;"
command="toggleShowPanesOnStartup"/>
<menuitem id="show-vars-only-enum"
type="checkbox"
label="&debuggerUI.showOnlyEnum;"
- accesskey="&debuggerUI.showOnlyEnum.key;"
+ accesskey="&debuggerUI.showOnlyEnum.accesskey;"
command="toggleShowOnlyEnum"/>
<menuitem id="show-vars-filter-box"
type="checkbox"
label="&debuggerUI.showVarsFilter;"
- accesskey="&debuggerUI.showVarsFilter.key;"
+ accesskey="&debuggerUI.showVarsFilter.accesskey;"
command="toggleShowVariablesFilterBox"/>
<menuitem id="show-original-source"
type="checkbox"
label="&debuggerUI.showOriginalSource;"
- accesskey="&debuggerUI.showOriginalSource.key;"
+ accesskey="&debuggerUI.showOriginalSource.accesskey;"
command="toggleShowOriginalSource"/>
</menupopup>
</popupset>
<keyset id="debuggerKeys">
<key id="nextSourceKey"
keycode="VK_DOWN"
modifiers="accel alt"
--- a/browser/devtools/styleeditor/StyleEditorUtil.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUtil.jsm
@@ -167,18 +167,21 @@ this.wire = function wire(aRoot, aSelect
* @param boolean toSave
* If true, the user is selecting a filename to save.
* @param nsIWindow parentWindow
* Optional parent window. If null the parent window of the file picker
* will be the window of the attached input element.
* @param callback
* The callback method, which will be called passing in the selected
* file or null if the user did not pick one.
+ * @param AString suggestedFilename
+ * The suggested filename when toSave is true.
*/
-this.showFilePicker = function showFilePicker(path, toSave, parentWindow, callback)
+this.showFilePicker = function showFilePicker(path, toSave, parentWindow,
+ callback, suggestedFilename)
{
if (typeof(path) == "string") {
try {
if (Services.io.extractScheme(path) == "file") {
let uri = Services.io.newURI(path, null, null);
let file = uri.QueryInterface(Ci.nsIFileURL).file;
callback(file);
return;
@@ -208,14 +211,18 @@ this.showFilePicker = function showFileP
let fpCallback = function(result) {
if (result == Ci.nsIFilePicker.returnCancel) {
callback(null);
} else {
callback(fp.file);
}
};
+ if (toSave && suggestedFilename) {
+ fp.defaultString = suggestedFilename;
+ }
+
fp.init(parentWindow, _(key + ".title"), mode);
fp.appendFilters(_(key + ".filter"), "*.css");
fp.appendFilters(fp.filterAll);
fp.open(fpCallback);
return;
}
--- a/browser/devtools/styleeditor/StyleSheetEditor.jsm
+++ b/browser/devtools/styleeditor/StyleSheetEditor.jsm
@@ -14,16 +14,17 @@ const Cu = Components.utils;
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
const Editor = require("devtools/sourceeditor/editor");
const promise = require("sdk/core/promise");
const {CssLogic} = require("devtools/styleinspector/css-logic");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
const LOAD_ERROR = "error-load";
const SAVE_ERROR = "error-save";
// max update frequency in ms (avoid potential typing lag and/or flicker)
// @see StyleEditor.updateStylesheet
@@ -354,18 +355,23 @@ StyleSheetEditor.prototype = {
callback(returnFile);
}
this.sourceEditor.setClean();
this.emit("property-change");
}.bind(this));
};
- showFilePicker(file || this._styleSheetFilePath, true, this._window, onFile);
- },
+ let defaultName;
+ if (this._friendlyName) {
+ defaultName = OS.Path.basename(this._friendlyName);
+ }
+ showFilePicker(file || this._styleSheetFilePath, true, this._window,
+ onFile, defaultName);
+ },
/**
* Retrieve custom key bindings objects as expected by Editor.
* Editor action names are not displayed to the user.
*
* @return {array} key binding objects for the source editor
*/
_getKeyBindings: function() {
@@ -389,18 +395,18 @@ StyleSheetEditor.prototype = {
this.styleSheet.off("property-change", this._onPropertyChange);
this.styleSheet.off("error", this._onError);
}
}
const TAB_CHARS = "\t";
-const OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-const LINE_SEPARATOR = OS === "WINNT" ? "\r\n" : "\n";
+const CURRENT_OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+const LINE_SEPARATOR = CURRENT_OS === "WINNT" ? "\r\n" : "\n";
/**
* Prettify minified CSS text.
* This prettifies CSS code where there is no indentation in usual places while
* keeping original indentation as-is elsewhere.
*
* @param string text
* The CSS source to prettify.
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -63,95 +63,102 @@
<!ENTITY debuggerUI.clearButton "Clear">
<!-- LOCALIZATION NOTE (debuggerUI.clearButton.tooltip): This is the tooltip for
- the button that clears the collected tracing data in the tracing tab. -->
<!ENTITY debuggerUI.clearButton.tooltip "Clear the collected traces">
<!-- LOCALIZATION NOTE (debuggerUI.pauseExceptions): This is the label for the
- checkbox that toggles pausing on exceptions. -->
-<!ENTITY debuggerUI.pauseExceptions "Pause on exceptions">
-<!ENTITY debuggerUI.pauseExceptions.key "E">
+<!ENTITY debuggerUI.pauseExceptions "Pause on exceptions">
+<!ENTITY debuggerUI.pauseExceptions.accesskey "E">
<!-- LOCALIZATION NOTE (debuggerUI.ignoreCaughtExceptions): This is the label for the
- checkbox that toggles ignoring caught exceptions. -->
-<!ENTITY debuggerUI.ignoreCaughtExceptions "Ignore caught exceptions">
-<!ENTITY debuggerUI.ignoreCaughtExceptions.key "C">
+<!ENTITY debuggerUI.ignoreCaughtExceptions "Ignore caught exceptions">
+<!ENTITY debuggerUI.ignoreCaughtExceptions.accesskey "C">
<!-- LOCALIZATION NOTE (debuggerUI.showPanesOnInit): This is the label for the
- checkbox that toggles visibility of panes when opening the debugger. -->
-<!ENTITY debuggerUI.showPanesOnInit "Show panes on startup">
-<!ENTITY debuggerUI.showPanesOnInit.key "S">
+<!ENTITY debuggerUI.showPanesOnInit "Show panes on startup">
+<!ENTITY debuggerUI.showPanesOnInit.accesskey "S">
<!-- LOCALIZATION NOTE (debuggerUI.showVarsFilter): This is the label for the
- checkbox that toggles visibility of a designated variables filter box. -->
-<!ENTITY debuggerUI.showVarsFilter "Show variables filter box">
-<!ENTITY debuggerUI.showVarsFilter.key "V">
+<!ENTITY debuggerUI.showVarsFilter "Show variables filter box">
+<!ENTITY debuggerUI.showVarsFilter.accesskey "V">
<!-- LOCALIZATION NOTE (debuggerUI.showOnlyEnum): This is the label for the
- checkbox that toggles visibility of hidden (non-enumerable) variables and
- properties in stack views. The "enumerable" flag is a state of a property
- defined in JavaScript. When in doubt, leave untranslated. -->
-<!ENTITY debuggerUI.showOnlyEnum "Show only enumerable properties">
-<!ENTITY debuggerUI.showOnlyEnum.key "P">
+<!ENTITY debuggerUI.showOnlyEnum "Show only enumerable properties">
+<!ENTITY debuggerUI.showOnlyEnum.accesskey "P">
<!-- LOCALIZATION NOTE (debuggerUI.showOriginalSource): This is the label for
- the checkbox that toggles the display of original or sourcemap-derived
- sources. -->
-<!ENTITY debuggerUI.showOriginalSource "Show original sources">
-<!ENTITY debuggerUI.showOriginalSource.key "O">
+<!ENTITY debuggerUI.showOriginalSource "Show original sources">
+<!ENTITY debuggerUI.showOriginalSource.accesskey "O">
<!-- LOCALIZATION NOTE (debuggerUI.searchPanelOperators): This is the text that
- appears in the filter panel popup as a header for the operators part. -->
<!ENTITY debuggerUI.searchPanelOperators "Operators:">
<!-- LOCALIZATION NOTE (debuggerUI.searchFile): This is the text that appears
- in the source editor's context menu for the scripts search operation. -->
-<!ENTITY debuggerUI.searchFile "Filter scripts">
-<!ENTITY debuggerUI.searchFile.key "P">
-<!ENTITY debuggerUI.searchFile.altkey "O">
+<!ENTITY debuggerUI.searchFile "Filter scripts">
+<!ENTITY debuggerUI.searchFile.key "P">
+<!ENTITY debuggerUI.searchFile.altkey "O">
+<!ENTITY debuggerUI.searchFile.accesskey "P">
<!-- LOCALIZATION NOTE (debuggerUI.searchGlobal): This is the text that appears
- in the source editor's context menu for the global search operation. -->
-<!ENTITY debuggerUI.searchGlobal "Search in all files">
-<!ENTITY debuggerUI.searchGlobal.key "F">
+<!ENTITY debuggerUI.searchGlobal "Search in all files">
+<!ENTITY debuggerUI.searchGlobal.key "F">
+<!ENTITY debuggerUI.searchGlobal.accesskey "F">
<!-- LOCALIZATION NOTE (debuggerUI.searchFunction): This is the text that appears
- in the source editor's context menu for the function search operation. -->
-<!ENTITY debuggerUI.searchFunction "Search for function definition">
-<!ENTITY debuggerUI.searchFunction.key "D">
+<!ENTITY debuggerUI.searchFunction "Search for function definition">
+<!ENTITY debuggerUI.searchFunction.key "D">
+<!ENTITY debuggerUI.searchFunction.accesskey "D">
<!-- LOCALIZATION NOTE (debuggerUI.searchToken): This is the text that appears
- in the source editor's context menu for the token search operation. -->
-<!ENTITY debuggerUI.searchToken "Find">
-<!ENTITY debuggerUI.searchToken.key "F">
+<!ENTITY debuggerUI.searchToken "Find">
+<!ENTITY debuggerUI.searchToken.key "F">
+<!ENTITY debuggerUI.searchToken.accesskey "F">
<!-- LOCALIZATION NOTE (debuggerUI.searchLine): This is the text that appears
- in the source editor's context menu for the line search operation. -->
-<!ENTITY debuggerUI.searchGoToLine "Go to line…">
-<!ENTITY debuggerUI.searchGoToLine.key "L">
+<!ENTITY debuggerUI.searchGoToLine "Go to line…">
+<!ENTITY debuggerUI.searchGoToLine.key "L">
+<!ENTITY debuggerUI.searchGoToLine.accesskey "L">
<!-- LOCALIZATION NOTE (debuggerUI.searchVariable): This is the text that appears
- in the source editor's context menu for the variables search operation. -->
-<!ENTITY debuggerUI.searchVariable "Filter variables">
-<!ENTITY debuggerUI.searchVariable.key "V">
+<!ENTITY debuggerUI.searchVariable "Filter variables">
+<!ENTITY debuggerUI.searchVariable.key "V">
+<!ENTITY debuggerUI.searchVariable.accesskey "V">
<!-- LOCALIZATION NOTE (debuggerUI.focusVariables): This is the text that appears
- in the source editor's context menu for the variables focus operation. -->
-<!ENTITY debuggerUI.focusVariables "Focus variables tree">
-<!ENTITY debuggerUI.focusVariables.key "V">
+<!ENTITY debuggerUI.focusVariables "Focus variables tree">
+<!ENTITY debuggerUI.focusVariables.key "V">
+<!ENTITY debuggerUI.focusVariables.accesskey "V">
<!-- LOCALIZATION NOTE (debuggerUI.condBreakPanelTitle): This is the text that
- appears in the conditional breakpoint panel popup as a description. -->
<!ENTITY debuggerUI.condBreakPanelTitle "This breakpoint will stop execution only if the following expression is true">
<!-- LOCALIZATION NOTE (debuggerUI.seMenuBreak): This is the text that
- appears in the source editor context menu for adding a breakpoint. -->
-<!ENTITY debuggerUI.seMenuBreak "Add breakpoint">
-<!ENTITY debuggerUI.seMenuBreak.key "B">
+<!ENTITY debuggerUI.seMenuBreak "Add breakpoint">
+<!ENTITY debuggerUI.seMenuBreak.key "B">
<!-- LOCALIZATION NOTE (debuggerUI.seMenuCondBreak): This is the text that
- appears in the source editor context menu for adding a conditional
- breakpoint. -->
<!ENTITY debuggerUI.seMenuCondBreak "Add conditional breakpoint">
<!ENTITY debuggerUI.seMenuCondBreak.key "B">
<!-- LOCALIZATION NOTE (debuggerUI.tabs.*): This is the text that
@@ -165,22 +172,23 @@
<!-- LOCALIZATION NOTE (debuggerUI.seMenuAddWatch): This is the text that
- appears in the source editor context menu for adding an expression. -->
<!ENTITY debuggerUI.seMenuAddWatch "Selection to watch expression">
<!ENTITY debuggerUI.seMenuAddWatch.key "E">
<!-- LOCALIZATION NOTE (debuggerUI.addWatch): This is the text that
- appears in the watch expressions context menu for adding an expression. -->
<!ENTITY debuggerUI.addWatch "Add watch expression">
-<!ENTITY debuggerUI.addWatch.key "E">
+<!ENTITY debuggerUI.addWatch.accesskey "E">
<!-- LOCALIZATION NOTE (debuggerUI.removeWatch): This is the text that
- appears in the watch expressions context menu for removing all expressions. -->
-<!ENTITY debuggerUI.removeAllWatch "Remove all watch expressions">
-<!ENTITY debuggerUI.removeAllWatch.key "E">
+<!ENTITY debuggerUI.removeAllWatch "Remove all watch expressions">
+<!ENTITY debuggerUI.removeAllWatch.key "E">
+<!ENTITY debuggerUI.removeAllWatch.accesskey "E">
<!-- LOCALIZATION NOTE (debuggerUI.stepping): These are the keycodes that
- control the stepping commands in the debugger (continue, step over,
- step in and step out). -->
<!ENTITY debuggerUI.stepping.resume1 "VK_F8">
<!ENTITY debuggerUI.stepping.resume2 "VK_SLASH">
<!ENTITY debuggerUI.stepping.stepOver1 "VK_F10">
<!ENTITY debuggerUI.stepping.stepOver2 "VK_QUOTE">
--- a/browser/metro/base/content/flyoutpanels/AboutFlyoutPanel.js
+++ b/browser/metro/base/content/flyoutpanels/AboutFlyoutPanel.js
@@ -449,17 +449,17 @@ appUpdater.prototype =
}
}
},
/**
* See XPIProvider.jsm
*/
onUpdateAvailable: function(aAddon, aInstall) {
- if (!Services.blocklist.isAddonBlocklisted(aAddon.id, aInstall.version,
+ if (!Services.blocklist.isAddonBlocklisted(aAddon,
this.update.appVersion,
this.update.platformVersion)) {
// Compatibility or new version updates mean the same thing here.
this.onCompatibilityUpdateAvailable(aAddon);
}
},
/**
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3212,30 +3212,16 @@ Tab.prototype = {
let x = aViewport.x / aViewport.zoom;
let y = aViewport.y / aViewport.zoom;
this.setScrollClampingSize(aViewport.zoom);
// Adjust the max line box width to be no more than the viewport width, but
// only if the reflow-on-zoom preference is enabled.
let isZooming = !fuzzyEquals(aViewport.zoom, this._zoom);
- if (BrowserApp.selectedTab.reflozPinchSeen &&
- isZooming && aViewport.zoom < 1.0) {
- // In this case, we want to restore the max line box width,
- // because we are pinch-zooming to zoom out.
- BrowserEventHandler.resetMaxLineBoxWidth();
- BrowserApp.selectedTab.reflozPinchSeen = false;
- } else if (BrowserApp.selectedTab.reflozPinchSeen &&
- isZooming) {
- // In this case, the user pinch-zoomed in, so we don't want to
- // preserve position as we would with reflow-on-zoom.
- BrowserApp.selectedTab.probablyNeedRefloz = false;
- BrowserApp.selectedTab.clearReflowOnZoomPendingActions();
- BrowserApp.selectedTab._mReflozPoint = null;
- }
let docViewer = null;
if (isZooming &&
BrowserEventHandler.mReflozPref &&
BrowserApp.selectedTab._mReflozPoint &&
BrowserApp.selectedTab.probablyNeedRefloz) {
let webNav = BrowserApp.selectedTab.window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation);
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -582,22 +582,22 @@ this.SocialService = {
let notificationid = "servicesInstall";
chromeWin.PopupNotifications.show(browser, notificationid, message, anchor,
action, [], {});
},
installProvider: function(aDOMDocument, data, installCallback) {
let installOrigin = aDOMDocument.nodePrincipal.origin;
- let id = getAddonIDFromOrigin(installOrigin);
- let version = data && data.version ? data.version : "0";
- if (Services.blocklist.getAddonBlocklistState(id, version) == Ci.nsIBlocklistService.STATE_BLOCKED)
+ let addon = new AddonWrapper(data);
+ if (addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
throw new Error("installProvider: provider with origin [" +
installOrigin + "] is blocklisted");
+ let id = getAddonIDFromOrigin(installOrigin);
AddonManager.getAddonByID(id, function(aAddon) {
if (aAddon && aAddon.userDisabled) {
aAddon.cancelUninstall();
aAddon.userDisabled = false;
}
schedule(function () {
this._installProvider(aDOMDocument, data, aManifest => {
this._notifyProviderListeners("provider-installed", aManifest.origin);
@@ -657,16 +657,20 @@ this.SocialService = {
this._showInstallNotification(aDOMDocument, installer);
break;
default:
throw new Error("SocialService.installProvider: Invalid install type "+installType+"\n");
break;
}
},
+ createWrapper: function(manifest) {
+ return new AddonWrapper(manifest);
+ },
+
/**
* updateProvider is used from the worker to self-update. Since we do not
* have knowledge of the currently selected provider here, we will notify
* the front end to deal with any reload.
*/
updateProvider: function(aUpdateOrigin, aManifest) {
let originUri = Services.io.newURI(aUpdateOrigin, null, null);
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(originUri);
@@ -711,18 +715,18 @@ this.SocialService = {
* @param {bool} boolean indicating whether this provider is "built in"
*/
function SocialProvider(input) {
if (!input.name)
throw new Error("SocialProvider must be passed a name");
if (!input.origin)
throw new Error("SocialProvider must be passed an origin");
- let id = getAddonIDFromOrigin(input.origin);
- if (Services.blocklist.getAddonBlocklistState(id, input.version || "0") == Ci.nsIBlocklistService.STATE_BLOCKED)
+ let addon = new AddonWrapper(input);
+ if (addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
throw new Error("SocialProvider: provider with origin [" +
input.origin + "] is blocklisted");
this.name = input.name;
this.iconURL = input.iconURL;
this.icon32URL = input.icon32URL;
this.icon64URL = input.icon64URL;
this.workerURL = input.workerURL;
@@ -1006,18 +1010,18 @@ var SocialAddonProvider = {
shutdown: function() {},
updateAddonAppDisabledStates: function() {
// we wont bother with "enabling" services that are released from blocklist
for (let manifest of SocialServiceInternal.manifests) {
try {
if (ActiveProviders.has(manifest.origin)) {
- let id = getAddonIDFromOrigin(manifest.origin);
- if (Services.blocklist.getAddonBlocklistState(id, manifest.version || "0") != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
+ let addon = new AddonWrapper(manifest);
+ if (addon.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
SocialService.removeProvider(manifest.origin);
}
}
} catch(e) {
Cu.reportError(e);
}
}
},
@@ -1095,21 +1099,21 @@ AddonWrapper.prototype = {
return true;
},
get providesUpdatesSecurely() {
return true;
},
get blocklistState() {
- return Services.blocklist.getAddonBlocklistState(this.id, this.version || "0");
+ return Services.blocklist.getAddonBlocklistState(this);
},
get blocklistURL() {
- return Services.blocklist.getAddonBlocklistURL(this.id, this.version || "0");
+ return Services.blocklist.getAddonBlocklistURL(this);
},
get screenshots() {
return [];
},
get pendingOperations() {
return this._pending || AddonManager.PENDING_NONE;
--- a/toolkit/components/url-classifier/Entries.h
+++ b/toolkit/components/url-classifier/Entries.h
@@ -235,20 +235,20 @@ struct SubComplete {
if (cmp != 0)
return cmp;
if (addChunk != aOther.addChunk)
return addChunk - aOther.addChunk;
return subChunk - aOther.subChunk;
}
};
-typedef nsTArray<AddPrefix> AddPrefixArray;
-typedef nsTArray<AddComplete> AddCompleteArray;
-typedef nsTArray<SubPrefix> SubPrefixArray;
-typedef nsTArray<SubComplete> SubCompleteArray;
+typedef FallibleTArray<AddPrefix> AddPrefixArray;
+typedef FallibleTArray<AddComplete> AddCompleteArray;
+typedef FallibleTArray<SubPrefix> SubPrefixArray;
+typedef FallibleTArray<SubComplete> SubCompleteArray;
/**
* Compares chunks by their add chunk, then their prefix.
*/
template<class T>
class EntryCompare {
public:
typedef T elem_type;
@@ -259,41 +259,41 @@ public:
}
};
/**
* Sort an array of store entries. nsTArray::Sort uses Equal/LessThan
* to sort, this does a single Compare so it's a bit quicker over the
* large sorts we do.
*/
-template<class T>
+template<class T, class Alloc>
void
-EntrySort(nsTArray<T>& aArray)
+EntrySort(nsTArray_Impl<T, Alloc>& aArray)
{
qsort(aArray.Elements(), aArray.Length(), sizeof(T),
EntryCompare<T>::Compare);
}
-template<class T>
+template<class T, class Alloc>
nsresult
-ReadTArray(nsIInputStream* aStream, nsTArray<T>* aArray, uint32_t aNumElements)
+ReadTArray(nsIInputStream* aStream, nsTArray_Impl<T, Alloc>* aArray, uint32_t aNumElements)
{
if (!aArray->SetLength(aNumElements))
return NS_ERROR_OUT_OF_MEMORY;
void *buffer = aArray->Elements();
nsresult rv = NS_ReadInputStreamToBuffer(aStream, &buffer,
(aNumElements * sizeof(T)));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
-template<class T>
+template<class T, class Alloc>
nsresult
-WriteTArray(nsIOutputStream* aStream, nsTArray<T>& aArray)
+WriteTArray(nsIOutputStream* aStream, nsTArray_Impl<T, Alloc>& aArray)
{
uint32_t written;
return aStream->Write(reinterpret_cast<char*>(aArray.Elements()),
aArray.Length() * sizeof(T),
&written);
}
} // namespace safebrowsing
--- a/toolkit/components/url-classifier/HashStore.cpp
+++ b/toolkit/components/url-classifier/HashStore.cpp
@@ -428,19 +428,19 @@ HashStore::BeginUpdate()
mInUpdate = true;
return NS_OK;
}
template<class T>
static nsresult
Merge(ChunkSet* aStoreChunks,
- nsTArray<T>* aStorePrefixes,
+ FallibleTArray<T>* aStorePrefixes,
ChunkSet& aUpdateChunks,
- nsTArray<T>& aUpdatePrefixes,
+ FallibleTArray<T>& aUpdatePrefixes,
bool aAllowMerging = false)
{
EntrySort(aUpdatePrefixes);
T* updateIter = aUpdatePrefixes.Elements();
T* updateEnd = aUpdatePrefixes.Elements() + aUpdatePrefixes.Length();
T* storeIter = aStorePrefixes->Elements();
@@ -533,17 +533,17 @@ HashStore::ClearCompletes()
mAddCompletes.Clear();
mSubCompletes.Clear();
UpdateHeader();
}
template<class T>
static void
-ExpireEntries(nsTArray<T>* aEntries, ChunkSet& aExpirations)
+ExpireEntries(FallibleTArray<T>* aEntries, ChunkSet& aExpirations)
{
T* addIter = aEntries->Elements();
T* end = aEntries->Elements() + aEntries->Length();
for (T *iter = addIter; iter != end; iter++) {
if (!aExpirations.Has(iter->Chunk())) {
*addIter = *iter;
addIter++;
@@ -570,18 +570,20 @@ HashStore::Expire()
return NS_OK;
}
template<class T>
nsresult DeflateWriteTArray(nsIOutputStream* aStream, nsTArray<T>& aIn)
{
uLongf insize = aIn.Length() * sizeof(T);
uLongf outsize = compressBound(insize);
- nsTArray<char> outBuff;
- outBuff.SetLength(outsize);
+ FallibleTArray<char> outBuff;
+ if (!outBuff.SetLength(outsize)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
int zerr = compress(reinterpret_cast<Bytef*>(outBuff.Elements()),
&outsize,
reinterpret_cast<const Bytef*>(aIn.Elements()),
insize);
if (zerr != Z_OK) {
return NS_ERROR_FAILURE;
}
@@ -711,17 +713,19 @@ nsresult
HashStore::ReadAddPrefixes()
{
FallibleTArray<uint32_t> chunks;
uint32_t count = mHeader.numAddPrefixes;
nsresult rv = ByteSliceRead(mInputStream, &chunks, count);
NS_ENSURE_SUCCESS(rv, rv);
- mAddPrefixes.SetCapacity(count);
+ if (!mAddPrefixes.SetCapacity(count)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
for (uint32_t i = 0; i < count; i++) {
AddPrefix *add = mAddPrefixes.AppendElement();
add->prefix.FromUint32(0);
add->addChunk = chunks[i];
}
return NS_OK;
}
@@ -738,17 +742,19 @@ HashStore::ReadSubPrefixes()
NS_ENSURE_SUCCESS(rv, rv);
rv = ByteSliceRead(mInputStream, &subchunks, count);
NS_ENSURE_SUCCESS(rv, rv);
rv = ByteSliceRead(mInputStream, &prefixes, count);
NS_ENSURE_SUCCESS(rv, rv);
- mSubPrefixes.SetCapacity(count);
+ if (!mSubPrefixes.SetCapacity(count)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
for (uint32_t i = 0; i < count; i++) {
SubPrefix *sub = mSubPrefixes.AppendElement();
sub->addChunk = addchunks[i];
sub->prefix.FromUint32(prefixes[i]);
sub->subChunk = subchunks[i];
}
return NS_OK;
@@ -847,17 +853,17 @@ HashStore::WriteFile()
rv = safeOut->Finish();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
template <class T>
static void
-Erase(nsTArray<T>* array, T* iterStart, T* iterEnd)
+Erase(FallibleTArray<T>* array, T* iterStart, T* iterEnd)
{
uint32_t start = iterStart - array->Elements();
uint32_t count = iterEnd - iterStart;
if (count > 0) {
array->RemoveElementsAt(start, count);
}
}
@@ -867,17 +873,17 @@ Erase(nsTArray<T>* array, T* iterStart,
// copies, the inputs are processing in parallel, so |subs| and |adds|
// should be compatibly ordered (either by SBAddPrefixLess or
// SBAddPrefixHashLess).
//
// |predAS| provides add < sub, |predSA| provides sub < add, for the
// tightest compare appropriate (see calls in SBProcessSubs).
template<class TSub, class TAdd>
static void
-KnockoutSubs(nsTArray<TSub>* aSubs, nsTArray<TAdd>* aAdds)
+KnockoutSubs(FallibleTArray<TSub>* aSubs, FallibleTArray<TAdd>* aAdds)
{
// Keep a pair of output iterators for writing kept items. Due to
// deletions, these may lag the main iterators. Using erase() on
// individual items would result in O(N^2) copies. Using a list
// would work around that, at double or triple the memory cost.
TAdd* addOut = aAdds->Elements();
TAdd* addIter = aAdds->Elements();
@@ -910,17 +916,17 @@ KnockoutSubs(nsTArray<TSub>* aSubs, nsTA
Erase(aAdds, addOut, addIter);
Erase(aSubs, subOut, subIter);
}
// Remove items in |removes| from |fullHashes|. |fullHashes| and
// |removes| should be ordered by SBAddPrefix component.
template <class T>
static void
-RemoveMatchingPrefixes(const SubPrefixArray& aSubs, nsTArray<T>* aFullHashes)
+RemoveMatchingPrefixes(const SubPrefixArray& aSubs, FallibleTArray<T>* aFullHashes)
{
// Where to store kept items.
T* out = aFullHashes->Elements();
T* hashIter = out;
T* hashEnd = aFullHashes->Elements() + aFullHashes->Length();
SubPrefix const * removeIter = aSubs.Elements();
SubPrefix const * removeEnd = aSubs.Elements() + aSubs.Length();
--- a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm
@@ -716,18 +716,17 @@ this.AddonUpdateChecker = {
let blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
let newest = null;
for (let update of aUpdates) {
if (!update.updateURL)
continue;
- let state = blocklist.getAddonBlocklistState(update.id, update.version,
- aAppVersion, aPlatformVersion);
+ let state = blocklist.getAddonBlocklistState(update, aAppVersion, aPlatformVersion);
if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED)
continue;
if ((newest == null || (Services.vc.compare(newest.version, update.version) < 0)) &&
matchesVersions(update, aAppVersion, aPlatformVersion,
aIgnoreMaxVersion, aIgnoreStrictCompat,
aCompatOverrides)) {
newest = update;
}
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -545,22 +545,20 @@ function applyBlocklistChanges(aOldAddon
aOldPlatformVersion) {
// Copy the properties by default
aNewAddon.userDisabled = aOldAddon.userDisabled;
aNewAddon.softDisabled = aOldAddon.softDisabled;
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
- let oldBlocklistState = bs.getAddonBlocklistState(aOldAddon.id,
- aOldAddon.version,
+ let oldBlocklistState = bs.getAddonBlocklistState(createWrapper(aOldAddon),
aOldAppVersion,
aOldPlatformVersion);
- let newBlocklistState = bs.getAddonBlocklistState(aNewAddon.id,
- aNewAddon.version);
+ let newBlocklistState = bs.getAddonBlocklistState(createWrapper(aNewAddon));
// If the blocklist state hasn't changed then the properties don't need to
// change
if (newBlocklistState == oldBlocklistState)
return;
if (newBlocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) {
if (aNewAddon.type != "theme") {
@@ -6196,29 +6194,29 @@ AddonInternal.prototype = {
get blocklistState() {
let staticItem = findMatchingStaticBlocklistItem(this);
if (staticItem)
return staticItem.level;
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
- return bs.getAddonBlocklistState(this.id, this.version);
+ return bs.getAddonBlocklistState(createWrapper(this));
},
get blocklistURL() {
let staticItem = findMatchingStaticBlocklistItem(this);
if (staticItem) {
let url = Services.urlFormatter.formatURLPref("extensions.blocklist.itemURL");
return url.replace(/%blockID%/g, staticItem.blockID);
}
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
- return bs.getAddonBlocklistURL(this.id, this.version);
+ return bs.getAddonBlocklistURL(createWrapper(this));
},
applyCompatibilityUpdate: function AddonInternal_applyCompatibilityUpdate(aUpdate, aSyncCompatibility) {
this.targetApplications.forEach(function(aTargetApp) {
aUpdate.targetApplications.forEach(function(aUpdateTarget) {
if (aTargetApp.id == aUpdateTarget.id && (aSyncCompatibility ||
Services.vc.compare(aTargetApp.maxVersion, aUpdateTarget.maxVersion) < 0)) {
aTargetApp.minVersion = aUpdateTarget.minVersion;
@@ -6326,17 +6324,17 @@ function AddonWrapper(aAddon) {
}
return [objValue, false];
}
["id", "syncGUID", "version", "type", "isCompatible", "isPlatformCompatible",
"providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled",
"softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents",
- "strictCompatibility", "compatibilityOverrides"].forEach(function(aProp) {
+ "strictCompatibility", "compatibilityOverrides", "updateURL"].forEach(function(aProp) {
this.__defineGetter__(aProp, function AddonWrapper_propertyGetter() aAddon[aProp]);
}, this);
["fullDescription", "developerComments", "eula", "supportURL",
"contributionURL", "contributionAmount", "averageRating", "reviewCount",
"reviewURL", "totalDownloads", "weeklyDownloads", "dailyUsers",
"repositoryStatus"].forEach(function(aProp) {
this.__defineGetter__(aProp, function AddonWrapper_repoPropertyGetter() {
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -44,16 +44,18 @@ const URI_BLOCKLIST_DIALOG =
const DEFAULT_SEVERITY = 3;
const DEFAULT_LEVEL = 2;
const MAX_BLOCK_LEVEL = 3;
const SEVERITY_OUTDATED = 0;
const VULNERABILITYSTATUS_NONE = 0;
const VULNERABILITYSTATUS_UPDATE_AVAILABLE = 1;
const VULNERABILITYSTATUS_NO_UPDATE = 2;
+const EXTENSION_BLOCK_FILTERS = ["id", "name", "creator", "homepageURL", "updateURL"];
+
var gLoggingEnabled = null;
var gBlocklistEnabled = true;
var gBlocklistLevel = DEFAULT_LEVEL;
XPCOMUtils.defineLazyServiceGetter(this, "gConsole",
"@mozilla.org/consoleservice;1",
"nsIConsoleService");
@@ -312,26 +314,26 @@ Blocklist.prototype = {
this._blocklistUpdated(null, null);
break;
}
break;
}
},
/* See nsIBlocklistService */
- isAddonBlocklisted: function Blocklist_isAddonBlocklisted(id, version, appVersion, toolkitVersion) {
- return this.getAddonBlocklistState(id, version, appVersion, toolkitVersion) ==
+ isAddonBlocklisted: function Blocklist_isAddonBlocklisted(addon, appVersion, toolkitVersion) {
+ return this.getAddonBlocklistState(addon, appVersion, toolkitVersion) ==
Ci.nsIBlocklistService.STATE_BLOCKED;
},
/* See nsIBlocklistService */
- getAddonBlocklistState: function Blocklist_getAddonBlocklistState(id, version, appVersion, toolkitVersion) {
+ getAddonBlocklistState: function Blocklist_getAddonBlocklistState(addon, appVersion, toolkitVersion) {
if (!this._addonEntries)
this._loadBlocklist();
- return this._getAddonBlocklistState(id, version, this._addonEntries,
+ return this._getAddonBlocklistState(addon, this._addonEntries,
appVersion, toolkitVersion);
},
/**
* Private version of getAddonBlocklistState that allows the caller to pass in
* the add-on blocklist entries to compare against.
*
* @param id
@@ -344,71 +346,98 @@ Blocklist.prototype = {
* The application version to compare to, will use the current
* version if null.
* @param toolkitVersion
* The toolkit version to compare to, will use the current version if
* null.
* @returns The blocklist state for the item, one of the STATE constants as
* defined in nsIBlocklistService.
*/
- _getAddonBlocklistState: function Blocklist_getAddonBlocklistStateCall(id,
- version, addonEntries, appVersion, toolkitVersion) {
+ _getAddonBlocklistState: function Blocklist_getAddonBlocklistStateCall(addon,
+ addonEntries, appVersion, toolkitVersion) {
if (!gBlocklistEnabled)
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
if (!appVersion)
appVersion = gApp.version;
if (!toolkitVersion)
toolkitVersion = gApp.platformVersion;
- var blItem = this._findMatchingAddonEntry(addonEntries, id);
+ var blItem = this._findMatchingAddonEntry(addonEntries, addon);
if (!blItem)
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
for (let currentblItem of blItem.versions) {
- if (currentblItem.includesItem(version, appVersion, toolkitVersion))
+ if (currentblItem.includesItem(addon.version, appVersion, toolkitVersion))
return currentblItem.severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED :
Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
}
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
},
/**
* Returns the set of prefs of the add-on stored in the blocklist file
* (probably to revert them on disabling).
- * @param id
- * ID of the add-on.
+ * @param addon
+ * The add-on whose to-be-reset prefs are to be found.
*/
- _getAddonPrefs: function Blocklist_getAddonPrefs(id) {
- let entry = this._findMatchingAddonEntry(this._addonEntries, id);
+ _getAddonPrefs: function Blocklist_getAddonPrefs(addon) {
+ let entry = this._findMatchingAddonEntry(this._addonEntries, addon);
return entry.prefs.slice(0);
},
_findMatchingAddonEntry: function Blocklist_findMatchingAddonEntry(aAddonEntries,
- aId) {
+ aAddon) {
+ if (!aAddon)
+ return null;
+ // Returns true if the params object passes the constraints set by entry.
+ // (For every non-null property in entry, the same key must exist in
+ // params and value must be the same)
+ function checkEntry(entry, params) {
+ for (let [key, value] of entry) {
+ if (value === null || value === undefined)
+ continue;
+ if (params[key]) {
+ if (value instanceof RegExp) {
+ if (!value.test(params[key])) {
+ return false;
+ }
+ } else if (value !== params[key]) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ let params = {};
+ for (let filter of EXTENSION_BLOCK_FILTERS) {
+ params[filter] = aAddon[filter];
+ }
+ if (params.creator)
+ params.creator = params.creator.name;
for (let entry of aAddonEntries) {
- if (entry.id instanceof RegExp) {
- if (entry.id.test(aId))
- return entry;
- } else if (entry.id == aId) {
- return entry;
- }
- }
- return null;
+ if (checkEntry(entry.attributes, params)) {
+ return entry;
+ }
+ }
+ return null;
},
/* See nsIBlocklistService */
- getAddonBlocklistURL: function Blocklist_getAddonBlocklistURL(id, version, appVersion, toolkitVersion) {
+ getAddonBlocklistURL: function Blocklist_getAddonBlocklistURL(addon, appVersion, toolkitVersion) {
if (!gBlocklistEnabled)
return "";
if (!this._addonEntries)
this._loadBlocklist();
- let blItem = this._findMatchingAddonEntry(this._addonEntries, id);
+ let blItem = this._findMatchingAddonEntry(this._addonEntries, addon);
if (!blItem || !blItem.blockID)
return null;
return this._createBlocklistURL(blItem.blockID);
},
_createBlocklistURL: function Blocklist_createBlocklistURL(id) {
let url = Services.urlFormatter.formatURLPref(PREF_BLOCKLIST_ITEM_URL);
@@ -729,28 +758,36 @@ Blocklist.prototype = {
return result;
},
_handleEmItemNode: function Blocklist_handleEmItemNode(blocklistElement, result) {
if (!matchesOSABI(blocklistElement))
return;
let blockEntry = {
- id: null,
versions: [],
prefs: [],
- blockID: null
+ blockID: null,
+ attributes: new Map()
+ // Atleast one of EXTENSION_BLOCK_FILTERS must get added to attributes
};
+ // Any filter starting with '/' is interpreted as a regex. So if an attribute
+ // starts with a '/' it must be checked via a regex.
+ function regExpCheck(attr) {
+ return attr.startsWith("/") ? parseRegExp(attr) : attr;
+ }
+
+ for (let filter of EXTENSION_BLOCK_FILTERS) {
+ let attr = blocklistElement.getAttribute(filter);
+ if (attr)
+ blockEntry.attributes.set(filter, regExpCheck(attr));
+ }
+
var childNodes = blocklistElement.childNodes;
- var id = blocklistElement.getAttribute("id");
- // Add-on IDs cannot contain '/', so an ID starting with '/' must be a regex
- if (id.startsWith("/"))
- id = parseRegExp(id);
- blockEntry.id = id;
for (let x = 0; x < childNodes.length; x++) {
var childElement = childNodes.item(x);
if (!(childElement instanceof Ci.nsIDOMElement))
continue;
if (childElement.localName === "prefs") {
let prefElements = childElement.childNodes;
for (let i = 0; i < prefElements.length; i++) {
@@ -923,30 +960,29 @@ Blocklist.prototype = {
}
var self = this;
const types = ["extension", "theme", "locale", "dictionary", "service"];
AddonManager.getAddonsByTypes(types, function blocklistUpdated_getAddonsByTypes(addons) {
for (let addon of addons) {
let oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED;
if (oldAddonEntries)
- oldState = self._getAddonBlocklistState(addon.id, addon.version,
- oldAddonEntries);
- let state = self.getAddonBlocklistState(addon.id, addon.version);
+ oldState = self._getAddonBlocklistState(addon, oldAddonEntries);
+ let state = self.getAddonBlocklistState(addon);
LOG("Blocklist state for " + addon.id + " changed from " +
oldState + " to " + state);
// We don't want to re-warn about add-ons
if (state == oldState)
continue;
if (state === Ci.nsIBlocklistService.STATE_BLOCKED) {
// It's a hard block. We must reset certain preferences.
- let prefs = self._getAddonPrefs(addon.id);
+ let prefs = self._getAddonPrefs(addon);
resetPrefs(prefs);
}
// Ensure that softDisabled is false if the add-on is not soft blocked
if (state != Ci.nsIBlocklistService.STATE_SOFTBLOCKED)
addon.softDisabled = false;
// Don't warn about add-ons becoming unblocked.
@@ -968,17 +1004,17 @@ Blocklist.prototype = {
addonList.push({
name: addon.name,
version: addon.version,
icon: addon.iconURL,
disable: false,
blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
item: addon,
- url: self.getAddonBlocklistURL(addon.id),
+ url: self.getAddonBlocklistURL(addon),
});
}
AddonManagerPrivate.updateAddonAppDisabledStates();
var phs = Cc["@mozilla.org/plugin/host;1"].
getService(Ci.nsIPluginHost);
var plugins = phs.getPluginTags();
@@ -1051,17 +1087,17 @@ Blocklist.prototype = {
continue;
if (addon.item instanceof Ci.nsIPluginTag)
addon.item.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
else {
// This add-on is softblocked.
addon.item.softDisabled = true;
// We must revert certain prefs.
- let prefs = self._getAddonPrefs(addon.item.id);
+ let prefs = self._getAddonPrefs(addon.item);
resetPrefs(prefs);
}
}
if (args.restart)
restartApp();
Services.obs.notifyObservers(self, "blocklist-updated", "");
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
+ <emItems>
+ <emItem name="/^Mozilla Corp\.$/">
+ <versionRange severity="1">
+ <targetApplication id="xpcshell@tests.mozilla.org">
+ <versionRange minVersion="1" maxVersion="2.*"/>
+ </targetApplication>
+ </versionRange>
+ </emItem>
+ <emItem id="/block2/" name="/^Moz/" creator="Dangerous"
+ homepageURL="/\.dangerous\.com/" updateURL="/\.dangerous\.com/">
+ <versionRange severity="3">
+ <targetApplication id="xpcshell@tests.mozilla.org">
+ <versionRange minVersion="1" maxVersion="2.*"/>
+ </targetApplication>
+ </versionRange>
+ </emItem>
+ </emItems>
+</blocklist>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_bug393285.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_bug393285.xml
@@ -1,14 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem id="test_bug393285_2@tests.mozilla.org"/>
- <emItem id="test_bug393285_3@tests.mozilla.org">
+ <emItem id="test_bug393285_3a@tests.mozilla.org">
+ <versionRange minVersion="1.0" maxVersion="1.0"/>
+ </emItem>
+ <emItem id="test_bug393285_3b@tests.mozilla.org">
<versionRange minVersion="1.0" maxVersion="1.0"/>
</emItem>
<emItem id="test_bug393285_4@tests.mozilla.org">
<versionRange minVersion="1.0" maxVersion="1.0">
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="1.0" maxVersion="1.0"/>
</targetApplication>
</versionRange>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
@@ -0,0 +1,159 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests blocking of extensions by ID, name, creator, homepageURL, updateURL
+// and RegExps for each. See bug 897735.
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
+
+Cu.import("resource://testing-common/httpd.js");
+var testserver = new HttpServer();
+testserver.start(-1);
+gPort = testserver.identity.primaryPort;
+
+// register static files with server and interpolate port numbers in them
+mapFile("/data/test_blocklist_metadata_filters_1.xml", testserver);
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+// Don't need the full interface, attempts to call other methods will just
+// throw which is just fine
+var WindowWatcher = {
+ openWindow: function(parent, url, name, features, arguments) {
+ // Should be called to list the newly blocklisted items
+ do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
+
+ // Simulate auto-disabling any softblocks
+ var list = arguments.wrappedJSObject.list;
+ list.forEach(function(aItem) {
+ if (!aItem.blocked)
+ aItem.disable = true;
+ });
+
+ //run the code after the blocklist is closed
+ Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
+
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIWindowWatcher)
+ || iid.equals(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+};
+
+var WindowWatcherFactory = {
+ createInstance: function createInstance(outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return WindowWatcher.QueryInterface(iid);
+ }
+};
+
+var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
+ "Fake Window Watcher",
+ "@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcherFactory);
+
+
+function load_blocklist(aFile, aCallback) {
+ Services.obs.addObserver(function() {
+ Services.obs.removeObserver(arguments.callee, "blocklist-updated");
+
+ do_execute_soon(aCallback);
+ }, "blocklist-updated", false);
+
+ Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
+ gPort + "/data/" + aFile);
+ var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
+ getService(Ci.nsITimerCallback);
+ blocklist.notify(null);
+}
+
+
+function end_test() {
+ testserver.stop(do_test_finished);
+}
+
+function run_test() {
+ do_test_pending();
+
+ createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+
+ // Should get blocked by name
+ writeInstallRDFForExtension({
+ id: "block1@tests.mozilla.org",
+ version: "1.0",
+ name: "Mozilla Corp.",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ // Should get blocked by all the attributes.
+ writeInstallRDFForExtension({
+ id: "block2@tests.mozilla.org",
+ version: "1.0",
+ name: "Moz-addon",
+ creator: "Dangerous",
+ homepageURL: "www.extension.dangerous.com",
+ updateURL: "www.extension.dangerous.com/update.rdf",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ // Fails to get blocked because of a different ID even though other
+ // attributes match against a blocklist entry.
+ writeInstallRDFForExtension({
+ id: "block3@tests.mozilla.org",
+ version: "1.0",
+ name: "Moz-addon",
+ creator: "Dangerous",
+ homepageURL: "www.extensions.dangerous.com",
+ updateURL: "www.extension.dangerous.com/update.rdf",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ startupManager();
+
+ AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
+ "block2@tests.mozilla.org",
+ "block3@tests.mozilla.org"], function([a1, a2, a3]) {
+ do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ do_check_eq(a2.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ do_check_eq(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ run_test_1();
+ });
+}
+
+function run_test_1() {
+ load_blocklist("test_blocklist_metadata_filters_1.xml", function() {
+ restartManager();
+
+ AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
+ "block2@tests.mozilla.org",
+ "block3@tests.mozilla.org"], function([a1, a2, a3]) {
+ do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ do_check_eq(a2.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED);
+ do_check_eq(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ end_test();
+ });
+ });
+}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js
@@ -74,30 +74,30 @@ var ADDONS = [
{id: "bug335238_3@tests.mozilla.org",
addon: "test_bug335238_3"},
{id: "bug335238_4@tests.mozilla.org",
addon: "test_bug335238_4"}
];
// This is a replacement for the blocklist service
var BlocklistService = {
- getAddonBlocklistState: function(aId, aVersion, aAppVersion, aToolkitVersion) {
- if (aId == "bug335238_3@tests.mozilla.org")
+ getAddonBlocklistState: function(aAddon, aAppVersion, aToolkitVersion) {
+ if (aAddon.id == "bug335238_3@tests.mozilla.org")
return Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
- if (aId == "bug335238_4@tests.mozilla.org")
+ if (aAddon.id == "bug335238_4@tests.mozilla.org")
return Ci.nsIBlocklistService.STATE_BLOCKED;
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
},
getPluginBlocklistState: function(aPlugin, aVersion, aAppVersion, aToolkitVersion) {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
},
- isAddonBlocklisted: function(aId, aVersion, aAppVersion, aToolkitVersion) {
- return this.getAddonBlocklistState(aId, aVersion, aAppVersion, aToolkitVersion) ==
+ isAddonBlocklisted: function(aAddon, aAppVersion, aToolkitVersion) {
+ return this.getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) ==
Ci.nsIBlocklistService.STATE_BLOCKED;
},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIBlocklistService)
|| iid.equals(Ci.nsISupports))
return this;
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
@@ -1,55 +1,327 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
+
+Cu.import("resource://testing-common/httpd.js");
+var testserver = new HttpServer();
+testserver.start(-1);
+gPort = testserver.identity.primaryPort;
+
+// register static files with server and interpolate port numbers in them
+mapFile("/data/test_bug393285.xml", testserver);
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+let addonIDs = ["test_bug393285_1@tests.mozilla.org",
+ "test_bug393285_2@tests.mozilla.org",
+ "test_bug393285_3a@tests.mozilla.org",
+ "test_bug393285_3b@tests.mozilla.org",
+ "test_bug393285_4@tests.mozilla.org",
+ "test_bug393285_5@tests.mozilla.org",
+ "test_bug393285_6@tests.mozilla.org",
+ "test_bug393285_7@tests.mozilla.org",
+ "test_bug393285_8@tests.mozilla.org",
+ "test_bug393285_9@tests.mozilla.org",
+ "test_bug393285_10@tests.mozilla.org",
+ "test_bug393285_11@tests.mozilla.org",
+ "test_bug393285_12@tests.mozilla.org",
+ "test_bug393285_13@tests.mozilla.org",
+ "test_bug393285_14@tests.mozilla.org"];
+
+// A window watcher to deal with the blocklist UI dialog.
+var WindowWatcher = {
+ openWindow: function(parent, url, name, features, arguments) {
+ // Should be called to list the newly blocklisted items
+ do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
+
+ // Simulate auto-disabling any softblocks
+ var list = arguments.wrappedJSObject.list;
+ list.forEach(function(aItem) {
+ if (!aItem.blocked)
+ aItem.disable = true;
+ });
+
+ //run the code after the blocklist is closed
+ Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
+
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIWindowWatcher)
+ || iid.equals(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+};
+
+var WindowWatcherFactory = {
+ createInstance: function createInstance(outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return WindowWatcher.QueryInterface(iid);
+ }
+};
+
+var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
+ "Fake Window Watcher",
+ "@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcherFactory);
+
+
+function load_blocklist(aFile, aCallback) {
+ Services.obs.addObserver(function() {
+ Services.obs.removeObserver(arguments.callee, "blocklist-updated");
+
+ do_execute_soon(aCallback);
+ }, "blocklist-updated", false);
+
+ Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
+ gPort + "/data/" + aFile);
+ var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
+ getService(Ci.nsITimerCallback);
+ blocklist.notify(null);
+}
+
+
+function end_test() {
+ testserver.stop(do_test_finished);
+}
+
function run_test() {
+ do_test_pending();
+
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
- // We cannot force the blocklist to update so just copy our test list to the profile
- var blocklistFile = gProfD.clone();
- blocklistFile.append("blocklist.xml");
- if (blocklistFile.exists())
- blocklistFile.remove(false);
- var source = do_get_file("data/test_bug393285.xml");
- source.copyTo(gProfD, "blocklist.xml");
+ writeInstallRDFForExtension({
+ id: "test_bug393285_1@tests.mozilla.org",
+ name: "extension 1",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_2@tests.mozilla.org",
+ name: "extension 2",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_3a@tests.mozilla.org",
+ name: "extension 3a",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_3b@tests.mozilla.org",
+ name: "extension 3b",
+ version: "2.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
- .getService(Components.interfaces.nsIBlocklistService);
-
- // No info in blocklist, shouldn't be blocked
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_1@tests.mozilla.org", "1", "1", "1.9"));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_4@tests.mozilla.org",
+ name: "extension 4",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_5@tests.mozilla.org",
+ name: "extension 5",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_6@tests.mozilla.org",
+ name: "extension 6",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- // Should always be blocked
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_2@tests.mozilla.org", "1", "1", "1.9"));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_7@tests.mozilla.org",
+ name: "extension 7",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- // Only version 1 should be blocked
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_3@tests.mozilla.org", "1", "1", "1.9"));
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_3@tests.mozilla.org", "2", "1", "1.9"));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_8@tests.mozilla.org",
+ name: "extension 8",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_9@tests.mozilla.org",
+ name: "extension 9",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- // Should be blocked for app version 1
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_4@tests.mozilla.org", "1", "1", "1.9"));
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_4@tests.mozilla.org", "1", "2", "1.9"));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_10@tests.mozilla.org",
+ name: "extension 10",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_11@tests.mozilla.org",
+ name: "extension 11",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- // Not blocklisted because we are a different OS
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_5@tests.mozilla.org", "1", "2", "1.9"));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_12@tests.mozilla.org",
+ name: "extension 12",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- // Blocklisted based on OS
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_6@tests.mozilla.org", "1", "2", "1.9"));
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_7@tests.mozilla.org", "1", "2", "1.9"));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_13@tests.mozilla.org",
+ name: "extension 13",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_14@tests.mozilla.org",
+ name: "extension 14",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ startupManager();
- // Not blocklisted because we are a different ABI
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_8@tests.mozilla.org", "1", "2", "1.9"));
+ AddonManager.getAddonsByIDs(addonIDs, function(addons) {
+ for (addon of addons) {
+ do_check_eq(addon.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ }
+ run_test_1();
+ });
+}
+
+function run_test_1() {
+ load_blocklist("test_bug393285.xml", function() {
+ restartManager();
- // Blocklisted based on ABI
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_9@tests.mozilla.org", "1", "2", "1.9"));
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_10@tests.mozilla.org", "1", "2", "1.9"));
+ var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsIBlocklistService);
+
+ AddonManager.getAddonsByIDs(addonIDs,
+ function([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15]) {
+ // No info in blocklist, shouldn't be blocked
+ do_check_false(blocklist.isAddonBlocklisted(a1, "1", "1.9"));
+
+ // Should always be blocked
+ do_check_true(blocklist.isAddonBlocklisted(a2, "1", "1.9"));
+
+ // Only version 1 should be blocked
+ do_check_true(blocklist.isAddonBlocklisted(a3, "1", "1.9"));
+ do_check_false(blocklist.isAddonBlocklisted(a4, "1", "1.9"));
- // Doesnt match both os and abi so not blocked
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_11@tests.mozilla.org", "1", "2", "1.9"));
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_12@tests.mozilla.org", "1", "2", "1.9"));
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_13@tests.mozilla.org", "1", "2", "1.9"));
+ // Should be blocked for app version 1
+ do_check_true(blocklist.isAddonBlocklisted(a5, "1", "1.9"));
+ do_check_false(blocklist.isAddonBlocklisted(a5, "2", "1.9"));
+
+ // Not blocklisted because we are a different OS
+ do_check_false(blocklist.isAddonBlocklisted(a6, "2", "1.9"));
+
+ // Blocklisted based on OS
+ do_check_true(blocklist.isAddonBlocklisted(a7, "2", "1.9"));
+ do_check_true(blocklist.isAddonBlocklisted(a8, "2", "1.9"));
+
+ // Not blocklisted because we are a different ABI
+ do_check_false(blocklist.isAddonBlocklisted(a9, "2", "1.9"));
- // Matches both os and abi so blocked
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_14@tests.mozilla.org", "1", "2", "1.9"));
+ // Blocklisted based on ABI
+ do_check_true(blocklist.isAddonBlocklisted(a10, "2", "1.9"));
+ do_check_true(blocklist.isAddonBlocklisted(a11, "2", "1.9"));
+
+ // Doesnt match both os and abi so not blocked
+ do_check_false(blocklist.isAddonBlocklisted(a12, "2", "1.9"));
+ do_check_false(blocklist.isAddonBlocklisted(a13, "2", "1.9"));
+ do_check_false(blocklist.isAddonBlocklisted(a14, "2", "1.9"));
+
+ // Matches both os and abi so blocked
+ do_check_true(blocklist.isAddonBlocklisted(a15, "2", "1.9"));
+ end_test();
+ });
+ });
}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
@@ -1,26 +1,167 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+let addonIDs = ["test_bug393285_1@tests.mozilla.org",
+ "test_bug393285_2@tests.mozilla.org",
+ "test_bug393285_3a@tests.mozilla.org",
+ "test_bug393285_4@tests.mozilla.org"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
+
+Cu.import("resource://testing-common/httpd.js");
+var testserver = new HttpServer();
+testserver.start(-1);
+gPort = testserver.identity.primaryPort;
+
+// register static files with server and interpolate port numbers in them
+mapFile("/data/test_bug393285.xml", testserver);
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+// A window watcher to deal with the blocklist UI dialog.
+var WindowWatcher = {
+ openWindow: function(parent, url, name, features, arguments) {
+ // Should be called to list the newly blocklisted items
+ do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
+
+ // Simulate auto-disabling any softblocks
+ var list = arguments.wrappedJSObject.list;
+ list.forEach(function(aItem) {
+ if (!aItem.blocked)
+ aItem.disable = true;
+ });
+
+ //run the code after the blocklist is closed
+ Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
+
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIWindowWatcher)
+ || iid.equals(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+};
+
+var WindowWatcherFactory = {
+ createInstance: function createInstance(outer, iid) {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ return WindowWatcher.QueryInterface(iid);
+ }
+};
+
+var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
+ "Fake Window Watcher",
+ "@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcherFactory);
+
+
+function load_blocklist(aFile, aCallback) {
+ Services.obs.addObserver(function() {
+ Services.obs.removeObserver(arguments.callee, "blocklist-updated");
+
+ do_execute_soon(aCallback);
+ }, "blocklist-updated", false);
+
+ Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
+ gPort + "/data/" + aFile);
+ var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
+ getService(Ci.nsITimerCallback);
+ blocklist.notify(null);
+}
+
+
+function end_test() {
+ testserver.stop(do_test_finished);
+}
+
function run_test() {
+ do_test_pending();
+
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
- // We cannot force the blocklist to update so just copy our test list to the profile
- var blocklistFile = gProfD.clone();
- blocklistFile.append("blocklist.xml");
- if (blocklistFile.exists())
- blocklistFile.remove(false);
- var source = do_get_file("data/test_bug393285.xml");
- source.copyTo(gProfD, "blocklist.xml");
+ writeInstallRDFForExtension({
+ id: "test_bug393285_1@tests.mozilla.org",
+ name: "extension 1",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_2@tests.mozilla.org",
+ name: "extension 2",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ writeInstallRDFForExtension({
+ id: "test_bug393285_3a@tests.mozilla.org",
+ name: "extension 3a",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
- var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
- .getService(Components.interfaces.nsIBlocklistService);
-
- // All these should be blocklisted for the current app.
- do_check_false(blocklist.isAddonBlocklisted("test_bug393285_1@tests.mozilla.org", "1", null, null));
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_2@tests.mozilla.org", "1", null, null));
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_3@tests.mozilla.org", "1", null, null));
- do_check_true(blocklist.isAddonBlocklisted("test_bug393285_4@tests.mozilla.org", "1", null, null));
+ writeInstallRDFForExtension({
+ id: "test_bug393285_4@tests.mozilla.org",
+ name: "extension 4",
+ version: "1.0",
+ targetApplications: [{
+ id: "xpcshell@tests.mozilla.org",
+ minVersion: "1",
+ maxVersion: "3"
+ }]
+ }, profileDir);
+
+ startupManager();
+
+ AddonManager.getAddonsByIDs(addonIDs, function(addons) {
+ for (addon of addons) {
+ do_check_eq(addon.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ }
+ run_test_1();
+ });
+}
+function run_test_1() {
+ load_blocklist("test_bug393285.xml", function() {
+ restartManager();
+
+ var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsIBlocklistService);
+
+ AddonManager.getAddonsByIDs(addonIDs,
+ function([a1, a2, a3, a4]) {
+ // No info in blocklist, shouldn't be blocked
+ do_check_false(blocklist.isAddonBlocklisted(a1, null, null));
+
+ // All these should be blocklisted for the current app.
+ do_check_true(blocklist.isAddonBlocklisted(a2, null, null));
+ do_check_true(blocklist.isAddonBlocklisted(a3, null, null));
+ do_check_true(blocklist.isAddonBlocklisted(a4, null, null));
+
+ end_test();
+ });
+ });
}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
@@ -456,21 +456,21 @@ function check_test_pt3() {
do_check_eq(check_plugin_state(PLUGINS[2]), "false,true");
do_check_eq(check_plugin_state(PLUGINS[3]), "true,true");
do_check_eq(check_plugin_state(PLUGINS[4]), "false,true");
// Should have gained the blocklist state but no longer be soft disabled
do_check_eq(check_addon_state(addons[3]), "false,false,true");
// Check blockIDs are correct
- do_check_eq(blocklist.getAddonBlocklistURL(addons[0].id,''),create_blocklistURL(addons[0].id));
- do_check_eq(blocklist.getAddonBlocklistURL(addons[1].id,''),create_blocklistURL(addons[1].id));
- do_check_eq(blocklist.getAddonBlocklistURL(addons[2].id,''),create_blocklistURL(addons[2].id));
- do_check_eq(blocklist.getAddonBlocklistURL(addons[3].id,''),create_blocklistURL(addons[3].id));
- do_check_eq(blocklist.getAddonBlocklistURL(addons[4].id,''),create_blocklistURL(addons[4].id));
+ do_check_eq(blocklist.getAddonBlocklistURL(addons[0]),create_blocklistURL(addons[0].id));
+ do_check_eq(blocklist.getAddonBlocklistURL(addons[1]),create_blocklistURL(addons[1].id));
+ do_check_eq(blocklist.getAddonBlocklistURL(addons[2]),create_blocklistURL(addons[2].id));
+ do_check_eq(blocklist.getAddonBlocklistURL(addons[3]),create_blocklistURL(addons[3].id));
+ do_check_eq(blocklist.getAddonBlocklistURL(addons[4]),create_blocklistURL(addons[4].id));
// All plugins have the same blockID on the test
do_check_eq(blocklist.getPluginBlocklistURL(PLUGINS[0]), create_blocklistURL('test_bug455906_plugin'));
do_check_eq(blocklist.getPluginBlocklistURL(PLUGINS[1]), create_blocklistURL('test_bug455906_plugin'));
do_check_eq(blocklist.getPluginBlocklistURL(PLUGINS[2]), create_blocklistURL('test_bug455906_plugin'));
do_check_eq(blocklist.getPluginBlocklistURL(PLUGINS[3]), create_blocklistURL('test_bug455906_plugin'));
do_check_eq(blocklist.getPluginBlocklistURL(PLUGINS[4]), create_blocklistURL('test_bug455906_plugin'));
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
@@ -12,16 +12,17 @@ skip-if = os == "android"
[test_DeferredSave.js]
[test_LightweightThemeManager.js]
[test_XPIcancel.js]
[test_backgroundupdate.js]
[test_bad_json.js]
[test_badschema.js]
[test_blocklistchange.js]
[test_blocklist_prefs.js]
+[test_blocklist_metadata_filters.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_blocklist_regexp.js]
skip-if = os == "android"
[test_bootstrap.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_bug299716.js]
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -864,17 +864,17 @@ var gIncompatibleCheckPage = {
},
onUpdateAvailable: function(addon, install) {
// If the new version of this add-on is blocklisted for the new application
// then it isn't a valid update and the user should still be warned that
// the add-on will become incompatible.
let bs = CoC["@mozilla.org/extensions/blocklist;1"].
getService(CoI.nsIBlocklistService);
- if (bs.isAddonBlocklisted(addon.id, install.version,
+ if (bs.isAddonBlocklisted(addon,
gUpdates.update.appVersion,
gUpdates.update.platformVersion))
return;
// Compatibility or new version updates mean the same thing here.
this.onCompatibilityUpdateAvailable(addon);
},
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -2967,17 +2967,17 @@ UpdateService.prototype = {
if (getPref("getIntPref", PREF_APP_UPDATE_INCOMPATIBLE_MODE, 0) == 1)
return;
// If the new version of this add-on is blocklisted for the new application
// then it isn't a valid update and the user should still be warned that
// the add-on will become incompatible.
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
- if (bs.isAddonBlocklisted(addon.id, install.version,
+ if (bs.isAddonBlocklisted(addon,
gUpdates.update.appVersion,
gUpdates.update.platformVersion))
return;
// Compatibility or new version updates mean the same thing here.
this.onCompatibilityUpdateAvailable(addon);
},
--- a/xpcom/system/nsIBlocklistService.idl
+++ b/xpcom/system/nsIBlocklistService.idl
@@ -24,52 +24,48 @@ interface nsIBlocklistService : nsISuppo
const unsigned long STATE_OUTDATED = 3;
// Indicates that the item is vulnerable and there is an update.
const unsigned long STATE_VULNERABLE_UPDATE_AVAILABLE = 4;
// Indicates that the item is vulnerable and there is no update.
const unsigned long STATE_VULNERABLE_NO_UPDATE = 5;
/**
* Determine if an item is blocklisted
- * @param id
- * The ID of the item.
- * @param version
- * The item's version.
+ * @param addon
+ * The addon item to be checked.
* @param appVersion
* The version of the application we are checking in the blocklist.
* If this parameter is null, the version of the running application
* is used.
* @param toolkitVersion
* The version of the toolkit we are checking in the blocklist.
* If this parameter is null, the version of the running toolkit
* is used.
* @returns true if the item is compatible with this version of the
* application or this version of the toolkit, false, otherwise.
*/
- boolean isAddonBlocklisted(in AString id, in AString version,
+ boolean isAddonBlocklisted(in jsval addon,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
/**
* Determine the blocklist state of an add-on
* @param id
- * The ID of the item.
- * @param version
- * The item's version.
+ * The addon item to be checked.
* @param appVersion
* The version of the application we are checking in the blocklist.
* If this parameter is null, the version of the running application
* is used.
* @param toolkitVersion
* The version of the toolkit we are checking in the blocklist.
* If this parameter is null, the version of the running toolkit
* is used.
* @returns The STATE constant.
*/
- unsigned long getAddonBlocklistState(in AString id, in AString version,
+ unsigned long getAddonBlocklistState(in jsval addon,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
/**
* Determine the blocklist state of a plugin
* @param plugin
* The plugin to get the state for
* @param appVersion
@@ -83,21 +79,21 @@ interface nsIBlocklistService : nsISuppo
* @returns The STATE constant.
*/
unsigned long getPluginBlocklistState(in nsIPluginTag plugin,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
/**
* Determine the blocklist web page of an add-on.
- * @param id
- * The ID of the blocked add-on.
+ * @param addon
+ * The addon item whose url is required.
* @returns The URL of the description page.
*/
- AString getAddonBlocklistURL(in AString id, in AString version,
+ AString getAddonBlocklistURL(in jsval addon,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
/**
* Determine the blocklist web page of a plugin.
* @param plugin
* The blocked plugin that we are determining the web page for.
* @returns The URL of the description page.