author | Ed Morley <emorley@mozilla.com> |
Mon, 06 Jan 2014 15:20:45 +0000 | |
changeset 162236 | 2068b0f801c9e3d680aeff54bddcaddebab13624 |
parent 162182 | bafaf8d078d8e0c2f61973b54231ef23ac3c7571 (current diff) |
parent 162235 | 70c67626470c213903c74718cf510b1bdcfe6d5e (diff) |
child 162237 | c467462fae8e0fb61578c19646f16f5998dc423f |
push id | 25941 |
push user | kwierso@gmail.com |
push date | Tue, 07 Jan 2014 01:20:54 +0000 |
treeherder | mozilla-central@ce917d3dd7c8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 29.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- 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.