Bug 1208242 - Part 1: hook up the blocklist service to b2g web extensions r=mossop,ferjm

* * *
Bug 1208242 - Part 3: don't ship things that should not ship r=me
This commit is contained in:
Fabrice Desré 2015-10-29 07:32:50 -07:00
parent 6fc8938032
commit 1021bedfa7
8 changed files with 147 additions and 23 deletions

View File

@ -1153,6 +1153,12 @@ pref("dom.performance.enable_notify_performance_timing", true);
pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html");
pref("b2g.multiscreen.system_remote_url", "index_remote.html");
// Blocklist service
pref("extensions.blocklist.enabled", true);
pref("extensions.blocklist.interval", 86400);
pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
// Because we can't have nice things.
#ifdef MOZ_GRAPHENE
#include ../graphene/graphene.js

View File

@ -537,15 +537,16 @@
#endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
#ifndef MOZ_WIDGET_GONK
@RESPATH@/components/extensions.manifest
@RESPATH@/components/addonManager.js
@RESPATH@/components/amContentHandler.js
@RESPATH@/components/amInstallTrigger.js
@RESPATH@/components/amWebInstallListener.js
@RESPATH@/components/nsBlocklistService.js
@RESPATH@/components/OopCommandLine.js
@RESPATH@/components/CommandLine.js
#endif
@RESPATH@/components/extensions.manifest
@RESPATH@/components/nsBlocklistService.js
@RESPATH@/components/BootstrapCommandLine.js
#ifdef MOZ_UPDATER

View File

@ -131,6 +131,10 @@ function _setAppProperties(aObj, aApp) {
aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
aObj.sideloaded = aApp.sideloaded;
aObj.extensionVersion = aApp.extensionVersion;
aObj.blockedStatus =
aApp.blockedStatus !== undefined ? aApp.blockedStatus
: Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
aObj.blocklistId = aApp.blocklistId;
#ifdef MOZ_B2GDROID
aObj.android_packagename = aApp.android_packagename;
aObj.android_classname = aApp.android_classname;

View File

@ -251,7 +251,9 @@ this.ImportExport = {
throw "NoManifestFound";
}
return [readObjectFromZip(appZipReader, "manifest.webapp"), file];
return [readObjectFromZip(appZipReader, "manifest.webapp"),
readObjectFromZip(appZipReader, "update.webapp"),
file];
},
// Returns a promise that resolves to the temp file path.
@ -307,6 +309,7 @@ this.ImportExport = {
let meta;
let appDir;
let manifest;
let updateManifest;
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Ci.nsIZipReader);
try {
@ -353,7 +356,7 @@ this.ImportExport = {
let appFile;
if (isPackage) {
[manifest, appFile] =
[manifest, updateManifest, appFile] =
this._importPackagedApp(zipReader, meta.manifestURL, appDir);
} else {
manifest = this._importHostedApp(zipReader, meta.manifestURL);
@ -395,6 +398,11 @@ this.ImportExport = {
meta.installerIsBrowser = false;
meta.role = manifest.role;
// If there is an id in the mini-manifest, use it for blocklisting purposes.
if (isPackage && updateManifest && ("id" in updateManifest)) {
meta.blocklistId = updateManifest["id"];
}
let devMode = false;
try {
devMode = Services.prefs.getBoolPref("dom.apps.developer_mode");

View File

@ -348,6 +348,10 @@ this.DOMApplicationRegistry = {
app.enabled = true;
}
if (app.blockedStatus === undefined) {
app.blockedStatus = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
// At startup we can't be downloading, and the $TMP directory
// will be empty so we can't just apply a staged update.
app.downloading = false;
@ -1211,6 +1215,7 @@ this.DOMApplicationRegistry = {
ppmm.removeMessageListener(msgName, this);
}).bind(this));
Services.obs.removeObserver(this, "xpcom-shutdown");
Services.obs.removeObserver(this, "memory-pressure");
cpmm = null;
ppmm = null;
if (AppConstants.MOZ_B2GDROID) {
@ -1222,6 +1227,55 @@ this.DOMApplicationRegistry = {
}
},
// Check extensions to be blocked.
blockExtensions: function(aExtensions) {
debug("blockExtensions");
let app;
let runtime = Services.appinfo.QueryInterface(Ci.nsIXULRuntime);
aExtensions.filter(extension => {
// Filter out id-less items and those who don't have a matching installed
// extension.
if (!extension.attributes.has("id")) {
return false;
}
// Check that we have an app with this extension id.
let extId = extension.attributes.get("id");
for (let id in this.webapps) {
if (this.webapps[id].blocklistId == extId) {
app = this.webapps[id];
return true;
}
}
// No webapp found for this extension id.
return false;
}).forEach(extension => {
// `extension` is a object such as:
// {"versions":[{"minVersion":"0.1",
// "maxVersion":"1.3.328.4",
// "severity":"1",
// "vulnerabilityStatus":0,
// "targetApps":{
// "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}":[{"minVersion":"3.7a1pre","maxVersion":"*"}]
// }
// }],
// "prefs":[],
// "blockID":"i24",
// "attributes": Map()
// }
//
// `versions` is array of BlocklistItemData (see nsBlocklistService.js)
let severity = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
for (let item of extension.versions) {
if (item.includesItem(app.extensionVersion, runtime.version, runtime.platformVersion)) {
severity = item.severity;
break;
}
}
this.setBlockedStatus(app.manifestURL, severity);
});
},
formatMessage: function(aData) {
let msg = aData;
delete msg["mm"];
@ -1919,6 +1973,9 @@ this.DOMApplicationRegistry = {
delete app.retryingDownload;
// Once updated we are not in the blocklist anymore.
app.blockedStatus = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
// Update the asm.js scripts we need to compile.
yield ScriptPreloader.preload(app, newManifest);
@ -2961,6 +3018,10 @@ this.DOMApplicationRegistry = {
this._writeManifestFile(app.id, false, aManifest);
if (aUpdateManifest) {
this._writeManifestFile(app.id, true, aUpdateManifest);
// If there is an id in the mini-manifest, use it for blocklisting purposes.
if (aData.isPackage && ("id" in aUpdateManifest)) {
this.webapps[app.id].blocklistId = aUpdateManifest["id"];
}
}
this._saveApps().then(() => {
@ -2995,6 +3056,10 @@ this.DOMApplicationRegistry = {
let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest;
yield this._writeManifestFile(id, aData.isPackage, jsonManifest);
// If there is an id in the mini-manifest, use it for blocklisting purposes.
if (aData.isPackage && ("id" in jsonManifest)) {
app.blocklistId = jsonManifest["id"];
}
debug("app.origin: " + app.origin);
let manifest =
@ -4581,6 +4646,20 @@ this.DOMApplicationRegistry = {
});
},
setBlockedStatus: function(aManifestURL, aSeverity) {
let id = this._appIdForManifestURL(aManifestURL);
if (!id || !this.webapps[id]) {
return;
}
debug(`Setting blocked status ${aSeverity} on ${id}`);
let app = this.webapps[id];
app.blockedStatus = aSeverity;
let enabled = aSeverity == Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
this.setEnabled({ manifestURL: aManifestURL, enabled });
},
setEnabled: function(aData) {
debug("setEnabled " + aData.manifestURL + " : " + aData.enabled);
let id = this._appIdForManifestURL(aData.manifestURL);
@ -4590,7 +4669,13 @@ this.DOMApplicationRegistry = {
debug("Enabling " + id);
let app = this.webapps[id];
app.enabled = aData.enabled;
// If we try to enable an app, check if it's not blocked.
if (!aData.enabled ||
app.blockedStatus == Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
app.enabled = aData.enabled;
}
this._saveApps().then(() => {
MessageBroadcaster.broadcastMessage("Webapps:UpdateState", {
app: app,

View File

@ -4,8 +4,8 @@ category profile-after-change nsBlocklistService @mozilla.org/extensions/blockli
component {e0a106ed-6ad4-47a4-b6af-2f1c8aa4712d} nsBlocklistServiceContent.js process=content
contract @mozilla.org/extensions/blocklist;1 {e0a106ed-6ad4-47a4-b6af-2f1c8aa4712d} process=content
#ifndef MOZ_WIDGET_GONK
category update-timer nsBlocklistService @mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400
#ifndef MOZ_WIDGET_GONK
component {4399533d-08d1-458c-a87a-235f74451cfa} addonManager.js
contract @mozilla.org/addons/integration;1 {4399533d-08d1-458c-a87a-235f74451cfa}
category update-timer addonManager @mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400

View File

@ -21,12 +21,12 @@ EXTRA_COMPONENTS += [
'amContentHandler.js',
'amInstallTrigger.js',
'amWebInstallListener.js',
'nsBlocklistService.js',
'nsBlocklistServiceContent.js',
]
EXTRA_PP_COMPONENTS += [
'extensions.manifest',
'nsBlocklistService.js',
]
EXTRA_JS_MODULES += [

View File

@ -12,6 +12,7 @@ const Cr = Components.results;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AppConstants.jsm");
try {
// AddonManager.jsm doesn't allow itself to be imported in the child
@ -29,6 +30,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DOMApplicationRegistry",
"resource://gre/modules/Webapps.jsm");
const TOOLKIT_ID = "toolkit@mozilla.org";
const KEY_PROFILEDIR = "ProfD";
@ -107,15 +110,16 @@ XPCOMUtils.defineLazyGetter(this, "gABI", function bls_gABI() {
catch (e) {
LOG("BlockList Global gABI: XPCOM ABI unknown.");
}
#ifdef XP_MACOSX
// Mac universal build should report a different ABI than either macppc
// or mactel.
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
getService(Ci.nsIMacUtils);
if (macutils.isUniversalBinary)
abi += "-u-" + macutils.architecturesInBinary;
#endif
if (AppConstants.platform == "macosx") {
// Mac universal build should report a different ABI than either macppc
// or mactel.
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
getService(Ci.nsIMacUtils);
if (macutils.isUniversalBinary)
abi += "-u-" + macutils.architecturesInBinary;
}
return abi;
});
@ -892,10 +896,21 @@ Blocklist.prototype = {
continue;
switch (element.localName) {
case "emItems":
// Special case for b2g, since we don't use the addon manager.
if (AppConstants.MOZ_B2G) {
let extensions = this._processItemNodes(element.childNodes, "em",
this._handleEmItemNode);
DOMApplicationRegistry.blockExtensions(extensions);
return;
}
this._addonEntries = this._processItemNodes(element.childNodes, "em",
this._handleEmItemNode);
break;
case "pluginItems":
// We don't support plugins on b2g.
if (AppConstants.MOZ_B2G) {
return;
}
this._pluginEntries = this._processItemNodes(element.childNodes, "plugin",
this._handlePluginItemNode);
break;
@ -1060,14 +1075,15 @@ Blocklist.prototype = {
/* See nsIBlocklistService */
getPluginBlocklistState: function Blocklist_getPluginBlocklistState(plugin,
appVersion, toolkitVersion) {
#ifdef ANDROID
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
#else
if (!this._isBlocklistLoaded())
this._loadBlocklist();
return this._getPluginBlocklistState(plugin, this._pluginEntries,
appVersion, toolkitVersion);
#endif // ifdef ANDROID
if (AppConstants.platform == "android" ||
AppConstants.MOZ_B2G) {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
} else {
if (!this._isBlocklistLoaded())
this._loadBlocklist();
return this._getPluginBlocklistState(plugin, this._pluginEntries,
appVersion, toolkitVersion);
}
},
/**
@ -1207,6 +1223,10 @@ Blocklist.prototype = {
},
_blocklistUpdated: function Blocklist_blocklistUpdated(oldAddonEntries, oldPluginEntries) {
if (AppConstants.MOZ_B2G) {
return;
}
var addonList = [];
// A helper function that reverts the prefs passed to default values.