diff options
author | Matt A. Tobin <email@mattatobin.com> | 2022-04-21 19:47:49 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2022-04-21 19:47:49 -0500 |
commit | 465f4eb3a68ef3fdd894dafc4a6b9ce7fd7ccf8c (patch) | |
tree | f897ef4b086d31539c914a1d9b35d7cfe82a8cd2 /components | |
parent | 13d6ff7e3399952875e7ff7673b2506e7e5f4026 (diff) | |
download | aura-central-465f4eb3a68ef3fdd894dafc4a6b9ce7fd7ccf8c.tar.gz |
Issue #25 - Part 18: Remove GMP (or nearly all of it)
I had planned to ifdef GMP but the infection is so deep that I couldn't do discrete parts and have it stay building.
Diffstat (limited to 'components')
-rw-r--r-- | components/addons/content/extensions.js | 21 | ||||
-rw-r--r-- | components/addons/content/extensions.xml | 6 | ||||
-rw-r--r-- | components/addons/content/gmpPrefs.xul | 8 | ||||
-rw-r--r-- | components/addons/extensions.manifest | 1 | ||||
-rw-r--r-- | components/addons/jar.mn | 1 | ||||
-rw-r--r-- | components/addons/locale/extensions.properties | 4 | ||||
-rw-r--r-- | components/addons/moz.build | 8 | ||||
-rw-r--r-- | components/addons/src/GMPInstallManager.jsm | 917 | ||||
-rw-r--r-- | components/addons/src/GMPProvider.jsm | 605 | ||||
-rw-r--r-- | components/addons/src/GMPUtils.jsm | 187 | ||||
-rw-r--r-- | components/addons/src/ProductAddonChecker.jsm | 464 | ||||
-rw-r--r-- | components/global/content/process-content.js | 7 |
12 files changed, 3 insertions, 2226 deletions
diff --git a/components/addons/content/extensions.js b/components/addons/content/extensions.js index fe84bc460..f65fb4573 100644 --- a/components/addons/content/extensions.js +++ b/components/addons/content/extensions.js @@ -1013,9 +1013,7 @@ var gViewController = { cmd_showItemPreferences: { isEnabled: function cmd_showItemPreferences_isEnabled(aAddon) { - if (!aAddon || - (!aAddon.isActive && !aAddon.isGMPlugin) || - !aAddon.optionsURL) { + if (!aAddon || (!aAddon.isActive) || !aAddon.optionsURL) { return false; } if (gViewController.currentViewObj == gDetailView && @@ -2753,15 +2751,7 @@ var gDetailView = { var fullDesc = document.getElementById("detail-fulldesc"); if (aAddon.fullDescription) { - // The following is part of an awful hack to include the licenses for GMP - // plugins without having bug 624602 fixed yet, and intentionally ignores - // localisation. - if (aAddon.isGMPlugin) { - fullDesc.innerHTML = aAddon.fullDescription; - } else { - fullDesc.textContent = aAddon.fullDescription; - } - + fullDesc.textContent = aAddon.fullDescription; fullDesc.hidden = false; } else { fullDesc.hidden = true; @@ -3036,13 +3026,6 @@ var gDetailView = { errorLink.value = gStrings.ext.GetStringFromName("details.notification.vulnerableNoUpdate.link"); errorLink.href = this._addon.blocklistURL; errorLink.hidden = false; - } else if (this._addon.isGMPlugin && !this._addon.isInstalled && - this._addon.isActive) { - this.node.setAttribute("notification", "warning"); - let warning = document.getElementById("detail-warning"); - warning.textContent = - gStrings.ext.formatStringFromName("details.notification.gmpPending", - [this._addon.name], 1); } else { this.node.removeAttribute("notification"); } diff --git a/components/addons/content/extensions.xml b/components/addons/content/extensions.xml index f862b0f7e..9ea6a50df 100644 --- a/components/addons/content/extensions.xml +++ b/components/addons/content/extensions.xml @@ -1328,12 +1328,6 @@ this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableNoUpdate.link"); this._errorLink.href = this.mAddon.blocklistURL; this._errorLink.hidden = false; - } else if (this.mAddon.isGMPlugin && !this.mAddon.isInstalled && - this.mAddon.isActive) { - this.setAttribute("notification", "warning"); - this._warning.textContent = - gStrings.ext.formatStringFromName("notification.gmpPending", - [this.mAddon.name], 1); } else { this.removeAttribute("notification"); } diff --git a/components/addons/content/gmpPrefs.xul b/components/addons/content/gmpPrefs.xul deleted file mode 100644 index ea7ee92fa..000000000 --- a/components/addons/content/gmpPrefs.xul +++ /dev/null @@ -1,8 +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/. --> - -<!-- This is intentionally empty and a dummy to let the GMPProvider - have a preferences button in the list view. --> diff --git a/components/addons/extensions.manifest b/components/addons/extensions.manifest index b56152e10..35d605575 100644 --- a/components/addons/extensions.manifest +++ b/components/addons/extensions.manifest @@ -13,4 +13,3 @@ contract @mozilla.org/addons/installtrigger;1 {9df8ef2b-94da-45c9-ab9f-132eb55fd category JavaScript-global-property InstallTrigger @mozilla.org/addons/installtrigger;1 category addon-provider-module PluginProvider resource://gre/modules/addons/PluginProvider.jsm -category addon-provider-module GMPProvider resource://gre/modules/addons/GMPProvider.jsm diff --git a/components/addons/jar.mn b/components/addons/jar.mn index 878be4df1..c674f8f83 100644 --- a/components/addons/jar.mn +++ b/components/addons/jar.mn @@ -29,7 +29,6 @@ toolkit.jar: content/mozapps/extensions/newaddon.js (content/newaddon.js) content/mozapps/extensions/setting.xml (content/setting.xml) content/mozapps/extensions/pluginPrefs.xul (content/pluginPrefs.xul) - content/mozapps/extensions/gmpPrefs.xul (content/gmpPrefs.xul) content/mozapps/extensions/OpenH264-license.txt (content/OpenH264-license.txt) content/mozapps/xpinstall/xpinstallConfirm.xul (content/xpinstallConfirm.xul) content/mozapps/xpinstall/xpinstallConfirm.js (content/xpinstallConfirm.js) diff --git a/components/addons/locale/extensions.properties b/components/addons/locale/extensions.properties index c5de4f0c0..43ab02a47 100644 --- a/components/addons/locale/extensions.properties +++ b/components/addons/locale/extensions.properties @@ -57,8 +57,6 @@ notification.downloadError.retry.tooltip=Try downloading this add-on again notification.installError=There was an error installing %1$S. notification.installError.retry=Try again notification.installError.retry.tooltip=Try downloading and installing this add-on again -#LOCALIZATION NOTE (notification.gmpPending) %1$S is the add-on name. -notification.gmpPending=%1$S will be installed shortly. #LOCALIZATION NOTE (contributionAmount2) %S is the currency amount recommended for contributions contributionAmount2=Suggested Contribution: %S @@ -100,8 +98,6 @@ details.notification.install=%1$S will be installed after you restart %2$S. details.notification.uninstall=%1$S will be uninstalled after you restart %2$S. #LOCALIZATION NOTE (details.notification.upgrade) %1$S is the add-on name, %2$S is brand name details.notification.upgrade=%1$S will be updated after you restart %2$S. -#LOCALIZATION NOTE (details.notification.gmpPending) %1$S is the add-on name -details.notification.gmpPending=%1$S will be installed shortly. installFromFile.dialogTitle=Select add-on to install installFromFile.filterName=Add-ons diff --git a/components/addons/moz.build b/components/addons/moz.build index 6b1e2fe93..f3e953c46 100644 --- a/components/addons/moz.build +++ b/components/addons/moz.build @@ -37,21 +37,15 @@ EXTRA_JS_MODULES += [ 'src/LightweightThemeManager.jsm', ] -EXTRA_PP_JS_MODULES += [ - 'src/AddonManager.jsm', - 'src/GMPInstallManager.jsm', - 'src/GMPUtils.jsm', -] +EXTRA_PP_JS_MODULES += ['src/AddonManager.jsm'] EXTRA_JS_MODULES.addons += [ 'src/AddonLogging.jsm', 'src/AddonRepository.jsm', 'src/AddonRepository_SQLiteMigrator.jsm', 'src/Content.js', - 'src/GMPProvider.jsm', 'src/LightweightThemeImageOptimizer.jsm', 'src/PluginProvider.jsm', - 'src/ProductAddonChecker.jsm', 'src/SpellCheckDictionaryBootstrap.js', ] diff --git a/components/addons/src/GMPInstallManager.jsm b/components/addons/src/GMPInstallManager.jsm deleted file mode 100644 index fe4e2de10..000000000 --- a/components/addons/src/GMPInstallManager.jsm +++ /dev/null @@ -1,917 +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"; - -this.EXPORTED_SYMBOLS = []; - -const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = - Components; -// Chunk size for the incremental downloader -const DOWNLOAD_CHUNK_BYTES_SIZE = 300000; -// Incremental downloader interval -const DOWNLOAD_INTERVAL = 0; -// 1 day default -const DEFAULT_SECONDS_BETWEEN_CHECKS = 60 * 60 * 24; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/ctypes.jsm"); -Cu.import("resource://gre/modules/GMPUtils.jsm"); - -this.EXPORTED_SYMBOLS = ["GMPInstallManager", "GMPExtractor", "GMPDownloader", - "GMPAddon"]; - -var gLocale = null; - -// Shared code for suppressing bad cert dialogs -XPCOMUtils.defineLazyGetter(this, "gCertUtils", function() { - let temp = { }; - Cu.import("resource://gre/modules/CertUtils.jsm", temp); - return temp; -}); - -XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", - "resource://gre/modules/UpdateUtils.jsm"); - -/** - * Number of milliseconds after which we need to cancel `checkForAddons`. - * - * Bug 1087674 suggests that the XHR we use in `checkForAddons` may - * never terminate in presence of network nuisances (e.g. strange - * antivirus behavior). This timeout is a defensive measure to ensure - * that we fail cleanly in such case. - */ -const CHECK_FOR_ADDONS_TIMEOUT_DELAY_MS = 20000; - -function getScopedLogger(prefix) { - // `PARENT_LOGGER_ID.` being passed here effectively links this logger - // to the parentLogger. - return Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP", prefix + " "); -} - -// This is copied directly from nsUpdateService.js -// It is used for calculating the URL string w/ var replacement. -// TODO: refactor this out somewhere else -XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() { - let osVersion; - let sysInfo = Cc["@mozilla.org/system-info;1"]. - getService(Ci.nsIPropertyBag2); - try { - osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); - } - catch (e) { - LOG("gOSVersion - OS Version unknown: updates are not possible."); - } - - if (osVersion) { -#ifdef XP_WIN - const BYTE = ctypes.uint8_t; - const WORD = ctypes.uint16_t; - const DWORD = ctypes.uint32_t; - const WCHAR = ctypes.char16_t; - const BOOL = ctypes.int; - - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx - const SZCSDVERSIONLENGTH = 128; - const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', - [ - {dwOSVersionInfoSize: DWORD}, - {dwMajorVersion: DWORD}, - {dwMinorVersion: DWORD}, - {dwBuildNumber: DWORD}, - {dwPlatformId: DWORD}, - {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, - {wServicePackMajor: WORD}, - {wServicePackMinor: WORD}, - {wSuiteMask: WORD}, - {wProductType: BYTE}, - {wReserved: BYTE} - ]); - - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx - const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', - [ - {wProcessorArchitecture: WORD}, - {wReserved: WORD}, - {dwPageSize: DWORD}, - {lpMinimumApplicationAddress: ctypes.voidptr_t}, - {lpMaximumApplicationAddress: ctypes.voidptr_t}, - {dwActiveProcessorMask: DWORD.ptr}, - {dwNumberOfProcessors: DWORD}, - {dwProcessorType: DWORD}, - {dwAllocationGranularity: DWORD}, - {wProcessorLevel: WORD}, - {wProcessorRevision: WORD} - ]); - - let kernel32 = false; - try { - kernel32 = ctypes.open("Kernel32"); - } catch (e) { - LOG("gOSVersion - Unable to open kernel32! " + e); - osVersion += ".unknown (unknown)"; - } - - if(kernel32) { - try { - // Get Service pack info - try { - let GetVersionEx = kernel32.declare("GetVersionExW", - ctypes.default_abi, - BOOL, - OSVERSIONINFOEXW.ptr); - let winVer = OSVERSIONINFOEXW(); - winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; - - if(0 !== GetVersionEx(winVer.address())) { - osVersion += "." + winVer.wServicePackMajor - + "." + winVer.wServicePackMinor; - } else { - LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); - osVersion += ".unknown"; - } - } catch (e) { - LOG("gOSVersion - error getting service pack information. Exception: " + e); - osVersion += ".unknown"; - } - - // Get processor architecture - let arch = "unknown"; - try { - let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", - ctypes.default_abi, - ctypes.void_t, - SYSTEM_INFO.ptr); - let sysInfo = SYSTEM_INFO(); - // Default to unknown - sysInfo.wProcessorArchitecture = 0xffff; - - GetNativeSystemInfo(sysInfo.address()); - switch(sysInfo.wProcessorArchitecture) { - case 9: - arch = "x64"; - break; - case 6: - arch = "IA64"; - break; - case 0: - arch = "x86"; - break; - } - } catch (e) { - LOG("gOSVersion - error getting processor architecture. Exception: " + e); - } finally { - osVersion += " (" + arch + ")"; - } - } finally { - kernel32.close(); - } - } -#endif - - try { - osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; - } - catch (e) { - // Not all platforms have a secondary widget library, so an error is nothing to worry about. - } - osVersion = encodeURIComponent(osVersion); - } - return osVersion; -}); - -/** - * Provides an easy API for downloading and installing GMP Addons - */ -function GMPInstallManager() { -} -/** - * Temp file name used for downloading - */ -GMPInstallManager.prototype = { - /** - * Obtains a URL with replacement of vars - */ - _getURL: function() { - let log = getScopedLogger("GMPInstallManager._getURL"); - // Use the override URL if it is specified. The override URL is just like - // the normal URL but it does not check the cert. - let url = GMPPrefs.get(GMPPrefs.KEY_URL_OVERRIDE); - if (url) { - log.info("Using override url: " + url); - } else { - url = GMPPrefs.get(GMPPrefs.KEY_URL); - log.info("Using url: " + url); - } - - url = UpdateUtils.formatUpdateURL(url); - log.info("Using url (with replacement): " + url); - return url; - }, - /** - * Performs an addon check. - * @return a promise which will be resolved or rejected. - * The promise is resolved with an array of GMPAddons - * The promise is rejected with an object with properties: - * target: The XHR request object - * status: The HTTP status code - * type: Sometimes specifies type of rejection - */ - checkForAddons: function() { - let log = getScopedLogger("GMPInstallManager.checkForAddons"); - if (this._deferred) { - log.error("checkForAddons already called"); - return Promise.reject({type: "alreadycalled"}); - } - this._deferred = Promise.defer(); - let url = this._getURL(); - - this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. - createInstance(Ci.nsISupports); - // This is here to let unit test code override XHR - if (this._request.wrappedJSObject) { - this._request = this._request.wrappedJSObject; - } - this._request.open("GET", url, true); - let allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, true); - this._request.channel.notificationCallbacks = - new gCertUtils.BadCertHandler(allowNonBuiltIn); - // Prevent the request from reading from the cache. - this._request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; - // Prevent the request from writing to the cache. - this._request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; - - this._request.overrideMimeType("text/xml"); - // The Cache-Control header is only interpreted by proxies and the - // final destination. It does not help if a resource is already - // cached locally. - this._request.setRequestHeader("Cache-Control", "no-cache"); - // HTTP/1.0 servers might not implement Cache-Control and - // might only implement Pragma: no-cache - this._request.setRequestHeader("Pragma", "no-cache"); - - this._request.timeout = CHECK_FOR_ADDONS_TIMEOUT_DELAY_MS; - this._request.addEventListener("error", event => this.onFailXML("onErrorXML", event), false); - this._request.addEventListener("abort", event => this.onFailXML("onAbortXML", event), false); - this._request.addEventListener("timeout", event => this.onFailXML("onTimeoutXML", event), false); - this._request.addEventListener("load", event => this.onLoadXML(event), false); - - log.info("sending request to: " + url); - this._request.send(null); - - return this._deferred.promise; - }, - /** - * Installs the specified addon and calls a callback when done. - * @param gmpAddon The GMPAddon object to install - * @return a promise which will be resolved or rejected - * The promise will resolve with an array of paths that were extracted - * The promise will reject with an error object: - * target: The XHR request object - * status: The HTTP status code - * type: A string to represent the type of error - * downloaderr, verifyerr or previouserrorencountered - */ - installAddon: function(gmpAddon) { - if (this._deferred) { - log.error("previous error encountered"); - return Promise.reject({type: "previouserrorencountered"}); - } - this.gmpDownloader = new GMPDownloader(gmpAddon); - return this.gmpDownloader.start(); - }, - _getTimeSinceLastCheck: function() { - let now = Math.round(Date.now() / 1000); - // Default to 0 here because `now - 0` will be returned later if that case - // is hit. We want a large value so a check will occur. - let lastCheck = GMPPrefs.get(GMPPrefs.KEY_UPDATE_LAST_CHECK, 0); - // Handle clock jumps, return now since we want it to represent - // a lot of time has passed since the last check. - if (now < lastCheck) { - return now; - } - return now - lastCheck; - }, - get _isEMEEnabled() { - return GMPPrefs.get(GMPPrefs.KEY_EME_ENABLED, true); - }, - _isAddonUpdateEnabled: function(aAddon) { - return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_ENABLED, true, aAddon) && - GMPPrefs.get(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, aAddon); - }, - _updateLastCheck: function() { - let now = Math.round(Date.now() / 1000); - GMPPrefs.set(GMPPrefs.KEY_UPDATE_LAST_CHECK, now); - }, - _versionchangeOccurred: function() { - let savedBuildID = GMPPrefs.get(GMPPrefs.KEY_BUILDID, null); - let buildID = Services.appinfo.platformBuildID; - if (savedBuildID == buildID) { - return false; - } - GMPPrefs.set(GMPPrefs.KEY_BUILDID, buildID); - return true; - }, - /** - * Wrapper for checkForAddons and installAddon. - * Will only install if not already installed and will log the results. - * This will only install/update the OpenH264 and EME plugins - * @return a promise which will be resolved if all addons could be installed - * successfully, rejected otherwise. - */ - simpleCheckAndInstall: Task.async(function*() { - let log = getScopedLogger("GMPInstallManager.simpleCheckAndInstall"); - - if (this._versionchangeOccurred()) { - log.info("A version change occurred. Ignoring " + - "media.gmp-manager.lastCheck to check immediately for " + - "new or updated GMPs."); - } else { - let secondsBetweenChecks = - GMPPrefs.get(GMPPrefs.KEY_SECONDS_BETWEEN_CHECKS, - DEFAULT_SECONDS_BETWEEN_CHECKS) - let secondsSinceLast = this._getTimeSinceLastCheck(); - log.info("Last check was: " + secondsSinceLast + - " seconds ago, minimum seconds: " + secondsBetweenChecks); - if (secondsBetweenChecks > secondsSinceLast) { - log.info("Will not check for updates."); - return {status: "too-frequent-no-check"}; - } - } - - try { - let gmpAddons = yield this.checkForAddons(); - this._updateLastCheck(); - log.info("Found " + gmpAddons.length + " addons advertised."); - let addonsToInstall = gmpAddons.filter(function(gmpAddon) { - log.info("Found addon: " + gmpAddon.toString()); - - if (!gmpAddon.isValid || GMPUtils.isPluginHidden(gmpAddon) || - gmpAddon.isInstalled) { - log.info("Addon invalid, hidden or already installed."); - return false; - } - - let addonUpdateEnabled = false; - if (GMP_PLUGIN_IDS.indexOf(gmpAddon.id) >= 0) { - addonUpdateEnabled = this._isAddonUpdateEnabled(gmpAddon.id); - if (!addonUpdateEnabled) { - log.info("Auto-update is off for " + gmpAddon.id + - ", skipping check."); - } - } else { - // Currently, we only support installs of OpenH264 and EME plugins. - log.info("Auto-update is off for unknown plugin '" + gmpAddon.id + - "', skipping check."); - } - - return addonUpdateEnabled; - }, this); - - if (!addonsToInstall.length) { - log.info("No new addons to install, returning"); - return {status: "nothing-new-to-install"}; - } - - let installResults = []; - let failureEncountered = false; - for (let addon of addonsToInstall) { - try { - yield this.installAddon(addon); - installResults.push({ - id: addon.id, - result: "succeeded", - }); - } catch (e) { - failureEncountered = true; - installResults.push({ - id: addon.id, - result: "failed", - }); - } - } - if (failureEncountered) { - throw {status: "failed", - results: installResults}; - } - return {status: "succeeded", - results: installResults}; - } catch(e) { - log.error("Could not check for addons", e); - throw e; - } - }), - - /** - * Makes sure everything is cleaned up - */ - uninit: function() { - let log = getScopedLogger("GMPInstallManager.uninit"); - if (this._request) { - log.info("Aborting request"); - this._request.abort(); - } - if (this._deferred) { - log.info("Rejecting deferred"); - this._deferred.reject({type: "uninitialized"}); - } - log.info("Done cleanup"); - }, - - /** - * If set to true, specifies to leave the temporary downloaded zip file. - * This is useful for tests. - */ - overrideLeaveDownloadedZip: false, - - /** - * The XMLHttpRequest succeeded and the document was loaded. - * @param event The nsIDOMEvent for the load - */ - onLoadXML: function(event) { - let log = getScopedLogger("GMPInstallManager.onLoadXML"); - try { - log.info("request completed downloading document"); - let certs = null; - if (!Services.prefs.prefHasUserValue(GMPPrefs.KEY_URL_OVERRIDE) && - GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, true)) { - certs = gCertUtils.readCertPrefs(GMPPrefs.KEY_CERTS_BRANCH); - } - - let allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_REQUIREBUILTIN, - true); - log.info("allowNonBuiltIn: " + allowNonBuiltIn); - - gCertUtils.checkCert(this._request.channel, allowNonBuiltIn, certs); - - this.parseResponseXML(); - } catch (ex) { - log.error("could not load xml: " + ex); - this._deferred.reject({ - target: event.target, - status: this._getChannelStatus(event.target), - message: "" + ex, - }); - delete this._deferred; - } - }, - - /** - * Returns the status code for the XMLHttpRequest - */ - _getChannelStatus: function(request) { - let log = getScopedLogger("GMPInstallManager._getChannelStatus"); - let status = null; - try { - status = request.status; - log.info("request.status is: " + request.status); - } - catch (e) { - } - - if (status == null) { - status = request.channel.QueryInterface(Ci.nsIRequest).status; - } - return status; - }, - - /** - * There was an error of some kind during the XMLHttpRequest. This - * error may have been caused by external factors (e.g. network - * issues) or internally (by a timeout). - * - * @param event The nsIDOMEvent for the error - */ - onFailXML: function(failure, event) { - let log = getScopedLogger("GMPInstallManager.onFailXML " + failure); - let request = event.target; - let status = this._getChannelStatus(request); - let message = "request.status: " + status + " (" + event.type + ")"; - log.warn(message); - this._deferred.reject({ - target: request, - status: status, - message: message - }); - delete this._deferred; - }, - - /** - * Returns an array of GMPAddon objects discovered by the update check. - * Or returns an empty array if there were any problems with parsing. - * If there's an error, it will be logged if logging is enabled. - */ - parseResponseXML: function() { - try { - let log = getScopedLogger("GMPInstallManager.parseResponseXML"); - let updatesElement = this._request.responseXML.documentElement; - if (!updatesElement) { - let message = "empty updates document"; - log.warn(message); - this._deferred.reject({ - target: this._request, - message: message - }); - delete this._deferred; - return; - } - - if (updatesElement.nodeName != "updates") { - let message = "got node name: " + updatesElement.nodeName + - ", expected: updates"; - log.warn(message); - this._deferred.reject({ - target: this._request, - message: message - }); - delete this._deferred; - return; - } - - const ELEMENT_NODE = Ci.nsIDOMNode.ELEMENT_NODE; - let gmpResults = []; - for (let i = 0; i < updatesElement.childNodes.length; ++i) { - let updatesChildElement = updatesElement.childNodes.item(i); - if (updatesChildElement.nodeType != ELEMENT_NODE) { - continue; - } - if (updatesChildElement.localName == "addons") { - gmpResults = GMPAddon.parseGMPAddonsNode(updatesChildElement); - } - } - this._deferred.resolve(gmpResults); - delete this._deferred; - } catch (e) { - this._deferred.reject({ - target: this._request, - message: e - }); - delete this._deferred; - } - }, -}; - -/** - * Used to construct a single GMP addon - * GMPAddon objects are returns from GMPInstallManager.checkForAddons - * GMPAddon objects can also be used in calls to GMPInstallManager.installAddon - * - * @param gmpAddon The AUS response XML's DOM element `addon` - */ -function GMPAddon(gmpAddon) { - let log = getScopedLogger("GMPAddon.constructor"); - gmpAddon.QueryInterface(Ci.nsIDOMElement); - ["id", "URL", "hashFunction", - "hashValue", "version", "size"].forEach(name => { - if (gmpAddon.hasAttribute(name)) { - this[name] = gmpAddon.getAttribute(name); - } - }); - this.size = Number(this.size) || undefined; - log.info ("Created new addon: " + this.toString()); -} -/** - * Parses an XML GMP addons node from AUS into an array - * @param addonsElement An nsIDOMElement compatible node with XML from AUS - * @return An array of GMPAddon results - */ -GMPAddon.parseGMPAddonsNode = function(addonsElement) { - let log = getScopedLogger("GMPAddon.parseGMPAddonsNode"); - let gmpResults = []; - if (addonsElement.localName !== "addons") { - return; - } - - addonsElement.QueryInterface(Ci.nsIDOMElement); - let addonCount = addonsElement.childNodes.length; - for (let i = 0; i < addonCount; ++i) { - let addonElement = addonsElement.childNodes.item(i); - if (addonElement.localName !== "addon") { - continue; - } - addonElement.QueryInterface(Ci.nsIDOMElement); - try { - gmpResults.push(new GMPAddon(addonElement)); - } catch (e) { - log.warn("invalid addon: " + e); - continue; - } - } - return gmpResults; -}; -GMPAddon.prototype = { - /** - * Returns a string representation of the addon - */ - toString: function() { - return this.id + " (" + - "isValid: " + this.isValid + - ", isInstalled: " + this.isInstalled + - ", hashFunction: " + this.hashFunction+ - ", hashValue: " + this.hashValue + - (this.size !== undefined ? ", size: " + this.size : "" ) + - ")"; - }, - /** - * If all the fields aren't specified don't consider this addon valid - * @return true if the addon is parsed and valid - */ - get isValid() { - return this.id && this.URL && this.version && - this.hashFunction && !!this.hashValue; - }, - get isInstalled() { - return this.version && - GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VERSION, "", this.id) === this.version; - }, - get isEME() { - return this.id == "gmp-widevinecdm" || this.id.indexOf("gmp-eme-") == 0; - }, -}; -/** - * Constructs a GMPExtractor object which is used to extract a GMP zip - * into the specified location. (Which typically leties per platform) - * @param zipPath The path on disk of the zip file to extract - */ -function GMPExtractor(zipPath, installToDirPath) { - this.zipPath = zipPath; - this.installToDirPath = installToDirPath; -} -GMPExtractor.prototype = { - /** - * Obtains a list of all the entries in a zipfile in the format of *.*. - * This also includes files inside directories. - * - * @param zipReader the nsIZipReader to check - * @return An array of string name entries which can be used - * in nsIZipReader.extract - */ - _getZipEntries: function(zipReader) { - let entries = []; - let enumerator = zipReader.findEntries("*.*"); - while (enumerator.hasMore()) { - entries.push(enumerator.getNext()); - } - return entries; - }, - /** - * Installs the this.zipPath contents into the directory used to store GMP - * addons for the current platform. - * - * @return a promise which will be resolved or rejected - * See GMPInstallManager.installAddon for resolve/rejected info - */ - install: function() { - try { - let log = getScopedLogger("GMPExtractor.install"); - this._deferred = Promise.defer(); - log.info("Installing " + this.zipPath + "..."); - // Get the input zip file - let zipFile = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsIFile); - zipFile.initWithPath(this.zipPath); - - // Initialize a zipReader and obtain the entries - var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]. - createInstance(Ci.nsIZipReader); - zipReader.open(zipFile) - let entries = this._getZipEntries(zipReader); - let extractedPaths = []; - - // Extract each of the entries - entries.forEach(entry => { - // We don't need these types of files - if (entry.includes("__MACOSX")) { - return; - } - let outFile = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsILocalFile); - outFile.initWithPath(this.installToDirPath); - outFile.appendRelativePath(entry); - - // Make sure the directory hierarchy exists - if(!outFile.parent.exists()) { - outFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8)); - } - zipReader.extract(entry, outFile); - extractedPaths.push(outFile.path); - log.info(entry + " was successfully extracted to: " + - outFile.path); - }); - zipReader.close(); - if (!GMPInstallManager.overrideLeaveDownloadedZip) { - zipFile.remove(false); - } - - log.info(this.zipPath + " was installed successfully"); - this._deferred.resolve(extractedPaths); - } catch (e) { - if (zipReader) { - zipReader.close(); - } - this._deferred.reject({ - target: this, - status: e, - type: "exception" - }); - } - return this._deferred.promise; - } -}; - - -/** - * Constructs an object which downloads and initiates an install of - * the specified GMPAddon object. - * @param gmpAddon The addon to install. - */ -function GMPDownloader(gmpAddon) -{ - this._gmpAddon = gmpAddon; -} -/** - * Computes the file hash of fileToHash with the specified hash function - * @param hashFunctionName A hash function name such as sha512 - * @param fileToHash An nsIFile to hash - * @return a promise which resolve to a digest in binary hex format - */ -GMPDownloader.computeHash = function(hashFunctionName, fileToHash) { - let log = getScopedLogger("GMPDownloader.computeHash"); - let digest; - let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(Ci.nsIFileInputStream); - fileStream.init(fileToHash, FileUtils.MODE_RDONLY, - FileUtils.PERMS_FILE, 0); - try { - let hash = Cc["@mozilla.org/security/hash;1"]. - createInstance(Ci.nsICryptoHash); - let hashFunction = - Ci.nsICryptoHash[hashFunctionName.toUpperCase()]; - if (!hashFunction) { - log.error("could not get hash function"); - return Promise.reject(); - } - hash.init(hashFunction); - hash.updateFromStream(fileStream, -1); - digest = binaryToHex(hash.finish(false)); - } catch (e) { - log.warn("failed to compute hash: " + e); - digest = ""; - } - fileStream.close(); - return Promise.resolve(digest); -}, -GMPDownloader.prototype = { - /** - * Starts the download process for an addon. - * @return a promise which will be resolved or rejected - * See GMPInstallManager.installAddon for resolve/rejected info - */ - start: function() { - let log = getScopedLogger("GMPDownloader.start"); - this._deferred = Promise.defer(); - if (!this._gmpAddon.isValid) { - log.info("gmpAddon is not valid, will not continue"); - return Promise.reject({ - target: this, - status: status, - type: "downloaderr" - }); - } - - let uri = Services.io.newURI(this._gmpAddon.URL, null, null); - this._request = Cc["@mozilla.org/network/incremental-download;1"]. - createInstance(Ci.nsIIncrementalDownload); - let gmpFile = FileUtils.getFile("TmpD", [this._gmpAddon.id + ".zip"]); - if (gmpFile.exists()) { - gmpFile.remove(false); - } - - log.info("downloading from " + uri.spec + " to " + gmpFile.path); - this._request.init(uri, gmpFile, DOWNLOAD_CHUNK_BYTES_SIZE, - DOWNLOAD_INTERVAL); - this._request.start(this, null); - return this._deferred.promise; - }, - // For nsIRequestObserver - onStartRequest: function(request, context) { - }, - // For nsIRequestObserver - // Called when the GMP addon zip file is downloaded - onStopRequest: function(request, context, status) { - let log = getScopedLogger("GMPDownloader.onStopRequest"); - log.info("onStopRequest called"); - if (!Components.isSuccessCode(status)) { - log.info("status failed: " + status); - this._deferred.reject({ - target: this, - status: status, - type: "downloaderr" - }); - return; - } - - let promise = this._verifyDownload(); - promise.then(() => { - log.info("GMP file is ready to unzip"); - let destination = this._request.destination; - - let zipPath = destination.path; - let gmpAddon = this._gmpAddon; - let installToDirPath = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsIFile); - let path = OS.Path.join(OS.Constants.Path.profileDir, - gmpAddon.id, - gmpAddon.version); - installToDirPath.initWithPath(path); - log.info("install to directory path: " + installToDirPath.path); - let gmpInstaller = new GMPExtractor(zipPath, installToDirPath.path); - let installPromise = gmpInstaller.install(); - installPromise.then(extractedPaths => { - // Success, set the prefs - let now = Math.round(Date.now() / 1000); - GMPPrefs.set(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, now, gmpAddon.id); - // Setting the version pref signals installation completion to consumers, - // if you need to set other prefs etc. do it before this. - GMPPrefs.set(GMPPrefs.KEY_PLUGIN_VERSION, gmpAddon.version, - gmpAddon.id); - this._deferred.resolve(extractedPaths); - }, err => { - this._deferred.reject(err); - }); - }, err => { - log.warn("verifyDownload check failed"); - this._deferred.reject({ - target: this, - status: 200, - type: "verifyerr" - }); - }); - }, - /** - * Verifies that the downloaded zip file's hash matches the GMPAddon hash. - * @return a promise which resolves if the download verifies - */ - _verifyDownload: function() { - let verifyDownloadDeferred = Promise.defer(); - let log = getScopedLogger("GMPDownloader._verifyDownload"); - log.info("_verifyDownload called"); - if (!this._request) { - return Promise.reject(); - } - - let destination = this._request.destination; - log.info("for path: " + destination.path); - - // Ensure that the file size matches the expected file size. - if (this._gmpAddon.size !== undefined && - destination.fileSize != this._gmpAddon.size) { - log.warn("Downloader:_verifyDownload downloaded size " + - destination.fileSize + " != expected size " + - this._gmpAddon.size + "."); - return Promise.reject(); - } - - let promise = GMPDownloader.computeHash(this._gmpAddon.hashFunction, destination); - promise.then(digest => { - let expectedDigest = this._gmpAddon.hashValue.toLowerCase(); - if (digest !== expectedDigest) { - log.warn("hashes do not match! Got: `" + - digest + "`, expected: `" + expectedDigest + "`"); - this._deferred.reject(); - return; - } - - log.info("hashes match!"); - verifyDownloadDeferred.resolve(); - }, err => { - verifyDownloadDeferred.reject(); - }); - return verifyDownloadDeferred.promise; - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver]) -}; - -/** - * Convert a string containing binary values to hex. - */ -function binaryToHex(input) { - let result = ""; - for (let i = 0; i < input.length; ++i) { - let hex = input.charCodeAt(i).toString(16); - if (hex.length == 1) - hex = "0" + hex; - result += hex; - } - return result; -} diff --git a/components/addons/src/GMPProvider.jsm b/components/addons/src/GMPProvider.jsm deleted file mode 100644 index c89427101..000000000 --- a/components/addons/src/GMPProvider.jsm +++ /dev/null @@ -1,605 +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"; - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; - -this.EXPORTED_SYMBOLS = []; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/GMPUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter( - this, "GMPInstallManager", "resource://gre/modules/GMPInstallManager.jsm"); -XPCOMUtils.defineLazyModuleGetter( - this, "setTimeout", "resource://gre/modules/Timer.jsm"); - -const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties"; -const STRING_TYPE_NAME = "type.%ID%.name"; - -const SEC_IN_A_DAY = 24 * 60 * 60; -// How long to wait after a user enabled EME before attempting to download CDMs. -const GMP_CHECK_DELAY = 10 * 1000; // milliseconds - -const NS_GRE_DIR = "GreD"; -const CLEARKEY_PLUGIN_ID = "gmp-clearkey"; -const CLEARKEY_VERSION = "0.1"; - -const GMP_LICENSE_INFO = "gmp_license_info"; - -const GMP_PLUGINS = [ - { - id: OPEN_H264_ID, - name: "openH264_name", - description: "openH264_description2", - // The following licenseURL is part of an awful hack to include the OpenH264 - // license without having bug 624602 fixed yet, and intentionally ignores - // localisation. - licenseURL: "chrome://mozapps/content/extensions/OpenH264-license.txt", - homepageURL: "http://www.openh264.org/", - optionsURL: "chrome://mozapps/content/extensions/gmpPrefs.xul" - }, - { - id: WIDEVINE_ID, - name: "widevine_name", - // Describe the purpose of both CDMs in the same way. - description: "widevine_description2", - licenseURL: "https://www.google.com/policies/privacy/", - homepageURL: "https://www.widevine.com/", - optionsURL: "chrome://mozapps/content/extensions/gmpPrefs.xul", - isEME: true - }]; -XPCOMUtils.defineConstant(this, "GMP_PLUGINS", GMP_PLUGINS); - -XPCOMUtils.defineLazyGetter(this, "pluginsBundle", - () => Services.strings.createBundle("chrome://global/locale/plugins.properties")); -XPCOMUtils.defineLazyGetter(this, "gmpService", - () => Cc["@mozilla.org/gecko-media-plugin-service;1"].getService(Ci.mozIGeckoMediaPluginChromeService)); - -var messageManager = Cc["@mozilla.org/globalmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); - -var gLogger; -var gLogAppenderDump = null; - -function configureLogging() { - if (!gLogger) { - gLogger = Log.repository.getLogger("Toolkit.GMP"); - gLogger.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); - } - gLogger.level = GMPPrefs.get(GMPPrefs.KEY_LOGGING_LEVEL, Log.Level.Warn); - - let logDumping = GMPPrefs.get(GMPPrefs.KEY_LOGGING_DUMP, false); - if (logDumping != !!gLogAppenderDump) { - if (logDumping) { - gLogAppenderDump = new Log.DumpAppender(new Log.BasicFormatter()); - gLogger.addAppender(gLogAppenderDump); - } else { - gLogger.removeAppender(gLogAppenderDump); - gLogAppenderDump = null; - } - } -} - - - -/** - * The GMPWrapper provides the info for the various GMP plugins to public - * callers through the API. - */ -function GMPWrapper(aPluginInfo) { - this._plugin = aPluginInfo; - this._log = - Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP", - "GMPWrapper(" + - this._plugin.id + ") "); - Preferences.observe(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED, - this._plugin.id), - this.onPrefEnabledChanged, this); - Preferences.observe(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION, - this._plugin.id), - this.onPrefVersionChanged, this); - if (this._plugin.isEME) { - Preferences.observe(GMPPrefs.KEY_EME_ENABLED, - this.onPrefEMEGlobalEnabledChanged, this); - messageManager.addMessageListener("EMEVideo:ContentMediaKeysRequest", this); - } -} - -GMPWrapper.prototype = { - // An active task that checks for plugin updates and installs them. - _updateTask: null, - _gmpPath: null, - _isUpdateCheckPending: false, - - optionsType: AddonManager.OPTIONS_TYPE_INLINE, - get optionsURL() { return this._plugin.optionsURL; }, - - set gmpPath(aPath) { this._gmpPath = aPath; }, - get gmpPath() { - if (!this._gmpPath && this.isInstalled) { - this._gmpPath = OS.Path.join(OS.Constants.Path.profileDir, - this._plugin.id, - GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VERSION, - null, this._plugin.id)); - } - return this._gmpPath; - }, - - get id() { return this._plugin.id; }, - get type() { return "plugin"; }, - get isGMPlugin() { return true; }, - get name() { return this._plugin.name; }, - get creator() { return null; }, - get homepageURL() { return this._plugin.homepageURL; }, - - get description() { return this._plugin.description; }, - get fullDescription() { return this._plugin.fullDescription; }, - - get version() { return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VERSION, null, - this._plugin.id); }, - - get isActive() { return !this.appDisabled && !this.userDisabled; }, - get appDisabled() { - if (this._plugin.isEME && !GMPPrefs.get(GMPPrefs.KEY_EME_ENABLED, true)) { - // If "media.eme.enabled" is false, all EME plugins are disabled. - return true; - } - return false; - }, - - get userDisabled() { - return !GMPPrefs.get(GMPPrefs.KEY_PLUGIN_ENABLED, true, this._plugin.id); - }, - set userDisabled(aVal) { GMPPrefs.set(GMPPrefs.KEY_PLUGIN_ENABLED, - aVal === false, - this._plugin.id); }, - - get blocklistState() { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; }, - get size() { return 0; }, - get scope() { return AddonManager.SCOPE_APPLICATION; }, - get pendingOperations() { return AddonManager.PENDING_NONE; }, - - get operationsRequiringRestart() { return AddonManager.OP_NEEDS_RESTART_NONE }, - - get permissions() { - let permissions = 0; - if (!this.appDisabled) { - permissions |= AddonManager.PERM_CAN_UPGRADE; - permissions |= this.userDisabled ? AddonManager.PERM_CAN_ENABLE : - AddonManager.PERM_CAN_DISABLE; - } - return permissions; - }, - - get updateDate() { - let time = Number(GMPPrefs.get(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, null, - this._plugin.id)); - if (time !== NaN && this.isInstalled) { - return new Date(time * 1000) - } - return null; - }, - - get isCompatible() { - return true; - }, - - get isPlatformCompatible() { - return true; - }, - - get providesUpdatesSecurely() { - return true; - }, - - get foreignInstall() { - return false; - }, - - isCompatibleWith: function(aAppVersion, aPlatformVersion) { - return true; - }, - - get applyBackgroundUpdates() { - if (!GMPPrefs.isSet(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, this._plugin.id)) { - return AddonManager.AUTOUPDATE_DEFAULT; - } - - return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, this._plugin.id) ? - AddonManager.AUTOUPDATE_ENABLE : AddonManager.AUTOUPDATE_DISABLE; - }, - - set applyBackgroundUpdates(aVal) { - if (aVal == AddonManager.AUTOUPDATE_DEFAULT) { - GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, this._plugin.id); - } else if (aVal == AddonManager.AUTOUPDATE_ENABLE) { - GMPPrefs.set(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, this._plugin.id); - } else if (aVal == AddonManager.AUTOUPDATE_DISABLE) { - GMPPrefs.set(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, false, this._plugin.id); - } - }, - - findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) { - this._log.trace("findUpdates() - " + this._plugin.id + " - reason=" + - aReason); - - AddonManagerPrivate.callNoUpdateListeners(this, aListener); - - if (aReason === AddonManager.UPDATE_WHEN_PERIODIC_UPDATE) { - if (!AddonManager.shouldAutoUpdate(this)) { - this._log.trace("findUpdates() - " + this._plugin.id + - " - no autoupdate"); - return Promise.resolve(false); - } - - let secSinceLastCheck = - Date.now() / 1000 - Preferences.get(GMPPrefs.KEY_UPDATE_LAST_CHECK, 0); - if (secSinceLastCheck <= SEC_IN_A_DAY) { - this._log.trace("findUpdates() - " + this._plugin.id + - " - last check was less then a day ago"); - return Promise.resolve(false); - } - } else if (aReason !== AddonManager.UPDATE_WHEN_USER_REQUESTED) { - this._log.trace("findUpdates() - " + this._plugin.id + - " - the given reason to update is not supported"); - return Promise.resolve(false); - } - - if (this._updateTask !== null) { - this._log.trace("findUpdates() - " + this._plugin.id + - " - update task already running"); - return this._updateTask; - } - - this._updateTask = Task.spawn(function* GMPProvider_updateTask() { - this._log.trace("findUpdates() - updateTask"); - try { - let installManager = new GMPInstallManager(); - let gmpAddons = yield installManager.checkForAddons(); - let update = gmpAddons.find(function(aAddon) { - return aAddon.id === this._plugin.id; - }, this); - if (update && update.isValid && !update.isInstalled) { - this._log.trace("findUpdates() - found update for " + - this._plugin.id + ", installing"); - yield installManager.installAddon(update); - } else { - this._log.trace("findUpdates() - no updates for " + this._plugin.id); - } - this._log.info("findUpdates() - updateTask succeeded for " + - this._plugin.id); - } catch (e) { - this._log.error("findUpdates() - updateTask for " + this._plugin.id + - " threw", e); - throw e; - } finally { - this._updateTask = null; - return true; - } - }.bind(this)); - - return this._updateTask; - }, - - get pluginMimeTypes() { return []; }, - get pluginLibraries() { - if (this.isInstalled) { - let path = this.version; - return [path]; - } - return []; - }, - get pluginFullpath() { - if (this.isInstalled) { - let path = OS.Path.join(OS.Constants.Path.profileDir, - this._plugin.id, - this.version); - return [path]; - } - return []; - }, - - get isInstalled() { - return this.version && this.version.length > 0; - }, - - _handleEnabledChanged: function() { - AddonManagerPrivate.callAddonListeners(this.isActive ? - "onEnabling" : "onDisabling", - this, false); - if (this._gmpPath) { - if (this.isActive) { - this._log.info("onPrefEnabledChanged() - adding gmp directory " + - this._gmpPath); - gmpService.addPluginDirectory(this._gmpPath); - } else { - this._log.info("onPrefEnabledChanged() - removing gmp directory " + - this._gmpPath); - gmpService.removePluginDirectory(this._gmpPath); - } - } - AddonManagerPrivate.callAddonListeners(this.isActive ? - "onEnabled" : "onDisabled", - this); - }, - - onPrefEMEGlobalEnabledChanged: function() { - AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, - ["appDisabled"]); - if (this.appDisabled) { - this.uninstallPlugin(); - } else { - AddonManagerPrivate.callInstallListeners("onExternalInstall", null, this, - null, false); - AddonManagerPrivate.callAddonListeners("onInstalling", this, false); - AddonManagerPrivate.callAddonListeners("onInstalled", this); - this.checkForUpdates(GMP_CHECK_DELAY); - } - if (!this.userDisabled) { - this._handleEnabledChanged(); - } - }, - - checkForUpdates: function(delay) { - if (this._isUpdateCheckPending) { - return; - } - this._isUpdateCheckPending = true; - GMPPrefs.reset(GMPPrefs.KEY_UPDATE_LAST_CHECK, null); - // Delay this in case the user changes his mind and doesn't want to - // enable EME after all. - setTimeout(() => { - if (!this.appDisabled) { - let gmpInstallManager = new GMPInstallManager(); - // We don't really care about the results, if someone is interested - // they can check the log. - gmpInstallManager.simpleCheckAndInstall().then(null, () => {}); - } - this._isUpdateCheckPending = false; - }, delay); - }, - - receiveMessage: function({target: browser, data: data}) { - this._log.trace("receiveMessage() data=" + data); - let parsedData; - try { - parsedData = JSON.parse(data); - } catch(ex) { - this._log.error("Malformed EME video message with data: " + data); - return; - } - let {status: status, keySystem: keySystem} = parsedData; - if (status == "cdm-not-installed" || status == "cdm-insufficient-version") { - this.checkForUpdates(0); - } - }, - - onPrefEnabledChanged: function() { - if (!this._plugin.isEME || !this.appDisabled) { - this._handleEnabledChanged(); - } - }, - - onPrefVersionChanged: function() { - AddonManagerPrivate.callAddonListeners("onUninstalling", this, false); - if (this._gmpPath) { - this._log.info("onPrefVersionChanged() - unregistering gmp directory " + - this._gmpPath); - gmpService.removeAndDeletePluginDirectory(this._gmpPath, true /* can defer */); - } - AddonManagerPrivate.callAddonListeners("onUninstalled", this); - - AddonManagerPrivate.callInstallListeners("onExternalInstall", null, this, - null, false); - AddonManagerPrivate.callAddonListeners("onInstalling", this, false); - this._gmpPath = null; - if (this.isInstalled) { - this._gmpPath = OS.Path.join(OS.Constants.Path.profileDir, - this._plugin.id, - GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VERSION, - null, this._plugin.id)); - } - if (this._gmpPath && this.isActive) { - this._log.info("onPrefVersionChanged() - registering gmp directory " + - this._gmpPath); - gmpService.addPluginDirectory(this._gmpPath); - } - AddonManagerPrivate.callAddonListeners("onInstalled", this); - }, - - uninstallPlugin: function() { - AddonManagerPrivate.callAddonListeners("onUninstalling", this, false); - if (this.gmpPath) { - this._log.info("uninstallPlugin() - unregistering gmp directory " + - this.gmpPath); - gmpService.removeAndDeletePluginDirectory(this.gmpPath); - } - GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_VERSION, this.id); - AddonManagerPrivate.callAddonListeners("onUninstalled", this); - }, - - shutdown: function() { - Preferences.ignore(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED, - this._plugin.id), - this.onPrefEnabledChanged, this); - Preferences.ignore(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION, - this._plugin.id), - this.onPrefVersionChanged, this); - if (this._plugin.isEME) { - Preferences.ignore(GMPPrefs.KEY_EME_ENABLED, - this.onPrefEMEGlobalEnabledChanged, this); - messageManager.removeMessageListener("EMEVideo:ContentMediaKeysRequest", this); - } - return this._updateTask; - }, -}; - -var GMPProvider = { - get name() { return "GMPProvider"; }, - - _plugins: null, - - startup: function() { - configureLogging(); - this._log = Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP", - "GMPProvider."); - this.buildPluginList(); - this.ensureProperCDMInstallState(); - - Preferences.observe(GMPPrefs.KEY_LOG_BASE, configureLogging); - - for (let [id, plugin] of this._plugins) { - let wrapper = plugin.wrapper; - let gmpPath = wrapper.gmpPath; - let isEnabled = wrapper.isActive; - this._log.trace("startup - enabled=" + isEnabled + ", gmpPath=" + - gmpPath); - - if (gmpPath && isEnabled) { - this._log.info("startup - adding gmp directory " + gmpPath); - try { - gmpService.addPluginDirectory(gmpPath); - } catch (e if e.name == 'NS_ERROR_NOT_AVAILABLE') { - this._log.warn("startup - adding gmp directory failed with " + - e.name + " - sandboxing not available?", e); - } - } - } - - if (Preferences.get(GMPPrefs.KEY_EME_ENABLED, false)) { - try { - let greDir = Services.dirsvc.get(NS_GRE_DIR, - Ci.nsILocalFile); - let clearkeyPath = OS.Path.join(greDir.path, - CLEARKEY_PLUGIN_ID, - CLEARKEY_VERSION); - this._log.info("startup - adding clearkey CDM directory " + - clearkeyPath); - gmpService.addPluginDirectory(clearkeyPath); - } catch (e) { - this._log.warn("startup - adding clearkey CDM failed", e); - } - } - }, - - shutdown: function() { - this._log.trace("shutdown"); - Preferences.ignore(GMPPrefs.KEY_LOG_BASE, configureLogging); - - let shutdownTask = Task.spawn(function* GMPProvider_shutdownTask() { - this._log.trace("shutdown - shutdownTask"); - let shutdownSucceeded = true; - - for (let plugin of this._plugins.values()) { - try { - yield plugin.wrapper.shutdown(); - } catch (e) { - shutdownSucceeded = false; - } - } - - this._plugins = null; - - if (!shutdownSucceeded) { - throw new Error("Shutdown failed"); - } - }.bind(this)); - - return shutdownTask; - }, - - getAddonByID: function(aId, aCallback) { - if (!this.isEnabled) { - aCallback(null); - return; - } - - let plugin = this._plugins.get(aId); - if (plugin && !GMPUtils.isPluginHidden(plugin)) { - aCallback(plugin.wrapper); - } else { - aCallback(null); - } - }, - - getAddonsByTypes: function(aTypes, aCallback) { - if (!this.isEnabled || - (aTypes && aTypes.indexOf("plugin") < 0)) { - aCallback([]); - return; - } - - // Tycho: - // let results = [p.wrapper for ([id, p] of this._plugins) - // if (!GMPUtils.isPluginHidden(p))]; - let results = []; - for (let [id, p] of this._plugins) { - if (!GMPUtils.isPluginHidden(p)) { - results.push(p.wrapper); - } - } - - aCallback(results); - }, - - get isEnabled() { - return GMPPrefs.get(GMPPrefs.KEY_PROVIDER_ENABLED, false); - }, - - generateFullDescription: function(aLicenseURL, aLicenseInfo) { - return "<xhtml:a href=\"" + aLicenseURL + "\" target=\"_blank\">" + - aLicenseInfo + "</xhtml:a>." - }, - - buildPluginList: function() { - let licenseInfo = pluginsBundle.GetStringFromName(GMP_LICENSE_INFO); - - this._plugins = new Map(); - for (let aPlugin of GMP_PLUGINS) { - let plugin = { - id: aPlugin.id, - name: pluginsBundle.GetStringFromName(aPlugin.name), - description: pluginsBundle.GetStringFromName(aPlugin.description), - homepageURL: aPlugin.homepageURL, - optionsURL: aPlugin.optionsURL, - wrapper: null, - isEME: aPlugin.isEME, - }; - if (aPlugin.licenseURL) { - plugin.fullDescription = - this.generateFullDescription(aPlugin.licenseURL, licenseInfo); - } - plugin.wrapper = new GMPWrapper(plugin); - this._plugins.set(plugin.id, plugin); - } - }, - - ensureProperCDMInstallState: function() { - if (!GMPPrefs.get(GMPPrefs.KEY_EME_ENABLED, true)) { - for (let [id, plugin] of this._plugins) { - if (plugin.isEME && plugin.wrapper.isInstalled) { - gmpService.addPluginDirectory(plugin.wrapper.gmpPath); - plugin.wrapper.uninstallPlugin(); - } - } - } - }, -}; - -AddonManagerPrivate.registerProvider(GMPProvider, [ - new AddonManagerPrivate.AddonType("plugin", URI_EXTENSION_STRINGS, - STRING_TYPE_NAME, - AddonManager.VIEW_TYPE_LIST, 6000, - AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) -]); diff --git a/components/addons/src/GMPUtils.jsm b/components/addons/src/GMPUtils.jsm deleted file mode 100644 index 593fc3c8d..000000000 --- a/components/addons/src/GMPUtils.jsm +++ /dev/null @@ -1,187 +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"; - -const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = - Components; - -this.EXPORTED_SYMBOLS = [ "GMP_PLUGIN_IDS", - "GMPPrefs", - "GMPUtils", - "OPEN_H264_ID", - "WIDEVINE_ID" ]; - -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -// GMP IDs -const OPEN_H264_ID = "gmp-gmpopenh264"; -const WIDEVINE_ID = "gmp-widevinecdm"; -const GMP_PLUGIN_IDS = [ OPEN_H264_ID, WIDEVINE_ID ]; - -var GMPPluginUnsupportedReason = { - NOT_WINDOWS: 1, - WINDOWS_VERSION: 2, -}; - -var GMPPluginHiddenReason = { - UNSUPPORTED: 1, - EME_DISABLED: 2, -}; - -this.GMPUtils = { - /** - * Checks whether or not a given plugin is hidden. Hidden plugins are neither - * downloaded nor displayed in the addons manager. - * @param aPlugin - * The plugin to check. - */ - isPluginHidden: function(aPlugin) { - if (!aPlugin.isEME) { - return false; - } - - if (!this._isPluginSupported(aPlugin) || - !this._isPluginVisible(aPlugin)) { - return true; - } - - if (!GMPPrefs.get(GMPPrefs.KEY_EME_ENABLED, true)) { - return true; - } - - return false; - }, - - /** - * Checks whether or not a given plugin is supported by the current OS. - * @param aPlugin - * The plugin to check. - */ - _isPluginSupported: function(aPlugin) { - if (this._isPluginForceSupported(aPlugin)) { - return true; - } - if (aPlugin.id == WIDEVINE_ID) { - -#if defined(XP_WIN) || defined(XP_LINUX) - // The Widevine plugin is available for Windows versions Vista and later, - // Mac OSX, and Linux. - return true; -#else - return false; -#endif - } - - return true; - }, - - /** - * Checks whether or not a given plugin is visible in the addons manager - * UI and the "enable DRM" notification box. This can be used to test - * plugins that aren't yet turned on in the mozconfig. - * @param aPlugin - * The plugin to check. - */ - _isPluginVisible: function(aPlugin) { - return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VISIBLE, false, aPlugin.id); - }, - - /** - * Checks whether or not a given plugin is forced-supported. This is used - * in automated tests to override the checks that prevent GMPs running on an - * unsupported platform. - * @param aPlugin - * The plugin to check. - */ - _isPluginForceSupported: function(aPlugin) { - return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, false, aPlugin.id); - }, -}; - -/** - * Manages preferences for GMP addons - */ -this.GMPPrefs = { - KEY_EME_ENABLED: "media.eme.enabled", - KEY_PLUGIN_ENABLED: "media.{0}.enabled", - KEY_PLUGIN_LAST_UPDATE: "media.{0}.lastUpdate", - KEY_PLUGIN_VERSION: "media.{0}.version", - KEY_PLUGIN_AUTOUPDATE: "media.{0}.autoupdate", - KEY_PLUGIN_VISIBLE: "media.{0}.visible", - KEY_PLUGIN_ABI: "media.{0}.abi", - KEY_PLUGIN_FORCE_SUPPORTED: "media.{0}.forceSupported", - KEY_URL: "media.gmp-manager.url", - KEY_URL_OVERRIDE: "media.gmp-manager.url.override", - KEY_CERT_CHECKATTRS: "media.gmp-manager.cert.checkAttributes", - KEY_CERT_REQUIREBUILTIN: "media.gmp-manager.cert.requireBuiltIn", - KEY_UPDATE_LAST_CHECK: "media.gmp-manager.lastCheck", - KEY_SECONDS_BETWEEN_CHECKS: "media.gmp-manager.secondsBetweenChecks", - KEY_UPDATE_ENABLED: "media.gmp-manager.updateEnabled", - KEY_APP_DISTRIBUTION: "distribution.id", - KEY_APP_DISTRIBUTION_VERSION: "distribution.version", - KEY_BUILDID: "media.gmp-manager.buildID", - KEY_CERTS_BRANCH: "media.gmp-manager.certs.", - KEY_PROVIDER_ENABLED: "media.gmp-provider.enabled", - KEY_LOG_BASE: "media.gmp.log.", - KEY_LOGGING_LEVEL: "media.gmp.log.level", - KEY_LOGGING_DUMP: "media.gmp.log.dump", - - /** - * Obtains the specified preference in relation to the specified plugin. - * @param aKey The preference key value to use. - * @param aDefaultValue The default value if no preference exists. - * @param aPlugin The plugin to scope the preference to. - * @return The obtained preference value, or the defaultValue if none exists. - */ - get: function(aKey, aDefaultValue, aPlugin) { - if (aKey === this.KEY_APP_DISTRIBUTION || - aKey === this.KEY_APP_DISTRIBUTION_VERSION) { - return Services.prefs.getDefaultBranch(null).getCharPref(aKey, "default"); - } - return Preferences.get(this.getPrefKey(aKey, aPlugin), aDefaultValue); - }, - - /** - * Sets the specified preference in relation to the specified plugin. - * @param aKey The preference key value to use. - * @param aVal The value to set. - * @param aPlugin The plugin to scope the preference to. - */ - set: function(aKey, aVal, aPlugin) { - Preferences.set(this.getPrefKey(aKey, aPlugin), aVal); - }, - - /** - * Checks whether or not the specified preference is set in relation to the - * specified plugin. - * @param aKey The preference key value to use. - * @param aPlugin The plugin to scope the preference to. - * @return true if the preference is set, false otherwise. - */ - isSet: function(aKey, aPlugin) { - return Preferences.isSet(this.getPrefKey(aKey, aPlugin)); - }, - - /** - * Resets the specified preference in relation to the specified plugin to its - * default. - * @param aKey The preference key value to use. - * @param aPlugin The plugin to scope the preference to. - */ - reset: function(aKey, aPlugin) { - Preferences.reset(this.getPrefKey(aKey, aPlugin)); - }, - - /** - * Scopes the specified preference key to the specified plugin. - * @param aKey The preference key value to use. - * @param aPlugin The plugin to scope the preference to. - * @return A preference key scoped to the specified plugin. - */ - getPrefKey: function(aKey, aPlugin) { - return aKey.replace("{0}", aPlugin || ""); - }, -}; diff --git a/components/addons/src/ProductAddonChecker.jsm b/components/addons/src/ProductAddonChecker.jsm deleted file mode 100644 index c6324da0a..000000000 --- a/components/addons/src/ProductAddonChecker.jsm +++ /dev/null @@ -1,464 +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"; - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - -const LOCAL_EME_SOURCES = [{ - "id": "gmp-gmpopenh264", - "src": "chrome://global/content/gmp-sources/openh264.json" -}, { - "id": "gmp-widevinecdm", - "src": "chrome://global/content/gmp-sources/widevinecdm.json" -}]; - -this.EXPORTED_SYMBOLS = [ "ProductAddonChecker" ]; - -Cu.importGlobalProperties(["XMLHttpRequest"]); - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://gre/modules/CertUtils.jsm"); -/* globals checkCert, BadCertHandler*/ -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); - -/* globals GMPPrefs */ -XPCOMUtils.defineLazyModuleGetter(this, "GMPPrefs", - "resource://gre/modules/GMPUtils.jsm"); - -/* globals OS */ - -XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", - "resource://gre/modules/UpdateUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest", - "resource://gre/modules/ServiceRequest.jsm"); - -// This exists so that tests can override the XHR behaviour for downloading -// the addon update XML file. -var CreateXHR = function() { - return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. - createInstance(Ci.nsISupports); -} - -var logger = Log.repository.getLogger("addons.productaddons"); - -/** - * Number of milliseconds after which we need to cancel `downloadXML`. - * - * Bug 1087674 suggests that the XHR we use in `downloadXML` may - * never terminate in presence of network nuisances (e.g. strange - * antivirus behavior). This timeout is a defensive measure to ensure - * that we fail cleanly in such case. - */ -const TIMEOUT_DELAY_MS = 20000; -// Chunk size for the incremental downloader -const DOWNLOAD_CHUNK_BYTES_SIZE = 300000; -// Incremental downloader interval -const DOWNLOAD_INTERVAL = 0; -// How much of a file to read into memory at a time for hashing -const HASH_CHUNK_SIZE = 8192; - -/** - * Gets the status of an XMLHttpRequest either directly or from its underlying - * channel. - * - * @param request - * The XMLHttpRequest. - * @return an integer status value. - */ -function getRequestStatus(request) { - let status = null; - try { - status = request.status; - } - catch (e) { - } - - if (status != null) { - return status; - } - - return request.channel.QueryInterface(Ci.nsIRequest).status; -} - -/** - * Downloads an XML document from a URL optionally testing the SSL certificate - * for certain attributes. - * - * @param url - * The url to download from. - * @param allowNonBuiltIn - * Whether to trust SSL certificates without a built-in CA issuer. - * @param allowedCerts - * The list of certificate attributes to match the SSL certificate - * against or null to skip checks. - * @return a promise that resolves to the DOM document downloaded or rejects - * with a JS exception in case of error. - */ -function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) { - return new Promise((resolve, reject) => { - let request = CreateXHR(); - // This is here to let unit test code override XHR - if (request.wrappedJSObject) { - request = request.wrappedJSObject; - } - request.open("GET", url, true); - request.channel.notificationCallbacks = new BadCertHandler(allowNonBuiltIn); - // Prevent the request from reading from the cache. - request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; - // Prevent the request from writing to the cache. - request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; - // Use conservative TLS settings. See bug 1325501. - // TODO move to ServiceRequest. - if (request.channel instanceof Ci.nsIHttpChannelInternal) { - request.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true; - } - request.timeout = TIMEOUT_DELAY_MS; - - request.overrideMimeType("text/xml"); - // The Cache-Control header is only interpreted by proxies and the - // final destination. It does not help if a resource is already - // cached locally. - request.setRequestHeader("Cache-Control", "no-cache"); - // HTTP/1.0 servers might not implement Cache-Control and - // might only implement Pragma: no-cache - request.setRequestHeader("Pragma", "no-cache"); - - let fail = (event) => { - let request = event.target; - let status = getRequestStatus(request); - let message = "Failed downloading XML, status: " + status + ", reason: " + event.type; - logger.warn(message); - let ex = new Error(message); - ex.status = status; - reject(ex); - }; - - let success = (event) => { - logger.info("Completed downloading document"); - let request = event.target; - - try { - checkCert(request.channel, allowNonBuiltIn, allowedCerts); - } catch (ex) { - logger.error("Request failed certificate checks: " + ex); - ex.status = getRequestStatus(request); - reject(ex); - return; - } - - resolve(request.responseXML); - }; - - request.addEventListener("error", fail, false); - request.addEventListener("abort", fail, false); - request.addEventListener("timeout", fail, false); - request.addEventListener("load", success, false); - - logger.info("sending request to: " + url); - request.send(null); - }); -} - -function downloadJSON(uri) { - logger.info("fetching config from: " + uri); - return new Promise((resolve, reject) => { - let xmlHttp = new ServiceRequest({mozAnon: true}); - - xmlHttp.onload = function(aResponse) { - resolve(JSON.parse(this.responseText)); - }; - - xmlHttp.onerror = function(e) { - reject("Fetching " + uri + " results in error code: " + e.target.status); - }; - - xmlHttp.open("GET", uri); - xmlHttp.overrideMimeType("application/json"); - xmlHttp.send(); - }); -} - - -/** - * Parses a list of add-ons from a DOM document. - * - * @param document - * The DOM document to parse. - * @return null if there is no <addons> element otherwise an object containing - * an array of the addons listed and a field notifying whether the - * fallback was used. - */ -function parseXML(document) { - // Check that the root element is correct - if (document.documentElement.localName != "updates") { - throw new Error("got node name: " + document.documentElement.localName + - ", expected: updates"); - } - - // Check if there are any addons elements in the updates element - let addons = document.querySelector("updates:root > addons"); - if (!addons) { - return null; - } - - let results = []; - let addonList = document.querySelectorAll("updates:root > addons > addon"); - for (let addonElement of addonList) { - let addon = {}; - - for (let name of ["id", "URL", "hashFunction", "hashValue", "version", "size"]) { - if (addonElement.hasAttribute(name)) { - addon[name] = addonElement.getAttribute(name); - } - } - addon.size = Number(addon.size) || undefined; - - results.push(addon); - } - - return { - usedFallback: false, - gmpAddons: results - }; -} - -/** - * If downloading from the network fails (AUS server is down), - * load the sources from local build configuration. - */ -function downloadLocalConfig() { - - if (!GMPPrefs.get(GMPPrefs.KEY_UPDATE_ENABLED, true)) { - logger.info("Updates are disabled via media.gmp-manager.updateEnabled"); - return Promise.resolve({usedFallback: true, gmpAddons: []}); - } - - return Promise.all(LOCAL_EME_SOURCES.map(conf => { - return downloadJSON(conf.src).then(addons => { - - let platforms = addons.vendors[conf.id].platforms; - let target = Services.appinfo.OS + "_" + UpdateUtils.ABI; - let details = null; - - while (!details) { - if (!(target in platforms)) { - // There was no matching platform so return false, this addon - // will be filtered from the results below - logger.info("no details found for: " + target); - return false; - } - // Field either has the details of the binary or is an alias - // to another build target key that does - if (platforms[target].alias) { - target = platforms[target].alias; - } else { - details = platforms[target]; - } - } - - logger.info("found plugin: " + conf.id); - return { - "id": conf.id, - "URL": details.fileUrl, - "hashFunction": addons.hashFunction, - "hashValue": details.hashValue, - "version": addons.vendors[conf.id].version, - "size": details.filesize - }; - }); - })).then(addons => { - - // Some filters may not match this platform so - // filter those out - addons = addons.filter(x => x !== false); - - return { - usedFallback: true, - gmpAddons: addons - }; - }); -} - -/** - * Downloads file from a URL using XHR. - * - * @param url - * The url to download from. - * @return a promise that resolves to the path of a temporary file or rejects - * with a JS exception in case of error. - */ -function downloadFile(url) { - return new Promise((resolve, reject) => { - let xhr = new XMLHttpRequest(); - xhr.onload = function(response) { - logger.info("downloadXHR File download. status=" + xhr.status); - if (xhr.status != 200 && xhr.status != 206) { - reject(Components.Exception("File download failed", xhr.status)); - return; - } - Task.spawn(function* () { - let f = yield OS.File.openUnique(OS.Path.join(OS.Constants.Path.tmpDir, "tmpaddon")); - let path = f.path; - logger.info(`Downloaded file will be saved to ${path}`); - yield f.file.close(); - yield OS.File.writeAtomic(path, new Uint8Array(xhr.response)); - return path; - }).then(resolve, reject); - }; - - let fail = (event) => { - let request = event.target; - let status = getRequestStatus(request); - let message = "Failed downloading via XHR, status: " + status + ", reason: " + event.type; - logger.warn(message); - let ex = new Error(message); - ex.status = status; - reject(ex); - }; - xhr.addEventListener("error", fail); - xhr.addEventListener("abort", fail); - - xhr.responseType = "arraybuffer"; - try { - xhr.open("GET", url); - // Use conservative TLS settings. See bug 1325501. - // TODO move to ServiceRequest. - if (xhr.channel instanceof Ci.nsIHttpChannelInternal) { - xhr.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true; - } - xhr.send(null); - } catch (ex) { - reject(ex); - } - }); -} - -/** - * Convert a string containing binary values to hex. - */ -function binaryToHex(input) { - let result = ""; - for (let i = 0; i < input.length; ++i) { - let hex = input.charCodeAt(i).toString(16); - if (hex.length == 1) { - hex = "0" + hex; - } - result += hex; - } - return result; -} - -/** - * Calculates the hash of a file. - * - * @param hashFunction - * The type of hash function to use, must be supported by nsICryptoHash. - * @param path - * The path of the file to hash. - * @return a promise that resolves to hash of the file or rejects with a JS - * exception in case of error. - */ -var computeHash = Task.async(function*(hashFunction, path) { - let file = yield OS.File.open(path, { existing: true, read: true }); - try { - let hasher = Cc["@mozilla.org/security/hash;1"]. - createInstance(Ci.nsICryptoHash); - hasher.initWithString(hashFunction); - - let bytes; - do { - bytes = yield file.read(HASH_CHUNK_SIZE); - hasher.update(bytes, bytes.length); - } while (bytes.length == HASH_CHUNK_SIZE); - - return binaryToHex(hasher.finish(false)); - } - finally { - yield file.close(); - } -}); - -/** - * Verifies that a downloaded file matches what was expected. - * - * @param properties - * The properties to check, `size` and `hashFunction` with `hashValue` - * are supported. Any properties missing won't be checked. - * @param path - * The path of the file to check. - * @return a promise that resolves if the file matched or rejects with a JS - * exception in case of error. - */ -var verifyFile = Task.async(function*(properties, path) { - if (properties.size !== undefined) { - let stat = yield OS.File.stat(path); - if (stat.size != properties.size) { - throw new Error("Downloaded file was " + stat.size + " bytes but expected " + properties.size + " bytes."); - } - } - - if (properties.hashFunction !== undefined) { - let expectedDigest = properties.hashValue.toLowerCase(); - let digest = yield computeHash(properties.hashFunction, path); - if (digest != expectedDigest) { - throw new Error("Hash was `" + digest + "` but expected `" + expectedDigest + "`."); - } - } -}); - -const ProductAddonChecker = { - /** - * Downloads a list of add-ons from a URL optionally testing the SSL - * certificate for certain attributes. - * - * @param url - * The url to download from. - * @param allowNonBuiltIn - * Whether to trust SSL certificates without a built-in CA issuer. - * @param allowedCerts - * The list of certificate attributes to match the SSL certificate - * against or null to skip checks. - * @return a promise that resolves to an object containing the list of add-ons - * and whether the local fallback was used, or rejects with a JS - * exception in case of error. - */ - getProductAddonList: function(url, allowNonBuiltIn = false, allowedCerts = null) { - if (!GMPPrefs.get(GMPPrefs.KEY_UPDATE_ENABLED, true)) { - logger.info("Updates are disabled via media.gmp-manager.updateEnabled"); - return Promise.resolve({usedFallback: true, gmpAddons: []}); - } - - return downloadXML(url, allowNonBuiltIn, allowedCerts) - .then(parseXML) - .catch(downloadLocalConfig); - }, - - /** - * Downloads an add-on to a local file and checks that it matches the expected - * file. The caller is responsible for deleting the temporary file returned. - * - * @param addon - * The addon to download. - * @return a promise that resolves to the temporary file downloaded or rejects - * with a JS exception in case of error. - */ - downloadAddon: Task.async(function*(addon) { - let path = yield downloadFile(addon.URL); - try { - yield verifyFile(addon, path); - return path; - } - catch (e) { - yield OS.File.remove(path); - throw e; - } - }) -} diff --git a/components/global/content/process-content.js b/components/global/content/process-content.js index 2ff8f908a..9d7e37100 100644 --- a/components/global/content/process-content.js +++ b/components/global/content/process-content.js @@ -14,13 +14,6 @@ Cu.import("resource://gre/modules/Services.jsm"); const gInContentProcess = Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT; -Services.cpmm.addMessageListener("gmp-plugin-crash", msg => { - let gmpservice = Cc["@mozilla.org/gecko-media-plugin-service;1"] - .getService(Ci.mozIGeckoMediaPluginService); - - gmpservice.RunPluginCrashCallbacks(msg.data.pluginID, msg.data.pluginName); -}); - if (gInContentProcess) { let ProcessObserver = { TOPICS: [ |