diff options
Diffstat (limited to 'toolkit/mozapps')
230 files changed, 2106 insertions, 850 deletions
diff --git a/toolkit/mozapps/defaultagent/BackgroundTask_defaultagent.sys.mjs b/toolkit/mozapps/defaultagent/BackgroundTask_defaultagent.sys.mjs index 691f76c319..c9da853cb5 100644 --- a/toolkit/mozapps/defaultagent/BackgroundTask_defaultagent.sys.mjs +++ b/toolkit/mozapps/defaultagent/BackgroundTask_defaultagent.sys.mjs @@ -100,7 +100,8 @@ const kNotificationAction = Object.freeze({ export async function runBackgroundTask(commandLine) { Services.fog.initializeFOG( undefined, - "firefox.desktop.background.defaultagent" + "firefox.desktop.background.defaultagent", + /* disableInternalPings */ true ); let defaultAgent = Cc["@mozilla.org/default-agent;1"].getService( diff --git a/toolkit/mozapps/defaultagent/nsIWindowsMutex.idl b/toolkit/mozapps/defaultagent/nsIWindowsMutex.idl index 69090aa764..39ab84bf1f 100644 --- a/toolkit/mozapps/defaultagent/nsIWindowsMutex.idl +++ b/toolkit/mozapps/defaultagent/nsIWindowsMutex.idl @@ -36,7 +36,7 @@ interface nsIWindowsMutex : nsISupports * * @return {boolean} true if locked, false if unlocked. */ - bool isLocked(); + boolean isLocked(); /** * Unlocks the mutex. diff --git a/toolkit/mozapps/extensions/.eslintrc.js b/toolkit/mozapps/extensions/.eslintrc.js index 2e1909b8fb..ef31f0780e 100644 --- a/toolkit/mozapps/extensions/.eslintrc.js +++ b/toolkit/mozapps/extensions/.eslintrc.js @@ -14,7 +14,7 @@ module.exports = { "no-unused-vars": [ "error", { - args: "none", + argsIgnorePattern: "^_", vars: "all", }, ], @@ -26,7 +26,7 @@ module.exports = { "no-unused-vars": [ "error", { - args: "none", + argsIgnorePattern: "^_", vars: "local", }, ], diff --git a/toolkit/mozapps/extensions/AbuseReporter.sys.mjs b/toolkit/mozapps/extensions/AbuseReporter.sys.mjs index 0d8df5c9f3..944cef507c 100644 --- a/toolkit/mozapps/extensions/AbuseReporter.sys.mjs +++ b/toolkit/mozapps/extensions/AbuseReporter.sys.mjs @@ -102,7 +102,7 @@ export class AbuseReportError extends Error { async function responseToErrorInfo(response) { return JSON.stringify({ status: response.status, - responseText: await response.text().catch(err => ""), + responseText: await response.text().catch(() => ""), }); } @@ -244,7 +244,7 @@ export const AbuseReporter = { } let errorInfo = await responseToErrorInfo(response).catch( - err => undefined + () => undefined ); if (response.status === 404) { @@ -550,7 +550,7 @@ export const AbuseReporter = { * A string that identify how the report has been triggered. */ class AbuseReport { - constructor({ addon, createErrorType, reportData, reportEntryPoint }) { + constructor({ addon, reportData, reportEntryPoint }) { this[PRIVATE_REPORT_PROPS] = { aborted: false, abortController: new AbortController(), @@ -599,7 +599,7 @@ class AbuseReport { // Leave errorInfo empty if there is no response or fails to // be converted into an error info object. const errorInfo = response - ? await responseToErrorInfo(response).catch(err => undefined) + ? await responseToErrorInfo(response).catch(() => undefined) : undefined; throw new AbuseReportError(errorType, errorInfo); diff --git a/toolkit/mozapps/extensions/AddonContentPolicy.cpp b/toolkit/mozapps/extensions/AddonContentPolicy.cpp index 983935f7c5..90d1283309 100644 --- a/toolkit/mozapps/extensions/AddonContentPolicy.cpp +++ b/toolkit/mozapps/extensions/AddonContentPolicy.cpp @@ -319,7 +319,7 @@ AddonContentPolicy::ValidateAddonCSP(const nsAString& aPolicyString, nsCOMPtr<nsIURI> selfURI; principal->GetURI(getter_AddRefs(selfURI)); RefPtr<nsCSPContext> csp = new nsCSPContext(); - rv = csp->SetRequestContextWithPrincipal(principal, selfURI, u""_ns, 0); + rv = csp->SetRequestContextWithPrincipal(principal, selfURI, ""_ns, 0); NS_ENSURE_SUCCESS(rv, rv); csp->AppendPolicy(aPolicyString, false, false); diff --git a/toolkit/mozapps/extensions/AddonManager.sys.mjs b/toolkit/mozapps/extensions/AddonManager.sys.mjs index c69cf4029e..a07a651895 100644 --- a/toolkit/mozapps/extensions/AddonManager.sys.mjs +++ b/toolkit/mozapps/extensions/AddonManager.sys.mjs @@ -160,7 +160,7 @@ var PrefObserver = { this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); }, - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { if (aTopic == "xpcom-shutdown") { Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); Services.obs.removeObserver(this, "xpcom-shutdown"); @@ -339,7 +339,7 @@ BrowserListener.prototype = { } }, - observe(subject, topic, data) { + observe(subject) { if (subject != this.messageManager) { return; } @@ -349,7 +349,7 @@ BrowserListener.prototype = { this.cancelInstall(); }, - onLocationChange(webProgress, request, location) { + onLocationChange() { if ( this.browser.contentPrincipal && this.principal.subsumes(this.browser.contentPrincipal) @@ -361,19 +361,19 @@ BrowserListener.prototype = { this.cancelInstall(); }, - onDownloadCancelled(install) { + onDownloadCancelled() { this.unregister(); }, - onDownloadFailed(install) { + onDownloadFailed() { this.unregister(); }, - onInstallFailed(install) { + onInstallFailed() { this.unregister(); }, - onInstallEnded(install) { + onInstallEnded() { this.unregister(); }, @@ -553,7 +553,7 @@ var AddonManagerInternal = { this.pendingProviders.add(aProvider); } - return new Promise((resolve, reject) => { + return new Promise(resolve => { logger.debug("Calling shutdown blocker for " + name); resolve(aProvider.shutdown()); }).catch(err => { @@ -1311,7 +1311,7 @@ var AddonManagerInternal = { } updates.push( - new Promise((resolve, reject) => { + new Promise(resolve => { addon.findUpdates( { onUpdateAvailable(aAddon, aInstall) { @@ -3892,7 +3892,7 @@ export var AddonManagerPrivate = { * This can be used as an implementation for Addon.findUpdates() when * no update mechanism is available. */ - callNoUpdateListeners(addon, listener, reason, appVersion, platformVersion) { + callNoUpdateListeners(addon, listener) { if ("onNoCompatibilityUpdateAvailable" in listener) { safeCall(listener.onNoCompatibilityUpdateAvailable.bind(listener), addon); } @@ -4739,7 +4739,7 @@ AMTelemetry = { // Observer Service notification callback. - observe(subject, topic, data) { + observe(subject, topic) { switch (topic) { case "addon-install-blocked": { const { installs } = subject.wrappedJSObject; diff --git a/toolkit/mozapps/extensions/amInstallTrigger.sys.mjs b/toolkit/mozapps/extensions/amInstallTrigger.sys.mjs index 068c0f07c4..b7cabba5b6 100644 --- a/toolkit/mozapps/extensions/amInstallTrigger.sys.mjs +++ b/toolkit/mozapps/extensions/amInstallTrigger.sys.mjs @@ -62,7 +62,7 @@ RemoteMediator.prototype = { } }, - enabled(url) { + enabled() { let params = { mimetype: XPINSTALL_MIMETYPE, }; @@ -237,14 +237,14 @@ InstallTrigger.prototype = { ); }, - startSoftwareUpdate(url, flags) { + startSoftwareUpdate(url) { let filename = Services.io.newURI(url).QueryInterface(Ci.nsIURL).filename; let args = {}; args[filename] = { URL: url }; return this.install(args); }, - installChrome(type, url, skin) { + installChrome(type, url) { return this.startSoftwareUpdate(url); }, diff --git a/toolkit/mozapps/extensions/amManager.sys.mjs b/toolkit/mozapps/extensions/amManager.sys.mjs index 5ce396d601..2571af55e4 100644 --- a/toolkit/mozapps/extensions/amManager.sys.mjs +++ b/toolkit/mozapps/extensions/amManager.sys.mjs @@ -67,7 +67,7 @@ export function amManager() { } amManager.prototype = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { switch (aTopic) { case "addons-startup": AddonManagerPrivate.startup(); @@ -129,7 +129,7 @@ amManager.prototype = { if (aCallback) { aInstall.addListener({ - onDownloadCancelled(aInstall) { + onDownloadCancelled() { callCallback(USER_CANCELLED); }, @@ -141,11 +141,11 @@ amManager.prototype = { } }, - onInstallFailed(aInstall) { + onInstallFailed() { callCallback(EXECUTION_ERROR); }, - onInstallEnded(aInstall, aStatus) { + onInstallEnded() { callCallback(SUCCESS); }, }); @@ -165,7 +165,7 @@ amManager.prototype = { return retval; }, - notify(aTimer) { + notify() { AddonManagerPrivate.backgroundUpdateTimerHandler(); }, diff --git a/toolkit/mozapps/extensions/amWebAPI.sys.mjs b/toolkit/mozapps/extensions/amWebAPI.sys.mjs index abe838af89..ae1b94cac7 100644 --- a/toolkit/mozapps/extensions/amWebAPI.sys.mjs +++ b/toolkit/mozapps/extensions/amWebAPI.sys.mjs @@ -214,7 +214,7 @@ export class WebAPI extends APIObject { super.init(window, broker, {}); - window.addEventListener("unload", event => { + window.addEventListener("unload", () => { this.broker.sendCleanup(this.allInstalls); }); } @@ -263,7 +263,7 @@ export class WebAPI extends APIObject { return lazy.AMO_ABUSEREPORT; } - eventListenerAdded(type) { + eventListenerAdded() { if (this.listenerCount == 0) { this.broker.setAddonListener(data => { let event = new this.window.AddonEvent(data.event, data); @@ -273,7 +273,7 @@ export class WebAPI extends APIObject { this.listenerCount++; } - eventListenerRemoved(type) { + eventListenerRemoved() { this.listenerCount--; if (this.listenerCount == 0) { this.broker.setAddonListener(null); diff --git a/toolkit/mozapps/extensions/content/aboutaddons.html b/toolkit/mozapps/extensions/content/aboutaddons.html index 55d6625c08..d0930ef42d 100644 --- a/toolkit/mozapps/extensions/content/aboutaddons.html +++ b/toolkit/mozapps/extensions/content/aboutaddons.html @@ -13,9 +13,6 @@ content="default-src chrome:; style-src chrome: 'unsafe-inline'; img-src chrome: file: jar: https: http:; connect-src chrome: data: https: http:; object-src 'none'" /> <meta name="color-scheme" content="light dark" /> - <link rel="stylesheet" href="chrome://global/content/tabprompts.css" /> - <link rel="stylesheet" href="chrome://global/skin/tabprompts.css" /> - <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" /> <link rel="stylesheet" diff --git a/toolkit/mozapps/extensions/content/aboutaddons.js b/toolkit/mozapps/extensions/content/aboutaddons.js index 39c4656210..d7d9c28ae6 100644 --- a/toolkit/mozapps/extensions/content/aboutaddons.js +++ b/toolkit/mozapps/extensions/content/aboutaddons.js @@ -322,12 +322,12 @@ function checkForUpdate(addon) { onDownloadFailed: failed, onInstallCancelled: failed, onInstallFailed: failed, - onInstallEnded: (...args) => { + onInstallEnded: () => { detachUpdateHandler(install); install.removeListener(updateListener); resolve({ installed: true, pending: false, found: true }); }, - onInstallPostponed: (...args) => { + onInstallPostponed: () => { detachUpdateHandler(install); install.removeListener(updateListener); resolve({ installed: false, pending: true, found: true }); @@ -375,7 +375,7 @@ const OPTIONS_TYPE_MAP = { // Check if an add-on has the provided options type, accounting for the pref // to disable inline options. -function getOptionsType(addon, type) { +function getOptionsType(addon) { return OPTIONS_TYPE_MAP[addon.optionsType]; } @@ -1064,7 +1064,7 @@ class AddonPageOptions extends HTMLElement { } } - async checkForUpdates(e) { + async checkForUpdates() { let message = document.getElementById("updates-message"); message.state = "updating"; message.hidden = false; @@ -2096,11 +2096,11 @@ class AddonDetails extends HTMLElement { } } - onDisabled(addon) { + onDisabled() { this.extensionShutdown(); } - onEnabled(addon) { + onEnabled() { this.extensionStartup(); } @@ -2451,45 +2451,27 @@ class AddonCard extends HTMLElement { async setAddonPermission(permission, type, action) { let { addon } = this; - let origins = [], - permissions = []; + let perms = { origins: [], permissions: [] }; + if (!["add", "remove"].includes(action)) { throw new Error("invalid action for permission change"); } - if (type == "permission") { - if ( - action == "add" && - !addon.optionalPermissions.permissions.includes(permission) - ) { - throw new Error("permission missing from manifest"); - } - permissions = [permission]; - } else if (type == "origin") { - if (action === "add") { - let { origins } = addon.optionalPermissions; - let patternSet = new MatchPatternSet(origins, { ignorePath: true }); - if (!patternSet.subsumes(new MatchPattern(permission))) { - throw new Error("origin missing from manifest"); - } - } - origins = [permission]; - // If this is one of the "all sites" permissions - if (Extension.isAllSitesPermission(permission)) { - // Grant/revoke ALL "all sites" optional permissions from the manifest. - origins = addon.optionalPermissions.origins.filter(perm => - Extension.isAllSitesPermission(perm) - ); - } + if (type === "permission") { + perms.permissions = [permission]; + } else if (type === "origin") { + perms.origins = [permission]; } else { throw new Error("unknown permission type changed"); } - let policy = WebExtensionPolicy.getByID(addon.id); - ExtensionPermissions[action]( - addon.id, - { origins, permissions }, - policy?.extension + + let normalized = ExtensionPermissions.normalizeOptional( + perms, + addon.optionalPermissions ); + + let policy = WebExtensionPolicy.getByID(addon.id); + ExtensionPermissions[action](addon.id, normalized, policy?.extension); } async handleEvent(e) { @@ -2968,18 +2950,18 @@ class AddonCard extends HTMLElement { this.sendEvent("update-postponed"); } - onDisabled(addon) { + onDisabled() { if (!this.reloading) { this.update(); } } - onEnabled(addon) { + onEnabled() { this.reloading = false; this.update(); } - onInstalled(addon) { + onInstalled() { // When a temporary addon is reloaded, onInstalled is triggered instead of // onEnabled. this.reloading = false; diff --git a/toolkit/mozapps/extensions/content/aboutaddonsCommon.js b/toolkit/mozapps/extensions/content/aboutaddonsCommon.js index 9315e35861..fd91ba58be 100644 --- a/toolkit/mozapps/extensions/content/aboutaddonsCommon.js +++ b/toolkit/mozapps/extensions/content/aboutaddonsCommon.js @@ -5,7 +5,7 @@ "use strict"; -/* exported attachUpdateHandler, detachUpdateHandler, gBrowser, +/* exported attachUpdateHandler, detachUpdateHandler, * getBrowserElement, installAddonsFromFilePicker, * isCorrectlySigned, isDisabledUnsigned, isDiscoverEnabled, * isPending, loadReleaseNotes, openOptionsInTab, promiseEvent, @@ -196,21 +196,6 @@ function showPermissionsPrompt(addon) { }); } -// Stub tabbrowser implementation for use by the tab-modal alert code -// when an alert/prompt/confirm method is called in a WebExtensions options_ui -// page (See Bug 1385548 for rationale). -var gBrowser = { - getTabModalPromptBox(browser) { - const parentWindow = window.docShell.chromeEventHandler.ownerGlobal; - - if (parentWindow.gBrowser) { - return parentWindow.gBrowser.getTabModalPromptBox(browser); - } - - return null; - }, -}; - function isCorrectlySigned(addon) { // Add-ons without an "isCorrectlySigned" property are correctly signed as // they aren't the correct type for signing. diff --git a/toolkit/mozapps/extensions/content/abuse-reports.js b/toolkit/mozapps/extensions/content/abuse-reports.js index c6461a071b..38fa0f9f46 100644 --- a/toolkit/mozapps/extensions/content/abuse-reports.js +++ b/toolkit/mozapps/extensions/content/abuse-reports.js @@ -185,7 +185,7 @@ async function openAbuseReport({ addonId, reportEntryPoint }) { // to be async, but it is so that both the implementations will be providing // the same type signatures (returning a promise) to the callers, independently // from which abuse reporting feature is enabled. -async function openAbuseReportAMOForm({ addonId, reportEntryPoint }) { +async function openAbuseReportAMOForm({ addonId }) { const amoUrl = AbuseReporter.getAMOFormURL({ addonId }); windowRoot.ownerGlobal.openTrustedLinkIn(amoUrl, "tab", { // Make sure the newly open tab is going to be focused, independently diff --git a/toolkit/mozapps/extensions/content/shortcuts.js b/toolkit/mozapps/extensions/content/shortcuts.js index 59420226df..99ab1c5161 100644 --- a/toolkit/mozapps/extensions/content/shortcuts.js +++ b/toolkit/mozapps/extensions/content/shortcuts.js @@ -283,7 +283,7 @@ ChromeUtils.defineESModuleGetters(this, { } return Object.entries(modifierMap) - .filter(([key, isDown]) => isDown) + .filter(([, isDown]) => isDown) .map(([key]) => key) .concat(getStringForEvent(e)) .join("+"); diff --git a/toolkit/mozapps/extensions/content/view-controller.js b/toolkit/mozapps/extensions/content/view-controller.js index 978a44d176..b82c1d6e6d 100644 --- a/toolkit/mozapps/extensions/content/view-controller.js +++ b/toolkit/mozapps/extensions/content/view-controller.js @@ -89,7 +89,7 @@ var gViewController = { } }, - observe(subject, topic, data) { + observe(subject, topic) { if (topic == "EM-ping") { this.readyForLoadView = true; Services.obs.notifyObservers(window, "EM-pong"); diff --git a/toolkit/mozapps/extensions/internal/AddonRepository.sys.mjs b/toolkit/mozapps/extensions/internal/AddonRepository.sys.mjs index e53e4af7a4..8d4d178924 100644 --- a/toolkit/mozapps/extensions/internal/AddonRepository.sys.mjs +++ b/toolkit/mozapps/extensions/internal/AddonRepository.sys.mjs @@ -466,13 +466,13 @@ export var AddonRepository = { request.open("GET", url, true); request.responseType = "json"; - request.addEventListener("error", aEvent => { + request.addEventListener("error", () => { reject(new Error(`GET ${url} failed`)); }); - request.addEventListener("timeout", aEvent => { + request.addEventListener("timeout", () => { reject(new Error(`GET ${url} timed out`)); }); - request.addEventListener("load", aEvent => { + request.addEventListener("load", () => { let response = request.response; if (!response || (request.status != 200 && request.status != 0)) { reject(new Error(`GET ${url} failed (status ${request.status})`)); diff --git a/toolkit/mozapps/extensions/internal/AddonTestUtils.sys.mjs b/toolkit/mozapps/extensions/internal/AddonTestUtils.sys.mjs index f53d32092d..7e4adacd11 100644 --- a/toolkit/mozapps/extensions/internal/AddonTestUtils.sys.mjs +++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.sys.mjs @@ -3,7 +3,7 @@ */ /* eslint "mozilla/no-aArgs": 1 */ -/* eslint "no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}] */ +/* eslint "no-unused-vars": [2, {"argsIgnorePattern": "^_", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}] */ /* eslint "semi": [2, "always"] */ /* eslint "valid-jsdoc": [2, {requireReturn: false}] */ @@ -424,6 +424,35 @@ export var AddonTestUtils = { }); }, + getXPIExports() { + return ChromeUtils.importESModule( + "resource://gre/modules/addons/XPIExports.sys.mjs" + ).XPIExports; + }, + + getWeakSignatureInstallPrefName() { + return this.getXPIExports().XPIInstall.getWeakSignatureInstallPrefName(); + }, + + setWeakSignatureInstallAllowed(allowed) { + const prefName = this.getWeakSignatureInstallPrefName(); + let cleanupCalled = false; + const cleanup = () => { + if (cleanupCalled) { + return; + } + this.testScope.info( + `=== clear ${prefName} pref value set by this test file ===` + ); + Services.prefs.clearUserPref(prefName); + cleanupCalled = true; + }; + this.testScope.registerCleanupFunction(cleanup); + this.testScope.info(`=== set ${prefName} pref value to ${allowed} ===`); + Services.prefs.setBoolPref(prefName, allowed); + return cleanup; + }, + /** * Iterates over the entries in a given directory. * diff --git a/toolkit/mozapps/extensions/internal/GMPProvider.sys.mjs b/toolkit/mozapps/extensions/internal/GMPProvider.sys.mjs index aaac109fc0..22ca2365d1 100644 --- a/toolkit/mozapps/extensions/internal/GMPProvider.sys.mjs +++ b/toolkit/mozapps/extensions/internal/GMPProvider.sys.mjs @@ -340,7 +340,7 @@ GMPWrapper.prototype = { return { source: "gmp-plugin" }; }, - isCompatibleWith(aAppVersion, aPlatformVersion) { + isCompatibleWith() { return true; }, @@ -377,7 +377,7 @@ GMPWrapper.prototype = { * Widevine is not yet installed, or if the user toggles prefs to enable EME. * For the function used in those cases see `checkForUpdates`. */ - findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) { + findUpdates(aListener, aReason) { this._log.trace( "findUpdates() - " + this._plugin.id + " - reason=" + aReason ); @@ -895,7 +895,7 @@ var GMPProvider = { } }, - observe(subject, topic, data) { + observe(subject, topic) { if (topic == FIRST_CONTENT_PROCESS_TOPIC) { lazy.AddonManagerPrivate.registerProvider(GMPProvider, ["plugin"]); Services.obs.notifyObservers(null, "gmp-provider-registered"); diff --git a/toolkit/mozapps/extensions/internal/ProductAddonChecker.sys.mjs b/toolkit/mozapps/extensions/internal/ProductAddonChecker.sys.mjs index 1615a551c8..64b337af3f 100644 --- a/toolkit/mozapps/extensions/internal/ProductAddonChecker.sys.mjs +++ b/toolkit/mozapps/extensions/internal/ProductAddonChecker.sys.mjs @@ -118,12 +118,18 @@ async function conservativeFetch(input) { * @param contentSignatureHeader * The contents of the 'content-signature' header received along with * `data`. + * @param trustedRoot + * The identifier of the trusted root to use for certificate validation. * @return A promise that will resolve to nothing if the signature verification * succeeds, or rejects on failure, with an Error that sets its * addonCheckerErr property disambiguate failure cases and a message * explaining the error. */ -async function verifyGmpContentSignature(data, contentSignatureHeader) { +async function verifyGmpContentSignature( + data, + contentSignatureHeader, + trustedRoot +) { if (!contentSignatureHeader) { logger.warn( "Unexpected missing content signature header during content signature validation" @@ -186,13 +192,6 @@ async function verifyGmpContentSignature(data, contentSignatureHeader) { "@mozilla.org/security/contentsignatureverifier;1" ].createInstance(Ci.nsIContentSignatureVerifier); - // See bug 1771992. In the future, this may need to handle staging and dev - // environments in addition to just production and testing. - let root = Ci.nsIContentSignatureVerifier.ContentSignatureProdRoot; - if (Services.env.exists("XPCSHELL_TEST_PROFILE_DIR")) { - root = Ci.nsIX509CertDB.AppXPCShellRoot; - } - let valid; try { valid = await verifier.asyncVerifyContentSignature( @@ -200,7 +199,7 @@ async function verifyGmpContentSignature(data, contentSignatureHeader) { signature, certChain, "aus.content-signature.mozilla.org", - root + trustedRoot ); } catch (err) { logger.warn(`Unexpected error while validating content signature: ${err}`); @@ -329,6 +328,9 @@ function downloadXMLWithRequest( * @param verifyContentSignature * When true, will verify the content signature information from the * response header. Failure to verify will result in an error. + * @param trustedContentSignatureRoot + * The trusted root to use for certificate validation. + * Must be set if verifyContentSignature is true. * @return a promise that resolves to the DOM document downloaded or rejects * with a JS exception in case of error. */ @@ -336,7 +338,8 @@ async function downloadXML( url, allowNonBuiltIn = false, allowedCerts = null, - verifyContentSignature = false + verifyContentSignature = false, + trustedContentSignatureRoot = null ) { let request = await downloadXMLWithRequest( url, @@ -346,7 +349,8 @@ async function downloadXML( if (verifyContentSignature) { await verifyGmpContentSignature( request.response, - request.getResponseHeader("content-signature") + request.getResponseHeader("content-signature"), + trustedContentSignatureRoot ); } return request.responseXML; @@ -422,7 +426,7 @@ function downloadFile(url, options = { httpsOnlyNoUpgrade: false }) { return new Promise((resolve, reject) => { let sr = new lazy.ServiceRequest(); - sr.onload = function (response) { + sr.onload = function () { logger.info("downloadFile File download. status=" + sr.status); if (sr.status != 200 && sr.status != 206) { reject(Components.Exception("File download failed", sr.status)); @@ -535,6 +539,9 @@ export const ProductAddonChecker = { * @param verifyContentSignature * When true, will verify the content signature information from the * response header. Failure to verify will result in an error. + * @param trustedContentSignatureRoot + * The trusted root to use for certificate validation. + * Must be set if verifyContentSignature is true. * @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. In the case of an error, a best effort @@ -545,13 +552,15 @@ export const ProductAddonChecker = { url, allowNonBuiltIn = false, allowedCerts = null, - verifyContentSignature = false + verifyContentSignature = false, + trustedContentSignatureRoot = null ) { return downloadXML( url, allowNonBuiltIn, allowedCerts, - verifyContentSignature + verifyContentSignature, + trustedContentSignatureRoot ).then(parseXML); }, diff --git a/toolkit/mozapps/extensions/internal/SitePermsAddonProvider.sys.mjs b/toolkit/mozapps/extensions/internal/SitePermsAddonProvider.sys.mjs index 7ca952dc8a..8af3c2affe 100644 --- a/toolkit/mozapps/extensions/internal/SitePermsAddonProvider.sys.mjs +++ b/toolkit/mozapps/extensions/internal/SitePermsAddonProvider.sys.mjs @@ -190,7 +190,7 @@ class SitePermsAddonWrapper { return 0; } - async updateBlocklistState(options = {}) {} + async updateBlocklistState() {} get blocklistState() { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; @@ -277,7 +277,7 @@ class SitePermsAddonWrapper { return { source: "siteperm-addon-provider", method: "synthetic-install" }; } - isCompatibleWith(aAppVersion, aPlatformVersion) { + isCompatibleWith() { return true; } } diff --git a/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs b/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs index af0b02444a..d7541167fa 100644 --- a/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs +++ b/toolkit/mozapps/extensions/internal/XPIDatabase.sys.mjs @@ -31,6 +31,7 @@ ChromeUtils.defineESModuleGetters(lazy, { DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs", ExtensionData: "resource://gre/modules/Extension.sys.mjs", ExtensionUtils: "resource://gre/modules/ExtensionUtils.sys.mjs", + ObjectUtils: "resource://gre/modules/ObjectUtils.sys.mjs", PermissionsUtils: "resource://gre/modules/PermissionsUtils.sys.mjs", QuarantinedDomains: "resource://gre/modules/ExtensionPermissions.sys.mjs", }); @@ -192,6 +193,7 @@ const PROP_JSON_FIELDS = [ "targetApplications", "targetPlatforms", "signedState", + "signedTypes", "signedDate", "seen", "dependencies", @@ -1556,6 +1558,7 @@ function defineAddonWrapperProperty(name, getter) { "validInstallOrigins", "dependencies", "signedState", + "signedTypes", "sitePermissions", "siteOrigin", "isCorrectlySigned", @@ -2175,7 +2178,7 @@ export const XPIDatabase = { */ async verifySignatures() { try { - let addons = await this.getAddonList(a => true); + let addons = await this.getAddonList(() => true); let changes = { enabled: [], @@ -2188,17 +2191,31 @@ export const XPIDatabase = { continue; } - let signedState = await XPIExports.verifyBundleSignedState( - addon._sourceBundle, - addon - ); + let { signedState, signedTypes } = + await XPIExports.verifyBundleSignedState(addon._sourceBundle, addon); + + const changedProperties = []; if (signedState != addon.signedState) { addon.signedState = signedState; + changedProperties.push("signedState"); + } + + if ( + !lazy.ObjectUtils.deepEqual( + signedTypes?.toSorted(), + addon.signedTypes?.toSorted() + ) + ) { + addon.signedTypes = signedTypes; + changedProperties.push("signedTypes"); + } + + if (changedProperties.length) { lazy.AddonManagerPrivate.callAddonListeners( "onPropertyChanged", addon.wrapper, - ["signedState"] + changedProperties ); } @@ -2426,7 +2443,7 @@ export const XPIDatabase = { if (!this.addonDB) { return []; } - return _filterDB(this.addonDB, aAddon => true); + return _filterDB(this.addonDB, () => true); }, /** @@ -3084,24 +3101,11 @@ export const XPIDatabaseReconcile = { * The new state of the add-on * @param {AddonInternal?} [aNewAddon] * The manifest for the new add-on if it has already been loaded - * @param {string?} [aOldAppVersion] - * The version of the application last run with this profile or null - * if it is a new profile or the version is unknown - * @param {string?} [aOldPlatformVersion] - * The version of the platform last run with this profile or null - * if it is a new profile or the version is unknown * @returns {boolean} * A boolean indicating if flushing caches is required to complete * changing this add-on */ - addMetadata( - aLocation, - aId, - aAddonState, - aNewAddon, - aOldAppVersion, - aOldPlatformVersion - ) { + addMetadata(aLocation, aId, aAddonState, aNewAddon) { logger.debug(`New add-on ${aId} installed in ${aLocation.name}`); // We treat this is a new install if, @@ -3348,6 +3352,10 @@ export const XPIDatabaseReconcile = { let signedDateMissing = aOldAddon.signedDate === undefined && (aOldAddon.signedState || checkSigning); + // signedTypes must be set if signedState is set. + let signedTypesMissing = + aOldAddon.signedTypes === undefined && + (aOldAddon.signedState || checkSigning); // If maxVersion was inadvertently updated for a locale, force a reload // from the manifest. See Bug 1646016 for details. @@ -3360,7 +3368,12 @@ export const XPIDatabaseReconcile = { } let manifest = null; - if (checkSigning || aReloadMetadata || signedDateMissing) { + if ( + checkSigning || + aReloadMetadata || + signedDateMissing || + signedTypesMissing + ) { try { manifest = XPIExports.XPIInstall.syncLoadManifest( aAddonState, @@ -3384,6 +3397,10 @@ export const XPIDatabaseReconcile = { aOldAddon.signedDate = manifest.signedDate; } + if (signedTypesMissing) { + aOldAddon.signedTypes = manifest.signedTypes; + } + // May be updating from a version of the app that didn't support all the // properties of the currently-installed add-ons. if (aReloadMetadata) { diff --git a/toolkit/mozapps/extensions/internal/XPIInstall.sys.mjs b/toolkit/mozapps/extensions/internal/XPIInstall.sys.mjs index 0402c2f2ca..4a26785da8 100644 --- a/toolkit/mozapps/extensions/internal/XPIInstall.sys.mjs +++ b/toolkit/mozapps/extensions/internal/XPIInstall.sys.mjs @@ -21,6 +21,7 @@ import { XPIExports } from "resource://gre/modules/addons/XPIExports.sys.mjs"; import { computeSha256HashAsString, getHashStringForCrypto, + hasStrongSignature, } from "resource://gre/modules/addons/crypto-utils.sys.mjs"; import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; import { @@ -94,6 +95,9 @@ const PREF_XPI_ENABLED = "xpinstall.enabled"; const PREF_XPI_DIRECT_WHITELISTED = "xpinstall.whitelist.directRequest"; const PREF_XPI_FILE_WHITELISTED = "xpinstall.whitelist.fileRequest"; const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required"; +const PREF_XPI_WEAK_SIGNATURES_ALLOWED = + "xpinstall.signatures.weakSignaturesTemporarilyAllowed"; +const PREF_XPI_WEAK_SIGNATURES_ALLOWED_DEFAULT = true; const PREF_SELECTED_THEME = "extensions.activeThemeID"; @@ -230,7 +234,15 @@ class Package { let root = Ci.nsIX509CertDB.AddonsPublicRoot; if ( - !AppConstants.MOZ_REQUIRE_SIGNING && + (!AppConstants.MOZ_REQUIRE_SIGNING || + // Allow mochitests to switch to dev-root on all channels. + Cu.isInAutomation || + // Allow xpcshell tests to switch to dev-root on all channels, + // included tests where "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer" + // pref is set to false and Cu.isInAutomation is going to be false (e.g. test_signed_langpack.js). + // TODO(Bug 1598804): we should be able to remove the following checks once Cu.isAutomation is fixed. + (Services.env.exists("XPCSHELL_TEST_PROFILE_DIR") && + Services.appinfo.name === "XPCShell")) && Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false) ) { root = Ci.nsIX509CertDB.AddonsStageRoot; @@ -287,7 +299,7 @@ DirPackage = class DirPackage extends Package { return IOUtils.read(PathUtils.join(this.filePath, ...path)); } - async verifySignedStateForRoot(addonId, root) { + async verifySignedStateForRoot() { return { signedState: AddonManager.SIGNEDSTATE_UNKNOWN, cert: null }; } }; @@ -341,8 +353,11 @@ XPIPackage = class XPIPackage extends Package { aZipReader.close(); } resolve({ - signedState: getSignedStatus(aRv, cert, addonId), cert, + signedState: getSignedStatus(aRv, cert, addonId), + signedTypes: aSignatureInfos?.map( + signatureInfo => signatureInfo.signatureAlgorithm + ), }); }, }; @@ -511,17 +526,18 @@ async function loadManifestFromWebManifest(aPackage, aLocation) { addon.siteOrigin = manifest.install_origins[0]; } - if (manifest.options_ui) { + const { optionsPageProperties } = extension; + if (optionsPageProperties) { // Store just the relative path here, the AddonWrapper getURL // wrapper maps this to a full URL. - addon.optionsURL = manifest.options_ui.page; - if (manifest.options_ui.open_in_tab) { + addon.optionsURL = optionsPageProperties.page; + if (optionsPageProperties.open_in_tab) { addon.optionsType = AddonManager.OPTIONS_TYPE_TAB; } else { addon.optionsType = AddonManager.OPTIONS_TYPE_INLINE_BROWSER; } - addon.optionsBrowserStyle = manifest.options_ui.browser_style; + addon.optionsBrowserStyle = optionsPageProperties.browser_style; } // WebExtensions don't use iconURLs @@ -693,9 +709,13 @@ var loadManifest = async function (aPackage, aLocation, aOldAddon) { addon.rootURI = aPackage.rootURI.spec; addon.location = aLocation; - let { signedState, cert } = verifiedSignedState; + let { cert, signedState, signedTypes } = verifiedSignedState; addon.signedState = signedState; addon.signedDate = cert?.validity?.notBefore / 1000 || null; + // An array of the algorithms used by the signatures found in the signed XPI files, + // as an array of integers (see nsIAppSignatureInfo_SignatureAlgorithm enum defined + // in nsIX509CertDB.idl). + addon.signedTypes = signedTypes; if (!addon.id) { if (cert) { @@ -909,18 +929,21 @@ function shouldVerifySignedState(aAddonType, aLocation) { * The nsIFile for the bundle to check, either a directory or zip file. * @param {AddonInternal} aAddon * The add-on object to verify. - * @returns {Promise<number>} - * A Promise that resolves to an AddonManager.SIGNEDSTATE_* constant. + * @returns {Promise<{ signedState: number, signedTypes: Array<number>}>?} + * A Promise that resolves to object including a signedState property set to + * an AddonManager.SIGNEDSTATE_* constant and a signedTypes property set to + * either an array of Ci.nsIAppSignatureInfo SignatureAlgorithm enum values + * or undefined if the file wasn't signed. */ export var verifyBundleSignedState = async function (aBundle, aAddon) { let pkg = Package.get(aBundle); try { - let { signedState } = await pkg.verifySignedState( + let { signedState, signedTypes } = await pkg.verifySignedState( aAddon.id, aAddon.type, aAddon.location ); - return signedState; + return { signedState, signedTypes }; } finally { pkg.close(); } @@ -1633,6 +1656,49 @@ class AddonInstall { "signature verification failed", ]); } + + // Restrict install for signed extension only signed with weak signature algorithms, unless the + // restriction is explicitly disabled through prefs or enterprise policies. + if ( + !XPIInstall.isWeakSignatureInstallAllowed() && + this.addon.signedDate && + !hasStrongSignature(this.addon) + ) { + const addonAllowedByPolicies = Services.policies.getExtensionSettings( + this.addon.id + )?.temporarily_allow_weak_signatures; + + const globallyAllowedByPolicies = + Services.policies.getExtensionSettings( + "*" + )?.temporarily_allow_weak_signatures; + + const allowedByPolicies = + (globallyAllowedByPolicies && + (addonAllowedByPolicies || addonAllowedByPolicies == null)) || + addonAllowedByPolicies; + + if ( + !allowedByPolicies && + (!this.existingAddon || hasStrongSignature(this.existingAddon)) + ) { + // Reject if it is a new install or installing over an existing addon including + // strong cryptographic signatures. + return Promise.reject([ + AddonManager.ERROR_CORRUPT_FILE, + "install rejected due to the package not including a strong cryptographic signature", + ]); + } + + // Still allow installs using weak signatures to install if either: + // - it is explicitly allowed through Enterprise Policies Settings + // - or there is an existing addon with a weak signature. + logger.warn( + allowedByPolicies + ? `Allow weak signature install for ${this.addon.id} XPI due to Enterprise Policies` + : `Allow weak signature install over existing "${this.existingAddon.id}" XPI` + ); + } } } finally { pkg.close(); @@ -2321,7 +2387,7 @@ var DownloadAddonInstall = class extends AddonInstall { } } - observe(aSubject, aTopic, aData) { + observe() { // Network is going offline this.cancel(); } @@ -2592,7 +2658,7 @@ var DownloadAddonInstall = class extends AddonInstall { new UpdateChecker( this.addon, { - onUpdateFinished: aAddon => this.downloadCompleted(), + onUpdateFinished: () => this.downloadCompleted(), }, AddonManager.UPDATE_WHEN_ADDON_INSTALLED ); @@ -3880,7 +3946,7 @@ class SystemAddonInstaller extends DirectoryInstaller { } // old system add-on upgrade dirs get automatically removed - uninstallAddon(aAddon) {} + uninstallAddon() {} } var AppUpdate = { @@ -4344,6 +4410,17 @@ export var XPIInstall = { return Services.prefs.getBoolPref(PREF_XPI_FILE_WHITELISTED, true); }, + isWeakSignatureInstallAllowed() { + return Services.prefs.getBoolPref( + PREF_XPI_WEAK_SIGNATURES_ALLOWED, + PREF_XPI_WEAK_SIGNATURES_ALLOWED_DEFAULT + ); + }, + + getWeakSignatureInstallPrefName() { + return PREF_XPI_WEAK_SIGNATURES_ALLOWED; + }, + /** * Called to test whether installing XPI add-ons from a URI is allowed. * diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.sys.mjs b/toolkit/mozapps/extensions/internal/XPIProvider.sys.mjs index 12d4fa1172..3c090b5f0f 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.sys.mjs +++ b/toolkit/mozapps/extensions/internal/XPIProvider.sys.mjs @@ -120,7 +120,7 @@ const XPI_PERMISSION = "install"; const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60; -const DB_SCHEMA = 35; +const DB_SCHEMA = 36; XPCOMUtils.defineLazyPreferenceGetter( lazy, @@ -1598,7 +1598,7 @@ var XPIStates = { * * @returns {XPIState?} */ - findAddon(aId, aFilter = location => true) { + findAddon(aId, aFilter = () => true) { // Fortunately the Map iterator returns in order of insertion, which is // also our highest -> lowest priority order. for (let location of this.locations()) { @@ -2706,7 +2706,7 @@ export var XPIProvider = { "profile-before-change", "test-load-xpi-database", ]; - let observer = (subject, topic, data) => { + let observer = (subject, topic) => { if ( topic == "xul-window-visible" && !Services.wm.getMostRecentWindow("devtools:toolbox") diff --git a/toolkit/mozapps/extensions/internal/crypto-utils.sys.mjs b/toolkit/mozapps/extensions/internal/crypto-utils.sys.mjs index b1304bcdfc..9ef096df0f 100644 --- a/toolkit/mozapps/extensions/internal/crypto-utils.sys.mjs +++ b/toolkit/mozapps/extensions/internal/crypto-utils.sys.mjs @@ -8,6 +8,14 @@ const CryptoHash = Components.Constructor( "initWithString" ); +const XPI_WEAK_SIGNATURES = [Ci.nsIAppSignatureInfo.PKCS7_WITH_SHA1]; + +export function hasStrongSignature(addon) { + return !!addon.signedTypes?.filter( + algorithm => !XPI_WEAK_SIGNATURES.includes(algorithm) + ).length; +} + export function computeHashAsString(hashType, input) { const data = new Uint8Array(new TextEncoder().encode(input)); const crypto = CryptoHash(hashType); @@ -42,7 +50,7 @@ export function computeSha1HashAsString(input) { /** * Returns the string representation (hex) of a given CryptoHashInstance. * - * @param {CryptoHash} aCrypto + * @param {nsICryptoHash} aCrypto * @returns {string} * The hex representation of a SHA256 hash. */ diff --git a/toolkit/mozapps/extensions/test/browser/.eslintrc.js b/toolkit/mozapps/extensions/test/browser/.eslintrc.js index f2b9e072f9..6987757bdc 100644 --- a/toolkit/mozapps/extensions/test/browser/.eslintrc.js +++ b/toolkit/mozapps/extensions/test/browser/.eslintrc.js @@ -8,7 +8,7 @@ module.exports = { rules: { "no-unused-vars": [ "error", - { args: "none", varsIgnorePattern: "^end_test$" }, + { argsIgnorePattern: "^_", varsIgnorePattern: "^end_test$" }, ], }, }; diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/manifest.mf b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/manifest.mf deleted file mode 100644 index 725ac8016f..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/manifest.mf +++ /dev/null @@ -1,8 +0,0 @@ -Manifest-Version: 1.0 - -Name: manifest.json -Digest-Algorithms: MD5 SHA1 SHA256 -MD5-Digest: mCLu38qfGN3trj7qKQQeEA== -SHA1-Digest: A1BaJErQY6KqnYDijP0lglrehk0= -SHA256-Digest: p2vjGP7DRqrK81NfT4LqnF7a5p8+lEuout5WLBhk9AA= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/mozilla.rsa b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/mozilla.rsa Binary files differdeleted file mode 100644 index 046a0285c7..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/mozilla.rsa +++ /dev/null diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/mozilla.sf b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/mozilla.sf deleted file mode 100644 index ad4e81b574..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/META-INF/mozilla.sf +++ /dev/null @@ -1,5 +0,0 @@ -Signature-Version: 1.0 -MD5-Digest-Manifest: LrrwWBKNYWeVd205Hq+JwQ== -SHA1-Digest-Manifest: MeqqQN+uuf0MVesMXxbBtYN+5tU= -SHA256-Digest-Manifest: iWCxfAJX593Cn4l8R63jaQETO5HX3XOhcnpQ7nMiPlg= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/manifest.mf b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/manifest.mf deleted file mode 100644 index 1da3c41b23..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/manifest.mf +++ /dev/null @@ -1,8 +0,0 @@ -Manifest-Version: 1.0 - -Name: manifest.json -Digest-Algorithms: MD5 SHA1 SHA256 -MD5-Digest: 3dL7JFDBPC63pSFI5x+Z7Q== -SHA1-Digest: l1cKPyWJIYdZyvumH9VfJ6fpqVA= -SHA256-Digest: QHTjPqTMXxt5tl8zOaAzpQ8FZLqZx8LRF9LmzY+RCDQ= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/mozilla.rsa b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/mozilla.rsa Binary files differdeleted file mode 100644 index 170a361620..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/mozilla.rsa +++ /dev/null diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/mozilla.sf b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/mozilla.sf deleted file mode 100644 index 5301e431f7..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/META-INF/mozilla.sf +++ /dev/null @@ -1,5 +0,0 @@ -Signature-Version: 1.0 -MD5-Digest-Manifest: c30hzcI1ISlt46ODjVVJ2w== -SHA1-Digest-Manifest: 2yMpQHuLM0J61T7vt11NHoYI1tU= -SHA256-Digest-Manifest: qtsYxiv1zGWBp7JWxLWrIztIdxIt+i3CToReEx5fkyw= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/manifest.mf b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/manifest.mf deleted file mode 100644 index e508bcd22f..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/manifest.mf +++ /dev/null @@ -1,8 +0,0 @@ -Manifest-Version: 1.0 - -Name: manifest.json -Digest-Algorithms: MD5 SHA1 SHA256 -MD5-Digest: Wzo/k6fhArpFb4UB2hIKlg== -SHA1-Digest: D/WDy9api0X7OgRM6Gkvfbyzogo= -SHA256-Digest: IWBdbytHgPLtCMKKhiZ3jenxKmKiRAhh3ce8iP5AVWU= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/mozilla.rsa b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/mozilla.rsa Binary files differdeleted file mode 100644 index a026680e91..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/mozilla.rsa +++ /dev/null diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/mozilla.sf b/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/mozilla.sf deleted file mode 100644 index 16a1461f37..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop_incompat/META-INF/mozilla.sf +++ /dev/null @@ -1,5 +0,0 @@ -Signature-Version: 1.0 -MD5-Digest-Manifest: ovtNeIie34gMM5l18zP2MA== -SHA1-Digest-Manifest: c5owdrvcOINxKp/HprYkWXXI/js= -SHA256-Digest-Manifest: uLPmoONlxFYxWeSTOEPJ9hN2yMDDZMJL1PoNIWcqKG4= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/manifest.mf b/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/manifest.mf deleted file mode 100644 index eea5cbd501..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/manifest.mf +++ /dev/null @@ -1,8 +0,0 @@ -Manifest-Version: 1.0 - -Name: manifest.json -Digest-Algorithms: MD5 SHA1 SHA256 -MD5-Digest: b4Q2C4GsIJfRLsXc7T2ldQ== -SHA1-Digest: UG5rHxpzKmdlGrquXaguiAGDu8E= -SHA256-Digest: WZrN9SdGBux9t3lV7TVIvyUG/L1px4er2dU3TsBpC4s= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/mozilla.rsa b/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/mozilla.rsa Binary files differdeleted file mode 100644 index 68621e19be..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/mozilla.rsa +++ /dev/null diff --git a/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/mozilla.sf b/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/mozilla.sf deleted file mode 100644 index fe6baa8dac..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/browser_installssl/META-INF/mozilla.sf +++ /dev/null @@ -1,5 +0,0 @@ -Signature-Version: 1.0 -MD5-Digest-Manifest: zqRm8+jxS0iRUGWeArGkXg== -SHA1-Digest-Manifest: pa/31Ll1PYx0dPBQ6C+fd1/wJO4= -SHA256-Digest-Manifest: DJELIyswfwgeL0kaRqogXW2bzUKhn+Pickfv6WHBsW8= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/manifest.mf b/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/manifest.mf deleted file mode 100644 index a8c72c4794..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/manifest.mf +++ /dev/null @@ -1,12 +0,0 @@ -Manifest-Version: 1.0 - -Name: manifest.json -Digest-Algorithms: MD5 SHA1 -MD5-Digest: Rnoaa6yWePDor5y5/SLFaw== -SHA1-Digest: k51DtKj7bYrwkFJDdmYNDQeUBlA= - -Name: options.html -Digest-Algorithms: MD5 SHA1 -MD5-Digest: vTjxWlRpioEhTZGKTNUqIw== -SHA1-Digest: Y/mr6A34LsvekgRpdhyZRwPF1Vw= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/mozilla.rsa b/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/mozilla.rsa Binary files differdeleted file mode 100644 index 8b6320adda..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/mozilla.rsa +++ /dev/null diff --git a/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/mozilla.sf b/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/mozilla.sf deleted file mode 100644 index ba5fd22caa..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/options_signed/META-INF/mozilla.sf +++ /dev/null @@ -1,4 +0,0 @@ -Signature-Version: 1.0 -MD5-Digest-Manifest: rdmx8VMNzkZ5tRf7tt8G1w== -SHA1-Digest-Manifest: gjtTe8X9Tg46Hz2h4Tru3T02hmE= - diff --git a/toolkit/mozapps/extensions/test/browser/addons/options_signed/manifest.json b/toolkit/mozapps/extensions/test/browser/addons/options_signed/manifest.json deleted file mode 100644 index e808cd5ab6..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/options_signed/manifest.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "manifest_version": 2, - - "name": "Test options_ui", - "description": "Test add-ons manager handling options_ui with no id in manifest.json", - "version": "1.2", - - "options_ui": { - "page": "options.html" - } -} diff --git a/toolkit/mozapps/extensions/test/browser/addons/options_signed/options.html b/toolkit/mozapps/extensions/test/browser/addons/options_signed/options.html deleted file mode 100644 index ea804601b5..0000000000 --- a/toolkit/mozapps/extensions/test/browser/addons/options_signed/options.html +++ /dev/null @@ -1,9 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8" /> - </head> - <body> - <div id="options-test-panel" /> - </body> -</html> diff --git a/toolkit/mozapps/extensions/test/browser/browser.toml b/toolkit/mozapps/extensions/test/browser/browser.toml index 0b4a2d8f0a..6556b95584 100644 --- a/toolkit/mozapps/extensions/test/browser/browser.toml +++ b/toolkit/mozapps/extensions/test/browser/browser.toml @@ -8,8 +8,6 @@ support-files = [ "addons/browser_dragdrop_incompat.xpi", "addons/browser_installssl.xpi", "addons/browser_theme.xpi", - "addons/options_signed.xpi", - "addons/options_signed/*", "addon_prefs.xhtml", "discovery/api_response.json", "discovery/api_response_empty.json", @@ -40,7 +38,6 @@ generated-files = [ "addons/browser_dragdrop_incompat.xpi", "addons/browser_installssl.xpi", "addons/browser_theme.xpi", - "addons/options_signed.xpi", ] skip-if = [ diff --git a/toolkit/mozapps/extensions/test/browser/browser_AMBrowserExtensionsImport.js b/toolkit/mozapps/extensions/test/browser/browser_AMBrowserExtensionsImport.js index 654e3cd91e..0d3956f941 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_AMBrowserExtensionsImport.js +++ b/toolkit/mozapps/extensions/test/browser/browser_AMBrowserExtensionsImport.js @@ -43,7 +43,7 @@ const ADDON_SEARCH_RESULTS = {}; const mockAddonRepository = ({ addons = [] }) => { return { - async getMappedAddons(browserID, extensionIDs) { + async getMappedAddons() { return Promise.resolve({ addons, matchedIDs: [], diff --git a/toolkit/mozapps/extensions/test/browser/browser_bug572561.js b/toolkit/mozapps/extensions/test/browser/browser_bug572561.js index 6f8a56bfba..51493570da 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_bug572561.js +++ b/toolkit/mozapps/extensions/test/browser/browser_bug572561.js @@ -17,22 +17,22 @@ var gInstallProperties = [ var gInstall; var gExpectedCancel = false; var gTestInstallListener = { - onInstallStarted(aInstall) { + onInstallStarted() { check_hidden(false); }, - onInstallEnded(aInstall) { + onInstallEnded() { check_hidden(false); run_next_test(); }, - onInstallCancelled(aInstall) { + onInstallCancelled() { ok(gExpectedCancel, "Should expect install cancel"); check_hidden(false); run_next_test(); }, - onInstallFailed(aInstall) { + onInstallFailed() { ok(false, "Did not expect onInstallFailed"); run_next_test(); }, diff --git a/toolkit/mozapps/extensions/test/browser/browser_dragdrop.js b/toolkit/mozapps/extensions/test/browser/browser_dragdrop.js index ae8625a18a..52881b39d1 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_dragdrop.js +++ b/toolkit/mozapps/extensions/test/browser/browser_dragdrop.js @@ -16,7 +16,7 @@ const dragService = Cc["@mozilla.org/widget/dragservice;1"].getService( async function checkInstallConfirmation(...names) { let notificationCount = 0; let observer = { - observe(aSubject, aTopic, aData) { + observe(aSubject) { let installInfo = aSubject.wrappedJSObject; isnot( installInfo.browser, diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js b/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js index 3ad8510aea..f20e5b357b 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js +++ b/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js @@ -603,7 +603,7 @@ add_task(async function test_abusereport_messagebars() { await AbuseReportTestUtils.promiseReportRendered(); AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message"); }, - ([submittingDetails, submittedDetails]) => { + ([, submittedDetails]) => { const buttonsL10nId = Array.from( submittedDetails.messagebar.querySelectorAll("button") ).map(el => el.getAttribute("data-l10n-id")); @@ -634,10 +634,8 @@ add_task(async function test_abusereport_messagebars() { await addon.uninstall(true); AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message"); }; - const assertMessageBarDetails = async ([ - submittingDetails, - submittedDetails, - ]) => AbuseReportTestUtils.assertFluentStrings(submittedDetails.messagebar); + const assertMessageBarDetails = async ([, submittedDetails]) => + AbuseReportTestUtils.assertFluentStrings(submittedDetails.messagebar); await assertMessageBars( ["submitting", "submitted-and-removed"], testFn, @@ -657,7 +655,7 @@ add_task(async function test_abusereport_messagebars() { await AbuseReportTestUtils.promiseReportRendered(); AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message"); }, - ([submittingDetails, submittedDetails]) => + ([, submittedDetails]) => AbuseReportTestUtils.assertFluentStrings(submittedDetails.messagebar) ); diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js b/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js index 939fe421c3..32543f3bc9 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js +++ b/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js @@ -613,7 +613,7 @@ add_task(async function testPermissionsViewStates() { let card = getAddonCard(view, addon.id); await Assert.rejects( card.setAddonPermission("webRequest", "permission", "add"), - /permission missing from manifest/, + /was not declared in optional_permissions/, "unable to set the addon permission" ); diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js b/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js index bc84ffaf89..30cb45dc60 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js +++ b/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js @@ -76,7 +76,7 @@ class DiscoveryAPIHandler { }); } - unblockResponses(responseText) { + unblockResponses() { throw new Error("You need to call blockNextResponses first!"); } diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_list_view_recommendations.js b/toolkit/mozapps/extensions/test/browser/browser_html_list_view_recommendations.js index db4067ab35..bc6ae47a8f 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_html_list_view_recommendations.js +++ b/toolkit/mozapps/extensions/test/browser/browser_html_list_view_recommendations.js @@ -119,7 +119,7 @@ async function installAddon({ card, recommendedList, manifestExtra = {} }) { return extension; } -async function testListRecommendations({ type, manifestExtra = {} }) { +async function testListRecommendations({ type }) { let win = await loadInitialView(type); let doc = win.document; diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_in_tab.js b/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_in_tab.js index 68faecfec0..fec3911bcd 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_in_tab.js +++ b/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_in_tab.js @@ -10,15 +10,19 @@ add_task(async function enableHtmlViews() { }); }); -async function testOptionsInTab({ id, options_ui_options }) { +async function testOptionsInTab({ + id, + options_ui_options = {}, + manifest = { + manifest_version: 2, + options_ui: { page: "options.html", ...options_ui_options }, + }, +}) { let extension = ExtensionTestUtils.loadExtension({ manifest: { name: "Prefs extension", browser_specific_settings: { gecko: { id } }, - options_ui: { - page: "options.html", - ...options_ui_options, - }, + ...manifest, }, background() { browser.test.sendMessage( @@ -84,10 +88,15 @@ async function testOptionsInTab({ id, options_ui_options }) { } add_task(async function testPreferencesLink() { - let id = "prefs@mochi.test"; + let id = "options_ui_open_in_tab@mochi.test"; await testOptionsInTab({ id, options_ui_options: { open_in_tab: true } }); }); +add_task(async function testOptionsPageOpensInNewTab() { + let id = "options_page@mochi.test"; + await testOptionsInTab({ id, manifest: { options_page: "options.html" } }); +}); + add_task(async function testPreferencesInlineDisabled() { await SpecialPowers.pushPrefEnv({ set: [["extensions.htmlaboutaddons.inline-options.enabled", false]], diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_updates.js b/toolkit/mozapps/extensions/test/browser/browser_html_updates.js index 78ffc5678c..757c322829 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_html_updates.js +++ b/toolkit/mozapps/extensions/test/browser/browser_html_updates.js @@ -53,7 +53,7 @@ add_task(async function testChangeAutoUpdates() { let win = await loadInitialView("extension"); let doc = win.document; - let getInputs = updateRow => ({ + let getInputs = () => ({ default: updatesRow.querySelector('input[value="1"]'), on: updatesRow.querySelector('input[value="2"]'), off: updatesRow.querySelector('input[value="0"]'), diff --git a/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js b/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js index 1d50da2833..b8e8ac80d0 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js +++ b/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js @@ -243,6 +243,7 @@ add_task(async function testInstallTriggerFromSubframe() { const testCases = [ ["blank iframe with no attributes", SECURE_TESTROOT, {}, expected.http], + ["iframe srcdoc=''", SECURE_TESTROOT, { srcdoc: "" }, expected.http], // These are blocked by a Firefox doorhanger and the user can't allow it neither. [ @@ -258,12 +259,6 @@ add_task(async function testInstallTriggerFromSubframe() { expected.otherBlockedOnOrigin, ], [ - "iframe srcdoc=''", - SECURE_TESTROOT, - { srcdoc: "" }, - expected.httpBlockedOnOrigin, - ], - [ "blank iframe embedded into a top-level sandbox page", `${SECURE_TESTROOT}sandboxed.html`, {}, diff --git a/toolkit/mozapps/extensions/test/browser/browser_local_install.js b/toolkit/mozapps/extensions/test/browser/browser_local_install.js index 5200b69e39..a26a4e283b 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_local_install.js +++ b/toolkit/mozapps/extensions/test/browser/browser_local_install.js @@ -66,7 +66,7 @@ AddonTestUtils.registerJSON(server, "/updates-now-compatible.json", { add_task(async function test_local_install_blocklisted() { let id = "amosigned-xpi@tests.mozilla.org"; - let version = "2.1"; + let version = "2.2"; await AddonTestUtils.loadBlocklistRawData({ extensionsMLBF: [ diff --git a/toolkit/mozapps/extensions/test/browser/browser_page_options_install_addon.js b/toolkit/mozapps/extensions/test/browser/browser_page_options_install_addon.js index 7bc7c08345..586f2b7720 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_page_options_install_addon.js +++ b/toolkit/mozapps/extensions/test/browser/browser_page_options_install_addon.js @@ -10,7 +10,7 @@ MockFilePicker.init(window.browsingContext); async function checkInstallConfirmation(...names) { let notificationCount = 0; let observer = { - observe(aSubject, aTopic, aData) { + observe(aSubject) { var installInfo = aSubject.wrappedJSObject; isnot( installInfo.browser, diff --git a/toolkit/mozapps/extensions/test/browser/browser_shortcuts_duplicate_check.js b/toolkit/mozapps/extensions/test/browser/browser_shortcuts_duplicate_check.js index 912ce8d62f..a8de1f96aa 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_shortcuts_duplicate_check.js +++ b/toolkit/mozapps/extensions/test/browser/browser_shortcuts_duplicate_check.js @@ -235,7 +235,7 @@ add_task(async function testDuplicateShortcutOnMacOSCtrlKey() { ); }; - const clearWarning = async inputEl => { + const clearWarning = async () => { anotherCommandInput.blur(); await TestUtils.waitForCondition( () => BrowserTestUtils.isHidden(errorEl), diff --git a/toolkit/mozapps/extensions/test/browser/browser_sidebar_hidden_categories.js b/toolkit/mozapps/extensions/test/browser/browser_sidebar_hidden_categories.js index 4cb641c2a0..0bb59d7748 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_sidebar_hidden_categories.js +++ b/toolkit/mozapps/extensions/test/browser/browser_sidebar_hidden_categories.js @@ -18,7 +18,7 @@ function installLocale() { return new Promise(resolve => { gInstall = gProvider.createInstalls(gInstallProperties)[0]; gInstall.addTestListener({ - onInstallEnded(aInstall) { + onInstallEnded() { gInstall.removeTestListener(this); resolve(); }, diff --git a/toolkit/mozapps/extensions/test/browser/browser_updatessl.js b/toolkit/mozapps/extensions/test/browser/browser_updatessl.js index 9dbeec4a84..792c24de58 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_updatessl.js +++ b/toolkit/mozapps/extensions/test/browser/browser_updatessl.js @@ -25,14 +25,7 @@ var gStart = 0; var gLast = 0; var HTTPObserver = { - observeActivity( - aChannel, - aType, - aSubtype, - aTimestamp, - aSizeData, - aStringData - ) { + observeActivity(aChannel, aType, aSubtype) { aChannel.QueryInterface(Ci.nsIChannel); dump( diff --git a/toolkit/mozapps/extensions/test/browser/browser_webapi_install.js b/toolkit/mozapps/extensions/test/browser/browser_webapi_install.js index 24d34c3f4d..a5823517d6 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_webapi_install.js +++ b/toolkit/mozapps/extensions/test/browser/browser_webapi_install.js @@ -17,12 +17,11 @@ const TESTPAGE = `${SECURE_TESTROOT}${TESTPATH}`; const XPI_URL = `${SECURE_TESTROOT}../xpinstall/amosigned.xpi`; const XPI_ADDON_ID = "amosigned-xpi@tests.mozilla.org"; -const XPI_SHA = - "sha256:91121ed2c27f670f2307b9aebdd30979f147318c7fb9111c254c14ddbb84e4b0"; - const ID = "amosigned-xpi@tests.mozilla.org"; -// eh, would be good to just stat the real file instead of this... -const XPI_LEN = 4287; +// Actual XPI file size and hash are computed in the add_setup callback. +let XPI_LEN = -1; +let XPI_SHA = + "sha256:0000000000000000000000000000000000000000000000000000000000000000"; AddonTestUtils.initMochitest(this); @@ -50,6 +49,17 @@ add_setup(async function () { ], }); info("added preferences"); + + // Get the file size (used in this test file to assert the + // expected maxProgress value set in the addon download + // dialog). + const xpiFilePath = getTestFilePath("../xpinstall/amosigned.xpi"); + const xpiStat = await IOUtils.stat(xpiFilePath); + XPI_LEN = xpiStat.size; + + // Compute the file hash. + const xpiFileHash = await IOUtils.computeHexDigest(xpiFilePath, "sha256"); + XPI_SHA = `sha256:${xpiFileHash}`; }); // Wrapper around a common task to run in the content process to test @@ -95,7 +105,7 @@ async function testInstall(browser, args, steps, description) { let receivedEvents = []; let prevEvent = null; events.forEach(event => { - install.addEventListener(event, e => { + install.addEventListener(event, () => { receivedEvents.push({ event, state: install.state, @@ -165,7 +175,7 @@ async function testInstall(browser, args, steps, description) { } } catch (err) { if (!nextStep.expectError) { - throw new Error("Install failed unexpectedly"); + throw new Error("Install failed unexpectedly: " + err); } } } else if (nextStep.action == "cancel") { @@ -287,12 +297,12 @@ add_task( "install with empty string for hash works" ) ); -add_task( - makeRegularTest( +add_task(async function test_install_successfully_with_filehash() { + await makeRegularTest( { url: XPI_URL, addonId, hash: XPI_SHA }, "install with hash works" - ) -); + ); +}); add_task( makeInstallTest(async function (browser) { @@ -531,7 +541,7 @@ add_task( add_task( makeInstallTest(async function (browser) { let id = "amosigned-xpi@tests.mozilla.org"; - let version = "2.1"; + let version = "2.2"; await AddonTestUtils.loadBlocklistRawData({ extensionsMLBF: [ diff --git a/toolkit/mozapps/extensions/test/browser/browser_webapi_theme.js b/toolkit/mozapps/extensions/test/browser/browser_webapi_theme.js index dd1df90907..f271cbd9e3 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_webapi_theme.js +++ b/toolkit/mozapps/extensions/test/browser/browser_webapi_theme.js @@ -13,7 +13,7 @@ add_task(async function test_theme_install() { await BrowserTestUtils.withNewTab(TESTPAGE, async browser => { let updates = []; - function observer(subject, topic, data) { + function observer(subject) { updates.push(JSON.stringify(subject.wrappedJSObject)); } Services.obs.addObserver(observer, "lightweight-theme-styling-update"); diff --git a/toolkit/mozapps/extensions/test/browser/head.js b/toolkit/mozapps/extensions/test/browser/head.js index 482429177c..949b375ec0 100644 --- a/toolkit/mozapps/extensions/test/browser/head.js +++ b/toolkit/mozapps/extensions/test/browser/head.js @@ -204,7 +204,7 @@ function run_next_test() { executeSoon(() => log_exceptions(test)); } -var get_tooltip_info = async function (addonEl, managerWindow) { +var get_tooltip_info = async function (addonEl) { // Extract from title attribute. const { addon } = addonEl; const name = addon.name; @@ -324,7 +324,7 @@ function open_manager( aLongerTimeout, aWin = window ) { - let p = new Promise((resolve, reject) => { + let p = new Promise(resolve => { async function setup_manager(aManagerWindow) { if (aLoadCallback) { log_exceptions(aLoadCallback, aManagerWindow); @@ -354,7 +354,7 @@ function open_manager( } info("Loading manager window in tab"); - Services.obs.addObserver(function observer(aSubject, aTopic, aData) { + Services.obs.addObserver(function observer(aSubject, aTopic) { Services.obs.removeObserver(observer, aTopic); if (aSubject.location.href != MANAGER_URI) { info("Ignoring load event for " + aSubject.location.href); @@ -434,7 +434,7 @@ function wait_for_window_open(aCallback) { ); }, - onCloseWindow(aWindow) {}, + onCloseWindow() {}, }); }); @@ -487,7 +487,7 @@ function promiseAddonsByIDs(aIDs) { */ async function install_addon(path, cb, pathPrefix = TESTROOT) { let install = await AddonManager.getInstallForURL(pathPrefix + path); - let p = new Promise((resolve, reject) => { + let p = new Promise(resolve => { install.addListener({ onInstallEnded: () => resolve(install.addon), }); @@ -946,7 +946,7 @@ MockProvider.prototype = { * true if the newly enabled add-on will only become enabled after a * restart */ - addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) { + addonChanged: function MP_addonChanged() { // Not implemented }, @@ -965,7 +965,7 @@ MockProvider.prototype = { * @param {object} aOptions * Options for the install */ - getInstallForURL: function MP_getInstallForURL(aUrl, aOptions) { + getInstallForURL: function MP_getInstallForURL() { // Not yet implemented }, @@ -975,7 +975,7 @@ MockProvider.prototype = { * @param aFile * The file to be installed */ - getInstallForFile: function MP_getInstallForFile(aFile) { + getInstallForFile: function MP_getInstallForFile() { // Not yet implemented }, @@ -996,7 +996,7 @@ MockProvider.prototype = { * The mimetype to check for * @return true if the mimetype is supported */ - supportsMimetype: function MP_supportsMimetype(aMimetype) { + supportsMimetype: function MP_supportsMimetype() { return false; }, @@ -1007,7 +1007,7 @@ MockProvider.prototype = { * The URI being installed from * @return true if installing is allowed */ - isInstallAllowed: function MP_isInstallAllowed(aUri) { + isInstallAllowed: function MP_isInstallAllowed() { return false; }, }; @@ -1143,11 +1143,11 @@ MockAddon.prototype = { ]); }, - isCompatibleWith(aAppVersion, aPlatformVersion) { + isCompatibleWith() { return true; }, - findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) { + findUpdates() { // Tests can implement this if they need to }, diff --git a/toolkit/mozapps/extensions/test/browser/head_abuse_report.js b/toolkit/mozapps/extensions/test/browser/head_abuse_report.js index f3a683e8d5..78c9206e0a 100644 --- a/toolkit/mozapps/extensions/test/browser/head_abuse_report.js +++ b/toolkit/mozapps/extensions/test/browser/head_abuse_report.js @@ -66,7 +66,7 @@ function waitForNewWindow() { } function waitClosedWindow(win) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { function onWindowClosed() { if (win && !win.closed) { // If a specific window reference has been passed, then check @@ -215,7 +215,7 @@ const AbuseReportTestUtils = { return abuseReportEl.ownerGlobal.ABUSE_REPORT_REASONS[reason]; }, - async promiseReportOpened({ addonId, reportEntryPoint, managerWindow }) { + async promiseReportOpened({ addonId, reportEntryPoint }) { let abuseReportEl; if (!this.getReportDialog()) { diff --git a/toolkit/mozapps/extensions/test/browser/moz.build b/toolkit/mozapps/extensions/test/browser/moz.build index 4cc6314d0e..74095966b1 100644 --- a/toolkit/mozapps/extensions/test/browser/moz.build +++ b/toolkit/mozapps/extensions/test/browser/moz.build @@ -14,7 +14,6 @@ addons = [ "browser_dragdrop_incompat", "browser_installssl", "browser_theme", - "options_signed", ] output_dir = ( diff --git a/toolkit/mozapps/extensions/test/xpcshell/.eslintrc.js b/toolkit/mozapps/extensions/test/xpcshell/.eslintrc.js index 8e3971b385..26a3e6177f 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/.eslintrc.js +++ b/toolkit/mozapps/extensions/test/xpcshell/.eslintrc.js @@ -4,7 +4,7 @@ module.exports = { rules: { "no-unused-vars": [ "error", - { args: "none", varsIgnorePattern: "^end_test$" }, + { argsIgnorePattern: "^_", varsIgnorePattern: "^end_test$" }, ], }, overrides: [ @@ -14,7 +14,7 @@ module.exports = { "no-unused-vars": [ "error", { - args: "none", + argsIgnorePattern: "^_", vars: "local", }, ], diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/langpack_signed.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/langpack_signed.xpi Binary files differindex f60d00348e..ab7db3926e 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/langpack_signed.xpi +++ b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/langpack_signed.xpi diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long.xpi Binary files differindex f95f3df91e..78124db3ae 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long.xpi +++ b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long.xpi diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/privileged.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/privileged.xpi Binary files differindex c22acaacd2..111385485b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/privileged.xpi +++ b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/privileged.xpi diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed1.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed1.xpi Binary files differindex e2ba7d6fd8..2e9d976a34 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed1.xpi +++ b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed1.xpi diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed2.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed2.xpi Binary files differindex ccb20796f2..2d6b9c020b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed2.xpi +++ b/toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed2.xpi diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/webext-implicit-id.xpi b/toolkit/mozapps/extensions/test/xpcshell/data/webext-implicit-id.xpi Binary files differindex 6b4abaa691..05a5ea2881 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/data/webext-implicit-id.xpi +++ b/toolkit/mozapps/extensions/test/xpcshell/data/webext-implicit-id.xpi diff --git a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js index 23614cdb2a..2f26d940f0 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js +++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js @@ -935,7 +935,7 @@ class EventChecker { return this.checkAddonEvent("onInstalled", addon); } - onUninstalling(addon, requiresRestart) { + onUninstalling(addon) { return this.checkAddonEvent("onUninstalling", addon); } @@ -1033,7 +1033,7 @@ class EventChecker { }); } - onInstallEnded(install, newAddon) { + onInstallEnded(install) { return this.checkInstall("onInstallEnded", install, { state: "STATE_INSTALLED", error: 0, @@ -1221,3 +1221,10 @@ async function installBuiltinExtension(extensionData, waitForStartup = true) { } return wrapper; } + +function useAMOStageCert() { + // NOTE: add_task internally calls add_test which mutate the add_task properties object, + // and so we should not reuse the same object as add_task options passed to multiple + // add_task calls. + return { pref_set: [["xpinstall.signatures.dev-root", true]] }; +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/head_compat.js b/toolkit/mozapps/extensions/test/xpcshell/head_compat.js index 79ddb8dd3f..76fafee50e 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/head_compat.js +++ b/toolkit/mozapps/extensions/test/xpcshell/head_compat.js @@ -22,7 +22,7 @@ AddonManager.addExternalExtensionLoader({ Object.assign(addon, manifest); return addon; }, - loadScope(addon, file) { + loadScope() { return { install() {}, uninstall() {}, diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_appversion.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_appversion.js index e8d03f088b..08e41b47fd 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_appversion.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_appversion.js @@ -227,7 +227,7 @@ function createAddon(addon) { * If a lastTest is provided checks that the notification dialog got passed * the newly blocked items compared to the previous test. */ -async function checkState(test, lastTest, callback) { +async function checkState(test) { let addons = await AddonManager.getAddonsByIDs(ADDONS.map(a => a.id)); const bls = Ci.nsIBlocklistService; diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf.js index 1f6cb3db05..f7e3a57152 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf.js @@ -11,11 +11,11 @@ createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1"); AddonTestUtils.useRealCertChecks = true; // A real, signed XPI for use in the test. -const SIGNED_ADDON_XPI_FILE = do_get_file("../data/webext-implicit-id.xpi"); -const SIGNED_ADDON_ID = "webext_implicit_id@tests.mozilla.org"; -const SIGNED_ADDON_VERSION = "1.0"; +const SIGNED_ADDON_XPI_FILE = do_get_file("amosigned.xpi"); +const SIGNED_ADDON_ID = "amosigned-xpi@tests.mozilla.org"; +const SIGNED_ADDON_VERSION = "2.2"; const SIGNED_ADDON_KEY = `${SIGNED_ADDON_ID}:${SIGNED_ADDON_VERSION}`; -const SIGNED_ADDON_SIGN_TIME = 1459980789000; // notBefore of certificate. +const SIGNED_ADDON_SIGN_TIME = 1711462525000; // notBefore of certificate. // A real, signed sitepermission XPI for use in the test. const SIGNED_SITEPERM_XPI_FILE = do_get_file("webmidi_permission.xpi"); @@ -78,7 +78,7 @@ add_task(async function signed_xpi_initially_unblocked() { await Blocklist.getAddonBlocklistEntry(addon), { state: Ci.nsIBlocklistService.STATE_BLOCKED, - url: "https://addons.mozilla.org/en-US/xpcshell/blocked-addon/webext_implicit_id@tests.mozilla.org/1.0/", + url: `https://addons.mozilla.org/en-US/xpcshell/blocked-addon/${SIGNED_ADDON_ID}/${SIGNED_ADDON_VERSION}/`, }, "Blocked addon should have blocked entry" ); @@ -174,7 +174,9 @@ add_task(async function signed_temporary() { await Assert.rejects( AddonManager.installTemporaryAddon(SIGNED_ADDON_XPI_FILE), - /Add-on webext_implicit_id@tests.mozilla.org is not compatible with application version/, + new RegExp( + `Add-on ${SIGNED_ADDON_ID} is not compatible with application version` + ), "Blocklisted add-on cannot be installed" ); }); @@ -183,19 +185,27 @@ add_task(async function signed_temporary() { // It can still be blocked by a stash, which is tested in // privileged_addon_blocked_by_stash in test_blocklist_mlbf_stashes.js. add_task(async function privileged_xpi_not_blocked() { + const PRIV_ADDON_ID = "test@tests.mozilla.org"; + const PRIV_ADDON_VERSION = "2.0buildid20240326.152244"; mockMLBF({ - blocked: ["test@tests.mozilla.org:2.0"], + blocked: [`${PRIV_ADDON_ID}:${PRIV_ADDON_VERSION}`], notblocked: [], generationTime: 1546297200000, // 1 jan 2019 = after the cert's notBefore }); await ExtensionBlocklistMLBF._onUpdate(); + // Prevent install to fail due to privileged.xpi version using + // an addon version that hits a manifest warning (see PRIV_ADDON_VERSION). + // TODO(Bug 1824240): remove this once privileged.xpi can be resigned with a + // version format that does not hit a manifest warning. + ExtensionTestUtils.failOnSchemaWarnings(false); const install = await promiseInstallFile( do_get_file("../data/signing_checks/privileged.xpi") ); + ExtensionTestUtils.failOnSchemaWarnings(true); Assert.equal(install.error, 0, "Install should not have an error"); - let addon = await promiseAddonByID("test@tests.mozilla.org"); + let addon = await promiseAddonByID(PRIV_ADDON_ID); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_PRIVILEGED); Assert.equal(addon.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); await addon.uninstall(); @@ -205,13 +215,17 @@ add_task(async function privileged_xpi_not_blocked() { // It can still be blocked by a stash, which is tested in // langpack_blocked_by_stash in test_blocklist_mlbf_stashes.js. add_task( - // We do not support langpacks on Android. - { skip_if: () => AppConstants.platform == "android" }, + { + // langpack_signed.xpi is signed with AMO staging signature. + pref_set: [["xpinstall.signatures.dev-root", true]], + // We do not support langpacks on Android. + skip_if: () => AppConstants.platform == "android", + }, async function langpack_not_blocked_on_Nightly() { mockMLBF({ blocked: ["langpack-klingon@firefox.mozilla.org:1.0"], notblocked: [], - generationTime: 1546297200000, // 1 jan 2019 = after the cert's notBefore + generationTime: 1712243366640, // 4 apr 2024 = after the cert's notBefore }); await ExtensionBlocklistMLBF._onUpdate(); @@ -226,12 +240,16 @@ add_task( Assert.equal( addon.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED, - "Langpacks cannot be blocked via the MLBF" + "Langpacks cannot be blocked via the MLBF on nightly" ); } else { // On non-Nightly, langpacks are submitted through AMO so we will enforce // the MLBF blocklist for them. - Assert.equal(addon.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED); + Assert.equal( + addon.blocklistState, + Ci.nsIBlocklistService.STATE_BLOCKED, + "Langpacks can be blocked via the MLBF on non-Nightly channels" + ); } await addon.uninstall(); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_update.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_update.js index b98d6e345d..77e5df2540 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_update.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_update.js @@ -25,7 +25,7 @@ add_task(async function collapse_multiple_pending_update_requests() { // Add a spy to the RemoteSettings client, so we can verify that the number // of RemoteSettings accesses matches with what we expect. const originalClientGet = ExtensionBlocklistMLBF._client.get; - const spyClientGet = (tag, returnValue) => { + const spyClientGet = tag => { ExtensionBlocklistMLBF._client.get = async function () { // Record the method call. observed.push(tag); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_severities.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_severities.js index fffbb8a51e..059d014197 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_severities.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_severities.js @@ -451,7 +451,7 @@ add_task(async function test_pt4() { await promiseRestartManager(); await checkInitialState(); - await loadBlocklist("empty", args => { + await loadBlocklist("empty", () => { dump("Checking notification pt 4\n"); // See note in other callback - we no longer notify for non-blocked add-ons. ok(false, "Should not get a notification as there are no blocked addons."); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js index 7383e093ee..b021a13c80 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js @@ -40,7 +40,7 @@ const useMLBF = Services.prefs.getBoolPref( var testserver = createHttpServer({ hosts: ["example.com"] }); -function permissionPromptHandler(subject, topic, data) { +function permissionPromptHandler(subject) { ok( subject?.wrappedJSObject?.info?.resolve, "Got a permission prompt notification as expected" @@ -280,7 +280,7 @@ if (useMLBF) { } // XXXgijs: according to https://bugzilla.mozilla.org/show_bug.cgi?id=1257565#c111 -// this code and the related code in Blocklist.jsm (specific to XML blocklist) is +// this code and the related code in Blocklist.sys.mjs (specific to XML blocklist) is // dead code and can be removed. See https://bugzilla.mozilla.org/show_bug.cgi?id=1549550 . // // Don't need the full interface, attempts to call other methods will just @@ -343,16 +343,16 @@ function Pload_blocklist(aId) { // Does a background update check for add-ons and returns a promise that // resolves when any started installs complete function Pbackground_update() { - return new Promise((resolve, reject) => { + return new Promise(resolve => { let installCount = 0; let backgroundCheckCompleted = false; AddonManager.addInstallListener({ - onNewInstall(aInstall) { + onNewInstall() { installCount++; }, - onInstallEnded(aInstall) { + onInstallEnded() { installCount--; // Wait until all started installs have completed if (installCount) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Device.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Device.js index 9b1d84b77d..68c9357356 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Device.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Device.js @@ -63,7 +63,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_DriverNew.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_DriverNew.js index a1bcde5566..fa274bde2d 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_DriverNew.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_DriverNew.js @@ -57,7 +57,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverNew.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverNew.js index ec74d813ae..a6a1dc1435 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverNew.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverNew.js @@ -102,7 +102,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverOld.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverOld.js index ff887a92eb..93ca432c6d 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverOld.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_DriverOld.js @@ -58,7 +58,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_OK.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_OK.js index 1eef119663..4be9215161 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_OK.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Equal_OK.js @@ -58,7 +58,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_DriverOld.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_DriverOld.js index 182c825ffb..d8b082bedc 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_DriverOld.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_DriverOld.js @@ -58,7 +58,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_OK.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_OK.js index 2cc3686007..0e419ec761 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_OK.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_GTE_OK.js @@ -60,7 +60,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_No_Comparison.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_No_Comparison.js index 169cdc5e62..4d457cff14 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_No_Comparison.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_No_Comparison.js @@ -59,7 +59,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OK.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OK.js index 04d766e027..991bfa8a96 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OK.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OK.js @@ -59,7 +59,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OS.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OS.js index ce5a61cb75..3f525b48ce 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OS.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OS.js @@ -58,7 +58,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_match.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_match.js index 7a4ec276ee..d9d357be76 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_match.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_match.js @@ -60,7 +60,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js index 61dba8db96..a1c8107f1d 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js @@ -60,7 +60,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js index 117e2a34ee..be076d98c3 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js @@ -61,7 +61,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Vendor.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Vendor.js index 37bc0d3c89..e5d137db60 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Vendor.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Vendor.js @@ -58,7 +58,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlacklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Version.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Version.js index 9a6a904465..cbd1699d53 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Version.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_Version.js @@ -180,7 +180,7 @@ async function run_test() { do_test_finished(); } - Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.addObserver(function () { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(checkBlocklist); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_prefs.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_prefs.js index 34e92b0e80..6e5f71b364 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_prefs.js +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_gfxBlacklist_prefs.js @@ -53,7 +53,7 @@ async function run_test() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "8"); await promiseStartupManager(); - function blacklistAdded(aSubject, aTopic, aData) { + function blacklistAdded() { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(ensureBlacklistSet); @@ -95,7 +95,7 @@ async function run_test() { ]); } - function blacklistRemoved(aSubject, aTopic, aData) { + function blacklistRemoved() { // If we wait until after we go through the event loop, gfxInfo is sure to // have processed the gfxItems event. executeSoon(ensureBlacklistUnset); diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/xpcshell.toml b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/xpcshell.toml index 2aee95e952..edb77da1bc 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/xpcshell.toml +++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/xpcshell.toml @@ -5,6 +5,7 @@ firefox-appdir = "browser" support-files = [ "../data/**", "../../xpinstall/webmidi_permission.xpi", + "../../xpinstall/amosigned.xpi", ] ["test_android_blocklist_dump.js"] diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js b/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js index e5dffe0b00..c94ef29e31 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js @@ -800,11 +800,7 @@ add_task(async function test_report_recommended() { }); add_task(async function test_query_amo_details() { - async function assertReportOnAMODetails({ - addonId, - addonType = "extension", - expectedReport, - } = {}) { + async function assertReportOnAMODetails({ addonId, expectedReport } = {}) { // Clear last report timestamp and any telemetry event recorded so far. clearAbuseReportState(); Services.telemetry.clearEvents(); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js index 6f1c99eaa8..9071328680 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Tests AddonRepository.jsm +// Tests AddonRepository.sys.mjs var gServer = createHttpServer({ hosts: ["example.com"] }); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_appIsShuttingDown.js b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_appIsShuttingDown.js index 4f23026ed3..c1f63496a3 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_appIsShuttingDown.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_appIsShuttingDown.js @@ -2,8 +2,8 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Tests AddonRepository.jsm when backgroundUpdateChecks are hit while the application -// shutdown has been already initiated (See Bug 1841444). +// Tests AddonRepository.sys.mjs when backgroundUpdateChecks are hit while the +// application shutdown has been already initiated (See Bug 1841444). const { sinon } = ChromeUtils.importESModule( "resource://testing-common/Sinon.sys.mjs" diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js index 2a1bc2721b..c7b10afa19 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js @@ -465,7 +465,7 @@ function check_cache(aExpectedToFind, aExpectedImmediately) { for (let i = 0; i < REPOSITORY_ADDONS.length; i++) { lookups.push( - new Promise((resolve, reject) => { + new Promise(resolve => { let immediatelyFound = true; let expected = aExpectedToFind[i] ? REPOSITORY_ADDONS[i] : null; // can't Promise-wrap this because we're also testing whether the callback is diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache_locale.js b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache_locale.js index 37e60e27dd..cf47e388d5 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache_locale.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache_locale.js @@ -152,7 +152,7 @@ function promiseLocaleChanged(requestedLocale) { } return new Promise(resolve => { let localeObserver = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { switch (aTopic) { case REQ_LOC_CHANGE_EVENT: let reqLocs = Services.locale.requestedLocales; @@ -169,7 +169,7 @@ function promiseLocaleChanged(requestedLocale) { function promiseMetaDataUpdate() { return new Promise(resolve => { - let listener = args => { + let listener = () => { Services.prefs.removeObserver(PREF_METADATA_LASTUPDATE, listener); resolve(); }; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_ProductAddonChecker_signatures.js b/toolkit/mozapps/extensions/test/xpcshell/test_ProductAddonChecker_signatures.js index 5ae61568ef..93602ffac9 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_ProductAddonChecker_signatures.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_ProductAddonChecker_signatures.js @@ -98,7 +98,8 @@ add_task(async function test_valid_content_signature() { signedBaseUri + goodXmlPath + "?" + validSignatureQuery, /*allowNonBuiltIn*/ false, /*allowedCerts*/ false, - /*verifyContentSignature*/ true + /*verifyContentSignature*/ true, + /*trustedContentSignatureRoot*/ Ci.nsIX509CertDB.AppXPCShellRoot ); Assert.ok(true, "Should successfully get addon list"); @@ -122,7 +123,8 @@ add_task(async function test_invalid_content_signature() { signedBaseUri + goodXmlPath + "?" + invalidSignatureQuery, /*allowNonBuiltIn*/ false, /*allowedCerts*/ false, - /*verifyContentSignature*/ true + /*verifyContentSignature*/ true, + /*trustedContentSignatureRoot*/ Ci.nsIX509CertDB.AppXPCShellRoot ); Assert.ok(false, "Should fail to get addon list"); } catch (e) { @@ -143,7 +145,8 @@ add_task(async function test_missing_content_signature_header() { signedBaseUri + goodXmlPath + "?" + missingSignatureQuery, /*allowNonBuiltIn*/ false, /*allowedCerts*/ false, - /*verifyContentSignature*/ true + /*verifyContentSignature*/ true, + /*trustedContentSignatureRoot*/ Ci.nsIX509CertDB.AppXPCShellRoot ); Assert.ok(false, "Should fail to get addon list"); } catch (e) { @@ -165,7 +168,8 @@ add_task(async function test_incomplete_content_signature_header() { signedBaseUri + goodXmlPath + "?" + incompleteSignatureQuery, /*allowNonBuiltIn*/ false, /*allowedCerts*/ false, - /*verifyContentSignature*/ true + /*verifyContentSignature*/ true, + /*trustedContentSignatureRoot*/ Ci.nsIX509CertDB.AppXPCShellRoot ); Assert.ok(false, "Should fail to get addon list"); } catch (e) { @@ -187,7 +191,8 @@ add_task(async function test_bad_x5u_content_signature_header() { signedBaseUri + goodXmlPath + "?" + badX5uSignatureQuery, /*allowNonBuiltIn*/ false, /*allowedCerts*/ false, - /*verifyContentSignature*/ true + /*verifyContentSignature*/ true, + /*trustedContentSignatureRoot*/ Ci.nsIX509CertDB.AppXPCShellRoot ); Assert.ok(false, "Should fail to get addon list"); } catch (e) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_addon_manager_telemetry_events.js b/toolkit/mozapps/extensions/test/xpcshell/test_addon_manager_telemetry_events.js index 6a533f540a..d4103420ff 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_addon_manager_telemetry_events.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_addon_manager_telemetry_events.js @@ -40,7 +40,7 @@ function getTelemetryEvents(includeMethods = EVENT_METHODS) { ); return snapshot.parent - .filter(([timestamp, category, method]) => { + .filter(([, category, method]) => { const includeMethod = includeMethods ? includeMethods.includes(method) : true; @@ -68,11 +68,9 @@ function assertNoTelemetryEvents() { return; } - let filteredEvents = snapshot.parent.filter( - ([timestamp, category, method]) => { - return category === EVENT_CATEGORY; - } - ); + let filteredEvents = snapshot.parent.filter(([_timestamp, category]) => { + return category === EVENT_CATEGORY; + }); Assert.deepEqual(filteredEvents, [], "Got no AMTelemetry events as expected"); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js b/toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js index 7b1c6fbef9..579f99687f 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js @@ -206,7 +206,7 @@ add_task(async function delay_updates_complete() { }, }, background() { - browser.runtime.onUpdateAvailable.addListener(details => { + browser.runtime.onUpdateAvailable.addListener(() => { browser.test.notifyPass("reload"); browser.runtime.reload(); }); @@ -273,7 +273,7 @@ add_task(async function delay_updates_defer() { }, }, background() { - browser.runtime.onUpdateAvailable.addListener(details => { + browser.runtime.onUpdateAvailable.addListener(() => { // Upgrade will only proceed when "allow" message received. browser.test.onMessage.addListener(msg => { if (msg == "allow") { @@ -371,7 +371,7 @@ add_task(async function delay_updates_staged() { }, }, background() { - browser.runtime.onUpdateAvailable.addListener(details => { + browser.runtime.onUpdateAvailable.addListener(() => { browser.test.sendMessage("denied"); }); browser.test.sendMessage("ready"); @@ -443,7 +443,7 @@ add_task(async function delay_updates_staged_no_update_url() { }, }, background() { - browser.runtime.onUpdateAvailable.addListener(details => { + browser.runtime.onUpdateAvailable.addListener(() => { browser.test.sendMessage("denied"); }); browser.test.sendMessage("ready"); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js b/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js index 7ef584b54d..0b1690f5a8 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js @@ -179,7 +179,7 @@ function testInstallEvent(expectTelemetry) { let events = snapshot.parent .filter( - ([timestamp, category, method, object, value, extra]) => + ([, category, method, , , extra]) => category === "addonsManager" && method == "install" && extra.step == expectTelemetry.step @@ -229,15 +229,13 @@ function promiseCompleteWebInstall( installInfo.install(); }); - TestUtils.topicObserved("addon-install-confirmation").then( - (subject, data) => { - info(`==== test got addon-install-confirmation`); - let installInfo = subject.wrappedJSObject; - for (let installer of installInfo.installs) { - installer.install(); - } + TestUtils.topicObserved("addon-install-confirmation").then(subject => { + info(`==== test got addon-install-confirmation`); + let installInfo = subject.wrappedJSObject; + for (let installer of installInfo.installs) { + installer.install(); } - ); + }); TestUtils.topicObserved("webextension-permission-prompt").then( ([subject]) => { const { info } = subject.wrappedJSObject || {}; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_install_cancel.js b/toolkit/mozapps/extensions/test/xpcshell/test_install_cancel.js index 0be6ec0359..b5902bc6ba 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_install_cancel.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_install_cancel.js @@ -35,7 +35,7 @@ class TestListener { function startListener(listener) { let observer = { - observe(subject, topic, data) { + observe(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if (channel.URI.spec === "http://example.com/addons/test.xpi") { let channelListener = new TestListener(listener); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_provider_markSafe.js b/toolkit/mozapps/extensions/test/xpcshell/test_provider_markSafe.js index e8062a2caf..033acf3dfc 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_provider_markSafe.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_provider_markSafe.js @@ -12,7 +12,7 @@ function mockAddonProvider(name) { AddonManager.isInstallEnabled("made-up-mimetype"); }, - supportsMimetype(mimetype) { + supportsMimetype() { this.apiAccessed = true; return false; }, diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_provider_shutdown.js b/toolkit/mozapps/extensions/test/xpcshell/test_provider_shutdown.js index 498b28a0c9..47612f1565 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_provider_shutdown.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_provider_shutdown.js @@ -31,7 +31,7 @@ function mockAddonProvider(aName) { mockProvider.doneResolve = resolve; mockProvider.doneReject = reject; }); - mockProvider.shutdownPromise = new Promise((resolve, reject) => { + mockProvider.shutdownPromise = new Promise(resolve => { mockProvider.shutdownResolve = resolve; }); return mockProvider; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js index 993c4a9c53..92e67c53c1 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js @@ -99,11 +99,11 @@ add_task(async function test_can_reload_permanent_addon() { let disabledCalled = false; let enabledCalled = false; AddonManager.addAddonListener({ - onDisabled: aAddon => { + onDisabled: () => { Assert.ok(!enabledCalled); disabledCalled = true; }, - onEnabled: aAddon => { + onEnabled: () => { Assert.ok(disabledCalled); enabledCalled = true; }, diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js b/toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js index 065463864d..99b6bca376 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js @@ -195,25 +195,25 @@ async function test_update_working(file1, file2, expectedSignedState) { await install.addon.uninstall(); } -add_task(async function setup() { +add_setup(async function setup() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4"); await promiseStartupManager(); }); // Try to install a broken add-on -add_task(async function test_install_invalid_modified() { +add_task(useAMOStageCert(), async function test_install_invalid_modified() { let file = createBrokenAddonModify(do_get_file(DATA + ADDONS.signed1)); await test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE); file.remove(true); }); -add_task(async function test_install_invalid_added() { +add_task(useAMOStageCert(), async function test_install_invalid_added() { let file = createBrokenAddonAdd(do_get_file(DATA + ADDONS.signed1)); await test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE); file.remove(true); }); -add_task(async function test_install_invalid_removed() { +add_task(useAMOStageCert(), async function test_install_invalid_removed() { let file = createBrokenAddonRemove(do_get_file(DATA + ADDONS.signed1)); await test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE); file.remove(true); @@ -226,58 +226,62 @@ add_task(async function test_install_invalid_unsigned() { }); // Try to install a signed add-on -add_task(async function test_install_valid() { +add_task(useAMOStageCert(), async function test_install_valid() { let file = do_get_file(DATA + ADDONS.signed1); await test_install_working(file, AddonManager.SIGNEDSTATE_SIGNED); }); add_task( - { - pref_set: [["xpinstall.signatures.dev-root", true]], - // `xpinstall.signatures.dev-root` is not taken into account on release - // builds because `MOZ_REQUIRE_SIGNING` is set to `true`. - skip_if: () => AppConstants.MOZ_REQUIRE_SIGNING, - }, - async function test_install_valid_file_with_different_root_cert() { - const TEST_CASES = [ - { - title: "XPI without ID in manifest", - xpi: "data/webext-implicit-id.xpi", - expectedMessage: - /Cannot find id for addon .+ Preference xpinstall.signatures.dev-root is set/, - }, - { - title: "XPI with ID in manifest", - xpi: DATA + ADDONS.signed1, - expectedMessage: /Add-on test@somewhere.com is not correctly signed/, - }, - ]; + useAMOStageCert(), + async function test_install_implicit_id_with_different_root_cert() { + info( + `test install error on fail to verify signature on XPI without ID in manifest` + ); - for (const { title, xpi, expectedMessage } of TEST_CASES) { - info(`test_install_valid_file_with_different_root_cert: ${title}`); + const xpi = do_get_file("data/webext-implicit-id.xpi"); + const expectedMessage = + /Cannot find id for addon .+ Preference xpinstall.signatures.dev-root is set/; - const file = do_get_file(xpi); + const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { + await test_install_broken( + xpi, + AddonManager.ERROR_CORRUPT_FILE, + // We don't expect the `addon` property on the `install` object to be + // `null` because that seems to happen later (when the signature is + // checked). + false + ); + }); - const awaitConsole = new Promise(resolve => { - Services.console.registerListener(function listener(message) { - if (expectedMessage.test(message.message)) { - Services.console.unregisterListener(listener); - resolve(); - } - }); - }); + AddonTestUtils.checkMessages(messages, { + expected: [{ message: expectedMessage }], + }); + } +); +add_task( + async function test_install_stage_signed_invalid_with_prod_root_cert() { + info( + `test install error on fail to verify signature on XPI with ID in manifest` + ); + + const xpi = do_get_file(DATA + ADDONS.signed1); + const expectedMessage = /Add-on test@somewhere.com is not correctly signed/; + + const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { await test_install_broken( - file, + xpi, AddonManager.ERROR_CORRUPT_FILE, // We don't expect the `addon` property on the `install` object to be // `null` because that seems to happen later (when the signature is // checked). false ); + }); - await awaitConsole; - } + AddonTestUtils.checkMessages(messages, { + expected: [{ message: expectedMessage }], + }); } ); @@ -291,25 +295,34 @@ add_task(async function test_install_valid_sha256() { // Try to install an add-on with the "Mozilla Extensions" OU add_task(async function test_install_valid_privileged() { let file = do_get_file(DATA + ADDONS.privileged); - await test_install_working(file, AddonManager.SIGNEDSTATE_PRIVILEGED); + try { + // Prevent install to fail due to privileged.xpi version using + // a version format that hits a manifest warning. + // TODO(Bug 1824240): remove this once privileged.xpi can be resigned with a + // version format that does not hit a manifest warning. + ExtensionTestUtils.failOnSchemaWarnings(false); + await test_install_working(file, AddonManager.SIGNEDSTATE_PRIVILEGED); + } finally { + ExtensionTestUtils.failOnSchemaWarnings(true); + } }); // Try to update to a broken add-on -add_task(async function test_update_invalid_modified() { +add_task(useAMOStageCert(), async function test_update_invalid_modified() { let file1 = do_get_file(DATA + ADDONS.signed1); let file2 = createBrokenAddonModify(do_get_file(DATA + ADDONS.signed2)); await test_update_broken(file1, file2, AddonManager.ERROR_CORRUPT_FILE); file2.remove(true); }); -add_task(async function test_update_invalid_added() { +add_task(useAMOStageCert(), async function test_update_invalid_added() { let file1 = do_get_file(DATA + ADDONS.signed1); let file2 = createBrokenAddonAdd(do_get_file(DATA + ADDONS.signed2)); await test_update_broken(file1, file2, AddonManager.ERROR_CORRUPT_FILE); file2.remove(true); }); -add_task(async function test_update_invalid_removed() { +add_task(useAMOStageCert(), async function test_update_invalid_removed() { let file1 = do_get_file(DATA + ADDONS.signed1); let file2 = createBrokenAddonRemove(do_get_file(DATA + ADDONS.signed2)); await test_update_broken(file1, file2, AddonManager.ERROR_CORRUPT_FILE); @@ -317,7 +330,7 @@ add_task(async function test_update_invalid_removed() { }); // Try to update to an unsigned add-on -add_task(async function test_update_invalid_unsigned() { +add_task(useAMOStageCert(), async function test_update_invalid_unsigned() { let file1 = do_get_file(DATA + ADDONS.signed1); let file2 = do_get_file(DATA + ADDONS.unsigned); await test_update_broken( @@ -328,7 +341,7 @@ add_task(async function test_update_invalid_unsigned() { }); // Try to update to a signed add-on -add_task(async function test_update_valid() { +add_task(useAMOStageCert(), async function test_update_valid() { let file1 = do_get_file(DATA + ADDONS.signed1); let file2 = do_get_file(DATA + ADDONS.signed2); await test_update_working(file1, file2, AddonManager.SIGNEDSTATE_SIGNED); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_signed_langpack.js b/toolkit/mozapps/extensions/test/xpcshell/test_signed_langpack.js index 8ad83b2ecb..421d40f4a0 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_langpack.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_langpack.js @@ -32,7 +32,7 @@ async function installShouldFail(file) { // Test that the preference controlling langpack signing works properly // (and that the general preference for addon signing does not affect // language packs). -add_task(async function () { +add_task(useAMOStageCert(), async function () { AddonTestUtils.useRealCertChecks = true; createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9"); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js b/toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js index 2aa76e8ff8..6213aa0f1b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js @@ -4,7 +4,7 @@ const ID = "123456789012345678901234567890123456789012345678901@somewhere.com"; // Tests that signature verification works correctly on an extension with // an ID that does not fit into a certificate CN field. -add_task(async function test_long_id() { +add_task(useAMOStageCert(), async function test_long_id() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1"); await promiseStartupManager(); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js b/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js index c17cb941cb..e801485c73 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js @@ -25,9 +25,439 @@ function verifySignatures() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4"); -add_task(async function test_no_change() { +add_setup(async () => { await promiseStartupManager(); +}); + +add_task(function test_hasStrongSignature_helper() { + const { hasStrongSignature } = ChromeUtils.importESModule( + "resource://gre/modules/addons/crypto-utils.sys.mjs" + ); + const { PKCS7_WITH_SHA1, PKCS7_WITH_SHA256, COSE_WITH_SHA256 } = + Ci.nsIAppSignatureInfo; + const testCases = [ + [false, "SHA1 only", [PKCS7_WITH_SHA1]], + [true, "SHA256 only", [PKCS7_WITH_SHA256]], + [true, "COSE only", [COSE_WITH_SHA256]], + [true, "SHA1 and SHA256", [PKCS7_WITH_SHA1, PKCS7_WITH_SHA256]], + [true, "SHA1 and COSE", [PKCS7_WITH_SHA1, COSE_WITH_SHA256]], + [true, "SHA256 and COSE", [PKCS7_WITH_SHA256, COSE_WITH_SHA256]], + ]; + for (const [expect, msg, signedTypes] of testCases) { + Assert.equal(hasStrongSignature({ signedTypes }), expect, msg); + } +}); + +add_task(async function test_addon_signedTypes() { + // This test is allowing weak signatures to run assertions on the AddonWrapper.signedTypes + // property also for extensions only including SHA1 signatures. + const resetWeakSignaturePref = + AddonTestUtils.setWeakSignatureInstallAllowed(true); + + const { PKCS7_WITH_SHA1, COSE_WITH_SHA256 } = Ci.nsIAppSignatureInfo; + + const { addon: addonSignedCOSE } = await promiseInstallFile( + do_get_file("amosigned-mv3-cose.xpi") + ); + const { addon: addonSignedSHA1 } = await promiseInstallFile( + do_get_file("amosigned-sha1only.xpi") + ); + + Assert.deepEqual( + addonSignedCOSE.signedTypes.sort(), + [COSE_WITH_SHA256, PKCS7_WITH_SHA1].sort(), + `Expect ${addonSignedCOSE.id} to be signed with both COSE and SHA1` + ); + + Assert.deepEqual( + addonSignedSHA1.signedTypes, + [PKCS7_WITH_SHA1], + `Expect ${addonSignedSHA1.id} to be signed with SHA1 only` + ); + + await addonSignedSHA1.uninstall(); + await addonSignedCOSE.uninstall(); + + resetWeakSignaturePref(); +}); + +add_task( + async function test_install_error_on_new_install_with_weak_signature() { + // Ensure restrictions on weak signatures are enabled (this should be removed when + // the new behavior is riding the train). + const resetWeakSignaturePref = + AddonTestUtils.setWeakSignatureInstallAllowed(false); + + const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { + let install = await AddonManager.getInstallForFile( + do_get_file("amosigned-sha1only.xpi") + ); + + await Assert.equal( + install.state, + AddonManager.STATE_DOWNLOAD_FAILED, + "Expect install state to be STATE_DOWNLOAD_FAILED" + ); + + await Assert.rejects( + install.install(), + /Install failed: onDownloadFailed/, + "Expected install to fail" + ); + }); + + resetWeakSignaturePref(); + + // Checking the message expected to be logged in the Browser Console. + AddonTestUtils.checkMessages(messages, { + expected: [ + { + message: + /Invalid XPI: install rejected due to the package not including a strong cryptographic signature/, + }, + ], + }); + } +); + +/** + * Test helper used to simulate an update from a given pre-installed add-on xpi to a new xpi file for the same + * add-on and assert the expected result and logged messages. + * + * @param {object} params + * @param {string} params.currentAddonXPI + * The path to the add-on xpi to be pre-installed and then updated to `newAddonXPI`. + * @param {string} params.newAddonXPI + * The path to the add-on xpi to be installed as an update over `currentAddonXPI`. + * @param {string} params.newAddonVersion + * The add-on version expected for `newAddonXPI`. + * @param {boolean} params.expectedInstallOK + * Set to true for an update scenario that is expected to be successful. + * @param {Array<string|RegExp>} params.expectedMessages + * Array of strings or RegExp for console messages expected to be logged. + * @param {Array<string|RegExp>} params.forbiddenMessages + * Array of strings or RegExp for console messages expected to NOT be logged. + */ +async function testWeakSignatureXPIUpdate({ + currentAddonXPI, + newAddonXPI, + newAddonVersion, + expectedInstallOK, + expectedMessages, + forbiddenMessages, +}) { + // Temporarily allow weak signature to install the xpi as a new install. + let resetWeakSignaturePref = + AddonTestUtils.setWeakSignatureInstallAllowed(true); + + const { addon: addonFirstInstall } = await promiseInstallFile( + currentAddonXPI + ); + const addonId = addonFirstInstall.id; + const initialAddonVersion = addonFirstInstall.version; + + resetWeakSignaturePref(); + + // Make sure the install over is executed while weak signature is not allowed + // for new installs to confirm that installing over is allowed. + resetWeakSignaturePref = AddonTestUtils.setWeakSignatureInstallAllowed(false); + + info("Install over the existing installed addon"); + let addonInstalledOver; + const { messages } = await AddonTestUtils.promiseConsoleOutput(async () => { + const fileURL = Services.io.newFileURI(newAddonXPI).spec; + let install = await AddonManager.getInstallForURL(fileURL, { + existingAddon: addonFirstInstall, + version: newAddonVersion, + }); + + addonInstalledOver = await install.install().catch(err => { + if (expectedInstallOK) { + ok(false, `Unexpected error hit on installing update XPI: ${err}`); + } else { + ok(true, `Install failed as expected: ${err}`); + } + }); + }); + + resetWeakSignaturePref(); + + if (expectedInstallOK) { + Assert.equal( + addonInstalledOver.id, + addonFirstInstall.id, + "Expect addon id to be the same" + ); + Assert.equal( + addonInstalledOver.version, + newAddonVersion, + "Got expected addon version after update xpi install completed" + ); + await addonInstalledOver.uninstall(); + } else { + Assert.equal( + addonInstalledOver?.version, + undefined, + "Expect update addon xpi not installed successfully" + ); + Assert.equal( + (await AddonManager.getAddonByID(addonId)).version, + initialAddonVersion, + "Expect the addon version to match the initial XPI version" + ); + await addonFirstInstall.uninstall(); + } + + Assert.equal( + await AddonManager.getAddonByID(addonId), + undefined, + "Expect the test addon to be fully uninstalled" + ); + + // Checking the message logged in the Browser Console. + AddonTestUtils.checkMessages(messages, { + expected: expectedMessages, + forbidden: forbiddenMessages, + }); +} + +add_task(async function test_weak_install_over_weak_existing() { + const addonId = "amosigned-xpi@tests.mozilla.org"; + await testWeakSignatureXPIUpdate({ + currentAddonXPI: do_get_file("amosigned-sha1only.xpi"), + newAddonXPI: do_get_file("amosigned-sha1only.xpi"), + newAddonVersion: "2.1", + expectedInstallOK: true, + expectedMessages: [ + { + message: new RegExp( + `Allow weak signature install over existing "${addonId}" XPI` + ), + }, + ], + }); +}); + +add_task(async function test_update_weak_to_strong_signature() { + const addonId = "amosigned-xpi@tests.mozilla.org"; + await testWeakSignatureXPIUpdate({ + currentAddonXPI: do_get_file("amosigned-sha1only.xpi"), + newAddonXPI: do_get_file("amosigned.xpi"), + newAddonVersion: "2.2", + expectedInstallOK: true, + forbiddenMessages: [ + { + message: new RegExp( + `Allow weak signature install over existing "${addonId}" XPI` + ), + }, + ], + }); +}); + +add_task(async function test_update_strong_to_weak_signature() { + const addonId = "amosigned-xpi@tests.mozilla.org"; + await testWeakSignatureXPIUpdate({ + currentAddonXPI: do_get_file("amosigned.xpi"), + newAddonXPI: do_get_file("amosigned-sha1only.xpi"), + newAddonVersion: "2.1", + expectedInstallOK: false, + expectedMessages: [ + { + message: new RegExp( + "Invalid XPI: install rejected due to the package not including a strong cryptographic signature" + ), + }, + ], + forbiddenMessages: [ + { + message: new RegExp( + `Allow weak signature install over existing "${addonId}" XPI` + ), + }, + ], + }); +}); + +add_task(async function test_signedTypes_stored_in_addonDB() { + const { addon: addonAfterInstalled } = await promiseInstallFile( + do_get_file("amosigned-mv3-cose.xpi") + ); + const addonId = addonAfterInstalled.id; + + const { PKCS7_WITH_SHA1, COSE_WITH_SHA256 } = Ci.nsIAppSignatureInfo; + const expectedSignedTypes = [COSE_WITH_SHA256, PKCS7_WITH_SHA1].sort(); + + Assert.deepEqual( + addonAfterInstalled.signedTypes.sort(), + expectedSignedTypes, + `Got expected ${addonId} signedTyped after install` + ); + + await promiseRestartManager(); + + const addonAfterAOMRestart = await AddonManager.getAddonByID(addonId); + + Assert.deepEqual( + addonAfterAOMRestart.signedTypes.sort(), + expectedSignedTypes, + `Got expected ${addonId} signedTyped after AOM restart` + ); + + const removeSignedStateFromAddonDB = async () => { + const addon_db_file = Services.dirsvc.get("ProfD", Ci.nsIFile); + addon_db_file.append("extensions.json"); + const addon_db_data = await IOUtils.readJSON(addon_db_file.path); + + const addon_db_data_tampered = { + ...addon_db_data, + addons: addon_db_data.addons.map(addonData => { + // Tamper the data of the test extension to mock the + // scenario. + delete addonData.signedTypes; + return addonData; + }), + }; + await IOUtils.writeJSON(addon_db_file.path, addon_db_data_tampered); + }; + + // Shutdown the AddonManager and tamper the AddonDB to confirm XPIProvider.checkForChanges + // calls originated internally when opening a profile created from a previous Firefox version + // is going to populate the new signedTypes property. + info( + "Check that XPIProvider.checkForChanges(true) will recompute missing signedTypes properties" + ); + await promiseShutdownManager(); + await removeSignedStateFromAddonDB(); + await promiseStartupManager(); + + // Expect the signedTypes property to be undefined because of the + // AddonDB data being tampered earlier in this test. + const addonAfterAppUpgrade = await AddonManager.getAddonByID(addonId); + Assert.deepEqual( + addonAfterAppUpgrade.signedTypes, + undefined, + `Got empty ${addonId} signedTyped set to undefied after AddonDB data tampered` + ); + + // Mock call to XPIDatabase.checkForChanges expected to be hit when the application + // is updated. + AddonTestUtils.getXPIExports().XPIProvider.checkForChanges( + /* aAppChanged */ true + ); + + Assert.deepEqual( + addonAfterAppUpgrade.signedTypes?.sort(), + expectedSignedTypes.sort(), + `Got expected ${addonId} signedTyped after XPIProvider.checkForChanges recomputed it` + ); + + // Shutdown the AddonManager and tamper the AddonDB to confirm XPIDatabase.updateCompatibility + // would populate signedTypes if missing. + info( + "Check that XPIDatabase.updateCompatibility will recompute missing signedTypes properties" + ); + await promiseShutdownManager(); + await removeSignedStateFromAddonDB(); + await promiseStartupManager(); + + // Expect the signedTypes property to be undefined because of the + // AddonDB data being tampered earlier in this test. + const addonAfterUpdateCompatibility = await AddonManager.getAddonByID( + addonId + ); + Assert.deepEqual( + addonAfterUpdateCompatibility.signedTypes, + undefined, + `Got empty ${addonId} signedTyped set to undefied after AddonDB data tampered` + ); + + // Mock call to XPIDatabase.updateCompatibility expected to be originated from + // XPIDatabaseReconcile.processFileChanges and confirm that signedTypes has been + // recomputed as expected. + AddonTestUtils.getXPIExports().XPIDatabaseReconcile.processFileChanges( + {}, + true + ); + Assert.deepEqual( + addonAfterUpdateCompatibility.signedTypes?.sort(), + expectedSignedTypes.sort(), + `Got expected ${addonId} signedTyped after XPIDatabase.updateCompatibility recomputed it` + ); + + // Restart the AddonManager and confirm that XPIDatabase.verifySignatures would not recompute + // the content of the signedTypes array if all values are still the same. + info( + "Check that XPIDatabase.updateCompatibility will recompute missing signedTypes properties" + ); + await promiseRestartManager(); + + let listener = { + onPropertyChanged(_addon, properties) { + Assert.deepEqual( + properties, + [], + `No properties should have been changed for ${_addon.id}` + ); + Assert.ok( + false, + `onPropertyChanged should have not been called for ${_addon.id}` + ); + }, + }; + + AddonManager.addAddonListener(listener); + await verifySignatures(); + AddonManager.removeAddonListener(listener); + + // Shutdown the AddonManager and tamper the AddonDB to set signedTypes to undefined + // then confirm that XPIDatabase.verifySignatures does not hit an exception due to + // signedTypes assumed to always be set to an array. + info( + "Check that XPIDatabase.verifySignatures does not fail when signedTypes is undefined" + ); + await promiseShutdownManager(); + await removeSignedStateFromAddonDB(); + await promiseStartupManager(); + + // Expect the signedTypes property to be undefined because of the + // AddonDB data being tampered earlier in this test. + const addonUndefinedSignedTypes = await AddonManager.getAddonByID(addonId); + Assert.deepEqual( + addonUndefinedSignedTypes.signedTypes, + undefined, + `Got empty ${addonId} signedTyped set to undefied after AddonDB data tampered` + ); + await verifySignatures(); + Assert.deepEqual( + addonUndefinedSignedTypes.signedTypes?.sort(), + expectedSignedTypes.sort(), + `Got expected ${addonId} signedTyped after XPIDatabase.verifySignatures recomputed it` + ); + + await addonUndefinedSignedTypes.uninstall(); +}); + +add_task( + { + pref_set: [["xpinstall.signatures.required", false]], + // Skip this test on builds where disabling xpi signature checks is not supported. + skip_if: () => AppConstants.MOZ_REQUIRE_SIGNING, + }, + async function test_weak_signature_not_restricted_on_disabled_signature_checks() { + // Ensure the restriction on installing xpi using only weak signatures is enabled. + let resetWeakSignaturePref = + AddonTestUtils.setWeakSignatureInstallAllowed(false); + const { addon } = await promiseInstallFile( + do_get_file("amosigned-sha1only.xpi") + ); + Assert.notEqual(addon, null, "Expect addon to be installed"); + resetWeakSignaturePref(); + await addon.uninstall(); + } +); +add_task(useAMOStageCert(), async function test_no_change() { // Install the first add-on await promiseInstallFile(do_get_file(`${DATA}/signed1.xpi`)); @@ -43,7 +473,7 @@ add_task(async function test_no_change() { await manuallyInstall(do_get_file(`${DATA}/signed2.xpi`), profileDir, ID); let listener = { - onPropetyChanged(_addon, properties) { + onPropertyChanged(_addon) { Assert.ok(false, `Got unexpected onPropertyChanged for ${_addon.id}`); }, }; @@ -63,7 +493,7 @@ add_task(async function test_no_change() { AddonManager.removeAddonListener(listener); }); -add_task(async function test_diable() { +add_task(useAMOStageCert(), async function test_disable() { // Install the first add-on await promiseInstallFile(do_get_file(`${DATA}/signed1.xpi`)); @@ -96,7 +526,7 @@ add_task(async function test_diable() { Assert.deepEqual( changedProperties, - ["signedState", "appDisabled"], + ["signedState", "signedTypes", "appDisabled"], "Got onPropertyChanged events for signedState and appDisabled" ); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js index 4490ec065b..b7dfd0ba72 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js @@ -26,7 +26,7 @@ registerCleanupFunction(() => { distroDir.remove(true); }); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42"); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js index dc1c96e7bc..342410992b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js @@ -29,7 +29,7 @@ add_task(async function test_app_addons() { `http://localhost:${gServer.identity.primaryPort}/get?%IDS%` ); - gServer.registerPathHandler("/get", (request, response) => { + gServer.registerPathHandler("/get", () => { do_throw("Unexpected request to server."); }); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_reset.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_reset.js index 93e4c516fa..37e056c140 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_reset.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_reset.js @@ -3,7 +3,7 @@ const updatesDir = FileUtils.getDir("ProfD", ["features"]); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(async function setup() { // Build the test sets @@ -489,7 +489,7 @@ add_task(async function test_bad_app_cert() { await promiseShutdownManager(); - AddonTestUtils.usePrivilegedSignatures = id => "system"; + AddonTestUtils.usePrivilegedSignatures = () => "system"; }); // A failed upgrade should revert to the default set. diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_blank.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_blank.js index 56d10436c7..a60d72f8b3 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_blank.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_blank.js @@ -6,7 +6,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(() => initSystemAddonDirs()); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_checkSizeHash.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_checkSizeHash.js index f9ac09255a..456164dfae 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_checkSizeHash.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_checkSizeHash.js @@ -6,7 +6,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; /** * Defines the set of initial conditions to run each test against. Each should diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js index b0310d3ceb..22250d6724 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js @@ -6,7 +6,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(initSystemAddonDirs); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_empty.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_empty.js index 3fae4272be..16c2084842 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_empty.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_empty.js @@ -6,7 +6,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(() => initSystemAddonDirs()); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_installTelemetryInfo.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_installTelemetryInfo.js index f67894289d..bc690cad71 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_installTelemetryInfo.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_installTelemetryInfo.js @@ -7,7 +7,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(() => initSystemAddonDirs()); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_newset.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_newset.js index fd93ba5d38..3a1746d28c 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_newset.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_newset.js @@ -6,7 +6,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(() => initSystemAddonDirs()); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_overlapping.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_overlapping.js index a6c5bc905c..61d3d91300 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_overlapping.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_overlapping.js @@ -7,7 +7,7 @@ distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); add_task(() => initSystemAddonDirs()); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; /** * Defines the set of initial conditions to run each test against. Each should diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_uninstall_check.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_uninstall_check.js index bf2dd85772..b2daa307db 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_uninstall_check.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_uninstall_check.js @@ -35,7 +35,7 @@ add_task(async function test_systems_update_uninstall_check() { }, ]); - const listener = (msg, { method, params, reason }) => { + const listener = (msg, { method, params }) => { if (params.id === "system2@tests.mozilla.org" && method === "uninstall") { Assert.ok( false, diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_upgrades.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_upgrades.js index d270f33190..8e2d7776ef 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_upgrades.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_upgrades.js @@ -6,7 +6,7 @@ let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]); distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", distroDir); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; add_task(() => initSystemAddonDirs()); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_upgrades.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_upgrades.js index f02003805c..ddf98c73ec 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_system_upgrades.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_upgrades.js @@ -20,7 +20,7 @@ const systemDefaults = FileUtils.getDir("ProfD", [ systemDefaults.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); registerDirectory("XREAppFeat", systemDefaults); -AddonTestUtils.usePrivilegedSignatures = id => "system"; +AddonTestUtils.usePrivilegedSignatures = () => "system"; const ADDON_ID = "updates@test"; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js b/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js index 80faa57fc1..0bef760261 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js @@ -80,7 +80,7 @@ add_task(async function test_new_temporary() { Assert.equal(aInstall.version, "1.0"); installedCalled = true; }, - onInstallStarted: aInstall => { + onInstallStarted: () => { do_throw("onInstallStarted called unexpectedly"); }, }); @@ -416,7 +416,7 @@ add_task(async function test_replace_permanent() { } installedCalled = true; }, - onInstallStarted: aInstall => { + onInstallStarted: () => { do_throw("onInstallStarted called unexpectedly"); }, }); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_update.js b/toolkit/mozapps/extensions/test/xpcshell/test_update.js index 1bd41e8d71..708b9de264 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_update.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_update.js @@ -595,25 +595,22 @@ add_task(async function test_params() { let resultsPromise = new Promise(resolve => { let results = new Map(); - testserver.registerPathHandler( - "/data/param_test.json", - function (request, response) { - let params = new URLSearchParams(request.queryString); - let itemId = params.get("item_id"); - ok( - !results.has(itemId), - `Should not see a duplicate request for item ${itemId}` - ); - - results.set(itemId, params); - - if (results.size === PARAM_IDS.length) { - resolve(results); - } - - request.setStatusLine(null, 500, "Server Error"); + testserver.registerPathHandler("/data/param_test.json", function (request) { + let params = new URLSearchParams(request.queryString); + let itemId = params.get("item_id"); + ok( + !results.has(itemId), + `Should not see a duplicate request for item ${itemId}` + ); + + results.set(itemId, params); + + if (results.size === PARAM_IDS.length) { + resolve(results); } - ); + + request.setStatusLine(null, 500, "Server Error"); + }); }); let addons = await getAddons(PARAM_IDS); @@ -746,11 +743,11 @@ add_task(async function test_no_auto_update() { equal(aInstall.existingAddon.id, "addon1@tests.mozilla.org"); }, - onDownloadFailed(aInstall) { + onDownloadFailed() { ok(false, "Should not have seen onDownloadFailed event"); }, - onDownloadCancelled(aInstall) { + onDownloadCancelled() { ok(false, "Should not have seen onDownloadCancelled event"); }, @@ -764,11 +761,11 @@ add_task(async function test_no_auto_update() { resolve(); }, - onInstallFailed(aInstall) { + onInstallFailed() { ok(false, "Should not have seen onInstallFailed event"); }, - onInstallCancelled(aInstall) { + onInstallCancelled() { ok(false, "Should not have seen onInstallCancelled event"); }, }; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js b/toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js index ac201f434c..bba7a1b77b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js @@ -27,7 +27,7 @@ function makeCancelListener() { }); return { - onUpdateAvailable(addon, install) { + onUpdateAvailable() { reject("Should not have seen onUpdateAvailable notification"); }, diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_update_addontype.js b/toolkit/mozapps/extensions/test/xpcshell/test_update_addontype.js index ca324cf4ef..221f9e003e 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_update_addontype.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_update_addontype.js @@ -67,7 +67,7 @@ add_task(async function test_update_theme_to_extension() { await Assert.rejects( install.install(), - err => install.error == AddonManager.ERROR_UNEXPECTED_ADDON_TYPE, + () => install.error == AddonManager.ERROR_UNEXPECTED_ADDON_TYPE, "Refusing to change addon type from theme to extension" ); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_update_noSystemAddonUpdate.js b/toolkit/mozapps/extensions/test/xpcshell/test_update_noSystemAddonUpdate.js index f13187ab33..93ff750066 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_update_noSystemAddonUpdate.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_update_noSystemAddonUpdate.js @@ -25,7 +25,7 @@ add_task(async function test_systems_update_uninstall_check() { await setupSystemAddonConditions(initialSetup, distroDir); const testserver = createHttpServer({ hosts: ["example.com"] }); - testserver.registerPathHandler("/update.json", (request, response) => { + testserver.registerPathHandler("/update.json", request => { Assert.ok( !request._queryString.includes("system2@tests.mozilla.org"), "System addon should not request update from normal update process" diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_updateid.js b/toolkit/mozapps/extensions/test/xpcshell/test_updateid.js index c88c8e637b..06dd536b9a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_updateid.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_updateid.js @@ -74,7 +74,7 @@ add_task(async function test_update_new_id() { await Assert.rejects( install.install(), - err => install.error == AddonManager.ERROR_INCORRECT_ID, + () => install.error == AddonManager.ERROR_INCORRECT_ID, "Upgrade to a different ID fails" ); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_updateversion.js b/toolkit/mozapps/extensions/test/xpcshell/test_updateversion.js index 4d1510c40f..5d6e045f21 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_updateversion.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_updateversion.js @@ -65,7 +65,7 @@ add_task(async function test_update_version_mismatch() { await Assert.rejects( install.install(), - err => install.error == AddonManager.ERROR_UNEXPECTED_ADDON_VERSION, + () => install.error == AddonManager.ERROR_UNEXPECTED_ADDON_VERSION, "Should refuse installation when downloaded version does not match" ); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js index cd4b376117..db5f1d5925 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js @@ -316,6 +316,73 @@ add_task(async function test_options_ui() { ); await addon.uninstall(); + + info("Test again with options_page manifest property"); + const ID3 = "options_page_alias@tests.mozilla.org"; + addon = await promiseInstallWebExtension({ + manifest: { + browser_specific_settings: { gecko: { id: ID3 } }, + options_page: "options.html", + }, + }); + + checkAddon(ID3, addon, { + optionsType: AddonManager.OPTIONS_TYPE_TAB, + }); + + ok( + OPTIONS_RE.test(addon.optionsURL), + "Addon should have a moz-extension: options URL for /options.html" + ); + + await addon.uninstall(); + + info("Test options_page and options_page set to a different page"); + + const ID4 = "options_page_warning@tests.mozilla.org"; + addon = await promiseInstallWebExtension({ + manifest: { + browser_specific_settings: { gecko: { id: ID4 } }, + options_page: "options_page.html", + options_ui: { + page: "options.html", + open_in_tab: false, + }, + }, + }); + + checkAddon(ID4, addon, { + optionsType: AddonManager.OPTIONS_TYPE_INLINE_BROWSER, + }); + + ok( + OPTIONS_RE.test(addon.optionsURL), + "Addon should have a moz-extension: options URL for /options.html" + ); + + await addon.uninstall(); + + info("Test options_page and options_page are both set to the same page"); + + const ID5 = "options_page_and_ui_same_page@tests.mozilla.org"; + addon = await promiseInstallWebExtension({ + manifest: { + browser_specific_settings: { gecko: { id: ID5 } }, + options_page: "options.html", + options_ui: { page: "options.html" }, + }, + }); + + checkAddon(ID5, addon, { + optionsType: AddonManager.OPTIONS_TYPE_INLINE_BROWSER, + }); + + ok( + OPTIONS_RE.test(addon.optionsURL), + "Addon should have a moz-extension: options URL for /options.html" + ); + + await addon.uninstall(); }); // Test that experiments permissions add the appropriate dependencies. diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js index 1b2080e8db..913c802609 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js @@ -11,8 +11,10 @@ add_task(async function setup() { await promiseStartupManager(); }); +// Extension without id in the manifest file and signed with AMO prod root +// (https://addons.mozilla.org/en-US/firefox/addon/reference-static-theme/). const IMPLICIT_ID_XPI = "data/webext-implicit-id.xpi"; -const IMPLICIT_ID_ID = "webext_implicit_id@tests.mozilla.org"; +const IMPLICIT_ID_ID = "{46607a7b-1b2a-40ce-9afe-91cda52c46a6}"; // webext-implicit-id.xpi has a minimal manifest with no // applications or browser_specific_settings, so its id comes diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml index 6b1cb010d4..e8d3807ab9 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml @@ -4,7 +4,12 @@ tags = "addons" head = "head_addons.js" firefox-appdir = "browser" dupe-manifest = true -support-files = ["data/**"] +support-files = [ + "data/**", + "../xpinstall/amosigned.xpi", + "../xpinstall/amosigned-mv3-cose.xpi", + "../xpinstall/amosigned-sha1only.xpi", +] ["test_AMBrowserExtensionsImport.js"] diff --git a/toolkit/mozapps/extensions/test/xpinstall/amosigned-mv3-cose.xpi b/toolkit/mozapps/extensions/test/xpinstall/amosigned-mv3-cose.xpi Binary files differnew file mode 100644 index 0000000000..e09747686b --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/amosigned-mv3-cose.xpi diff --git a/toolkit/mozapps/extensions/test/xpinstall/amosigned-sha1only.xpi b/toolkit/mozapps/extensions/test/xpinstall/amosigned-sha1only.xpi Binary files differnew file mode 100644 index 0000000000..f2948e6994 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/amosigned-sha1only.xpi diff --git a/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi b/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi Binary files differindex f2948e6994..9e895dbbb4 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi +++ b/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser.toml b/toolkit/mozapps/extensions/test/xpinstall/browser.toml index f6ca43982e..f2c73b0a1d 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser.toml +++ b/toolkit/mozapps/extensions/test/xpinstall/browser.toml @@ -96,7 +96,7 @@ https_first_disabled = true # Bug 1737265 ["browser_doorhanger_installs.js"] https_first_disabled = true # Bug 1737265 skip-if = [ - "os == 'win' && os_version == '10.0' && bits == 64", #Bug 1615449 + "os == 'win' && os_version == '10.2009' && bits == 64", #Bug 1615449 ] ["browser_empty.js"] diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_auth.js b/toolkit/mozapps/extensions/test/xpinstall/browser_auth.js index 2248af4270..171504049c 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth.js @@ -42,7 +42,7 @@ function get_auth_info() { return ["testuser", "testpass"]; } -function download_failed(install) { +function download_failed() { ok(false, "Install should not have failed"); } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js b/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js index 46ee2b5cb6..0763d2e55c 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js @@ -45,7 +45,7 @@ function get_auth_info() { return ["testuser", "testpass"]; } -function download_failed(install) { +function download_failed() { ok(false, "Install should not have failed"); } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js index 690ac2b3eb..ca05f822b6 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js @@ -54,7 +54,7 @@ function allow_blocked(installInfo) { return false; } -function confirm_install(panel) { +function confirm_install() { ok(false, "Should not see the install dialog"); return false; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699_postDownload.js b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699_postDownload.js index aa8b948c14..a857d11405 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699_postDownload.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699_postDownload.js @@ -40,7 +40,7 @@ function allow_blocked(installInfo) { return false; } -function confirm_install(panel) { +function confirm_install() { ok(false, "Should not see the install dialog"); return false; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js b/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js index 216d543458..2961d327d3 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js @@ -36,7 +36,7 @@ function test() { ); } -function confirm_install(panel) { +function confirm_install() { ok(false, "Should not see the install dialog"); return false; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js b/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js index 01c8089180..073c44eecd 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_doorhanger_installs.js @@ -52,7 +52,7 @@ async function waitForProgressNotification( let topic = getObserverTopic(notificationId); let observerPromise = new Promise(resolve => { - Services.obs.addObserver(function observer(aSubject, aTopic, aData) { + Services.obs.addObserver(function observer(aSubject, aTopic) { // Ignore the progress notification unless that is the notification we want if ( notificationId != PROGRESS_NOTIFICATION && @@ -208,7 +208,7 @@ async function waitForNotification( let observerPromise; if (aId !== "addon-webext-permissions") { observerPromise = new Promise(resolve => { - Services.obs.addObserver(function observer(aSubject, aTopic, aData) { + Services.obs.addObserver(function observer(aSubject, aTopic) { // Ignore the progress notification unless that is the notification we want if ( aId != PROGRESS_NOTIFICATION && @@ -298,7 +298,7 @@ function acceptInstallDialog(installDialog) { installDialog.button.click(); } -async function waitForSingleNotification(aCallback) { +async function waitForSingleNotification() { while (PopupNotifications.panel.childNodes.length != 1) { await new Promise(resolve => executeSoon(resolve)); @@ -697,27 +697,37 @@ var TESTS = [ let installDialogPromise = waitForInstallDialog(); - let tab = await BrowserTestUtils.openNewForegroundTab( - gBrowser, - TESTROOT + "installtrigger.html?" + triggers - ); + try { + // Prevent install to fail due to privileged.xpi version using + // an addon version that hits a manifest warning (see PRIV_ADDON_VERSION). + // TODO(Bug 1824240): remove this once privileged.xpi can be resigned with a + // version format that does not hit a manifest warning. + ExtensionTestUtils.failOnSchemaWarnings(false); + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + TESTROOT + "installtrigger.html?" + triggers + ); - let notificationPromise = acceptAppMenuNotificationWhenShown( - "addon-installed", - "test@tests.mozilla.org", - { incognitoHidden: true } - ); + let notificationPromise = acceptAppMenuNotificationWhenShown( + "addon-installed", + "test@tests.mozilla.org", + { incognitoHidden: true } + ); - (await installDialogPromise).button.click(); - await notificationPromise; + (await installDialogPromise).button.click(); + await notificationPromise; - let installs = await AddonManager.getAllInstalls(); - is(installs.length, 0, "Should be no pending installs"); + let installs = await AddonManager.getAllInstalls(); + is(installs.length, 0, "Should be no pending installs"); - let addon = await AddonManager.getAddonByID("test@tests.mozilla.org"); - await addon.uninstall(); + let addon = await AddonManager.getAddonByID("test@tests.mozilla.org"); + await addon.uninstall(); + + await BrowserTestUtils.removeTab(tab); + } finally { + ExtensionTestUtils.failOnSchemaWarnings(true); + } - await BrowserTestUtils.removeTab(tab); await SpecialPowers.popPrefEnv(); AddonManager.checkUpdateSecurity = true; }, @@ -1477,7 +1487,7 @@ var TESTS = [ var gTestStart = null; var XPInstallObserver = { - observe(aSubject, aTopic, aData) { + observe(aSubject, aTopic) { var installInfo = aSubject.wrappedJSObject; info( "Observed " + aTopic + " for " + installInfo.installs.length + " installs" diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js b/toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js index b8ee1b254f..f00d6ca0d8 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js @@ -51,17 +51,17 @@ add_task(async function test_disabled() { add_task(async function test_disabled2() { let installDisabledCalled = false; - Harness.installDisabledCallback = installInfo => { + Harness.installDisabledCallback = () => { installDisabledCalled = true; ok(true, "Saw installation disabled"); }; - Harness.installBlockedCallback = installInfo => { + Harness.installBlockedCallback = () => { ok(false, "Should never see the blocked install notification"); return false; }; - Harness.installConfirmCallback = panel => { + Harness.installConfirmCallback = () => { ok(false, "Should never see an install confirmation dialog"); return false; }; diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_hash.js b/toolkit/mozapps/extensions/test/xpinstall/browser_hash.js index ab7d21b64e..2563b64dd4 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_hash.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_hash.js @@ -1,12 +1,17 @@ // ---------------------------------------------------------------------------- // Test whether an install succeeds when a valid hash is included // This verifies bug 302284 -function test() { +add_task(async function test_install_with_hash() { // This test currently depends on InstallTrigger.install availability. setInstallTriggerPrefs(); - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; + const xpiFilePath = getTestFilePath("./amosigned.xpi"); + const xpiFileHash = await IOUtils.computeHexDigest(xpiFilePath, "sha256"); + + const deferredInstallCompleted = Promise.withResolvers(); + + Harness.installEndedCallback = (install, addon) => addon.uninstall(); + Harness.installsCompletedCallback = deferredInstallCompleted.resolve; Harness.setup(); PermissionTestUtils.add( @@ -19,7 +24,7 @@ function test() { JSON.stringify({ "Unsigned XPI": { URL: TESTROOT + "amosigned.xpi", - Hash: "sha1:ee95834ad862245a9ef99ccecc2a857cadc16404", + Hash: `sha256:${xpiFileHash}`, toString() { return this.URL; }, @@ -31,17 +36,13 @@ function test() { gBrowser, TESTROOT + "installtrigger.html?" + triggers ); -} - -function install_ended(install, addon) { - return addon.uninstall(); -} -function finish_test(count) { + info("Wait for the install to be completed"); + const count = await deferredInstallCompleted.promise; is(count, 1, "1 Add-on should have been successfully installed"); PermissionTestUtils.remove("http://example.com", "install"); gBrowser.removeCurrentTab(); Harness.finish(); -} +}); diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js b/toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js index 9fd0c66292..e7779792ac 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js @@ -1,12 +1,17 @@ // ---------------------------------------------------------------------------- // Test whether an install succeeds using case-insensitive hashes // This verifies bug 603021 -function test() { +add_task(async function test_install_hash_case_insensitive() { // This test currently depends on InstallTrigger.install availability. setInstallTriggerPrefs(); - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; + const xpiFilePath = getTestFilePath("./amosigned.xpi"); + const xpiFileHash = await IOUtils.computeHexDigest(xpiFilePath, "sha256"); + + const deferredInstallCompleted = Promise.withResolvers(); + + Harness.installEndedCallback = (install, addon) => addon.uninstall(); + Harness.installsCompletedCallback = deferredInstallCompleted.resolve; Harness.setup(); PermissionTestUtils.add( @@ -19,7 +24,7 @@ function test() { JSON.stringify({ "Unsigned XPI": { URL: TESTROOT + "amosigned.xpi", - Hash: "sha1:EE95834AD862245A9EF99CCECC2A857CADC16404", + Hash: `sha256:${xpiFileHash.toUpperCase()}`, toString() { return this.URL; }, @@ -31,17 +36,13 @@ function test() { gBrowser, TESTROOT + "installtrigger.html?" + triggers ); -} - -function install_ended(install, addon) { - return addon.uninstall(); -} -function finish_test(count) { + info("Wait for the install to be completed"); + const count = await deferredInstallCompleted.promise; is(count, 1, "1 Add-on should have been successfully installed"); PermissionTestUtils.remove("http://example.com", "install"); gBrowser.removeCurrentTab(); Harness.finish(); -} +}); diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js index 1ce8eb55af..6f788e5122 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js @@ -2,12 +2,21 @@ // Test whether an install succeeds when a valid hash is included in the HTTPS // request // This verifies bug 591070 -function test() { +add_task(async function test_instal_hash_https() { // This test currently depends on InstallTrigger.install availability. setInstallTriggerPrefs(); - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; + await SpecialPowers.pushPrefEnv({ + set: [[PREF_INSTALL_REQUIREBUILTINCERTS, false]], + }); + + const xpiFilePath = getTestFilePath("./amosigned.xpi"); + const xpiFileHash = await IOUtils.computeHexDigest(xpiFilePath, "sha256"); + + const deferredInstallCompleted = Promise.withResolvers(); + + Harness.installEndedCallback = (install, addon) => addon.uninstall(); + Harness.installsCompletedCallback = deferredInstallCompleted.resolve; Harness.setup(); PermissionTestUtils.add( @@ -15,13 +24,8 @@ function test() { "install", Services.perms.ALLOW_ACTION ); - Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false); - var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs"; - url += - "?sha1:ee95834ad862245a9ef99ccecc2a857cadc16404|" + - TESTROOT + - "amosigned.xpi"; + const url = `https://example.com/browser/${RELATIVE_DIR}hashRedirect.sjs?sha256:${xpiFileHash}|${TESTROOT}amosigned.xpi`; var triggers = encodeURIComponent( JSON.stringify({ @@ -38,18 +42,14 @@ function test() { gBrowser, TESTROOT + "installtrigger.html?" + triggers ); -} - -function install_ended(install, addon) { - return addon.uninstall(); -} -function finish_test(count) { + info("Wait for the install to be completed"); + const count = await deferredInstallCompleted.promise; is(count, 1, "1 Add-on should have been successfully installed"); PermissionTestUtils.remove("http://example.com", "install"); - Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS); + await SpecialPowers.popPrefEnv(); gBrowser.removeCurrentTab(); Harness.finish(); -} +}); diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js index ffb5a3ddb4..d76ba58135 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js @@ -1,12 +1,25 @@ // ---------------------------------------------------------------------------- // Tests that the HTTPS hash is ignored when InstallTrigger is passed a hash. // This verifies bug 591070 -function test() { +add_task(async function test_installTrigger_hash_override() { // This test currently depends on InstallTrigger.install availability. + // NOTE: this test is covering a feature that we don't support anymore on any + // on the Firefox channels, and so we can remove this test along with + // removing InstallTrigger implementation (even if the InstallTrigger global + // is going to stay defined as null on all channels). setInstallTriggerPrefs(); - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; + await SpecialPowers.pushPrefEnv({ + set: [[PREF_INSTALL_REQUIREBUILTINCERTS, false]], + }); + + const xpiFilePath = getTestFilePath("./amosigned.xpi"); + const xpiFileHash = await IOUtils.computeHexDigest(xpiFilePath, "sha256"); + + const deferredInstallCompleted = Promise.withResolvers(); + + Harness.installEndedCallback = (install, addon) => addon.uninstall(); + Harness.installsCompletedCallback = deferredInstallCompleted.resolve; Harness.setup(); PermissionTestUtils.add( @@ -14,7 +27,6 @@ function test() { "install", Services.perms.ALLOW_ACTION ); - Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false); var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs"; url += "?sha1:foobar|" + TESTROOT + "amosigned.xpi"; @@ -23,7 +35,7 @@ function test() { JSON.stringify({ "Unsigned XPI": { URL: url, - Hash: "sha1:ee95834ad862245a9ef99ccecc2a857cadc16404", + Hash: `sha256:${xpiFileHash}`, toString() { return this.URL; }, @@ -35,18 +47,14 @@ function test() { gBrowser, TESTROOT + "installtrigger.html?" + triggers ); -} - -function install_ended(install, addon) { - return addon.uninstall(); -} -function finish_test(count) { + info("Wait for the install to be completed"); + const count = await deferredInstallCompleted.promise; is(count, 1, "1 Add-on should have been successfully installed"); PermissionTestUtils.remove("http://example.com", "install"); - Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS); + await SpecialPowers.popPrefEnv(); gBrowser.removeCurrentTab(); Harness.finish(); -} +}); diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js index 727f13180b..489582dc0a 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js @@ -1,12 +1,21 @@ // ---------------------------------------------------------------------------- // Test that only the first HTTPS hash is used // This verifies bug 591070 -function test() { +add_task(async function test_only_first_https_hash_used() { // This test currently depends on InstallTrigger.install availability. setInstallTriggerPrefs(); - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; + await SpecialPowers.pushPrefEnv({ + set: [[PREF_INSTALL_REQUIREBUILTINCERTS, false]], + }); + + const xpiFilePath = getTestFilePath("./amosigned.xpi"); + const xpiFileHash = await IOUtils.computeHexDigest(xpiFilePath, "sha256"); + + const deferredInstallCompleted = Promise.withResolvers(); + + Harness.installEndedCallback = (install, addon) => addon.uninstall(); + Harness.installsCompletedCallback = deferredInstallCompleted.resolve; Harness.setup(); PermissionTestUtils.add( @@ -14,10 +23,9 @@ function test() { "install", Services.perms.ALLOW_ACTION ); - Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false); var url = "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs"; - url += "?sha1:ee95834ad862245a9ef99ccecc2a857cadc16404|"; + url += `?sha256:${xpiFileHash}|`; url += "https://example.com/browser/" + RELATIVE_DIR + "hashRedirect.sjs"; url += "?sha1:foobar|" + TESTROOT + "amosigned.xpi"; @@ -36,18 +44,14 @@ function test() { gBrowser, TESTROOT + "installtrigger.html?" + triggers ); -} - -function install_ended(install, addon) { - return addon.uninstall(); -} -function finish_test(count) { + info("Wait for the install to be completed"); + const count = await deferredInstallCompleted.promise; is(count, 1, "1 Add-on should have been successfully installed"); PermissionTestUtils.remove("http://example.com", "install"); - Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS); + await SpecialPowers.popPrefEnv(); gBrowser.removeCurrentTab(); Harness.finish(); -} +}); diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile3.js b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile3.js index c8d8532ed0..6d4014b7e4 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile3.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile3.js @@ -27,7 +27,7 @@ function test() { }); } -function allow_blocked(installInfo) { +function allow_blocked() { ok(true, "Seen blocked"); return false; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4.js b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4.js index 771832a72b..96052129d4 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4.js @@ -40,7 +40,7 @@ function test() { ); } -function allow_blocked(installInfo) { +function allow_blocked() { ok(true, "Seen blocked"); return false; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4_postDownload.js b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4_postDownload.js index 8f8484a1c9..5e1707611d 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4_postDownload.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile4_postDownload.js @@ -39,7 +39,7 @@ function test() { ); } -function allow_blocked(installInfo) { +function allow_blocked() { ok(true, "Seen blocked"); return false; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js b/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js index 946ad1dff7..8ab0194519 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_offline.js @@ -28,7 +28,7 @@ function test() { ); } -function download_progress(addon, value, maxValue) { +function download_progress() { try { // Tests always connect to localhost, and per bug 87717, localhost is now // reachable in offline mode. To avoid this, disable any proxy. diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js index 7edbf318a0..8b43cc1383 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js @@ -40,7 +40,7 @@ function test() { ); } -function install_blocked(installInfo) { +function install_blocked() { wasOriginBlocked = true; } diff --git a/toolkit/mozapps/extensions/test/xpinstall/head.js b/toolkit/mozapps/extensions/test/xpinstall/head.js index 33ac33c830..a114b6efcd 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/head.js +++ b/toolkit/mozapps/extensions/test/xpinstall/head.js @@ -133,7 +133,6 @@ var Harness = { Services.obs.addObserver(this, "addon-install-failed"); // For browser_auth tests which trigger auth dialogs. - Services.obs.addObserver(this, "tabmodal-dialog-loaded"); Services.obs.addObserver(this, "common-dialog-loaded"); this._boundWin = Cu.getWeakReference(win); // need this so our addon manager listener knows which window to use. @@ -157,7 +156,6 @@ var Harness = { Services.obs.removeObserver(self, "addon-install-blocked"); Services.obs.removeObserver(self, "addon-install-failed"); - Services.obs.removeObserver(self, "tabmodal-dialog-loaded"); Services.obs.removeObserver(self, "common-dialog-loaded"); AddonManager.removeInstallListener(self); @@ -512,7 +510,7 @@ var Harness = { // nsIObserver - observe(subject, topic, data) { + observe(subject, topic) { var installInfo = subject.wrappedJSObject; switch (topic) { case "addon-install-started": @@ -553,11 +551,6 @@ var Harness = { ); }, this); break; - case "tabmodal-dialog-loaded": - let browser = subject.ownerGlobal.gBrowser.selectedBrowser; - let prompt = browser.tabModalPromptBox.getPrompt(subject); - this.promptReady(prompt.Dialog); - break; case "common-dialog-loaded": this.promptReady(subject.Dialog); break; diff --git a/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi b/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi Binary files differdeleted file mode 100644 index 9fee8f60b1..0000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi +++ /dev/null diff --git a/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html b/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html index 1b098d6948..40ebd7f0d8 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html +++ b/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html @@ -10,7 +10,7 @@ <script type="text/javascript"> /* globals InstallTrigger */ /* exported startInstall */ -function installCallback(url, status) { +function installCallback() { document.location = "#foo"; dump("Sending InstallComplete\n"); diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index aeba614e40..6d36d51375 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -83,14 +83,14 @@ ifdef ENABLE_MOZSEARCH_PLUGIN cd $(topobjdir)/ && cp _build_manifests/install/dist_include '$(ABS_DIST)/$(PKG_PATH)$(MOZSEARCH_INCLUDEMAP_BASENAME).map' @echo 'Generating mozsearch scip index...' $(RM) $(MOZSEARCH_SCIP_INDEX_BASENAME).zip - cp $(topsrcdir)/.cargo/config.in $(topsrcdir)/.cargo/config + cp $(topsrcdir)/.cargo/config.toml.in $(topsrcdir)/.cargo/config.toml cd $(topsrcdir)/ && \ CARGO=$(MOZ_FETCHES_DIR)/rustc/bin/cargo \ RUSTC=$(MOZ_FETCHES_DIR)/rustc/bin/rustc \ $(MOZ_FETCHES_DIR)/rustc/bin/rust-analyzer scip . && \ zip -r5D '$(ABS_DIST)/$(PKG_PATH)$(MOZSEARCH_SCIP_INDEX_BASENAME).zip' \ index.scip - rm $(topsrcdir)/.cargo/config + rm $(topsrcdir)/.cargo/config.toml ifeq ($(MOZ_BUILD_APP),mobile/android) @echo 'Generating mozsearch java/kotlin semanticdb tarball...' $(RM) $(MOZSEARCH_JAVA_INDEX_BASENAME).zip diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefs/ChannelPrefs.h b/toolkit/mozapps/macos-frameworks/ChannelPrefs/ChannelPrefs.h new file mode 100644 index 0000000000..670fa2e091 --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefs/ChannelPrefs.h @@ -0,0 +1,17 @@ +/* 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/. */ + +#ifndef ChannelPrefs_h_ +#define ChannelPrefs_h_ + +#import <Foundation/Foundation.h> + +extern "C" { + +// Returns the channel name, as an autoreleased string. +extern NSString* ChannelPrefsGetChannel(void) __attribute__((weak_import)) +__attribute__((visibility("default"))); +} + +#endif // ChannelPrefs_h_ diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefs/ChannelPrefs.mm b/toolkit/mozapps/macos-frameworks/ChannelPrefs/ChannelPrefs.mm new file mode 100644 index 0000000000..f437bb857d --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefs/ChannelPrefs.mm @@ -0,0 +1,12 @@ +/* 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 "ChannelPrefs.h" + +#include "mozilla/HelperMacros.h" + +NSString* ChannelPrefsGetChannel() { + return [NSString stringWithCString:MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL) + encoding:NSUTF8StringEncoding]; +} diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefs/Info.plist b/toolkit/mozapps/macos-frameworks/ChannelPrefs/Info.plist new file mode 100644 index 0000000000..f7ce763d75 --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefs/Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>ChannelPrefs</string> + <key>CFBundleIdentifier</key> + <string>org.mozilla.channelprefs</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>ChannelPrefs</string> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1.0</string> +</dict> +</plist> diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefs/Makefile.in b/toolkit/mozapps/macos-frameworks/ChannelPrefs/Makefile.in new file mode 100644 index 0000000000..43552a771e --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefs/Makefile.in @@ -0,0 +1,14 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# 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 $(topsrcdir)/config/rules.mk + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +libs:: + rm -rf $(DIST)/bin/ChannelPrefs.framework + + $(NSINSTALL) $(DIST)/bin/ChannelPrefs $(DIST)/bin/ChannelPrefs.framework + $(NSINSTALL) $(srcdir)/Info.plist $(DIST)/bin/ChannelPrefs.framework/Resources +endif diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefs/README.md b/toolkit/mozapps/macos-frameworks/ChannelPrefs/README.md new file mode 100644 index 0000000000..a6285323f6 --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefs/README.md @@ -0,0 +1,70 @@ +# ChannelPrefs macOS Framework + +## Summary + +The ChannelPrefs macOS Framework is used to initialize the `app.update.channel` +pref during startup. + +## What is `app.update.channel` and what is it used for? + +`app.update.channel` is used to set the download channel for application +updates. + +## Why do we need a Framework instead of compiling the download channel directly into the executable? + +There are three main use cases that make it necessary for the +`app.update.channel` pref to be set by external means, such as a macOS +Framework: + + 1. Allowing users on the Beta channel to test RC builds + +Beta users have their update channel set to 'beta'. However, RC builds by +definition have their channel set to `release`, since these are release +candidates that could get released to our release population. If we were to +indiscriminately update our Beta users to an RC build, we would lose our entire +Beta population since everyone would get switched to the `release` channel. + + 2. Switching users to another channel, such as ESR + +In contrast to the Beta use case outlined above, there are times where we +explicitly WANT to switch users to a different channel. An example of this is +when hardware or a particular macOS version have reached their EOL. In this +case, we usually switch users to our ESR channel for extended support. + + 3. QA update testing + +QA requires a way to temporarily switch the update channel to a test channel in +order to test updates before new releases. + +## How does the ChannelPrefs macOS Framework address these use cases? + +We are able to accommodate all three use cases above by enabling the updater to +ignore certain files on disk if they were already present, but continue to force +update them if so desired. + +In the case of a Beta user updating to an RC build, the updater would encounter +a ChannelPrefs macOS Framework inside the .app bundle that has an update channel +of `beta`. In this case, the updater will not update the Framework, but update +everything else. This beta user is now able to run the RC build with the update +channel still set to `beta`. + +In the case of switching users to the ESR channel, the updater will be set to +forcefully update the ChannelPrefs macOS Framework, even if already present on +disk. After the update, the user will now be set to the `esr` channel and start +receiving updates through this channel. + +Before releases, QA replaces the ChannelPrefs macOS Framework within the .app +bundle and point the channel at a test channel in order to test updates. During +testing, the new Framework file would remain in place for typical update +testing, but gets replaced in case QA was testing channel switching. + +## Why is a macOS Framework the best solution to store the update channel? + +Apple has started strengthening code signature checks and the requirements on +developers such as ourselves on how their apps are signed. In particular, +most files in the .app bundle are now included in signature verifications. + +A macOS Framework is the ideal solution to store the update channel because +Frameworks are the only component within a .app bundle that can be replaced +without invalidating the code signature on the .app bundle, as long as both the +previous and the new Framework are signed. diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefs/moz.build b/toolkit/mozapps/macos-frameworks/ChannelPrefs/moz.build new file mode 100644 index 0000000000..13f4186b99 --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefs/moz.build @@ -0,0 +1,22 @@ +# -*- 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/. + +with Files("**"): + BUG_COMPONENT = ("Toolkit", "Application Update") + +Framework("ChannelPrefs") + +EXPORTS += [ + "ChannelPrefs.h", +] + +UNIFIED_SOURCES += [ + "ChannelPrefs.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefsUtil.h b/toolkit/mozapps/macos-frameworks/ChannelPrefsUtil.h new file mode 100644 index 0000000000..0f2c38632e --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefsUtil.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#ifndef ChannelPrefsUtil_h_ +#define ChannelPrefsUtil_h_ + +#include "Units.h" + +class ChannelPrefsUtil { + public: + static bool GetChannelPrefValue(nsACString& aValue); +}; + +#endif // ChannelPrefsUtil_h_ diff --git a/toolkit/mozapps/macos-frameworks/ChannelPrefsUtil.mm b/toolkit/mozapps/macos-frameworks/ChannelPrefsUtil.mm new file mode 100644 index 0000000000..4113b84f5b --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/ChannelPrefsUtil.mm @@ -0,0 +1,26 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: + * 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#import <ChannelPrefs/ChannelPrefs.h> + +#include "ChannelPrefsUtil.h" + +#include "nsCocoaUtils.h" + +/* static */ +bool ChannelPrefsUtil::GetChannelPrefValue(nsACString& aValue) { + // `ChannelPrefsGetChannel` is resolved at runtime and requires + // the ChannelPrefs framework to be loaded. + if (ChannelPrefsGetChannel) { + nsAutoString value; + nsCocoaUtils::GetStringForNSString(ChannelPrefsGetChannel(), value); + CopyUTF16toUTF8(value, aValue); + return true; + } + + return false; +} diff --git a/toolkit/mozapps/macos-frameworks/moz.build b/toolkit/mozapps/macos-frameworks/moz.build new file mode 100644 index 0000000000..b1a315500c --- /dev/null +++ b/toolkit/mozapps/macos-frameworks/moz.build @@ -0,0 +1,22 @@ +# -*- 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/. + +with Files("**"): + BUG_COMPONENT = ("Toolkit", "Application Update") + +FINAL_LIBRARY = "xul" + +DIRS += [ + "ChannelPrefs", +] + +EXPORTS += [ + "ChannelPrefsUtil.h", +] + +UNIFIED_SOURCES += [ + "ChannelPrefsUtil.mm", +] diff --git a/toolkit/mozapps/update/common/readstrings.cpp b/toolkit/mozapps/update/common/readstrings.cpp index 17c2d002a1..28dc8ea6ff 100644 --- a/toolkit/mozapps/update/common/readstrings.cpp +++ b/toolkit/mozapps/update/common/readstrings.cpp @@ -38,16 +38,6 @@ class AutoFILE { FILE* fp_; }; -class AutoCharArray { - public: - explicit AutoCharArray(size_t len) { ptr_ = new char[len]; } - ~AutoCharArray() { delete[] ptr_; } - operator char*() { return ptr_; } - - private: - char* ptr_; -}; - static const char kNL[] = "\r\n"; static const char kEquals[] = "="; static const char kWhitespace[] = " \t"; @@ -153,7 +143,8 @@ int ReadStrings(const NS_tchar* path, const char* keyList, } size_t flen = size_t(len); - AutoCharArray fileContents(flen + 1); + + char* fileContents = new char[flen + 1]; if (!fileContents) { return READ_STRINGS_MEM_ERROR; } @@ -170,12 +161,53 @@ int ReadStrings(const NS_tchar* path, const char* keyList, fileContents[flen] = '\0'; - char* buffer = fileContents; + int result = ReadStringsFromBuffer(fileContents, keyList, numStrings, results, + section); + delete[] fileContents; + return result; +} + +// A wrapper function to read strings for the updater. +// Added for compatibility with the original code. +int ReadStrings(const NS_tchar* path, StringTable* results) { + const unsigned int kNumStrings = 2; + const char* kUpdaterKeys = "Title\0Info\0"; + mozilla::UniquePtr<char[]> updater_strings[kNumStrings]; + + int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings); + + if (result == OK) { + results->title.swap(updater_strings[0]); + results->info.swap(updater_strings[1]); + } + + return result; +} + +/** + * A very basic parser for updater.ini taken mostly from nsINIParser.cpp + * that can be used by standalone apps. + * + * @param stringBuffer The string buffer to parse + * @param keyList List of zero-delimited keys ending with two zero + * characters + * @param numStrings Number of strings to read into results buffer - must be + * equal to the number of keys + * @param results Array of strings. Array's length must be equal to + * numStrings. Each string will be populated with the value + * corresponding to the key with the same index in keyList. + * @param section Optional name of the section to read; defaults to + * "Strings" + */ +int ReadStringsFromBuffer(char* stringBuffer, const char* keyList, + unsigned int numStrings, + mozilla::UniquePtr<char[]>* results, + const char* section) { bool inStringsSection = false; unsigned int read = 0; - while (char* token = NS_strtok(kNL, &buffer)) { + while (char* token = NS_strtok(kNL, &stringBuffer)) { if (token[0] == '#' || token[0] == ';') { // it's a comment continue; } @@ -233,23 +265,6 @@ int ReadStrings(const NS_tchar* path, const char* keyList, return (read == numStrings) ? OK : PARSE_ERROR; } -// A wrapper function to read strings for the updater. -// Added for compatibility with the original code. -int ReadStrings(const NS_tchar* path, StringTable* results) { - const unsigned int kNumStrings = 2; - const char* kUpdaterKeys = "Title\0Info\0"; - mozilla::UniquePtr<char[]> updater_strings[kNumStrings]; - - int result = ReadStrings(path, kUpdaterKeys, kNumStrings, updater_strings); - - if (result == OK) { - results->title.swap(updater_strings[0]); - results->info.swap(updater_strings[1]); - } - - return result; -} - IniReader::IniReader(const NS_tchar* iniPath, const char* section /* = nullptr */) { if (iniPath) { diff --git a/toolkit/mozapps/update/common/readstrings.h b/toolkit/mozapps/update/common/readstrings.h index 9e0ebbefb5..8fa8a49756 100644 --- a/toolkit/mozapps/update/common/readstrings.h +++ b/toolkit/mozapps/update/common/readstrings.h @@ -24,6 +24,15 @@ struct StringTable { mozilla::UniquePtr<char[]> info; }; +struct MARChannelStringTable { + MARChannelStringTable() { + MARChannelID = mozilla::MakeUnique<char[]>(1); + MARChannelID[0] = '\0'; + } + + mozilla::UniquePtr<char[]> MARChannelID; +}; + /** * This function reads in localized strings from updater.ini */ @@ -38,6 +47,15 @@ int ReadStrings(const NS_tchar* path, const char* keyList, const char* section = nullptr); /** + * This function reads in localized strings corresponding to the keys from a + * given string buffer. + */ +int ReadStringsFromBuffer(char* stringBuffer, const char* keyList, + unsigned int numStrings, + mozilla::UniquePtr<char[]>* results, + const char* section = nullptr); + +/** * This class is meant to be a slightly cleaner interface into the ReadStrings * function. */ diff --git a/toolkit/mozapps/update/nsIUpdateService.idl b/toolkit/mozapps/update/nsIUpdateService.idl index ab1712587c..972d0f4f55 100644 --- a/toolkit/mozapps/update/nsIUpdateService.idl +++ b/toolkit/mozapps/update/nsIUpdateService.idl @@ -380,7 +380,7 @@ interface nsIApplicationUpdateService : nsISupports * check starting does not necessarily mean that the check will * succeed or that an update will be downloaded. */ - bool checkForBackgroundUpdates(); + boolean checkForBackgroundUpdates(); /** * Selects the best update to install from a list of available updates. @@ -654,7 +654,7 @@ interface nsIUpdateProcessor : nsISupports * @throws NS_ERROR_NOT_IMPLEMENTED * If this is called on a non-Windows platform. */ - bool getServiceRegKeyExists(); + boolean getServiceRegKeyExists(); /** * Attempts to restart the application manually on program exit with the same @@ -724,7 +724,7 @@ interface nsIUpdateSyncManager : nsISupports * Returns whether another instance of this application is running. * @returns true if another instance has the lock open, false if not */ - bool isOtherInstanceRunning(); + boolean isOtherInstanceRunning(); /** * Should only be used for testing. diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js index 07e7bf51fa..0ca510cfcf 100644 --- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate.js @@ -64,7 +64,7 @@ add_task(async function doorhanger_bc_multiUpdate() { is( PanelUI.menuButton.getAttribute("badge-status"), - "", + null, "Should not have restart badge during staging" ); diff --git a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js index 00c61bcbb4..8012250f36 100644 --- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js +++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_multiUpdate_promptWaitTime.js @@ -74,7 +74,7 @@ add_task(async function doorhanger_bc_multiUpdate() { is( PanelUI.menuButton.getAttribute("badge-status"), - "", + null, "Should not have restart badge during staging" ); diff --git a/toolkit/mozapps/update/tests/browser/head.js b/toolkit/mozapps/update/tests/browser/head.js index c5acdad8e4..b606331fd3 100644 --- a/toolkit/mozapps/update/tests/browser/head.js +++ b/toolkit/mozapps/update/tests/browser/head.js @@ -368,9 +368,15 @@ function copyTestUpdater(attempt = 0) { testUpdater.copyToFollowingLinks(greBinDir, FILE_UPDATER_BIN); let greDir = getGREDir(); - let updateSettingsIni = greDir.clone(); - updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); - writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); + + // On macOS, update settings is a Framework, not an INI. This was already + // built into updater-xpcshell using the `UpdateSettings-xpcshell` + // Framework, so we don't need to do any additional work here. + if (AppConstants.platform != "macosx") { + let updateSettingsIni = greDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); + } let precomplete = greDir.clone(); precomplete.append(FILE_PRECOMPLETE); diff --git a/toolkit/mozapps/update/tests/data/README.md b/toolkit/mozapps/update/tests/data/README.md new file mode 100644 index 0000000000..52a7e9a5b7 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/README.md @@ -0,0 +1,15 @@ +README +====== + +I needed to make changes to some of the test MARs in this directory and it was a bit difficult to figure out how, so I want to document what I did so that this is easier next time. In my specific case, I wanted to rename some files in several MARs. These are approximately the steps I used to make changes to `partial_mac.mar`: + + - `./mach build` so that `<obj>/dist/bin/signmar` is available. + - We want use the [Python MAR tool](https://github.com/mozilla-releng/build-mar) to build the replacement MAR, but it currently has a problem that we need to fix before we can build a MAR that will allow tests to pass on Apple silicon. Once [this issue](https://github.com/mozilla-releng/build-mar/issues/63) is addressed, we can just use `pip install mar`. Until then, we need to checkout the project and tweak it before we use it. First clone the repository: `cd ~ && git clone https://github.com/mozilla-releng/build-mar`. Next, we want to remove [this line](https://github.com/mozilla-releng/build-mar/blob/2d37c446015b97d6f700fef5766a49609bdc22ea/src/mardor/utils.py#L158). Then make the tweaked version available with `cd ~/build-mar && virtualenv mardor && source mardor/bin/activate && pip install .`. + - Made a temporary working directory: `cd /path/to/mozilla/repo && mkdir temp && cd temp` + - Extracted the MAR that I wanted to change: `mar -J -x ../toolkit/mozapps/update/tests/data/partial_mac.mar`. The `-J` specifies a compression type of `xz`. You can also specify `--auto` to automatically detect the compression type (though you may want to know the original compression later for recompression) or you can check the compression type by running `mar -T ../toolkit/mozapps/update/tests/data/partial_mac.mar` and looking for the `Compression type:` line. + - Made the changes that I wanted to make to the extracted files. This included moving the old files to their new locations and updating those paths in `updatev2.manifest` and `updatev3.manifest`. + - Run `mar -T ../toolkit/mozapps/update/tests/data/partial_mac.mar` to get a complete list of the files originally in that MAR as well as the product/version and channel strings (in this case `xpcshell-test` and `*` respectively). + - Create the new MAR: `mar -J -c partial_mac_unsigned.mar -V '*' -H xpcshell-test <file1> <file2> ...`, individually specifying each file path listed in by `mar -T`, substituting with renamed paths as necessary. + - I had a bit of trouble figuring out the signing. Eventually I discovered the following things: (a) The test MAR signatures successfully verify against `toolkit/mozapps/update/updater/xpcshellCertificate.der` and (b) according to [this comment](https://searchfox.org/mozilla-central/rev/fc00627e34639ef1014e87d9fa24091905e9dc5d/toolkit/mozapps/update/updater/moz.build#41-43), that certificate was generated from `mycert` in `modules/libmar/tests/unit/data`. Thus, I signed the MAR like this: `../<obj>/dist/bin/signmar -d ../modules/libmar/tests/unit/data -n mycert -s partial_mac_unsigned.mar partial_mac.mar`. + - I wanted to do some verification to make sure that the new MAR looked right. First I verified the signature: `../<obj>/dist/bin/signmar -D ../toolkit/mozapps/update/updater/xpcshellCertificate.der -v partial_mac.mar`. This appears to output nothing on success, but it's probably good to check to make sure `echo $?` is `0`. I also compared the output of `mar -T partial_mac.mar` to that of the original. I saw a few unexpected size changes which I believe are likely due to slight differences in the compression used (maybe the algorithm changed slightly since this was last generated?). To make sure that these did not correspond to effective changes, I extracted the new MAR with `mkdir cmp && cd cmp && mar -J -x ../partial_mac.mar && cd ..` and compared the resulting files to make sure they had the expected contents. + - Overwrite the original MAR with the new one and remove the `temp` directory: `cd .. && mv -f temp/partial_mac.mar toolkit/mozapps/update/tests/data/partial_mac.mar && rm -rf temp` diff --git a/toolkit/mozapps/update/tests/data/complete_mac.mar b/toolkit/mozapps/update/tests/data/complete_mac.mar Binary files differindex c54088610a..f4603f1eef 100644 --- a/toolkit/mozapps/update/tests/data/complete_mac.mar +++ b/toolkit/mozapps/update/tests/data/complete_mac.mar diff --git a/toolkit/mozapps/update/tests/data/partial_mac.mar b/toolkit/mozapps/update/tests/data/partial_mac.mar Binary files differindex bcc04b9939..9b17747e43 100644 --- a/toolkit/mozapps/update/tests/data/partial_mac.mar +++ b/toolkit/mozapps/update/tests/data/partial_mac.mar diff --git a/toolkit/mozapps/update/tests/data/shared.js b/toolkit/mozapps/update/tests/data/shared.js index 60de6feeb8..e8553f7273 100644 --- a/toolkit/mozapps/update/tests/data/shared.js +++ b/toolkit/mozapps/update/tests/data/shared.js @@ -71,17 +71,20 @@ const FILE_ACTIVE_UPDATE_XML = "active-update.xml"; const FILE_ACTIVE_UPDATE_XML_TMP = "active-update.xml.tmp"; const FILE_APPLICATION_INI = "application.ini"; const FILE_BACKUP_UPDATE_CONFIG_JSON = "backup-update-config.json"; -const FILE_BACKUP_UPDATE_LOG = "backup-update.log"; const FILE_BACKUP_UPDATE_ELEVATED_LOG = "backup-update-elevated.log"; +const FILE_BACKUP_UPDATE_LOG = "backup-update.log"; const FILE_BT_RESULT = "bt.result"; -const FILE_LAST_UPDATE_LOG = "last-update.log"; +const FILE_CHANNEL_PREFS = + AppConstants.platform == "macosx" ? "ChannelPrefs" : "channel-prefs.js"; const FILE_LAST_UPDATE_ELEVATED_LOG = "last-update-elevated.log"; +const FILE_LAST_UPDATE_LOG = "last-update.log"; const FILE_PRECOMPLETE = "precomplete"; const FILE_PRECOMPLETE_BAK = "precomplete.bak"; const FILE_UPDATE_CONFIG_JSON = "update-config.json"; -const FILE_UPDATE_LOG = "update.log"; const FILE_UPDATE_ELEVATED_LOG = "update-elevated.log"; +const FILE_UPDATE_LOG = "update.log"; const FILE_UPDATE_MAR = "update.mar"; +const FILE_UPDATE_SETTINGS_FRAMEWORK = "UpdateSettings"; const FILE_UPDATE_SETTINGS_INI = "update-settings.ini"; const FILE_UPDATE_SETTINGS_INI_BAK = "update-settings.ini.bak"; const FILE_UPDATE_STATUS = "update.status"; @@ -223,6 +226,7 @@ function setUpdateChannel(aChannel) { debugDump( "setting default pref " + PREF_APP_UPDATE_CHANNEL + " to " + gChannel ); + gDefaultPrefBranch.unlockPref(PREF_APP_UPDATE_CHANNEL); gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel); gPrefRoot.addObserver(PREF_APP_UPDATE_CHANNEL, observer); } diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js index 4b12edf6f0..6374f82b52 100644 --- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -181,6 +181,7 @@ var gDebugTestLog = false; var gTestsToLog = []; var gRealDump; var gFOS; +var gUpdateBin; var gTestFiles = []; var gTestDirs = []; @@ -189,6 +190,23 @@ var gTestDirs = []; var gTestFilesCommon = [ { description: "Should never change", + fileName: FILE_CHANNEL_PREFS, + relPathDir: + AppConstants.platform == "macosx" + ? "Contents/Frameworks/ChannelPrefs.framework/" + : DIR_RESOURCES + "defaults/pref/", + originalContents: "ShouldNotBeReplaced\n", + compareContents: "ShouldNotBeReplaced\n", + originalFile: null, + compareFile: null, + originalPerms: 0o767, + comparePerms: 0o767, + }, +]; + +var gTestFilesCommonNonMac = [ + { + description: "Should never change", fileName: FILE_UPDATE_SETTINGS_INI, relPathDir: DIR_RESOURCES, originalContents: UPDATE_SETTINGS_CONTENTS, @@ -198,19 +216,32 @@ var gTestFilesCommon = [ originalPerms: 0o767, comparePerms: 0o767, }, +]; + +if (AppConstants.platform != "macosx") { + gTestFilesCommon = gTestFilesCommon.concat(gTestFilesCommonNonMac); +} + +var gTestFilesCommonMac = [ { description: "Should never change", - fileName: "channel-prefs.js", - relPathDir: DIR_RESOURCES + "defaults/pref/", - originalContents: "ShouldNotBeReplaced\n", - compareContents: "ShouldNotBeReplaced\n", + fileName: FILE_UPDATE_SETTINGS_FRAMEWORK, + relPathDir: + "Contents/MacOS/updater.app/Contents/Frameworks/UpdateSettings.framework/", + originalContents: null, + compareContents: null, originalFile: null, compareFile: null, - originalPerms: 0o767, - comparePerms: 0o767, + originalPerms: null, + comparePerms: null, + existingFile: true, }, ]; +if (AppConstants.platform == "macosx") { + gTestFilesCommon = gTestFilesCommon.concat(gTestFilesCommonMac); +} + // Files for a complete successful update. This can be used for a complete // failed update by calling setTestFilesAndDirsForFailure. var gTestFilesCompleteSuccess = [ @@ -657,6 +688,20 @@ var gTestFilesPartialSuccess = [ // Concatenate the common files to the end of the array. gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon); +/** + * Searches `gTestFiles` for the file with the given filename. This is currently + * not very efficient (it searches the whole array every time). + * + * @param filename + * The name of the file to search for (i.e. the `fileName` attribute). + * @returns + * The object in `gTestFiles` that describes the requested file. + * Or `null`, if the file is not in `gTestFiles`. + */ +function getTestFileByName(filename) { + return gTestFiles.find(f => f.fileName == filename) ?? null; +} + var gTestDirsCommon = [ { relPathDir: DIR_RESOURCES + "3/", @@ -2019,8 +2064,13 @@ function runUpdate( Services.env.set("MOZ_TEST_SHORTER_WAIT_PID", "1"); } - let updateBin = copyTestUpdaterToBinDir(); - Assert.ok(updateBin.exists(), MSG_SHOULD_EXIST + getMsgPath(updateBin.path)); + if (!gUpdateBin) { + gUpdateBin = copyTestUpdaterToBinDir(); + } + Assert.ok( + gUpdateBin.exists(), + MSG_SHOULD_EXIST + getMsgPath(gUpdateBin.path) + ); let updatesDirPath = aPatchDirPath || getUpdateDirFile(DIR_PATCH).path; let installDirPath = aInstallDirPath || getApplyDirFile().path; @@ -2045,13 +2095,13 @@ function runUpdate( args[3] = pid; } - let launchBin = gIsServiceTest && isInvalidArgTest ? callbackApp : updateBin; + let launchBin = gIsServiceTest && isInvalidArgTest ? callbackApp : gUpdateBin; if (!isInvalidArgTest) { args = args.concat([callbackApp.parent.path, callbackApp.path]); args = args.concat(gCallbackArgs); } else if (gIsServiceTest) { - args = ["launch-service", updateBin.path].concat(args); + args = ["launch-service", gUpdateBin.path].concat(args); } else if (aCallbackPath) { args = args.concat([callbackApp.parent.path, aCallbackPath]); } @@ -3125,6 +3175,13 @@ async function setupUpdaterTest( helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile); helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile); + // On macOS, some test files (like the Update Settings file) may be within the + // updater app bundle, so make sure it is in place now in case we want to + // manipulate it. + if (!gUpdateBin) { + gUpdateBin = copyTestUpdaterToBinDir(); + } + gTestFiles.forEach(function SUT_TF_FE(aTestFile) { debugDump("start - setup test file: " + aTestFile.fileName); if (aTestFile.originalFile || aTestFile.originalContents) { @@ -3163,6 +3220,24 @@ async function setupUpdaterTest( aTestFile.comparePerms = testFile.permissions; } } + } else if (aTestFile.existingFile) { + const testFile = getApplyDirFile( + aTestFile.relPathDir + aTestFile.fileName + ); + if (aTestFile.removeOriginalFile) { + testFile.remove(false); + } else { + const fileContents = readFileBytes(testFile); + if (!aTestFile.originalContents && !aTestFile.originalFile) { + aTestFile.originalContents = fileContents; + } + if (!aTestFile.compareContents && !aTestFile.compareFile) { + aTestFile.compareContents = fileContents; + } + if (!aTestFile.comparePerms) { + aTestFile.comparePerms = testFile.permissions; + } + } } debugDump("finish - setup test file: " + aTestFile.fileName); }); @@ -3424,21 +3499,13 @@ function checkUpdateLogContents( // Remove leading timestamps updateLogContents = removeTimeStamps(updateLogContents); - // The channel-prefs.js is defined in gTestFilesCommon which will always be - // located to the end of gTestFiles when it is present. - if ( - gTestFiles.length > 1 && - gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && - !gTestFiles[gTestFiles.length - 1].originalContents - ) { + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + if (channelPrefs && !channelPrefs.originalContents) { updateLogContents = updateLogContents.replace(/.*defaults\/.*/g, ""); } - if ( - gTestFiles.length > 2 && - gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && - !gTestFiles[gTestFiles.length - 2].originalContents - ) { + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI); + if (updateSettings && !updateSettings.originalContents) { updateLogContents = updateLogContents.replace( /.*update-settings.ini.*/g, "" @@ -3529,21 +3596,11 @@ function checkUpdateLogContents( // Remove leading timestamps compareLogContents = removeTimeStamps(compareLogContents); - // The channel-prefs.js is defined in gTestFilesCommon which will always be - // located to the end of gTestFiles. - if ( - gTestFiles.length > 1 && - gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && - !gTestFiles[gTestFiles.length - 1].originalContents - ) { + if (channelPrefs && !channelPrefs.originalContents) { compareLogContents = compareLogContents.replace(/.*defaults\/.*/g, ""); } - if ( - gTestFiles.length > 2 && - gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && - !gTestFiles[gTestFiles.length - 2].originalContents - ) { + if (updateSettings && !updateSettings.originalContents) { compareLogContents = compareLogContents.replace( /.*update-settings.ini.*/g, "" @@ -4879,3 +4936,33 @@ function resetEnvironment() { Services.env.set("MOZ_NO_SERVICE_FALLBACK", ""); } } + +/** + * `gTestFiles` needs to be set such that it contains the Update Settings file + * before this function is called. + */ +function setUpdateSettingsUseWrongChannel() { + if (AppConstants.platform == "macosx") { + let replacementUpdateSettings = Services.dirsvc.get("CurWorkD", Ci.nsIFile); + replacementUpdateSettings = replacementUpdateSettings.parent; + replacementUpdateSettings.append("UpdateSettings-WrongChannel"); + + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_FRAMEWORK); + if (!updateSettings) { + throw new Error( + "gTestFiles does not contain the update settings framework" + ); + } + updateSettings.existingFile = false; + updateSettings.originalContents = readFileBytes(replacementUpdateSettings); + } else { + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI); + if (!updateSettings) { + throw new Error("gTestFiles does not contain the update settings INI"); + } + updateSettings.originalContents = UPDATE_SETTINGS_CONTENTS.replace( + "xpcshell-test", + "wrong-channel" + ); + } +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js b/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js index 9e23fab5e0..1e27efb753 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/languagePackUpdates.js @@ -177,9 +177,12 @@ add_task(async function testLangpackStaged() { copyTestUpdaterToBinDir(); let greDir = getGREDir(); - let updateSettingsIni = greDir.clone(); - updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); - writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); + + if (AppConstants.platform != "macosx") { + let updateSettingsIni = greDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); + } await downloadUpdate(); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js b/toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js deleted file mode 100644 index 4cca77c73d..0000000000 --- a/toolkit/mozapps/update/tests/unit_aus_update/verifyChannelPrefsFile.js +++ /dev/null @@ -1,38 +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/. - */ - -/** - * This test exists solely to ensure that channel-prefs.js is not changed. - * If it does get changed, it will cause a variation of Bug 1431342. - * To summarize, our updater doesn't update that file. But, on macOS, it is - * still used to compute the application's signature. This means that if Firefox - * updates and that file has been changed, the signature no will no longer - * validate. - */ - -const expectedChannelPrefsContents = `/* 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 pref is in its own file for complex reasons. See the comment in -// browser/app/Makefile.in, bug 756325, and bug 1431342 for details. Do not add -// other prefs to this file. - -pref("app.update.channel", "${UpdateUtils.UpdateChannel}"); -`; - -async function run_test() { - let channelPrefsFile = Services.dirsvc.get("GreD", Ci.nsIFile); - channelPrefsFile.append("defaults"); - channelPrefsFile.append("pref"); - channelPrefsFile.append("channel-prefs.js"); - - const contents = await IOUtils.readUTF8(channelPrefsFile.path); - Assert.equal( - contents, - expectedChannelPrefsContents, - "Channel Prefs file should should not change" - ); -} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml index 74790016e4..160427ac5e 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml +++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.toml @@ -83,7 +83,3 @@ reason = "Update directory migration is currently Windows only" ["urlConstruction.js"] skip-if = ["socketprocess_networking"] # Bug 1759035 - -["verifyChannelPrefsFile.js"] -run-if = ["appname == 'firefox'"] -reason = "File being verified is Firefox-specific." diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js index 29c2c2a30e..faac7510d0 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js @@ -10,9 +10,12 @@ async function run_test() { } const STATE_AFTER_STAGE = STATE_APPLIED; gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + if (channelPrefs) { + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromComplete\n"; + channelPrefs.comparePerms = 0o644; + } gTestDirs = gTestDirsCompleteSuccess; await setupUpdaterTest(FILE_COMPLETE_MAR, true); setupSymLinks(); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js index de8db067bc..379fb00a27 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js @@ -10,7 +10,7 @@ async function run_test() { return; } gTestFiles = gTestFilesPartialSuccess; - gTestFiles[11].originalFile = "partial.png"; + getTestFileByName("0exe0.exe").originalFile = "partial.png"; gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js index b93b023934..11181f4420 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js @@ -15,10 +15,8 @@ async function run_test() { gTestFiles = gTestFilesCompleteSuccess; gTestDirs = gTestDirsCompleteSuccess; await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperFileInUse( - gTestFiles[13].relPathDir + gTestFiles[13].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); checkFilesAfterUpdateSuccess(getStageDirFile, true); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js index b41da12396..def7f8db9c 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js @@ -15,10 +15,8 @@ async function run_test() { gTestFiles = gTestFilesPartialSuccess; gTestDirs = gTestDirsPartialSuccess; await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperFileInUse( - gTestFiles[11].relPathDir + gTestFiles[11].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); checkFilesAfterUpdateSuccess(getStageDirFile, true); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js index 4b946ac3e4..d1f938bb02 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js @@ -11,10 +11,8 @@ async function run_test() { gTestFiles = gTestFilesCompleteSuccess; gTestDirs = gTestDirsCompleteSuccess; await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperFileInUse( - gTestFiles[13].relPathDir + gTestFiles[13].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); runUpdate(STATE_SUCCEEDED, false, 0, true); await waitForHelperExit(); await checkPostUpdateAppLog(); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js index 15c3a1121a..f851c543a6 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js @@ -11,10 +11,8 @@ async function run_test() { gTestFiles = gTestFilesPartialSuccess; gTestDirs = gTestDirsPartialSuccess; await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperFileInUse( - gTestFiles[11].relPathDir + gTestFiles[11].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); runUpdate(STATE_SUCCEEDED, false, 0, true); await waitForHelperExit(); await checkPostUpdateAppLog(); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js index 698ccb7fe5..5517d5ed81 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js @@ -12,7 +12,7 @@ async function run_test() { gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperLockFile(gTestFiles[3]); + await runHelperLockFile(getTestFileByName("searchpluginspng0.png")); runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, true); await waitForHelperExit(); standardInit(); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js index c8c019ec5c..03eb6122c8 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js @@ -12,7 +12,7 @@ async function run_test() { gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperLockFile(gTestFiles[2]); + await runHelperLockFile(getTestFileByName("searchpluginspng1.png")); runUpdate(STATE_FAILED_READ_ERROR, false, 1, true); await waitForHelperExit(); standardInit(); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js index 7b582dbd45..4d5fe599cf 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js @@ -13,7 +13,7 @@ async function run_test() { gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperLockFile(gTestFiles[3]); + await runHelperLockFile(getTestFileByName("searchpluginspng0.png")); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); // Files aren't checked after staging since this test locks a file which diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js index bf3abd8c37..3d4a8e0c51 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js @@ -13,7 +13,7 @@ async function run_test() { gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperLockFile(gTestFiles[2]); + await runHelperLockFile(getTestFileByName("searchpluginspng1.png")); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); // Files aren't checked after staging since this test locks a file which diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js index b0a0cfe657..fbb0e7c4cd 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettings.js @@ -14,7 +14,17 @@ async function run_test() { return; } gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 2].originalContents = null; + if (AppConstants.platform == "macosx") { + // On macOS, the update settings Framework already exists. Remove it. + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_FRAMEWORK); + updateSettings.removeOriginalFile = true; + } else { + // On non-macOS, the update settings INI will normally be written out with + // the contents specified by `originalContents`. Setting this to `null` + // prevents anything from being written out. + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI); + updateSettings.originalContents = null; + } gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js index e26d2aefc3..a6d204aa92 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marMissingUpdateSettingsStage.js @@ -15,7 +15,17 @@ async function run_test() { } const STATE_AFTER_STAGE = STATE_FAILED; gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 2].originalContents = null; + if (AppConstants.platform == "macosx") { + // On macOS, the update settings Framework already exists. Remove it. + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_FRAMEWORK); + updateSettings.removeOriginalFile = true; + } else { + // On non-macOS, the update settings INI will normally be written out with + // the contents specified by `originalContents`. Setting this to `null` + // prevents anything from being written out. + const updateSettings = getTestFileByName(FILE_UPDATE_SETTINGS_INI); + updateSettings.originalContents = null; + } gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js index a1a0de0fe4..47c184e67b 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js @@ -11,7 +11,7 @@ async function run_test() { } const STATE_AFTER_STAGE = STATE_FAILED; gTestFiles = gTestFilesPartialSuccess; - gTestFiles[11].originalFile = "partial.png"; + getTestFileByName("0exe0.exe").originalFile = "partial.png"; gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js index 943a45ba95..2c9c3298d4 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js @@ -11,9 +11,10 @@ async function run_test() { } const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED; gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromComplete\n"; + channelPrefs.comparePerms = 0o644; gTestDirs = gTestDirsCompleteSuccess; setupSymLinks(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js index dd5c240919..e565ffe550 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js @@ -11,9 +11,10 @@ async function run_test() { } const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED; gTestFiles = gTestFilesPartialSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromPartial\n"; + channelPrefs.comparePerms = 0o644; gTestDirs = gTestDirsPartialSuccess; preventDistributionFiles(); await setupUpdaterTest(FILE_PARTIAL_MAR, true); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js index 8e8e9d094a..f4f856278c 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js @@ -10,9 +10,10 @@ async function run_test() { return; } gTestFiles = gTestFilesPartialSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromPartial\n"; + channelPrefs.comparePerms = 0o644; gTestDirs = gTestDirsPartialSuccess; // The third parameter will test that a relative path that contains a // directory traversal to the post update binary doesn't execute. diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js index 37511bd789..e80e52e9a3 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartialWhileBackgroundTaskRunning.js @@ -45,8 +45,7 @@ async function run_test() { // won't be updated if it already exists. The manipulations below arrange a) // for the file to exist and b) for the comparison afterward to succeed. gTestFiles = gTestFilesPartialSuccess; - let channelPrefs = gTestFiles[gTestFiles.length - 1]; - Assert.equal("channel-prefs.js", channelPrefs.fileName); + let channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); let f = gGREDirOrig.clone(); f.append("defaults"); f.append("pref"); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js index d31188dcca..5d6ee61776 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js @@ -14,8 +14,7 @@ async function run_test() { return; } gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 2].originalContents = - UPDATE_SETTINGS_CONTENTS.replace("xpcshell-test", "wrong-channel"); + setUpdateSettingsUseWrongChannel(); gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js index 4d512fd12a..9aca22df66 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannelStage.js @@ -15,8 +15,7 @@ async function run_test() { } const STATE_AFTER_STAGE = STATE_FAILED; gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 2].originalContents = - UPDATE_SETTINGS_CONTENTS.replace("xpcshell-test", "wrong-channel"); + setUpdateSettingsUseWrongChannel(); gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js index de8db067bc..379fb00a27 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js @@ -10,7 +10,7 @@ async function run_test() { return; } gTestFiles = gTestFilesPartialSuccess; - gTestFiles[11].originalFile = "partial.png"; + getTestFileByName("0exe0.exe").originalFile = "partial.png"; gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js index b93b023934..11181f4420 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js @@ -15,10 +15,8 @@ async function run_test() { gTestFiles = gTestFilesCompleteSuccess; gTestDirs = gTestDirsCompleteSuccess; await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperFileInUse( - gTestFiles[13].relPathDir + gTestFiles[13].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); checkFilesAfterUpdateSuccess(getStageDirFile, true); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js index b41da12396..def7f8db9c 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js @@ -15,10 +15,8 @@ async function run_test() { gTestFiles = gTestFilesPartialSuccess; gTestDirs = gTestDirsPartialSuccess; await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperFileInUse( - gTestFiles[11].relPathDir + gTestFiles[11].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); checkFilesAfterUpdateSuccess(getStageDirFile, true); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js index 4b946ac3e4..d1f938bb02 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js @@ -11,10 +11,8 @@ async function run_test() { gTestFiles = gTestFilesCompleteSuccess; gTestDirs = gTestDirsCompleteSuccess; await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperFileInUse( - gTestFiles[13].relPathDir + gTestFiles[13].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); runUpdate(STATE_SUCCEEDED, false, 0, true); await waitForHelperExit(); await checkPostUpdateAppLog(); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js index 15c3a1121a..f851c543a6 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js @@ -11,10 +11,8 @@ async function run_test() { gTestFiles = gTestFilesPartialSuccess; gTestDirs = gTestDirsPartialSuccess; await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperFileInUse( - gTestFiles[11].relPathDir + gTestFiles[11].fileName, - false - ); + const testFile = getTestFileByName("0exe0.exe"); + await runHelperFileInUse(testFile.relPathDir + testFile.fileName, false); runUpdate(STATE_SUCCEEDED, false, 0, true); await waitForHelperExit(); await checkPostUpdateAppLog(); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js index 698ccb7fe5..5517d5ed81 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js @@ -12,7 +12,7 @@ async function run_test() { gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperLockFile(gTestFiles[3]); + await runHelperLockFile(getTestFileByName("searchpluginspng0.png")); runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, true); await waitForHelperExit(); standardInit(); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js index c8c019ec5c..03eb6122c8 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js @@ -12,7 +12,7 @@ async function run_test() { gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperLockFile(gTestFiles[2]); + await runHelperLockFile(getTestFileByName("searchpluginspng1.png")); runUpdate(STATE_FAILED_READ_ERROR, false, 1, true); await waitForHelperExit(); standardInit(); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js index 7b582dbd45..4d5fe599cf 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js @@ -13,7 +13,7 @@ async function run_test() { gTestDirs = gTestDirsCompleteSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); - await runHelperLockFile(gTestFiles[3]); + await runHelperLockFile(getTestFileByName("searchpluginspng0.png")); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); // Files aren't checked after staging since this test locks a file which diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js index bf3abd8c37..3d4a8e0c51 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js @@ -13,7 +13,7 @@ async function run_test() { gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); - await runHelperLockFile(gTestFiles[2]); + await runHelperLockFile(getTestFileByName("searchpluginspng1.png")); await stageUpdate(STATE_AFTER_STAGE, true); checkPostUpdateRunningFile(false); // Files aren't checked after staging since this test locks a file which diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js index a1a0de0fe4..47c184e67b 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js @@ -11,7 +11,7 @@ async function run_test() { } const STATE_AFTER_STAGE = STATE_FAILED; gTestFiles = gTestFilesPartialSuccess; - gTestFiles[11].originalFile = "partial.png"; + getTestFileByName("0exe0.exe").originalFile = "partial.png"; gTestDirs = gTestDirsPartialSuccess; setTestFilesAndDirsForFailure(); await setupUpdaterTest(FILE_PARTIAL_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js index 943a45ba95..2c9c3298d4 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js @@ -11,9 +11,10 @@ async function run_test() { } const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED; gTestFiles = gTestFilesCompleteSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromComplete\n"; + channelPrefs.comparePerms = 0o644; gTestDirs = gTestDirsCompleteSuccess; setupSymLinks(); await setupUpdaterTest(FILE_COMPLETE_MAR, false); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js index dd5c240919..e565ffe550 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js @@ -11,9 +11,10 @@ async function run_test() { } const STATE_AFTER_STAGE = gIsServiceTest ? STATE_APPLIED_SVC : STATE_APPLIED; gTestFiles = gTestFilesPartialSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromPartial\n"; + channelPrefs.comparePerms = 0o644; gTestDirs = gTestDirsPartialSuccess; preventDistributionFiles(); await setupUpdaterTest(FILE_PARTIAL_MAR, true); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js index 8e8e9d094a..f4f856278c 100644 --- a/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js +++ b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js @@ -10,9 +10,10 @@ async function run_test() { return; } gTestFiles = gTestFilesPartialSuccess; - gTestFiles[gTestFiles.length - 1].originalContents = null; - gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n"; - gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + const channelPrefs = getTestFileByName(FILE_CHANNEL_PREFS); + channelPrefs.originalContents = null; + channelPrefs.compareContents = "FromPartial\n"; + channelPrefs.comparePerms = 0o644; gTestDirs = gTestDirsPartialSuccess; // The third parameter will test that a relative path that contains a // directory traversal to the post update binary doesn't execute. diff --git a/toolkit/mozapps/update/updater/Makefile.in b/toolkit/mozapps/update/updater/Makefile.in index 70cf32378a..ec3ad9773a 100644 --- a/toolkit/mozapps/update/updater/Makefile.in +++ b/toolkit/mozapps/update/updater/Makefile.in @@ -25,4 +25,7 @@ libs:: $(call py_action,preprocessor updater.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings) $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS $(NSINSTALL) $(DIST)/bin/org.mozilla.updater $(DIST)/bin/updater.app/Contents/MacOS + $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/Frameworks + $(NSINSTALL) $(DIST)/bin/UpdateSettings $(DIST)/bin/updater.app/Contents/Frameworks/UpdateSettings.framework + $(NSINSTALL) $(srcdir)/macos-frameworks/UpdateSettings/Info.plist $(DIST)/bin/updater.app/Contents/Frameworks/UpdateSettings.framework/Resources endif diff --git a/toolkit/mozapps/update/updater/launchchild_osx.mm b/toolkit/mozapps/update/updater/launchchild_osx.mm index 917f282d9f..b64e85980c 100644 --- a/toolkit/mozapps/update/updater/launchchild_osx.mm +++ b/toolkit/mozapps/update/updater/launchchild_osx.mm @@ -280,8 +280,9 @@ void CleanupElevatedMacUpdate(bool aFailureOccurred) { LaunchChild(3, launchctlArgs); } -// Note: Caller is responsible for freeing argv. -bool ObtainUpdaterArguments(int* argc, char*** argv) { +// Note: Caller is responsible for freeing aArgv. +bool ObtainUpdaterArguments(int* aArgc, char*** aArgv, + MARChannelStringTable* aMARStrings) { MacAutoreleasePool pool; id updateServer = ConnectToUpdateServer(); @@ -294,15 +295,22 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { @try { NSArray* updaterArguments = [updateServer performSelector:@selector(getArguments)]; - *argc = [updaterArguments count]; - char** tempArgv = (char**)malloc(sizeof(char*) * (*argc)); - for (int i = 0; i < *argc; i++) { + *aArgc = [updaterArguments count]; + char** tempArgv = (char**)malloc(sizeof(char*) * (*aArgc)); + for (int i = 0; i < *aArgc; i++) { int argLen = [[updaterArguments objectAtIndex:i] length] + 1; tempArgv[i] = (char*)malloc(argLen); strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String], argLen); } - *argv = tempArgv; + *aArgv = tempArgv; + + NSString* channelID = + [updateServer performSelector:@selector(getMARChannelID)]; + const char* channelIDStr = [channelID UTF8String]; + aMARStrings->MARChannelID = + mozilla::MakeUnique<char[]>(strlen(channelIDStr) + 1); + strcpy(aMARStrings->MARChannelID.get(), channelIDStr); } @catch (NSException* e) { // Let's try our best and clean up. CleanupElevatedMacUpdate(true); @@ -321,10 +329,12 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { NSArray* mUpdaterArguments; BOOL mShouldKeepRunning; BOOL mAborted; + NSString* mMARChannelID; } -- (id)initWithArgs:(NSArray*)args; +- (id)initWithArgs:(NSArray*)aArgs marChannelID:(NSString*)aMARChannelID; - (BOOL)runServer; - (NSArray*)getArguments; +- (NSString*)getMARChannelID; - (void)abort; - (BOOL)wasAborted; - (void)shutdown; @@ -333,12 +343,13 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { @implementation ElevatedUpdateServer -- (id)initWithArgs:(NSArray*)args { +- (id)initWithArgs:(NSArray*)aArgs marChannelID:(NSString*)aMARChannelID { self = [super init]; if (!self) { return nil; } - mUpdaterArguments = args; + mUpdaterArguments = aArgs; + mMARChannelID = aMARChannelID; mShouldKeepRunning = YES; mAborted = NO; return self; @@ -367,6 +378,20 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { return mUpdaterArguments; } +/** + * The MAR channel ID(s) are stored in the UpdateSettings.framework that ships + * with the updater.app bundle. When an elevated update is occurring, the + * org.mozilla.updater binary is extracted and installed individually as a + * Privileged Helper Tool. This Privileged Helper Tool does not have access to + * the UpdateSettings.framework and we therefore rely on the unelevated updater + * process to pass this information to the elevated updater process in the same + * fashion that the command line arguments are passed to the elevated updater + * process by `getArguments`. + */ +- (NSString*)getMARChannelID { + return mMARChannelID; +} + - (void)abort { mAborted = YES; [self shutdown]; @@ -386,16 +411,19 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { @end -bool ServeElevatedUpdate(int argc, const char** argv) { +bool ServeElevatedUpdate(int aArgc, const char** aArgv, + const char* aMARChannelID) { MacAutoreleasePool pool; - NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:argc]; - for (int i = 0; i < argc; i++) { - [updaterArguments addObject:[NSString stringWithUTF8String:argv[i]]]; + NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:aArgc]; + for (int i = 0; i < aArgc; i++) { + [updaterArguments addObject:[NSString stringWithUTF8String:aArgv[i]]]; } + NSString* channelID = [NSString stringWithUTF8String:aMARChannelID]; ElevatedUpdateServer* updater = - [[ElevatedUpdateServer alloc] initWithArgs:[updaterArguments copy]]; + [[ElevatedUpdateServer alloc] initWithArgs:updaterArguments + marChannelID:channelID]; bool didSucceed = [updater runServer]; [updater release]; diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build new file mode 100644 index 0000000000..e1f4ad0981 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build @@ -0,0 +1,18 @@ +# -*- 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/. + +Framework("UpdateSettings-WrongChannel") +FINAL_TARGET = "_tests/xpcshell/toolkit/mozapps/update/tests" + +DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"wrong-channel"' + +UNIFIED_SOURCES += [ + "../UpdateSettings/UpdateSettings.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build new file mode 100644 index 0000000000..6c9b43b146 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build @@ -0,0 +1,18 @@ +# -*- 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/. + +Framework("UpdateSettings-xpcshell") +FINAL_TARGET = "_tests/xpcshell/toolkit/mozapps/update/tests" + +DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"xpcshell-test"' + +UNIFIED_SOURCES += [ + "../UpdateSettings/UpdateSettings.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist new file mode 100644 index 0000000000..65777a475f --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>UpdateSettings</string> + <key>CFBundleIdentifier</key> + <string>org.mozilla.updatesettings</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>UpdateSettings</string> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1.0</string> +</dict> +</plist> diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md new file mode 100644 index 0000000000..32b9d2ea48 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md @@ -0,0 +1,77 @@ +# UpdateSettings macOS Framework + +## Summary + +The UpdateSettings macOS Framework is used to set the accepted MAR download +channels. + +## What are MAR update channels and what are they used for? + +As the name implies, MAR update channels are the channels where MAR update files +are served from and we want to ensure that the updater only applies MAR files +from accepted channels. + +## Why do we need a Framework instead of compiling the accepted MAR update channels directly into the executable? + +There are three main use cases that make it necessary for the accepted MAR +update channels to be set by external means, such as a macOS Framework: + + 1. Allowing users on the Beta channel to test RC builds + +Our beta users test release candidate builds before they are released to the +release population. The MAR files related to release candidates have their MAR +channel set to `release`. We make it possible for beta users to test these +release candidate MAR files by having beta Firefox installs accept MAR files +with their internal update channel set to either `release` or `beta`. + + 2. Switching users to another channel, such as ESR + +In contrast to the Beta use case outlined above, there are times where we +explicitly WANT to switch users to a different channel. An example of this is +when hardware or a particular macOS version have reached their EOL. In this +case, we usually switch users to our ESR channel for extended support. We switch +users to a different channel by serving a MAR file that forces a change to the +update channels that will be accepted for future updates. In other words, while +users may have previously accepted MAR update files from the `release` channel, +they now only accept MAR files from the `esr` channel. + + 3. QA update testing + +QA requires a way to temporarily switch the MAR update channel to a test channel +in order to test MAR updates before new releases. + +## How does the UpdateSettings macOS Framework address these use cases? + +We are able to accommodate all three use cases above by enabling the updater to +ignore certain files on disk if they are already present, but continue to force +update them if so desired. + +In the case of a Beta user updating to an RC build, the updater would encounter +an UpdateSettings macOS Framework inside the .app bundle that has the accepted +MAR update channels set to `beta` and `release`. In this case, the updater will +not update the Framework, but update everything else. This beta user is now able +to run the RC build with the update channel still set to `beta` and `release` +and will be able to apply MAR files related to the next beta cycle once the end +of RC builds is reached. + +In the case of switching users to the ESR channel, the updater will be set to +forcefully update the UpdateSettings macOS Framework, even if already present on +disk. After the update, the user will now be set to accept MAR updates from the +`esr` channel only. + +Before releases, QA replaces the UpdateSettings macOS Framework within the .app +bundle and set the accepted MAR update channels to a test channel in order to +test MAR updates. During testing, the new Framework file would remain in place +for typical update testing, but gets replaced in case QA was testing channel +switching. + +## Why is a macOS Framework the best solution to store the accepted MAR update channels? + +Apple has started strengthening code signature checks and the requirements on +developers such as ourselves on how their apps are signed. In particular, +most files in the .app bundle are now included in signature verifications. + +A macOS Framework is the ideal solution to store the accepted MAR update +channels because Frameworks are the only component within a .app bundle that can +be replaced without invalidating the code signature on the .app bundle, as long +as both the previous and the new Framework are signed. diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h new file mode 100644 index 0000000000..65a7ba3e00 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h @@ -0,0 +1,17 @@ +/* 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/. */ + +#ifndef UpdateSettings_h_ +#define UpdateSettings_h_ + +#import <Foundation/Foundation.h> + +extern "C" { + +// Returns the accepted MAR channels, as an autoreleased string. +extern NSString* UpdateSettingsGetAcceptedMARChannels(void) + __attribute__((weak_import)) __attribute__((visibility("default"))); +} + +#endif // UpdateSettings_h_ diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm new file mode 100644 index 0000000000..2c39f13f3b --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm @@ -0,0 +1,13 @@ +/* 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 "UpdateSettings.h" + +#include "mozilla/HelperMacros.h" + +NSString* UpdateSettingsGetAcceptedMARChannels(void) { + return + [NSString stringWithFormat:@"[Settings]\nACCEPTED_MAR_CHANNEL_IDS=%s\n", + ACCEPTED_MAR_CHANNEL_IDS]; +} diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build new file mode 100644 index 0000000000..67de1d68f7 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build @@ -0,0 +1,24 @@ +# -*- 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/. + +Framework("UpdateSettings") + +if CONFIG["ACCEPTED_MAR_CHANNEL_IDS"]: + DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"%s"' % CONFIG["ACCEPTED_MAR_CHANNEL_IDS"] +else: + DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '""' + +EXPORTS += [ + "UpdateSettings.h", +] + +UNIFIED_SOURCES += [ + "UpdateSettings.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h new file mode 100644 index 0000000000..5964d9fb18 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#ifndef UpdateSettingsUtil_h_ +#define UpdateSettingsUtil_h_ + +#include <optional> +#include <string> + +class UpdateSettingsUtil { + public: + static std::optional<std::string> GetAcceptedMARChannelsValue(); +}; + +#endif // UpdateSettingsUtil_h_ diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm new file mode 100644 index 0000000000..6555fd1350 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm @@ -0,0 +1,21 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: + * 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#import "UpdateSettings/UpdateSettings.h" + +#include "UpdateSettingsUtil.h" + +/* static */ +std::optional<std::string> UpdateSettingsUtil::GetAcceptedMARChannelsValue() { + // `UpdateSettingsGetAcceptedMARChannels` is resolved at runtime and requires + // the UpdateSettings framework to be loaded. + if (UpdateSettingsGetAcceptedMARChannels) { + NSString* marChannels = UpdateSettingsGetAcceptedMARChannels(); + return [marChannels UTF8String]; + } + return {}; +} diff --git a/toolkit/mozapps/update/updater/macos-frameworks/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/moz.build new file mode 100644 index 0000000000..19fa11942e --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/moz.build @@ -0,0 +1,18 @@ +# -*- 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/. + +with Files("**"): + BUG_COMPONENT = ("Toolkit", "Application Update") + +DIRS += ["UpdateSettings", "UpdateSettings-xpcshell", "UpdateSettings-WrongChannel"] + +EXPORTS += [ + "UpdateSettingsUtil.h", +] + +UNIFIED_SOURCES += [ + "UpdateSettingsUtil.mm", +] diff --git a/toolkit/mozapps/update/updater/moz.build b/toolkit/mozapps/update/updater/moz.build index eede9cd723..9620dde22c 100644 --- a/toolkit/mozapps/update/updater/moz.build +++ b/toolkit/mozapps/update/updater/moz.build @@ -26,6 +26,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": "__launchd_plist", SRCDIR + "/Launchd.plist", ] + DIRS += [ + "macos-frameworks", + ] GENERATED_FILES = [ "dep1Cert.h", diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build index fe0b4a85fa..6c6d0adf6f 100644 --- a/toolkit/mozapps/update/updater/updater-common.build +++ b/toolkit/mozapps/update/updater/updater-common.build @@ -22,6 +22,17 @@ if CONFIG["MOZ_VERIFY_MAR_SIGNATURE"]: "verifymar", ] + if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": + srcs += [ + "macos-frameworks/UpdateSettingsUtil.mm", + ] + USE_LIBS += [ + "UpdateSettings", + ] + LDFLAGS += [ + "-Wl,-rpath,@executable_path/../Frameworks/UpdateSettings.framework" + ] + if CONFIG["OS_ARCH"] == "WINNT": have_progressui = 1 srcs += [ @@ -114,7 +125,7 @@ if CONFIG["MOZ_TSAN"]: DEFINES["SPRINTF_H_USES_VSNPRINTF"] = True DEFINES["NS_NO_XPCOM"] = True DisableStlWrapping() -for var in ("MAR_CHANNEL_ID", "MOZ_APP_VERSION"): +for var in ("MAR_CHANNEL_ID", "MOZ_APP_VERSION", "ACCEPTED_MAR_CHANNEL_IDS"): DEFINES[var] = '"%s"' % CONFIG[var] LOCAL_INCLUDES += [ diff --git a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in index 533533c4d9..7ef90f9ce5 100644 --- a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in +++ b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in @@ -30,6 +30,10 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) $(call py_action,preprocessor updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings) $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/MacOS $(NSINSTALL) $(FINAL_TARGET)/updater-xpcshell $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/MacOS + $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks + $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework + cp $(XPCSHELLTESTDIR)/UpdateSettings-xpcshell $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework/UpdateSettings + $(NSINSTALL) $(srcdir)/../macos-frameworks/UpdateSettings/Info.plist $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework/Resources rm -Rf $(XPCSHELLTESTDIR)/data/updater.app mv $(XPCSHELLTESTDIR)/data/updater-xpcshell.app $(XPCSHELLTESTDIR)/data/updater.app mv $(XPCSHELLTESTDIR)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTDIR)/data/updater.app/Contents/MacOS/org.mozilla.updater diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 6b01450b31..084945dc44 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -46,6 +46,7 @@ #include "updatecommon.h" #ifdef XP_MACOSX +# include "UpdateSettingsUtil.h" # include "updaterfileutils_osx.h" #endif // XP_MACOSX @@ -75,13 +76,16 @@ bool IsOwnedByGroupAdmin(const char* aAppBundle); bool IsRecursivelyWritable(const char* aPath); void LaunchChild(int argc, const char** argv); void LaunchMacPostProcess(const char* aAppBundle); -bool ObtainUpdaterArguments(int* argc, char*** argv); -bool ServeElevatedUpdate(int argc, const char** argv); +bool ObtainUpdaterArguments(int* aArgc, char*** aArgv, + MARChannelStringTable* aMARStrings); +bool ServeElevatedUpdate(int aArgc, const char** aArgv, + const char* aMARChannelID); void SetGroupOwnershipAndPermissions(const char* aAppBundle); bool PerformInstallationFromDMG(int argc, char** argv); struct UpdateServerThreadArgs { int argc; const NS_tchar** argv; + const char* marChannelID; }; #endif @@ -187,15 +191,6 @@ class AutoFile { } }; -struct MARChannelStringTable { - MARChannelStringTable() { - MARChannelID = mozilla::MakeUnique<char[]>(1); - MARChannelID[0] = '\0'; - } - - mozilla::UniquePtr<char[]> MARChannelID; -}; - //----------------------------------------------------------------------------- #ifdef XP_MACOSX @@ -292,6 +287,10 @@ static bool sUsingService = false; // that iteration will run with `gIsElevated == true`. static bool gIsElevated = false; +// This string contains the MAR channel IDs that are later extracted by one of +// the `ReadMARChannelIDsFrom` variants. +static MARChannelStringTable gMARStrings; + // Normally, we run updates as a result of user action (the user started Firefox // or clicked a "Restart to Update" button). But there are some cases when // we are not: @@ -2659,23 +2658,67 @@ static void WaitForServiceFinishThread(void* param) { #endif #ifdef MOZ_VERIFY_MAR_SIGNATURE +# ifndef XP_MACOSX /** * This function reads in the ACCEPTED_MAR_CHANNEL_IDS from update-settings.ini * - * @param path The path to the ini file that is to be read - * @param results A pointer to the location to store the read strings + * @param aPath The path to the ini file that is to be read + * @param aResults A pointer to the location to store the read strings + * @return OK on success + */ +static int ReadMARChannelIDsFromPath(const NS_tchar* aPath, + MARChannelStringTable* aResults) { + const unsigned int kNumStrings = 1; + const char* kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0"; + return ReadStrings(aPath, kUpdaterKeys, kNumStrings, &aResults->MARChannelID, + "Settings"); +} +# else // XP_MACOSX +/** + * This function reads in the ACCEPTED_MAR_CHANNEL_IDS from a string buffer. + * + * @param aChannels A string buffer containing the MAR channel(s). + * @param aResults A pointer to the location to store the read strings. * @return OK on success */ -static int ReadMARChannelIDs(const NS_tchar* path, - MARChannelStringTable* results) { +static int ReadMARChannelIDsFromBuffer(char* aChannels, + MARChannelStringTable* aResults) { const unsigned int kNumStrings = 1; const char* kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0"; - int result = ReadStrings(path, kUpdaterKeys, kNumStrings, - &results->MARChannelID, "Settings"); + return ReadStringsFromBuffer(aChannels, kUpdaterKeys, kNumStrings, + &aResults->MARChannelID, "Settings"); +} +# endif // XP_MACOSX - return result; +/** + * This function reads in the `ACCEPTED_MAR_CHANNEL_IDS` from the appropriate + * (platform-dependent) source and populates `gMARStrings`. + * + * @return + * `OK` on success, `UPDATE_SETTINGS_FILE_CHANNEL` on failure. + */ +static int PopulategMARStrings() { + int rv = UPDATE_SETTINGS_FILE_CHANNEL; +# ifdef XP_MACOSX + if (gIsElevated) { + // An elevated update process will have already populated gMARStrings when + // it connected to the unelevated update process to obtain the command line + // args. See `ObtainUpdaterArguments`. + rv = OK; + } else if (auto marChannels = + UpdateSettingsUtil::GetAcceptedMARChannelsValue()) { + rv = ReadMARChannelIDsFromBuffer(marChannels->data(), &gMARStrings); + } +# else + NS_tchar updateSettingsPath[MAXPATHLEN]; + NS_tsnprintf(updateSettingsPath, + sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), + NS_T("%s/update-settings.ini"), gInstallDirPath); + rv = ReadMARChannelIDsFromPath(updateSettingsPath, &gMARStrings); +# endif + return rv == OK ? OK : UPDATE_SETTINGS_FILE_CHANNEL; } -#endif +#endif // MOZ_VERIFY_MAR_SIGNATURE static int GetUpdateFileName(NS_tchar* fileName, int maxChars) { NS_tsnprintf(fileName, maxChars, NS_T("%s/update.mar"), gPatchDirPath); @@ -2700,21 +2743,10 @@ static void UpdateThreadFunc(void* param) { } if (rv == OK) { - NS_tchar updateSettingsPath[MAXPATHLEN]; - NS_tsnprintf(updateSettingsPath, - sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), -# ifdef XP_MACOSX - NS_T("%s/Contents/Resources/update-settings.ini"), -# else - NS_T("%s/update-settings.ini"), -# endif - gInstallDirPath); - MARChannelStringTable MARStrings; - if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) { - rv = UPDATE_SETTINGS_FILE_CHANNEL; - } else { + rv = PopulategMARStrings(); + if (rv == OK) { rv = gArchiveReader.VerifyProductInformation( - MARStrings.MARChannelID.get(), MOZ_APP_VERSION); + gMARStrings.MARChannelID.get(), MOZ_APP_VERSION); } } #endif @@ -2819,7 +2851,8 @@ static void UpdateThreadFunc(void* param) { #ifdef XP_MACOSX static void ServeElevatedUpdateThreadFunc(void* param) { UpdateServerThreadArgs* threadArgs = (UpdateServerThreadArgs*)param; - gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv); + gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv, + threadArgs->marChannelID); if (!gSucceeded) { WriteStatusFile(ELEVATION_CANCELED); } @@ -2955,6 +2988,21 @@ int NS_main(int argc, NS_tchar** argv) { putenv(const_cast<char*>("MOZ_USING_SERVICE=")); #endif + if (argc == 2 && NS_tstrcmp(argv[1], NS_T("--channels-allowed")) == 0) { +#ifdef MOZ_VERIFY_MAR_SIGNATURE + int rv = PopulategMARStrings(); + if (rv == OK) { + printf("Channels Allowed: %s\n", gMARStrings.MARChannelID.get()); + return 0; + } + printf("Error: %d\n", rv); + return 1; +#else + printf("Not Applicable: No support for signature verification\n"); + return 0; +#endif + } + // The callback is the remaining arguments starting at callbackIndex. // The argument specified by callbackIndex is the callback executable and the // argument prior to callbackIndex is the working directory. @@ -2977,7 +3025,7 @@ int NS_main(int argc, NS_tchar** argv) { strstr(argv[0], "/Library/PrivilegedHelperTools/org.mozilla.updater") != 0; if (isElevated) { - if (!ObtainUpdaterArguments(&argc, &argv)) { + if (!ObtainUpdaterArguments(&argc, &argv, &gMARStrings)) { // Won't actually get here because ObtainUpdaterArguments will terminate // the current process on failure. return 1; @@ -3288,6 +3336,7 @@ int NS_main(int argc, NS_tchar** argv) { UpdateServerThreadArgs threadArgs; threadArgs.argc = argc; threadArgs.argv = const_cast<const NS_tchar**>(argv); + threadArgs.marChannelID = gMARStrings.MARChannelID.get(); Thread t1; if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) { @@ -4179,7 +4228,7 @@ int NS_main(int argc, NS_tchar** argv) { // Run update process on a background thread. ShowProgressUI may return // before QuitProgressUI has been called, so wait for UpdateThreadFunc to // terminate. Avoid showing the progress UI when staging an update, or if - // this is an elevated process on OSX. + // this is an elevated process on macOS. Thread t; if (t.Run(UpdateThreadFunc, nullptr) == 0) { if (!sStagedUpdate && !sReplaceRequest && !sUpdateSilently |