Enhanced WebExtension support + detailed reason on why a extension is "corrupt"

This commit is contained in:
ownedbywuigi 2026-03-31 14:37:57 +01:00
commit c961f4e45c
4 changed files with 60 additions and 7 deletions

View file

@ -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);

View file

@ -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.
*

View file

@ -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);

View file

@ -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() {