diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 75a0f290c49b..4f7eaec8ea65 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -2104,10 +2104,17 @@ pref("identity.fxaccounts.telemetry.clientAssociationPing.enabled", true); // unsupported. #ifdef MOZ_WIDEVINE_EME + pref("media.gmp-manager.chromium-update-url", "https://update.googleapis.com/service/update2/crx?response=redirect&x=id%3D%GUID%%26uc&acceptformat=crx3&updaterversion=999"); pref("media.gmp-widevinecdm.visible", true); pref("media.gmp-widevinecdm.enabled", true); + pref("media.gmp-widevinecdm.chromium-guid", "oimompecagnajdejgnnjijobebaeigek"); + pref("media.gmp-widevinecdm.force-chromium-update", false); + pref("media.gmp-widevinecdm.force-chromium-beta", false); #if defined(MOZ_WMF_CDM) && defined(_M_AMD64) pref("media.gmp-widevinecdm-l1.forceInstall", false); + pref("media.gmp-widevinecdm-l1.chromium-guid", "neifaoindggfcjicffkgpmnlppeffabd"); + pref("media.gmp-widevinecdm-l1.force-chromium-update", false); + pref("media.gmp-widevinecdm-l1.force-chromium-beta", false); #ifdef NIGHTLY_BUILD pref("media.gmp-widevinecdm-l1.visible", true); pref("media.gmp-widevinecdm-l1.enabled", true); diff --git a/toolkit/modules/GMPInstallManager.sys.mjs b/toolkit/modules/GMPInstallManager.sys.mjs index 32355418a1ec..5d851053f389 100644 --- a/toolkit/modules/GMPInstallManager.sys.mjs +++ b/toolkit/modules/GMPInstallManager.sys.mjs @@ -59,6 +59,27 @@ function getLocalSources() { return []; } +function redirectChromiumUpdateService(uri) { + let log = getScopedLogger("GMPInstallManager.checkForAddons"); + log.info("fetching redirect from: " + uri); + return new Promise((resolve, reject) => { + let xmlHttp = new lazy.ServiceRequest({ mozAnon: true }); + + xmlHttp.onload = function () { + resolve(this.responseURL); + }; + + xmlHttp.onerror = function (e) { + reject("Fetching " + uri + " results in error code: " + e.target.status); + }; + + xmlHttp.open("GET", uri); + xmlHttp.overrideMimeType("*/*"); + xmlHttp.setRequestHeader("Range", "bytes=0-0"); + xmlHttp.send(); + }); +} + function downloadJSON(uri) { let log = getScopedLogger("GMPInstallManager.checkForAddons"); log.info("fetching config from: " + uri); @@ -447,6 +468,72 @@ GMPInstallManager.prototype = { log.info("Failed to force addons: " + err); } + // Now let's check the addons that we are configured to override to go + // directly to the Chromium component update service. + try { + for (let gmpAddon of addons) { + if ( + !GMPPrefs.getBool( + GMPPrefs.KEY_PLUGIN_FORCE_CHROMIUM_UPDATE, + false, + gmpAddon.id + ) + ) { + continue; + } + + const guid = GMPPrefs.getString( + GMPPrefs.KEY_PLUGIN_CHROMIUM_GUID, + "", + gmpAddon.id + ); + if (guid === "") { + log.warn("Skipping chromium update, missing GUID for ", gmpAddon.id); + continue; + } + + const params = GMPUtils._getChromiumUpdateParameters(gmpAddon); + const serviceUrl = GMPPrefs.getString( + GMPPrefs.KEY_CHROMIUM_UPDATE_URL, + "" + ); + const redirectUrl = await redirectChromiumUpdateService( + serviceUrl.replace("%GUID%", guid) + params + ); + const versionMatch = redirectUrl.match(/_(\d+\.\d+\.\d+\.\d+)\//); + if (!versionMatch || versionMatch.length !== 2) { + log.warn( + "Skipping chromium update, no version from URL: ", + redirectUrl + ); + continue; + } + + const version = versionMatch[1]; + log.info( + "Forcing " + + gmpAddon.id + + " to version " + + version + + " from chromium update " + + redirectUrl + ); + + // Update the addon with the final URL and the extracted version. + gmpAddon.URL = redirectUrl; + gmpAddon.version = version; + gmpAddon.usedChromiumUpdate = true; + + // Delete these properties to avoid verifying the addon against our + // balrog configuration, which may or may not match. + delete gmpAddon.size; + delete gmpAddon.hash; + delete gmpAddon.hashFunction; + } + } catch (err) { + log.info("Failed to switch addons to Chromium update service: " + err); + } + this._deferred.resolve({ addons }); delete this._deferred; return deferredPromise; @@ -669,6 +756,7 @@ GMPInstallManager.prototype = { export function GMPAddon(addon) { let log = getScopedLogger("GMPAddon.constructor"); this.usedFallback = false; + this.usedChromiumUpdate = false; for (let name of Object.keys(addon)) { this[name] = addon[name]; } @@ -704,18 +792,18 @@ GMPAddon.prototype = { this.id && this.URL && this.version && - this.hashFunction && - !!this.hashValue + (this.usedChromiumUpdate || (this.hashFunction && !!this.hashValue)) ); }, get isInstalled() { return ( this.version && - !!this.hashValue && GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION, "", this.id) === this.version && - GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_HASHVALUE, "", this.id) === - this.hashValue + (this.usedChromiumUpdate || + (!!this.hashValue && + GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_HASHVALUE, "", this.id) === + this.hashValue)) ); }, get isEME() { @@ -849,12 +937,16 @@ GMPDownloader.prototype = { log.info("Setting ABI to '" + abi + "' for " + gmpAddon.id); GMPPrefs.setString(GMPPrefs.KEY_PLUGIN_ABI, abi, gmpAddon.id); // We use the combination of the hash and version to ensure we are - // up to date. - GMPPrefs.setString( - GMPPrefs.KEY_PLUGIN_HASHVALUE, - gmpAddon.hashValue, - gmpAddon.id - ); + // up to date. Ignored if we used the Chromium update service directly. + if (!gmpAddon.usedChromiumUpdate) { + GMPPrefs.setString( + GMPPrefs.KEY_PLUGIN_HASHVALUE, + gmpAddon.hashValue, + gmpAddon.id + ); + } else { + GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_HASHVALUE, gmpAddon.id); + } // Setting the version pref signals installation completion to consumers, // if you need to set other prefs etc. do it before this. GMPPrefs.setString( diff --git a/toolkit/modules/GMPUtils.sys.mjs b/toolkit/modules/GMPUtils.sys.mjs index e2fee781e18c..0522560f4301 100644 --- a/toolkit/modules/GMPUtils.sys.mjs +++ b/toolkit/modules/GMPUtils.sys.mjs @@ -101,6 +101,42 @@ export var GMPUtils = { ); }, + _getChromiumUpdateParameters(aPlugin) { + let params = ""; + if (AppConstants.platform === "win") { + params += "&os=win"; + } else if (AppConstants.platform === "macosx") { + params += "&os=mac"; + } else if (AppConstants.platform === "linux") { + params += "&os=Linux"; + } else { + throw new Error("Unknown platform " + AppConstants.platform); + } + + const abi = Services.appinfo.XPCOMABI; + if (abi.match(/aarch64/)) { + params += "&arch=arm64&os_arch=arm64"; + } else if (abi.match(/x86_64/)) { + params += "&arch=x64&os_arch=x64"; + } else if (abi.match(/x86/)) { + params += "&arch=x86&os_arch=x86"; + } else { + throw new Error("Unknown ABI " + abi); + } + + if ( + GMPPrefs.getBool( + GMPPrefs.KEY_PLUGIN_FORCE_CHROMIUM_BETA, + false, + aPlugin.id + ) + ) { + params += "&testrequest=1"; + } + + return params; + }, + _expectedABI(aPlugin) { let defaultABI = lazy.UpdateUtils.ABI; let expectedABIs = [defaultABI]; @@ -134,9 +170,13 @@ export var GMPPrefs = { KEY_PLUGIN_FORCE_SUPPORTED: "media.{0}.forceSupported", KEY_PLUGIN_FORCE_INSTALL: "media.{0}.forceInstall", KEY_PLUGIN_ALLOW_X64_ON_ARM64: "media.{0}.allow-x64-plugin-on-arm64", + KEY_PLUGIN_CHROMIUM_GUID: "media.{0}.chromium-guid", + KEY_PLUGIN_FORCE_CHROMIUM_UPDATE: "media.{0}.force-chromium-update", + KEY_PLUGIN_FORCE_CHROMIUM_BETA: "media.{0}.force-chromium-beta", KEY_ALLOW_LOCAL_SOURCES: "media.gmp-manager.allowLocalSources", KEY_URL: "media.gmp-manager.url", KEY_URL_OVERRIDE: "media.gmp-manager.url.override", + KEY_CHROMIUM_UPDATE_URL: "media.gmp-manager.chromium-update-url", KEY_CERT_CHECKATTRS: "media.gmp-manager.cert.checkAttributes", KEY_CERT_REQUIREBUILTIN: "media.gmp-manager.cert.requireBuiltIn", KEY_CHECK_CONTENT_SIGNATURE: "media.gmp-manager.checkContentSignature",