зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
bba6d38dfb
Коммит
0e34d4d48b
|
@ -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;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче