Bug 1682030 - Remove NPAPI blocklisting r=Gijs,jmathies,mixedpuppy

Removes the PluginProvider and NPAPI plugin blocklist handling as part of removing all NPAPI support.  This allows us to remove nsIPluginHost.

Differential Revision: https://phabricator.services.mozilla.com/D107148
This commit is contained in:
David Parks 2021-04-05 23:48:38 +00:00
Родитель bba6d38dfb
Коммит 0e34d4d48b
26 изменённых файлов: 22 добавлений и 1835 удалений

Просмотреть файл

@ -522,16 +522,6 @@ class PluginChild extends JSWindowActorChild {
break;
case "PluginVulnerableUpdatable":
let updateLink = this.getPluginUI(pluginElement, "checkForUpdatesLink");
let { pluginTag } = this._getPluginInfo(pluginElement);
this.addLinkClickCallback(
updateLink,
"forwardCallback",
"openPluginUpdatePage",
pluginTag.id
);
/* FALLTHRU */
case "PluginVulnerableNoUpdate":
case "PluginClickToPlay":
this._handleClickToPlayEvent(pluginElement);
@ -542,19 +532,6 @@ class PluginChild extends JSWindowActorChild {
);
let overlayText = this.getPluginUI(pluginElement, "clickToPlay");
overlayText.textContent = messageString;
if (
eventType == "PluginVulnerableUpdatable" ||
eventType == "PluginVulnerableNoUpdate"
) {
let vulnerabilityString = gNavigatorBundle.GetStringFromName(
eventType
);
let vulnerabilityText = this.getPluginUI(
pluginElement,
"vulnerabilityStatus"
);
vulnerabilityText.textContent = vulnerabilityString;
}
shouldShowNotification = true;
break;

Просмотреть файл

@ -359,9 +359,6 @@ class PluginParent extends JSWindowActorParent {
case "openHelpPage":
this[msg.data.name](win);
break;
case "openPluginUpdatePage":
this.openPluginUpdatePage(win, msg.data.pluginId);
break;
}
break;
case "PluginContent:GetCrashData":
@ -387,20 +384,6 @@ class PluginParent extends JSWindowActorParent {
window.BrowserOpenAddonsMgr("addons://list/plugin");
}
// Callback for user clicking on the link in a click-to-play plugin
// (where the plugin has an update)
async openPluginUpdatePage(window, pluginId) {
let pluginTag = PluginManager.getPluginTagById(pluginId);
if (!pluginTag) {
return;
}
let { Blocklist } = ChromeUtils.import(
"resource://gre/modules/Blocklist.jsm"
);
let url = await Blocklist.getPluginBlockURL(pluginTag);
window.openTrustedLinkIn(url, "tab");
}
submitReport(runID, keyVals, submitURLOptIn) {
if (!AppConstants.MOZ_CRASHREPORTER) {
return;
@ -469,19 +452,7 @@ class PluginParent extends JSWindowActorParent {
case "block":
permission = Ci.nsIPermissionManager.PROMPT_ACTION;
histogram.add(2);
let pluginTag = PluginManager.getPluginTagById(aActivationInfo.id);
switch (pluginTag.blocklistState) {
case Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE:
aActivationInfo.fallbackType = PLUGIN_VULNERABLE_UPDATABLE;
break;
case Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE:
aActivationInfo.fallbackType = PLUGIN_VULNERABLE_NO_UPDATE;
break;
default:
// PLUGIN_CLICK_TO_PLAY_QUIET will only last until they reload the page, at
// which point it will be PLUGIN_CLICK_TO_PLAY (the overlays will appear)
aActivationInfo.fallbackType = PLUGIN_CLICK_TO_PLAY_QUIET;
}
aActivationInfo.fallbackType = PLUGIN_CLICK_TO_PLAY_QUIET;
notification.options.extraAttr = "inactive";
break;

Просмотреть файл

@ -10,7 +10,6 @@
#include "nsIWebNavigation.h"
#include "nsServiceManagerUtils.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIPluginHost.h"
#include "nsIDocShell.h"
#include "nsContentUtils.h"
#include "imgLoader.h"
@ -52,40 +51,7 @@ uint32_t nsWebNavigationInfo::IsTypeSupported(const nsACString& aType,
}
const nsCString& flatType = PromiseFlatCString(aType);
uint32_t result = IsTypeSupportedInternal(flatType);
if (result != nsIWebNavigationInfo::UNSUPPORTED) {
return result;
}
// As of FF 52, we only support flash and test plugins, so if the mime types
// don't match for that, exit before we start loading plugins.
if (!nsPluginHost::CanUsePluginForMIMEType(aType)) {
return nsIWebNavigationInfo::UNSUPPORTED;
}
// If this request is for a docShell that isn't going to allow plugins,
// there's no need to try and find a plugin to handle it.
if (!aPluginsAllowed) {
return nsIWebNavigationInfo::UNSUPPORTED;
}
// Try reloading plugins in case they've changed.
nsCOMPtr<nsIPluginHost> pluginHost =
do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
if (pluginHost) {
// false will ensure that currently running plugins will not
// be shut down
nsresult rv = pluginHost->ReloadPlugins();
if (NS_SUCCEEDED(rv)) {
// OK, we reloaded plugins and there were new ones
// (otherwise NS_ERROR_PLUGINS_PLUGINSNOTCHANGED would have
// been returned). Try checking whether we can handle the
// content now.
return IsTypeSupportedInternal(flatType);
}
}
return nsIWebNavigationInfo::UNSUPPORTED;
return IsTypeSupportedInternal(flatType);
}
uint32_t nsWebNavigationInfo::IsTypeSupportedInternal(const nsCString& aType) {

Просмотреть файл

@ -1,16 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
Classes = [
{
'cid': '{23e8fd98-a625-4b08-be1a-f7cc18a5b106}',
'contract_ids': ['@mozilla.org/plugin/host;1'],
'singleton': True,
'type': 'nsPluginHost',
'headers': ['nsPluginHost.h'],
'constructor': 'nsPluginHost::GetInst',
},
]

Просмотреть файл

@ -5,7 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
"nsIPluginHost.idl",
"nsIPluginTag.idl",
"nspluginroot.idl",
]
@ -30,10 +29,6 @@ SOURCES += [
"nsPluginHost.cpp", # Conflict with NS_NPAPIPLUGIN_CALLBACK
]
XPCOM_MANIFESTS += [
"components.conf",
]
LOCAL_INCLUDES += [
"/dom/base",
"/layout/generic",

Просмотреть файл

@ -1,179 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nspluginroot.idl"
#include "nsISupports.idl"
#include "nsIPluginTag.idl"
%{C++
#define MOZ_PLUGIN_HOST_CONTRACTID \
"@mozilla.org/plugin/host;1"
%}
[scriptable, function, uuid(9c311778-7c2c-4ad8-b439-b8a2786a20dd)]
interface nsIClearSiteDataCallback : nsISupports
{
/**
* callback with the result from a call to clearSiteData
*/
void callback(in nsresult rv);
};
[scriptable, uuid(f938f5ba-7093-42cd-a559-af8039d99204)]
interface nsIPluginHost : nsISupports
{
/**
* Causes the plugins directory to be searched again for new plugin
* libraries.
*/
void reloadPlugins();
Array<nsIPluginTag> getPluginTags();
/*
* Flags for use with clearSiteData.
*
* FLAG_CLEAR_ALL: clear all data associated with a site.
* FLAG_CLEAR_CACHE: clear cached data that can be retrieved again without
* loss of functionality. To be used out of concern for
* space and not necessarily privacy.
*/
const uint32_t FLAG_CLEAR_ALL = 0;
const uint32_t FLAG_CLEAR_CACHE = 1;
/*
* For use with Get*ForType functions
*/
const uint32_t EXCLUDE_NONE = 0;
const uint32_t EXCLUDE_DISABLED = 1 << 0;
const uint32_t EXCLUDE_FAKE = 1 << 1;
/*
* Clear site data for a given plugin.
*
* @param plugin: the plugin to clear data for, such as one returned by
* nsIPluginHost.getPluginTags.
* @param domain: the domain to clear data for. If this argument is null,
* clear data for all domains. Otherwise, it must be a domain
* only (not a complete URI or IRI). The base domain for the
* given site will be determined; any data for the base domain
* or its subdomains will be cleared.
* @param flags: a flag value defined above.
* @param maxAge: the maximum age in seconds of data to clear, inclusive. If
* maxAge is 0, no data is cleared; if it is -1, all data is
* cleared.
*
* @throws NS_ERROR_INVALID_ARG if the domain argument is malformed.
* @throws NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED if maxAge is a value other
* than -1 and the plugin does not support clearing by timerange in
* general or for that particular site and/or flag combination.
*/
void clearSiteData(in nsIPluginTag plugin, in AUTF8String domain,
in uint64_t flags, in int64_t maxAge,
in nsIClearSiteDataCallback callback);
/*
* Determine if a plugin has stored data for a given site.
*
* @param plugin: the plugin to query, such as one returned by
* nsIPluginHost.getPluginTags.
* @param domain: the domain to test. If this argument is null, test if data
* is stored for any site. The base domain for the given domain
* will be determined; if any data for the base domain or its
* subdomains is found, return true.
*/
boolean siteHasData(in nsIPluginTag plugin, in AUTF8String domain);
/**
* Get the "permission string" for the plugin. This is a string that can be
* passed to the permission manager to see whether the plugin is allowed to
* run, for example. This will typically be based on the plugin's "nice name"
* and its blocklist state.
*
* @mimeType The MIME type we're interested in.
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
*/
ACString getPermissionStringForType(in AUTF8String mimeType,
[optional] in uint32_t excludeFlags);
/**
* Get the "permission string" for the plugin. This is a string that can be
* passed to the permission manager to see whether the plugin is allowed to
* run, for example. This will typically be based on the plugin's "nice name"
* and its blocklist state.
*
* @tag The tage we're interested in
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
*/
ACString getPermissionStringForTag(in nsIPluginTag tag,
[optional] in uint32_t excludeFlags);
/**
* Get the nsIPluginTag for this MIME type. This method works with both
* enabled and disabled/blocklisted plugins, but an enabled plugin will
* always be returned if available.
*
* A fake plugin tag, if one exists and is available, will be returned in
* preference to NPAPI plugin tags unless excluded by the excludeFlags.
*
* @mimeType The MIME type we're interested in.
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
*
* @throws NS_ERROR_NOT_AVAILABLE if no plugin is available for this MIME
* type.
*/
nsIPluginTag getPluginTagForType(in AUTF8String mimeType,
[optional] in uint32_t excludeFlags);
/**
* Get the nsIPluginTag enabled state for this MIME type. See
* nsIPluginTag.enabledState.
*
* @mimeType The MIME type we're interested in.
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
*/
unsigned long getStateForType(in AUTF8String mimeType,
[optional] in uint32_t excludeFlags);
/**
* Get the blocklist state for a MIME type. See nsIPluginTag.blocklistState.
*
* @mimeType The MIME type we're interested in.
* @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE.
*/
uint32_t getBlocklistStateForType(in AUTF8String aMimeType,
[optional] in uint32_t excludeFlags);
/**
* Create a fake plugin tag, register it, and return it. The argument is a
* FakePluginTagInit dictionary. See documentation in
* FakePluginTagInit.webidl for what it should look like. Will throw
* NS_ERROR_UNEXPECTED if there is already a fake plugin registered with the
* given handler URI.
*/
[implicit_jscontext]
nsIFakePluginTag registerFakePlugin(in jsval initDictionary);
/**
* Create a fake plugin tag without registering it.
*
* Only for use in tests.
*/
[implicit_jscontext]
nsIFakePluginTag createFakePlugin(in jsval initDictionary);
/**
* Get a reference to an existing fake plugin tag for the given MIME type, if
* any. Can return null.
*/
nsIFakePluginTag getFakePlugin(in AUTF8String mimeType);
/**
* Unregister a fake plugin. The argument can be the .handlerURI.spec of an
* existing nsIFakePluginTag, or just a known handler URI string that was
* passed in the FakePluginTagInit when registering.
*/
void unregisterFakePlugin(in AUTF8String handlerURI);
};

Просмотреть файл

@ -298,9 +298,6 @@ nsPluginHost::nsPluginHost()
mozilla::services::GetObserverService();
if (obsService) {
obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
if (XRE_IsParentProcess()) {
obsService->AddObserver(this, "plugin-blocklist-updated", false);
}
}
#ifdef PLUGIN_LOGGING
@ -337,7 +334,7 @@ nsPluginHost::~nsPluginHost() {
UnloadPlugins();
}
NS_IMPL_ISUPPORTS(nsPluginHost, nsIPluginHost, nsIObserver, nsITimerCallback,
NS_IMPL_ISUPPORTS(nsPluginHost, nsIObserver, nsITimerCallback,
nsISupportsWeakReference, nsINamed)
already_AddRefed<nsPluginHost> nsPluginHost::GetInst() {
@ -525,39 +522,6 @@ nsPluginHost::GetPluginTagForType(const nsACString& aMimeType,
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsPluginHost::GetStateForType(const nsACString& aMimeType,
uint32_t aExcludeFlags, uint32_t* aResult) {
nsCOMPtr<nsIPluginTag> tag;
nsresult rv =
GetPluginTagForType(aMimeType, aExcludeFlags, getter_AddRefs(tag));
NS_ENSURE_SUCCESS(rv, rv);
return tag->GetEnabledState(aResult);
}
NS_IMETHODIMP
nsPluginHost::GetBlocklistStateForType(const nsACString& aMimeType,
uint32_t aExcludeFlags,
uint32_t* aState) {
nsCOMPtr<nsIPluginTag> tag;
nsresult rv =
GetPluginTagForType(aMimeType, aExcludeFlags, getter_AddRefs(tag));
NS_ENSURE_SUCCESS(rv, rv);
return tag->GetBlocklistState(aState);
}
NS_IMETHODIMP
nsPluginHost::GetPermissionStringForType(const nsACString& aMimeType,
uint32_t aExcludeFlags,
nsACString& aPermissionString) {
nsCOMPtr<nsIPluginTag> tag;
nsresult rv =
GetPluginTagForType(aMimeType, aExcludeFlags, getter_AddRefs(tag));
NS_ENSURE_SUCCESS(rv, rv);
return GetPermissionStringForTag(tag, aExcludeFlags, aPermissionString);
}
NS_IMETHODIMP
nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
uint32_t aExcludeFlags,
@ -569,13 +533,7 @@ nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
nsresult rv = aTag->GetBlocklistState(&blocklistState);
NS_ENSURE_SUCCESS(rv, rv);
if (blocklistState ==
nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
aPermissionString.AssignLiteral("plugin-vulnerable:");
} else {
aPermissionString.AssignLiteral("plugin:");
}
aPermissionString.AssignLiteral("plugin:");
nsCString niceName;
rv = aTag->GetNiceName(niceName);
@ -630,22 +588,6 @@ void nsPluginHost::GetPlugins(
}
}
// FIXME-jsplugins Check users for order of fake v non-fake
NS_IMETHODIMP
nsPluginHost::GetPluginTags(nsTArray<RefPtr<nsIPluginTag>>& aResults) {
LoadPlugins();
for (nsPluginTag* plugin = mPlugins; plugin; plugin = plugin->mNext) {
aResults.AppendElement(plugin);
}
for (nsIInternalPluginTag* plugin : mFakePlugins) {
aResults.AppendElement(plugin);
}
return NS_OK;
}
nsPluginTag* nsPluginHost::FindPreferredPlugin(
const nsTArray<nsPluginTag*>& matches) {
// We prefer the plugin with the highest version number.
@ -924,106 +866,6 @@ static bool MimeTypeIsAllowedForFakePlugin(const nsString& aMimeType) {
return false;
}
NS_IMETHODIMP
nsPluginHost::RegisterFakePlugin(JS::Handle<JS::Value> aInitDictionary,
JSContext* aCx, nsIFakePluginTag** aResult) {
FakePluginTagInit initDictionary;
if (!initDictionary.Init(aCx, aInitDictionary)) {
return NS_ERROR_FAILURE;
}
for (const FakePluginMimeEntry& mimeEntry : initDictionary.mMimeEntries) {
if (!MimeTypeIsAllowedForFakePlugin(mimeEntry.mType)) {
return NS_ERROR_FAILURE;
}
}
RefPtr<nsFakePluginTag> newTag;
nsresult rv = nsFakePluginTag::Create(initDictionary, getter_AddRefs(newTag));
NS_ENSURE_SUCCESS(rv, rv);
for (const auto& existingTag : mFakePlugins) {
if (newTag->HandlerURIMatches(existingTag->HandlerURI())) {
return NS_ERROR_UNEXPECTED;
}
}
mFakePlugins.AppendElement(newTag);
nsAutoCString disableFullPage;
Preferences::GetCString(kPrefDisableFullPage, disableFullPage);
for (uint32_t i = 0; i < newTag->MimeTypes().Length(); i++) {
if (!IsTypeInList(newTag->MimeTypes()[i], disableFullPage)) {
RegisterWithCategoryManager(newTag->MimeTypes()[i], ePluginRegister);
}
}
newTag.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
nsPluginHost::CreateFakePlugin(JS::Handle<JS::Value> aInitDictionary,
JSContext* aCx, nsIFakePluginTag** aResult) {
FakePluginTagInit initDictionary;
if (!initDictionary.Init(aCx, aInitDictionary)) {
return NS_ERROR_FAILURE;
}
RefPtr<nsFakePluginTag> newTag;
nsresult rv = nsFakePluginTag::Create(initDictionary, getter_AddRefs(newTag));
NS_ENSURE_SUCCESS(rv, rv);
newTag.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
nsPluginHost::UnregisterFakePlugin(const nsACString& aHandlerURI) {
nsCOMPtr<nsIURI> handlerURI;
nsresult rv = NS_NewURI(getter_AddRefs(handlerURI), aHandlerURI);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0; i < mFakePlugins.Length(); ++i) {
if (mFakePlugins[i]->HandlerURIMatches(handlerURI)) {
mFakePlugins.RemoveElementAt(i);
return NS_OK;
}
}
return NS_OK;
}
// FIXME-jsplugins Is this method actually needed?
NS_IMETHODIMP
nsPluginHost::GetFakePlugin(const nsACString& aMimeType,
nsIFakePluginTag** aResult) {
RefPtr<nsFakePluginTag> result = FindFakePluginForType(aMimeType, false);
if (result) {
result.forget(aResult);
return NS_OK;
}
*aResult = nullptr;
return NS_ERROR_NOT_AVAILABLE;
}
// FIXME-jsplugins what should this do for fake plugins?
NS_IMETHODIMP
nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
uint64_t flags, int64_t maxAge,
nsIClearSiteDataCallback* callbackFunc) {
return NS_ERROR_FAILURE;
}
// This will spin the event loop while waiting on an async
// call to GetSitesWithData
NS_IMETHODIMP
nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
bool* result) {
return NS_ERROR_FAILURE;
}
nsPluginHost::SpecialType nsPluginHost::GetSpecialType(
const nsACString& aMIMEType) {
if (aMIMEType.LowerCaseEqualsASCII("application/x-test")) {
@ -1093,26 +935,6 @@ void nsPluginHost::AddPluginTag(nsPluginTag* aPluginTag) {
}
}
void nsPluginHost::UpdatePluginBlocklistState(nsPluginTag* aPluginTag,
bool aShouldSoftblock) {
nsCOMPtr<nsIBlocklistService> blocklist =
do_GetService("@mozilla.org/extensions/blocklist;1");
MOZ_ASSERT(blocklist, "Should be able to access the blocklist");
if (!blocklist) {
return;
}
// Asynchronously get the blocklist state.
RefPtr<Promise> promise;
blocklist->GetPluginBlocklistState(aPluginTag, u""_ns, u""_ns,
getter_AddRefs(promise));
MOZ_ASSERT(promise,
"Should always get a promise for plugin blocklist state.");
if (promise) {
promise->AppendNativeHandler(new mozilla::plugins::BlocklistPromiseHandler(
aPluginTag, aShouldSoftblock));
}
}
void nsPluginHost::IncrementChromeEpoch() {
MOZ_ASSERT(XRE_IsParentProcess());
mPluginEpoch++;
@ -1314,17 +1136,7 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports* aSubject, const char* aTopic,
LoadPlugins();
}
}
if (XRE_IsParentProcess() && !strcmp("plugin-blocklist-updated", aTopic)) {
// The blocklist has updated. Asynchronously get blocklist state for all
// items. The promise resolution handler takes care of checking if anything
// changed, and writing an updated state to file, as well as sending data to
// child processes.
nsPluginTag* plugin = mPlugins;
while (plugin) {
UpdatePluginBlocklistState(plugin);
plugin = plugin->mNext;
}
}
return NS_OK;
}

Просмотреть файл

@ -9,7 +9,6 @@
#include "mozilla/LinkedList.h"
#include "mozilla/StaticPtr.h"
#include "nsIPluginHost.h"
#include "nsIObserver.h"
#include "nsCOMPtr.h"
#include "prlink.h"
@ -52,8 +51,7 @@ struct _NPP;
typedef _NPP* NPP;
#endif
class nsPluginHost final : public nsIPluginHost,
public nsIObserver,
class nsPluginHost final : public nsIObserver,
public nsITimerCallback,
public nsSupportsWeakReference,
public nsINamed {
@ -67,17 +65,21 @@ class nsPluginHost final : public nsIPluginHost,
static already_AddRefed<nsPluginHost> GetInst();
NS_DECL_ISUPPORTS
NS_DECL_NSIPLUGINHOST
NS_DECL_NSIOBSERVER
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSINAMED
// Acts like a bitfield
enum PluginFilter {
eExcludeNone = nsIPluginHost::EXCLUDE_NONE,
eExcludeDisabled = nsIPluginHost::EXCLUDE_DISABLED,
eExcludeFake = nsIPluginHost::EXCLUDE_FAKE
};
enum PluginFilter { eExcludeNone, eExcludeDisabled, eExcludeFake };
NS_IMETHOD GetPluginTagForType(const nsACString& aMimeType,
uint32_t aExcludeFlags,
nsIPluginTag** aResult);
NS_IMETHOD GetPermissionStringForTag(nsIPluginTag* aTag,
uint32_t aExcludeFlags,
nsACString& aPermissionString);
NS_IMETHOD ReloadPlugins();
// FIXME-jsplugins comment about fake
bool HavePluginForType(const nsACString& aMimeType,
PluginFilter aFilter = eExcludeDisabled);
@ -152,9 +154,6 @@ class nsPluginHost final : public nsIPluginHost,
nsresult UpdateCachedSerializablePluginList();
nsresult SendPluginsToContent(mozilla::dom::ContentParent* parent);
void UpdatePluginBlocklistState(nsPluginTag* aPluginTag,
bool aShouldSoftblock = false);
private:
nsresult LoadPlugins();
nsresult UnloadPlugins();

Просмотреть файл

@ -46,13 +46,7 @@ RPMSendQuery("RequestPlugins", {}).then(aPlugins => {
fragment.appendChild(deprecation);
var stateNames = {};
[
"STATE_SOFTBLOCKED",
"STATE_BLOCKED",
"STATE_OUTDATED",
"STATE_VULNERABLE_UPDATE_AVAILABLE",
"STATE_VULNERABLE_NO_UPDATE",
].forEach(function(label) {
["STATE_SOFTBLOCKED", "STATE_BLOCKED"].forEach(function(label) {
stateNames[Ci.nsIBlocklistService[label]] = label;
});

Просмотреть файл

@ -9,8 +9,6 @@ updateName=%S %S
noThanksButton=No Thanks
noThanksButton.accesskey=N
# NOTE: The restartLaterButton string is also used in
# mozapps/extensions/content/blocklist.js
restartLaterButton=Restart Later
restartLaterButton.accesskey=L
restartNowButton=Restart %S

Просмотреть файл

@ -1,22 +0,0 @@
# 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
blocklist-window =
.title = Add-ons may be causing problems
.style = width: 45em; height: 30em
blocklist-accept =
.label = Restart { -brand-short-name }
.accesskey = R
blocklist-label-summary = { -brand-short-name } has determined that the following add-ons are known to cause stability or security problems:
blocklist-soft-and-hard = The add-ons that have a high risk of causing stability or security problems have been blocked. The others are lower risk, but it is highly recommended that you restart with them disabled.
blocklist-hard-blocked = These add-ons have a high risk of causing stability or security problems and have been blocked, but a restart is required to disable them completely.
blocklist-soft-blocked = For your protection, it is highly recommended that you restart with these add-ons disabled.
blocklist-more-information =
.value = More information
blocklist-blocked =
.label = Blocked
blocklist-checkbox =
.label = Disable

Просмотреть файл

@ -136,31 +136,19 @@ const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL";
const PREF_BLOCKLIST_ADDONITEM_URL = "extensions.blocklist.addonItemURL";
const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
const PREF_BLOCKLIST_LEVEL = "extensions.blocklist.level";
const PREF_BLOCKLIST_SUPPRESSUI = "extensions.blocklist.suppressUI";
const PREF_BLOCKLIST_USE_MLBF = "extensions.blocklist.useMLBF";
const PREF_BLOCKLIST_USE_MLBF_STASHES = "extensions.blocklist.useMLBF.stashes";
const PREF_EM_LOGGING_ENABLED = "extensions.logging.enabled";
const URI_BLOCKLIST_DIALOG =
"chrome://mozapps/content/extensions/blocklist.xhtml";
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;
// Remote Settings blocklist constants
const PREF_BLOCKLIST_BUCKET = "services.blocklist.bucket";
const PREF_BLOCKLIST_GFX_COLLECTION = "services.blocklist.gfx.collection";
const PREF_BLOCKLIST_GFX_CHECKED_SECONDS = "services.blocklist.gfx.checked";
const PREF_BLOCKLIST_GFX_SIGNER = "services.blocklist.gfx.signer";
const PREF_BLOCKLIST_PLUGINS_COLLECTION =
"services.blocklist.plugins.collection";
const PREF_BLOCKLIST_PLUGINS_CHECKED_SECONDS =
"services.blocklist.plugins.checked";
const PREF_BLOCKLIST_PLUGINS_SIGNER = "services.blocklist.plugins.signer";
// Blocklist v2 - legacy JSON format.
const PREF_BLOCKLIST_ADDONS_COLLECTION = "services.blocklist.addons.collection";
const PREF_BLOCKLIST_ADDONS_CHECKED_SECONDS =
"services.blocklist.addons.checked";
@ -328,7 +316,7 @@ const Utils = {
/**
* Given a blocklist JS object entry, ensure it has a versionRange property, where
* each versionRange property has valid severity and vulnerabilityStatus properties,
* each versionRange property has a valid severity property
* and at least 1 valid targetApplication.
* If it didn't have a valid targetApplication array before and/or it was empty,
* fill it with an entry with null min/maxVersion properties, which will match
@ -348,10 +336,6 @@ const Utils = {
if (!vr.hasOwnProperty("severity")) {
vr.severity = DEFAULT_SEVERITY;
}
if (!vr.hasOwnProperty("vulnerabilityStatus")) {
vr.vulnerabilityStatus = VULNERABILITYSTATUS_NONE;
}
if (!Array.isArray(vr.targetApplication)) {
vr.targetApplication = [];
}
@ -617,433 +601,6 @@ this.GfxBlocklistRS = {
},
};
/**
* The plugins blocklist implementation. The JSON objects for plugin blocks look
* something like:
*
* {
* "blockID":"p906",
* "details": {
* "bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1159917",
* "who":"Which users it affects",
* "why":"Why it's being blocklisted",
* "name":"Java Plugin 7 update 45 to 78 (click-to-play), Windows",
* "created":"2015-05-19T09:02:45Z"
* },
* "enabled":true,
* "infoURL":"https://java.com/",
* "matchName":"Java\\(TM\\) Platform SE 7 U(4[5-9]|(5|6)\\d|7[0-8])(\\s[^\\d\\._U]|$)",
* "versionRange":[
* {
* "severity":0,
* "targetApplication":[
* {
* "guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
* "maxVersion":"57.0.*",
* "minVersion":"0"
* }
* ],
* "vulnerabilityStatus":1
* }
* ],
* "matchFilename":"npjp2\\.dll",
* "id":"f254e5bc-12c7-7954-fe6b-8f1fdab0ae88",
* "last_modified":1519390914542,
* }
*
* Note: we assign to the global to allow tests to reach the object directly.
*/
this.PluginBlocklistRS = {
_matchProps: {
matchDescription: "description",
matchFilename: "filename",
matchName: "name",
},
async _ensureEntries() {
await this.ensureInitialized();
if (!this._entries && gBlocklistEnabled) {
await this._updateEntries();
// Dispatch to mainthread because consumers may try to construct nsIPluginHost
// again based on this notification, while we were called from nsIPluginHost
// anyway, leading to re-entrancy.
Services.tm.dispatchToMainThread(function() {
Services.obs.notifyObservers(null, "plugin-blocklist-loaded");
});
}
},
async _updateEntries() {
if (!gBlocklistEnabled) {
this._entries = [];
return;
}
this._entries = await this._client.get().catch(ex => Cu.reportError(ex));
// Handle error silently. This can happen if our request to fetch data is aborted,
// e.g. by application shutdown.
if (!this._entries) {
this._entries = [];
return;
}
this._entries.forEach(entry => {
entry.matches = {};
for (let k of Object.keys(this._matchProps)) {
if (entry[k]) {
try {
entry.matches[this._matchProps[k]] = new RegExp(entry[k], "m");
} catch (ex) {
/* Ignore invalid regexes */
}
}
}
Utils.ensureVersionRangeIsSane(entry);
});
BlocklistTelemetry.recordRSBlocklistLastModified("plugins", this._client);
},
async _filterItem(entry, environment) {
if (!(await targetAppFilter(entry, environment))) {
return null;
}
if (!Utils.matchesOSABI(entry)) {
return null;
}
if (!entry.matchFilename && !entry.matchName && !entry.matchDescription) {
let blockID = entry.blockID || entry.id;
Cu.reportError(new Error(`Nothing to filter plugin item ${blockID}`));
return null;
}
return entry;
},
sync() {
this.ensureInitialized();
return this._client.sync();
},
ensureInitialized() {
if (!gBlocklistEnabled || this._initialized) {
return;
}
this._initialized = true;
this._client = RemoteSettings(
Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_COLLECTION),
{
bucketNamePref: PREF_BLOCKLIST_BUCKET,
lastCheckTimePref: PREF_BLOCKLIST_PLUGINS_CHECKED_SECONDS,
signerName: Services.prefs.getCharPref(PREF_BLOCKLIST_PLUGINS_SIGNER),
filterFunc: this._filterItem,
}
);
this._onUpdate = this._onUpdate.bind(this);
this._client.on("sync", this._onUpdate);
},
shutdown() {
if (this._client) {
this._client.off("sync", this._onUpdate);
}
},
async _onUpdate() {
let oldEntries = this._entries || [];
this.ensureInitialized();
await this._updateEntries();
const pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(
Ci.nsIPluginHost
);
const plugins = pluginHost.getPluginTags();
let blockedItems = [];
for (let plugin of plugins) {
let oldState = this._getState(plugin, oldEntries);
let state = this._getState(plugin, this._entries);
LOG(
"Blocklist state for " +
plugin.name +
" changed from " +
oldState +
" to " +
state
);
// We don't want to re-warn about items
if (state == oldState) {
continue;
}
if (oldState == Ci.nsIBlocklistService.STATE_BLOCKED) {
if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) {
plugin.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
}
} else if (
!plugin.disabled &&
state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED
) {
if (
state != Ci.nsIBlocklistService.STATE_OUTDATED &&
state != Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE &&
state != Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE
) {
blockedItems.push({
name: plugin.name,
version: plugin.version,
icon: "chrome://global/skin/icons/plugin.svg",
disable: false,
blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
item: plugin,
url: await this.getURL(plugin),
});
}
}
}
if (blockedItems.length) {
this._showBlockedPluginsPrompt(blockedItems);
} else {
this._notifyUpdate();
}
},
_showBlockedPluginsPrompt(blockedPlugins) {
let args = {
restart: false,
list: blockedPlugins,
};
// This lets the dialog get the raw js object
args.wrappedJSObject = args;
/*
Some tests run without UI, so the async code listens to a message
that can be sent programatically
*/
let applyBlocklistChanges = async () => {
Services.obs.removeObserver(
applyBlocklistChanges,
"addon-blocklist-closed"
);
for (let blockedData of blockedPlugins) {
if (!blockedData.disable) {
continue;
}
// This will disable all the plugins immediately.
if (blockedData.item instanceof Ci.nsIPluginTag) {
blockedData.item.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
}
}
if (!args.restart) {
this._notifyUpdate();
return;
}
// We need to ensure the new blocklist state is written to disk before restarting.
// We'll notify about the blocklist update, then wait for nsIPluginHost
// to finish processing it, then restart the browser.
let pluginUpdatesFinishedPromise = new Promise(resolve => {
Services.obs.addObserver(function updatesFinished() {
Services.obs.removeObserver(
updatesFinished,
"plugin-blocklist-updates-finished"
);
resolve();
}, "plugin-blocklist-updates-finished");
});
this._notifyUpdate();
await pluginUpdatesFinishedPromise;
// Notify all windows that an application quit has been requested.
var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
Ci.nsISupportsPRBool
);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
// Something aborted the quit process.
if (cancelQuit.data) {
return;
}
Services.startup.quit(
Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit
);
};
Services.obs.addObserver(applyBlocklistChanges, "addon-blocklist-closed");
if (Services.prefs.getBoolPref(PREF_BLOCKLIST_SUPPRESSUI, false)) {
applyBlocklistChanges();
return;
}
function blocklistUnloadHandler(event) {
if (event.target.location == URI_BLOCKLIST_DIALOG) {
applyBlocklistChanges();
blocklistWindow.removeEventListener("unload", blocklistUnloadHandler);
}
}
let blocklistWindow = Services.ww.openWindow(
null,
URI_BLOCKLIST_DIALOG,
"",
"chrome,centerscreen,dialog,titlebar",
args
);
if (blocklistWindow) {
blocklistWindow.addEventListener("unload", blocklistUnloadHandler);
}
},
_notifyUpdate() {
Services.obs.notifyObservers(null, "plugin-blocklist-updated");
},
async getURL(plugin) {
await this._ensureEntries();
let r = this._getEntry(plugin, this._entries);
if (!r) {
return null;
}
let blockEntry = r.entry;
let blockID = blockEntry.blockID || blockEntry.id;
return blockEntry.infoURL || Utils._createBlocklistURL(blockID);
},
async getState(plugin, appVersion, toolkitVersion) {
if (AppConstants.platform == "android") {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
await this._ensureEntries();
return this._getState(plugin, this._entries, appVersion, toolkitVersion);
},
/**
* Private helper to get the blocklist entry for a plugin given a set of
* blocklist entries and versions.
*
* @param {nsIPluginTag} plugin
* The nsIPluginTag to get the blocklist state for.
* @param {object[]} pluginEntries
* The plugin blocklist entries to compare against.
* @param {string?} appVersion
* The application version to compare to, will use the current
* version if null.
* @param {string?} toolkitVersion
* The toolkit version to compare to, will use the current version if
* null.
* @returns {object?}
* {entry: blocklistEntry, version: blocklistEntryVersion},
* or null if there is no matching entry.
*/
_getEntry(plugin, pluginEntries, appVersion, toolkitVersion) {
if (!gBlocklistEnabled) {
return null;
}
// Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
if (!appVersion && !gApp.version) {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
if (!appVersion) {
appVersion = gApp.version;
}
if (!toolkitVersion) {
toolkitVersion = gApp.platformVersion;
}
const pluginProperties = {
description: plugin.description,
filename: plugin.filename,
name: plugin.name,
version: plugin.version,
};
if (!pluginEntries) {
Cu.reportError(
new Error("There are no plugin entries. This should never happen.")
);
}
for (let blockEntry of pluginEntries) {
var matchFailed = false;
for (var name in blockEntry.matches) {
let pluginProperty = pluginProperties[name];
if (
typeof pluginProperty != "string" ||
!blockEntry.matches[name].test(pluginProperty)
) {
matchFailed = true;
break;
}
}
if (matchFailed) {
continue;
}
for (let versionRange of blockEntry.versionRange) {
if (
Utils.versionsMatch(
versionRange,
pluginProperties.version,
appVersion,
toolkitVersion
)
) {
return { entry: blockEntry, version: versionRange };
}
}
}
return null;
},
/**
* Private version of getState that allows the caller to pass in
* the plugin blocklist entries.
*
* @param {nsIPluginTag} plugin
* The nsIPluginTag to get the blocklist state for.
* @param {object[]} pluginEntries
* The plugin blocklist entries to compare against.
* @param {string?} appVersion
* The application version to compare to, will use the current
* version if null.
* @param {string?} toolkitVersion
* The toolkit version to compare to, will use the current version if
* null.
* @returns {integer}
* The blocklist state for the item, one of the STATE constants as
* defined in nsIBlocklistService.
*/
_getState(plugin, pluginEntries, appVersion, toolkitVersion) {
let r = this._getEntry(plugin, pluginEntries, appVersion, toolkitVersion);
if (!r) {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
let { version: versionRange } = r;
if (versionRange.severity >= gBlocklistLevel) {
return Ci.nsIBlocklistService.STATE_BLOCKED;
}
if (versionRange.severity == SEVERITY_OUTDATED) {
let vulnerabilityStatus = versionRange.vulnerabilityStatus;
if (vulnerabilityStatus == VULNERABILITYSTATUS_UPDATE_AVAILABLE) {
return Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE;
}
if (vulnerabilityStatus == VULNERABILITYSTATUS_NO_UPDATE) {
return Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE;
}
return Ci.nsIBlocklistService.STATE_OUTDATED;
}
return Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
},
};
/**
* The extensions blocklist implementation. The JSON objects for extension
* blocks look something like:
@ -1772,24 +1329,11 @@ let Blocklist = {
this._chooseExtensionBlocklistImplementationFromPref();
Services.prefs.addObserver("extensions.blocklist.", this);
Services.prefs.addObserver(PREF_EM_LOGGING_ENABLED, this);
// If the stub blocklist service deferred any queries because we
// weren't loaded yet, execute them now.
for (let entry of Services.blocklist.pluginQueries.splice(0)) {
entry.resolve(
this.getPluginBlocklistState(
entry.plugin,
entry.appVersion,
entry.toolkitVersion
)
);
}
},
isLoaded: true,
shutdown() {
GfxBlocklistRS.shutdown();
PluginBlocklistRS.shutdown();
this.ExtensionBlocklist.shutdown();
Services.obs.removeObserver(this, "xpcom-shutdown");
@ -1858,15 +1402,6 @@ let Blocklist = {
// Need to ensure we notify gfx of new stuff.
GfxBlocklistRS.checkForEntries();
this.ExtensionBlocklist.ensureInitialized();
PluginBlocklistRS.ensureInitialized();
},
getPluginBlocklistState(plugin, appVersion, toolkitVersion) {
return PluginBlocklistRS.getState(plugin, appVersion, toolkitVersion);
},
getPluginBlockURL(plugin) {
return PluginBlocklistRS.getURL(plugin);
},
getAddonBlocklistState(addon, appVersion, toolkitVersion) {
@ -1891,7 +1426,6 @@ let Blocklist = {
_blocklistUpdated() {
this.ExtensionBlocklist._onUpdate();
PluginBlocklistRS._onUpdate();
},
};

Просмотреть файл

@ -10,12 +10,6 @@
"use strict";
ChromeUtils.defineModuleGetter(
this,
"AppConstants",
"resource://gre/modules/AppConstants.jsm"
);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
@ -351,44 +345,17 @@ ChromeUtils.defineModuleGetter(this, "Blocklist", BLOCKLIST_JSM);
function BlocklistService() {
this.wrappedJSObject = this;
this.pluginQueries = [];
}
BlocklistService.prototype = {
STATE_NOT_BLOCKED: Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
STATE_SOFTBLOCKED: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
STATE_BLOCKED: Ci.nsIBlocklistService.STATE_BLOCKED,
STATE_OUTDATED: Ci.nsIBlocklistService.STATE_OUTDATED,
STATE_VULNERABLE_UPDATE_AVAILABLE:
Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE,
STATE_VULNERABLE_NO_UPDATE: Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE,
get isLoaded() {
return Cu.isModuleLoaded(BLOCKLIST_JSM) && Blocklist.isLoaded;
},
async getPluginBlocklistState(plugin, appVersion, toolkitVersion) {
if (AppConstants.platform == "android") {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
}
if (Cu.isModuleLoaded(BLOCKLIST_JSM)) {
return Blocklist.getPluginBlocklistState(
plugin,
appVersion,
toolkitVersion
);
}
// Blocklist module isn't loaded yet. Queue the query until it is.
let request = { plugin, appVersion, toolkitVersion };
let promise = new Promise(resolve => {
request.resolve = resolve;
});
this.pluginQueries.push(request);
return promise;
},
observe(...args) {
return Blocklist.observe(...args);
},

Просмотреть файл

@ -280,13 +280,7 @@ function isInState(install, state) {
async function getAddonMessageInfo(addon) {
const { name } = addon;
const appName = brandBundle.GetStringFromName("brandShortName");
const {
STATE_BLOCKED,
STATE_OUTDATED,
STATE_SOFTBLOCKED,
STATE_VULNERABLE_UPDATE_AVAILABLE,
STATE_VULNERABLE_NO_UPDATE,
} = Ci.nsIBlocklistService;
const { STATE_BLOCKED, STATE_SOFTBLOCKED } = Ci.nsIBlocklistService;
const formatString = (name, args) =>
extBundle.formatStringFromName(
@ -338,27 +332,6 @@ async function getAddonMessageInfo(addon) {
message: formatString("softblocked", [name]),
type: "warning",
};
} else if (addon.blocklistState === STATE_OUTDATED) {
return {
linkText: getString("outdated.link"),
linkUrl: await addon.getBlocklistURL(),
message: formatString("outdated", [name]),
type: "warning",
};
} else if (addon.blocklistState === STATE_VULNERABLE_UPDATE_AVAILABLE) {
return {
linkText: getString("vulnerableUpdatable.link"),
linkUrl: await addon.getBlocklistURL(),
message: formatString("vulnerableUpdatable", [name]),
type: "error",
};
} else if (addon.blocklistState === STATE_VULNERABLE_NO_UPDATE) {
return {
linkText: getString("vulnerableNoUpdate.link"),
linkUrl: await addon.getBlocklistURL(),
message: formatString("vulnerableNoUpdate", [name]),
type: "error",
};
} else if (addon.isGMPlugin && !addon.isInstalled && addon.isActive) {
return {
message: formatString("gmpPending", [name]),
@ -2225,11 +2198,7 @@ class PluginOptions extends AddonOptions {
if (action in userDisabledStates) {
let userDisabled = userDisabledStates[action];
el.checked = addon.userDisabled === userDisabled;
let resultProp =
action == "always-activate" && addon.isFlashPlugin
? "hidden"
: "disabled";
el[resultProp] = !(el.checked || hasPermission(addon, action));
el.disabled = !(el.checked || hasPermission(addon, action));
} else {
super.setElementState(el, card, addon);
}

Просмотреть файл

@ -1,119 +0,0 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* 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/. */
"use strict";
/* exported init, finish */
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var gArgs;
function init() {
var hasHardBlocks = false;
var hasSoftBlocks = false;
gArgs = window.arguments[0].wrappedJSObject;
document.addEventListener("dialogaccept", function() {
finish(true);
});
document.addEventListener("dialogcancel", function() {
finish(false);
});
// NOTE: We use strings from the "updates.properties" bundleset to change the
// text on the "Cancel" button to "Restart Later". (bug 523784)
let bundle = Services.strings.createBundle(
"chrome://mozapps/locale/update/updates.properties"
);
let cancelButton = document
.getElementById("BlocklistDialog")
.getButton("cancel");
cancelButton.setAttribute(
"label",
bundle.GetStringFromName("restartLaterButton")
);
cancelButton.setAttribute(
"accesskey",
bundle.GetStringFromName("restartLaterButton.accesskey")
);
var richlist = document.getElementById("addonList");
var list = gArgs.list;
list.sort((a, b) => String(a.name).localeCompare(b.name));
for (let listItem of list) {
let item = document.createXULElement("richlistitem");
const icon = document.createXULElement("image");
icon.src = listItem.icon;
const container = document.createXULElement("vbox");
container.flex = 1;
const nameVersion = document.createXULElement("hbox");
nameVersion.className = "addon-name-version";
const name = document.createXULElement("label");
name.className = "addonName";
name.value = listItem.name;
name.crop = "end";
const version = document.createXULElement("label");
version.value = listItem.version;
nameVersion.append(name, version);
const fragment = document.createXULElement("hbox");
fragment.setAttribute("pack", "end");
if (listItem.blocked) {
const label = document.createXULElement("label");
label.className = "blockedLabel";
label.setAttribute("data-l10n-id", "blocklist-blocked");
fragment.appendChild(label);
hasHardBlocks = true;
} else {
const checkbox = document.createXULElement("checkbox");
checkbox.className = "disableCheckbox";
checkbox.setAttribute("data-l10n-id", "blocklist-checkbox");
checkbox.checked = true;
fragment.appendChild(checkbox);
hasSoftBlocks = true;
}
container.append(nameVersion, fragment);
item.append(icon, container);
richlist.appendChild(item);
}
if (hasHardBlocks && hasSoftBlocks) {
document.getElementById("bothMessage").hidden = false;
} else if (hasHardBlocks) {
document.getElementById("hardBlockMessage").hidden = false;
} else {
document.getElementById("softBlockMessage").hidden = false;
}
var link = document.getElementById("moreInfo");
if (list.length == 1 && list[0].url) {
link.setAttribute("href", list[0].url);
} else {
var url = Services.urlFormatter.formatURLPref(
"extensions.blocklist.detailsURL"
);
link.setAttribute("href", url);
}
}
function finish(shouldRestartNow) {
gArgs.restart = shouldRestartNow;
var list = gArgs.list;
var items = document.getElementById("addonList").childNodes;
for (let i = 0; i < list.length; i++) {
if (!list[i].blocked) {
list[i].disable = items[i].querySelector(".disableCheckbox").checked;
}
}
}

Просмотреть файл

@ -1,51 +0,0 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://mozapps/skin/extensions/blocklist.css"?>
<!DOCTYPE window>
<window windowtype="Addons:Blocklist"
data-l10n-id="blocklist-window"
data-l10n-attrs="title,style"
align="stretch"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
onload="init();"
>
<dialog id="BlocklistDialog"
buttons="accept,cancel"
buttonidaccept="blocklist-accept">
<linkset>
<html:link rel="localization" href="branding/brand.ftl"/>
<html:link rel="localization" href="toolkit/extensions/blocklist.ftl"/>
</linkset>
<script src="chrome://global/content/globalOverlay.js"/>
<script src="chrome://mozapps/content/extensions/blocklist.js"/>
<hbox align="stretch" flex="1">
<vbox pack="start">
<image class="error-icon"/>
</vbox>
<vbox flex="1">
<label data-l10n-id="blocklist-label-summary" />
<separator class="thin"/>
<richlistbox id="addonList" flex="1" style="-moz-user-focus: none;"/>
<separator class="thin"/>
<description id="bothMessage" class="bold" hidden="true" data-l10n-id="blocklist-soft-and-hard"/>
<description id="hardBlockMessage" class="bold" hidden="true" data-l10n-id="blocklist-hard-blocked"/>
<description id="softBlockMessage" class="bold" hidden="true" data-l10n-id="blocklist-soft-blocked"/>
<hbox pack="start">
<label id="moreInfo" data-l10n-attrs="blocklist-more-information" is="text-link"/>
</hbox>
</vbox>
</hbox>
</dialog>
</window>

Просмотреть файл

@ -3,7 +3,6 @@ category update-timer addonManager @mozilla.org/addons/integration;1,getService,
#endif
#ifndef MOZ_THUNDERBIRD
#ifndef MOZ_WIDGET_ANDROID
category addon-provider-module PluginProvider resource://gre/modules/addons/PluginProvider.jsm
category addon-provider-module GMPProvider resource://gre/modules/addons/GMPProvider.jsm
#endif
#endif

Просмотреть файл

@ -1,533 +0,0 @@
/* 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/. */
"use strict";
/* exported logger */
var EXPORTED_SYMBOLS = [];
const { AddonManager, AddonManagerPrivate } = ChromeUtils.import(
"resource://gre/modules/AddonManager.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(
this,
"Blocklist",
"resource://gre/modules/Blocklist.jsm"
);
const URI_EXTENSION_STRINGS =
"chrome://mozapps/locale/extensions/extensions.properties";
const LIST_UPDATED_TOPIC = "plugins-list-updated";
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
const LOGGER_ID = "addons.plugins";
// Create a new logger for use by the Addons Plugin Provider
// (Requires AddonManager.jsm)
var logger = Log.repository.getLogger(LOGGER_ID);
var PluginProvider = {
get name() {
return "PluginProvider";
},
// A dictionary mapping IDs to names and descriptions
plugins: null,
startup() {
Services.obs.addObserver(this, LIST_UPDATED_TOPIC);
},
/**
* Called when the application is shutting down. Only necessary for tests
* to be able to simulate a shutdown.
*/
shutdown() {
this.plugins = null;
Services.obs.removeObserver(this, LIST_UPDATED_TOPIC);
},
async observe(aSubject, aTopic, aData) {
switch (aTopic) {
case LIST_UPDATED_TOPIC:
if (this.plugins) {
this.updatePluginList();
}
break;
}
},
/**
* Creates a PluginWrapper for a plugin object.
*/
buildWrapper(aPlugin) {
return new PluginWrapper(
aPlugin.id,
aPlugin.name,
aPlugin.description,
aPlugin.tags
);
},
/**
* Called to get an Addon with a particular ID.
*
* @param aId
* The ID of the add-on to retrieve
*/
async getAddonByID(aId) {
if (!this.plugins) {
this.buildPluginList();
}
if (aId in this.plugins) {
return this.buildWrapper(this.plugins[aId]);
}
return null;
},
/**
* Called to get Addons of a particular type.
*
* @param aTypes
* An array of types to fetch. Can be null to get all types.
*/
async getAddonsByTypes(aTypes) {
if (aTypes && !aTypes.includes("plugin")) {
return [];
}
if (!this.plugins) {
this.buildPluginList();
}
return Promise.all(
Object.keys(this.plugins).map(id => this.getAddonByID(id))
);
},
/**
* Called to get the current AddonInstalls, optionally restricting by type.
*
* @param aTypes
* An array of types or null to get all types
*/
getInstallsByTypes(aTypes) {
return [];
},
/**
* Builds a list of the current plugins reported by the plugin host
*
* @return a dictionary of plugins indexed by our generated ID
*/
getPluginList() {
let tags = Cc["@mozilla.org/plugin/host;1"]
.getService(Ci.nsIPluginHost)
.getPluginTags();
let list = {};
let seenPlugins = {};
for (let tag of tags) {
if (!(tag.name in seenPlugins)) {
seenPlugins[tag.name] = {};
}
if (!(tag.description in seenPlugins[tag.name])) {
let plugin = {
id: tag.name + tag.description,
name: tag.name,
description: tag.description,
tags: [tag],
};
seenPlugins[tag.name][tag.description] = plugin;
list[plugin.id] = plugin;
} else {
seenPlugins[tag.name][tag.description].tags.push(tag);
}
}
return list;
},
/**
* Builds the list of known plugins from the plugin host
*/
buildPluginList() {
this.plugins = this.getPluginList();
},
/**
* Updates the plugins from the plugin host by comparing the current plugins
* to the last known list sending out any necessary API notifications for
* changes.
*/
updatePluginList() {
let newList = this.getPluginList();
let lostPlugins = Object.keys(this.plugins)
.filter(id => !(id in newList))
.map(id => this.buildWrapper(this.plugins[id]));
let newPlugins = Object.keys(newList)
.filter(id => !(id in this.plugins))
.map(id => this.buildWrapper(newList[id]));
let matchedIDs = Object.keys(newList).filter(id => id in this.plugins);
// The plugin host generates new tags for every plugin after a scan and
// if the plugin's filename has changed then the disabled state won't have
// been carried across, send out notifications for anything that has
// changed (see bug 830267).
let changedWrappers = [];
for (let id of matchedIDs) {
let oldWrapper = this.buildWrapper(this.plugins[id]);
let newWrapper = this.buildWrapper(newList[id]);
if (newWrapper.isActive != oldWrapper.isActive) {
AddonManagerPrivate.callAddonListeners(
newWrapper.isActive ? "onEnabling" : "onDisabling",
newWrapper,
false
);
changedWrappers.push(newWrapper);
}
}
// Notify about new installs
for (let plugin of newPlugins) {
AddonManagerPrivate.callInstallListeners(
"onExternalInstall",
null,
plugin,
null,
false
);
AddonManagerPrivate.callAddonListeners("onInstalling", plugin, false);
}
// Notify for any plugins that have vanished.
for (let plugin of lostPlugins) {
AddonManagerPrivate.callAddonListeners("onUninstalling", plugin, false);
}
this.plugins = newList;
// Signal that new installs are complete
for (let plugin of newPlugins) {
AddonManagerPrivate.callAddonListeners("onInstalled", plugin);
}
// Signal that enables/disables are complete
for (let wrapper of changedWrappers) {
AddonManagerPrivate.callAddonListeners(
wrapper.isActive ? "onEnabled" : "onDisabled",
wrapper
);
}
// Signal that uninstalls are complete
for (let plugin of lostPlugins) {
AddonManagerPrivate.callAddonListeners("onUninstalled", plugin);
}
},
};
const wrapperMap = new WeakMap();
let pluginFor = wrapper => wrapperMap.get(wrapper);
/**
* The PluginWrapper wraps a set of nsIPluginTags to provide the data visible to
* public callers through the API.
*/
function PluginWrapper(id, name, description, tags) {
wrapperMap.set(this, { id, name, description, tags });
}
PluginWrapper.prototype = {
get id() {
return pluginFor(this).id;
},
get type() {
return "plugin";
},
get name() {
return pluginFor(this).name;
},
get creator() {
return null;
},
get description() {
return pluginFor(this).description.replace(/<\/?[a-z][^>]*>/gi, " ");
},
get version() {
let {
tags: [tag],
} = pluginFor(this);
return tag.version;
},
get homepageURL() {
let { description } = pluginFor(this);
if (/<A\s+HREF=[^>]*>/i.test(description)) {
return /<A\s+HREF=["']?([^>"'\s]*)/i.exec(description)[1];
}
return null;
},
get isActive() {
let {
tags: [tag],
} = pluginFor(this);
return !tag.blocklisted && !tag.disabled;
},
get appDisabled() {
let {
tags: [tag],
} = pluginFor(this);
return tag.blocklisted;
},
get userDisabled() {
let {
tags: [tag],
} = pluginFor(this);
if (tag.disabled) {
return true;
}
if (
tag.clicktoplay ||
this.blocklistState ==
Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE ||
this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE
) {
return AddonManager.STATE_ASK_TO_ACTIVATE;
}
return false;
},
set userDisabled(val) {
let previousVal = this.userDisabled;
if (val === false && this.isFlashPlugin) {
val = AddonManager.STATE_ASK_TO_ACTIVATE;
}
if (val === previousVal) {
return;
}
let { tags } = pluginFor(this);
for (let tag of tags) {
if (val === true) {
tag.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
} else if (val === false) {
tag.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
} else if (val == AddonManager.STATE_ASK_TO_ACTIVATE) {
tag.enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
}
}
// If 'userDisabled' was 'true' and we're going to a state that's not
// that, we're enabling, so call those listeners.
if (previousVal === true && val !== true) {
AddonManagerPrivate.callAddonListeners("onEnabling", this, false);
AddonManagerPrivate.callAddonListeners("onEnabled", this);
}
// If 'userDisabled' was not 'true' and we're going to a state where
// it is, we're disabling, so call those listeners.
if (previousVal !== true && val === true) {
AddonManagerPrivate.callAddonListeners("onDisabling", this, false);
AddonManagerPrivate.callAddonListeners("onDisabled", this);
}
// If the 'userDisabled' value involved AddonManager.STATE_ASK_TO_ACTIVATE,
// call the onPropertyChanged listeners.
if (
previousVal == AddonManager.STATE_ASK_TO_ACTIVATE ||
val == AddonManager.STATE_ASK_TO_ACTIVATE
) {
AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, [
"userDisabled",
]);
}
},
async enable() {
this.userDisabled = false;
},
async disable() {
this.userDisabled = true;
},
get blocklistState() {
let {
tags: [tag],
} = pluginFor(this);
return tag.blocklistState;
},
async getBlocklistURL() {
let {
tags: [tag],
} = pluginFor(this);
return Blocklist.getPluginBlockURL(tag);
},
get pluginLibraries() {
let libs = [];
for (let tag of pluginFor(this).tags) {
libs.push(tag.filename);
}
return libs;
},
get pluginFullpath() {
let paths = [];
for (let tag of pluginFor(this).tags) {
paths.push(tag.fullpath);
}
return paths;
},
get pluginMimeTypes() {
let types = [];
for (let tag of pluginFor(this).tags) {
let mimeTypes = tag.getMimeTypes();
let mimeDescriptions = tag.getMimeDescriptions();
let extensions = tag.getExtensions();
for (let i = 0; i < mimeTypes.length; i++) {
let type = {};
type.type = mimeTypes[i];
type.description = mimeDescriptions[i];
type.suffixes = extensions[i];
types.push(type);
}
}
return types;
},
get installDate() {
let date = 0;
for (let tag of pluginFor(this).tags) {
date = Math.max(date, tag.lastModifiedTime);
}
return new Date(date);
},
get scope() {
let {
tags: [tag],
} = pluginFor(this);
let path = tag.fullpath;
// Plugins inside the profile directory are in the profile scope
let dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
if (path.startsWith(dir.path)) {
return AddonManager.SCOPE_PROFILE;
}
// Plugins anywhere else in the user's home are in the user scope,
// but not all platforms have a home directory.
try {
dir = Services.dirsvc.get("Home", Ci.nsIFile);
if (path.startsWith(dir.path)) {
return AddonManager.SCOPE_USER;
}
} catch (e) {
if (!e.result || e.result != Cr.NS_ERROR_FAILURE) {
throw e;
}
// Do nothing: missing "Home".
}
// Any other locations are system scope
return AddonManager.SCOPE_SYSTEM;
},
get pendingOperations() {
return AddonManager.PENDING_NONE;
},
get operationsRequiringRestart() {
return AddonManager.OP_NEEDS_RESTART_NONE;
},
get permissions() {
return 0;
},
get optionsType() {
return null;
},
get optionsURL() {
return null;
},
get updateDate() {
return this.installDate;
},
get isCompatible() {
return true;
},
get isPlatformCompatible() {
return true;
},
get providesUpdatesSecurely() {
return true;
},
get foreignInstall() {
return true;
},
get installTelemetryInfo() {
return { source: "plugin" };
},
isCompatibleWith(aAppVersion, aPlatformVersion) {
return true;
},
findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
if ("onNoCompatibilityUpdateAvailable" in aListener) {
aListener.onNoCompatibilityUpdateAvailable(this);
}
if ("onNoUpdateAvailable" in aListener) {
aListener.onNoUpdateAvailable(this);
}
if ("onUpdateFinished" in aListener) {
aListener.onUpdateFinished(this);
}
},
get isFlashPlugin() {
return pluginFor(this).tags.some(t => t.isFlashPlugin);
},
};
AddonManagerPrivate.registerProvider(PluginProvider, [
new AddonManagerPrivate.AddonType(
"plugin",
URI_EXTENSION_STRINGS,
"type.plugin.name",
AddonManager.VIEW_TYPE_LIST,
6000,
AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE
),
]);

Просмотреть файл

@ -18,7 +18,6 @@ EXTRA_JS_MODULES.addons += [
if CONFIG["MOZ_WIDGET_TOOLKIT"] != "android":
EXTRA_JS_MODULES.addons += [
"GMPProvider.jsm",
"PluginProvider.jsm",
]
TESTING_JS_MODULES += [

Просмотреть файл

@ -14,8 +14,6 @@ toolkit.jar:
content/mozapps/extensions/abuse-report-frame.html (content/abuse-report-frame.html)
content/mozapps/extensions/abuse-report-panel.css (content/abuse-report-panel.css)
content/mozapps/extensions/abuse-report-panel.js (content/abuse-report-panel.js)
content/mozapps/extensions/blocklist.xhtml (content/blocklist.xhtml)
content/mozapps/extensions/blocklist.js (content/blocklist.js)
content/mozapps/extensions/default-theme.svg (content/default-theme.svg)
content/mozapps/extensions/drag-drop-addon-installer.js (content/drag-drop-addon-installer.js)
content/mozapps/extensions/firefox-compact-dark.svg (content/firefox-compact-dark.svg)

Просмотреть файл

@ -1,20 +0,0 @@
/* 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/. */
richlistitem {
padding-top: 6px;
padding-bottom: 6px;
padding-inline-start: 7px;
padding-inline-end: 7px;
border-bottom: 1px solid #C0C0C0;
}
.addon-name-version {
font-size: 110%;
}
.blockedLabel {
font-weight: bold;
font-style: italic;
}

Просмотреть файл

@ -5,7 +5,6 @@
toolkit.jar:
#include ../../shared/mozapps.inc.mn
skin/classic/mozapps/downloads/unknownContentType.css (downloads/unknownContentType.css)
skin/classic/mozapps/extensions/blocklist.css (extensions/blocklist.css)
skin/classic/mozapps/profile/profileSelection.css (profile/profileSelection.css)
skin/classic/mozapps/update/updates.css (update/updates.css)
skin/classic/mozapps/handling/handling.css (handling/handling.css)

Просмотреть файл

@ -22,7 +22,6 @@
skin/classic/global/icons/search-textbox.svg (../../windows/global/icons/search-textbox.svg)
skin/classic/mozapps/downloads/unknownContentType.css (../../windows/mozapps/downloads/unknownContentType.css)
skin/classic/mozapps/extensions/blocklist.css (../../windows/mozapps/extensions/blocklist.css)
skin/classic/mozapps/handling/handling.css (../../windows/mozapps/handling/handling.css)
skin/classic/mozapps/profile/profileSelection.css (../../windows/mozapps/profile/profileSelection.css)

Просмотреть файл

@ -1,20 +0,0 @@
/* 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/. */
richlistitem {
padding-top: 6px;
padding-bottom: 6px;
padding-inline-start: 7px;
padding-inline-end: 7px;
border-bottom: 1px solid #C0C0C0;
}
.addonName {
font-weight: bold;
}
.blockedLabel {
font-weight: bold;
font-style: italic;
}

Просмотреть файл

@ -153,7 +153,6 @@
"passwords.jsm": ["Password", "DumpPasswords"],
"PdfJsNetwork.jsm": ["NetworkManager"],
"PhoneNumberMetaData.jsm": ["PHONE_NUMBER_META_DATA"],
"PluginProvider.jsm": [],
"PointerAdapter.jsm": ["PointerRelay", "PointerAdapter"],
"policies.js": ["ErrorHandler", "SyncScheduler"],
"PreferenceExperiments.jsm": ["PreferenceExperiments", "migrateStorage"],

Просмотреть файл

@ -6,9 +6,6 @@
#include "nsISupports.idl"
interface nsIPluginTag;
interface nsIVariant;
[scriptable, uuid(a6dcc76e-9f62-4cc1-a470-b483a1a6f096)]
interface nsIBlocklistService : nsISupports
{
@ -19,34 +16,9 @@ interface nsIBlocklistService : nsISupports
const unsigned long STATE_SOFTBLOCKED = 1;
// Indicates that the item should be blocked and never used.
const unsigned long STATE_BLOCKED = 2;
// Indicates that the item is considered outdated, and there is a known
// update available.
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;
// Unused; Please increment if we add more blocklist states.
const unsigned long STATE_MAX = 6;
/**
* Determine the blocklist state of a plugin
* @param plugin
* The plugin to get the state for
* @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 Promise that resolves to the STATE constant.
*/
Promise getPluginBlocklistState(in nsIPluginTag plugin,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
const unsigned long STATE_MAX = 3;
readonly attribute boolean isLoaded;
};