From c961f4e45c281b7ca8bdf721c35df8038d013eb7 Mon Sep 17 00:00:00 2001 From: ownedbywuigi Date: Tue, 31 Mar 2026 14:37:57 +0100 Subject: [PATCH] Enhanced WebExtension support + detailed reason on why a extension is "corrupt" --- .../basilisk/base/content/browser-addons.js | 6 ++++++ .../basilisk/base/content/utilityOverlay.js | 21 +++++++++++++++++++ .../extensions/internal/XPIProvider.jsm | 19 ++++++++++++++--- .../webextensions/internal/XPIProvider.jsm | 21 +++++++++++++++---- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/application/basilisk/base/content/browser-addons.js b/application/basilisk/base/content/browser-addons.js index 0ecfc32040..2cbb1da864 100644 --- a/application/basilisk/base/content/browser-addons.js +++ b/application/basilisk/base/content/browser-addons.js @@ -334,6 +334,12 @@ const gXPInstallObserver = { messageString = gNavigatorBundle.getFormattedString(error, args); + if (install.error == AddonManager.ERROR_CORRUPT_FILE && + install.errorDetail && + typeof install.errorDetail == "string") { + messageString += "\n" + "Details: " + install.errorDetail; + } + PopupNotifications.show(browser, notificationID, messageString, anchorID, action, null, options); diff --git a/application/basilisk/base/content/utilityOverlay.js b/application/basilisk/base/content/utilityOverlay.js index 9b58953c65..f355179cb5 100644 --- a/application/basilisk/base/content/utilityOverlay.js +++ b/application/basilisk/base/content/utilityOverlay.js @@ -88,6 +88,7 @@ function getBoolPref(prefname, def) */ function openUILink(url, event, aIgnoreButton, aIgnoreAlt, aAllowThirdPartyFixup, aPostData, aReferrerURI) { + event = getRootEvent(event); let params; if (aIgnoreButton && typeof aIgnoreButton == "object") { @@ -112,6 +113,26 @@ function openUILink(url, event, aIgnoreButton, aIgnoreAlt, aAllowThirdPartyFixup openUILinkIn(url, where, params); } +// Utility function to inspect command events for wrapped middle-click events +// and return the originating event when available. +function getRootEvent(aEvent) +{ + if (!aEvent) { + return aEvent; + } + + let tempEvent = aEvent; + while (tempEvent.sourceEvent) { + if (tempEvent.sourceEvent.button == 1) { + aEvent = tempEvent.sourceEvent; + break; + } + tempEvent = tempEvent.sourceEvent; + } + + return aEvent; +} + /* whereToOpenLink() looks at an event to decide where to open a link. * diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index f3125011e3..fbb1b3e8b6 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -5275,8 +5275,10 @@ AddonInstall.prototype = { this.certName = this.certificate.organization; } } else { - zipreader.close(); - throw new Error("XPI is incorrectly signed"); + // Don't treat unverifiable object signatures as file corruption. + // UXP may encounter AMO signatures it cannot verify, while the + // package itself is still valid and installable. + logger.warn("XPI signature verification failed; continuing install"); } } @@ -5598,6 +5600,17 @@ AddonInstall.prototype = { logger.warn("Download of " + this.sourceURI.spec + " failed", aError); this.state = AddonManager.STATE_DOWNLOAD_FAILED; this.error = aReason; + if (aError !== undefined && aError !== null) { + if (typeof aError == "string") { + this.errorDetail = aError; + } else if (aError && typeof aError.message == "string" && aError.message) { + this.errorDetail = aError.message; + } else { + this.errorDetail = String(aError); + } + } else { + this.errorDetail = null; + } XPIProvider.removeActiveInstall(this); AddonManagerPrivate.callInstallListeners("onDownloadFailed", this.listeners, this.wrapper); @@ -6007,7 +6020,7 @@ function AddonInstallWrapper(aInstall) { }); #endif - ["name", "type", "version", "icons", "releaseNotesURI", "file", "state", "error", + ["name", "type", "version", "icons", "releaseNotesURI", "file", "state", "error", "errorDetail", "progress", "maxProgress", "certificate", "certName"].forEach(function(aProp) { this.__defineGetter__(aProp, function AIW_propertyGetter() aInstall[aProp]); }, this); diff --git a/toolkit/mozapps/webextensions/internal/XPIProvider.jsm b/toolkit/mozapps/webextensions/internal/XPIProvider.jsm index 042caeda34..4dcb5267d9 100644 --- a/toolkit/mozapps/webextensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/webextensions/internal/XPIProvider.jsm @@ -5533,9 +5533,11 @@ class AddonInstall { this.certName = this.certificate.organization; } } else { - zipreader.close(); - return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, - "XPI is incorrectly signed"]); + // In non-required-signing mode, allow installation to proceed + // when signature verification fails instead of treating it as a + // corrupt XPI. This improves compatibility with third-party + // signed add-ons on older platforms. + logger.warn("XPI signature verification failed; continuing because signatures are not required"); } } } @@ -6321,6 +6323,17 @@ class DownloadAddonInstall extends AddonInstall { logger.warn("Download of " + this.sourceURI.spec + " failed", aError); this.state = AddonManager.STATE_DOWNLOAD_FAILED; this.error = aReason; + if (aError !== undefined && aError !== null) { + if (typeof aError == "string") { + this.errorDetail = aError; + } else if (aError && typeof aError.message == "string" && aError.message) { + this.errorDetail = aError.message; + } else { + this.errorDetail = String(aError); + } + } else { + this.errorDetail = null; + } XPIProvider.removeActiveInstall(this); AddonManagerPrivate.callInstallListeners("onDownloadFailed", this.listeners, this.wrapper); @@ -6655,7 +6668,7 @@ AddonInstallWrapper.prototype = { }, }; -["name", "version", "icons", "releaseNotesURI", "file", "state", "error", +["name", "version", "icons", "releaseNotesURI", "file", "state", "error", "errorDetail", "progress", "maxProgress", "certificate", "certName"].forEach(function(aProp) { Object.defineProperty(AddonInstallWrapper.prototype, aProp, { get: function() {