зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset c0f94e1d6f11 (bug 1308295)
This commit is contained in:
Родитель
0c0f805af3
Коммит
22246e78b5
|
@ -10,23 +10,15 @@ const ID = "permissions@test.mozilla.org";
|
|||
|
||||
const DEFAULT_EXTENSION_ICON = "chrome://browser/content/extension.svg";
|
||||
|
||||
Services.perms.add(makeURI("https://example.com/"), "install",
|
||||
Services.perms.ALLOW_ACTION);
|
||||
|
||||
function promisePopupNotificationShown(name) {
|
||||
return new Promise(resolve => {
|
||||
function popupshown() {
|
||||
PopupNotifications.panel.addEventListener("popupshown", () => {
|
||||
let notification = PopupNotifications.getNotification(name);
|
||||
if (!notification) { return; }
|
||||
|
||||
ok(notification, `${name} notification shown`);
|
||||
ok(PopupNotifications.isPanelOpen, "notification panel open");
|
||||
|
||||
PopupNotifications.panel.removeEventListener("popupshown", popupshown);
|
||||
resolve(PopupNotifications.panel.firstChild);
|
||||
}
|
||||
|
||||
PopupNotifications.panel.addEventListener("popupshown", popupshown);
|
||||
}, {once: true});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -68,14 +60,8 @@ function checkNotification(panel, url) {
|
|||
|
||||
const INSTALL_FUNCTIONS = [
|
||||
function installMozAM(url) {
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, url, function*(cUrl) {
|
||||
content.wrappedJSObject.installMozAM(cUrl);
|
||||
});
|
||||
},
|
||||
|
||||
function installTrigger(url) {
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, url, function*(cUrl) {
|
||||
content.wrappedJSObject.installTrigger(cUrl);
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, url, function*(cUrl) {
|
||||
return content.wrappedJSObject.installMozAM(cUrl);
|
||||
});
|
||||
},
|
||||
];
|
||||
|
@ -92,37 +78,7 @@ add_task(function* () {
|
|||
function* runOnce(installFn, url, cancel) {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
||||
|
||||
let installPromise = new Promise(resolve => {
|
||||
let listener = {
|
||||
onDownloadCancelled() {
|
||||
AddonManager.removeInstallListener(listener);
|
||||
resolve(false);
|
||||
},
|
||||
|
||||
onDownloadFailed() {
|
||||
AddonManager.removeInstallListener(listener);
|
||||
resolve(false);
|
||||
},
|
||||
|
||||
onInstallCancelled() {
|
||||
AddonManager.removeInstallListener(listener);
|
||||
resolve(false);
|
||||
},
|
||||
|
||||
onInstallEnded() {
|
||||
AddonManager.removeInstallListener(listener);
|
||||
resolve(true);
|
||||
},
|
||||
|
||||
onInstallFailed() {
|
||||
AddonManager.removeInstallListener(listener);
|
||||
resolve(false);
|
||||
},
|
||||
};
|
||||
AddonManager.addInstallListener(listener);
|
||||
});
|
||||
|
||||
installFn(url);
|
||||
let installPromise = installFn(url);
|
||||
|
||||
let panel = yield promisePopupNotificationShown("addon-webext-permissions");
|
||||
checkNotification(panel, url);
|
||||
|
@ -136,10 +92,10 @@ add_task(function* () {
|
|||
let result = yield installPromise;
|
||||
let addon = yield promiseGetAddonByID(ID);
|
||||
if (cancel) {
|
||||
ok(!result, "Installation was cancelled");
|
||||
is(result, "onInstallCancelled", "Installation was cancelled");
|
||||
is(addon, null, "Extension is not installed");
|
||||
} else {
|
||||
ok(result, "Installation completed");
|
||||
is(result, "onInstallEnded", "Installation completed");
|
||||
isnot(addon, null, "Extension is installed");
|
||||
addon.uninstall();
|
||||
}
|
||||
|
|
|
@ -7,13 +7,19 @@
|
|||
<body>
|
||||
<script type="text/javascript">
|
||||
function installMozAM(url) {
|
||||
return navigator.mozAddonManager.createInstall({url}).then(install => {
|
||||
return navigator.mozAddonManager.createInstall({url}).then(install => new Promise(resolve => {
|
||||
const EVENTS = [
|
||||
"onDownloadCancelled",
|
||||
"onDownloadFailed",
|
||||
"onInstallCancelled",
|
||||
"onInstallEnded",
|
||||
"onInstallFailed",
|
||||
];
|
||||
for (let event of EVENTS) {
|
||||
install.addEventListener(event, () => { resolve(event); });
|
||||
}
|
||||
install.install();
|
||||
});
|
||||
}
|
||||
|
||||
function installTrigger(url) {
|
||||
InstallTrigger.install({extension: url});
|
||||
}));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -21,12 +21,6 @@ this.ExtensionsUI = {
|
|||
observe(subject, topic, data) {
|
||||
if (topic == "webextension-permission-prompt") {
|
||||
let {target, info} = subject.wrappedJSObject;
|
||||
|
||||
let progressNotification = target.ownerGlobal.PopupNotifications.getNotification("addon-progress", target);
|
||||
if (progressNotification) {
|
||||
progressNotification.remove();
|
||||
}
|
||||
|
||||
this.showPermissionsPrompt(target, info).then(answer => {
|
||||
Services.obs.notifyObservers(subject, "webextension-permission-response",
|
||||
JSON.stringify(answer));
|
||||
|
|
|
@ -47,7 +47,7 @@ const UNKNOWN_XPCOM_ABI = "unknownABI";
|
|||
|
||||
const PREF_MIN_WEBEXT_PLATFORM_VERSION = "extensions.webExtensionsMinPlatformVersion";
|
||||
const PREF_WEBAPI_TESTING = "extensions.webapi.testing";
|
||||
const PREF_WEBEXT_PERM_PROMPTS = "extensions.webextPermissionPrompts";
|
||||
const PREF_WEBEXT_PREF_PROMPTS = "extensions.webextPermissionPrompts";
|
||||
|
||||
const UPDATE_REQUEST_VERSION = 2;
|
||||
const CATEGORY_UPDATE_PARAMS = "extension-update-params";
|
||||
|
@ -73,8 +73,6 @@ const WEBAPI_TEST_INSTALL_HOSTS = [
|
|||
"example.com",
|
||||
];
|
||||
|
||||
const URI_XPINSTALL_DIALOG = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
|
||||
|
@ -102,9 +100,6 @@ XPCOMUtils.defineLazyGetter(this, "CertUtils", function() {
|
|||
return certUtils;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "WEBEXT_PERMISSION_PROMPTS",
|
||||
PREF_WEBEXT_PERM_PROMPTS, false);
|
||||
|
||||
const INTEGER = /^[1-9]\d*$/;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ];
|
||||
|
@ -453,6 +448,228 @@ BrowserListener.prototype = {
|
|||
Ci.nsIObserver])
|
||||
};
|
||||
|
||||
function installNotifyObservers(aTopic, aBrowser, aUri, aInstall, aInstallFn) {
|
||||
let info = {
|
||||
wrappedJSObject: {
|
||||
browser: aBrowser,
|
||||
originatingURI: aUri,
|
||||
installs: [aInstall],
|
||||
install: aInstallFn,
|
||||
},
|
||||
};
|
||||
Services.obs.notifyObservers(info, aTopic, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to monitor a download and prompt to install when ready
|
||||
*/
|
||||
class Installer {
|
||||
/**
|
||||
*
|
||||
* @param aBrowser
|
||||
* The browser that started the installations
|
||||
* @param aUrl
|
||||
* The URL that started the installations
|
||||
* @param aInstall
|
||||
* An AddonInstall
|
||||
*/
|
||||
constructor(aBrowser, aUrl, aInstall) {
|
||||
this.browser = aBrowser;
|
||||
this.url = aUrl;
|
||||
this.install = aInstall;
|
||||
this.isDownloading = true;
|
||||
|
||||
installNotifyObservers("addon-install-started", aBrowser, aUrl, aInstall);
|
||||
|
||||
this.install.addListener(this);
|
||||
|
||||
// Start downloading if it hasn't already begun
|
||||
const READY_STATES = [
|
||||
AddonManager.STATE_AVAILABLE,
|
||||
AddonManager.STATE_DOWNLOAD_FAILED,
|
||||
AddonManager.STATE_INSTALL_FAILED,
|
||||
AddonManager.STATE_CANCELLED,
|
||||
];
|
||||
if (READY_STATES.includes(this.install.state)) {
|
||||
this.install.install();
|
||||
}
|
||||
|
||||
this.checkDownloaded();
|
||||
}
|
||||
|
||||
get URI_XPINSTALL_DIALOG() {
|
||||
return "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the download is complete and if so prompts to install.
|
||||
*/
|
||||
checkDownloaded() {
|
||||
// Prevent re-entrancy caused by the confirmation dialog cancelling
|
||||
// unwanted installs.
|
||||
if (!this.isDownloading)
|
||||
return;
|
||||
|
||||
let failed = false;
|
||||
|
||||
switch (this.install.state) {
|
||||
case AddonManager.STATE_AVAILABLE:
|
||||
case AddonManager.STATE_DOWNLOADING:
|
||||
// Exit early if the add-on hasn't started downloading yet or is
|
||||
// still downloading
|
||||
return;
|
||||
case AddonManager.STATE_DOWNLOAD_FAILED:
|
||||
failed = true;
|
||||
break;
|
||||
case AddonManager.STATE_DOWNLOADED:
|
||||
// App disabled items are not compatible and so fail to install
|
||||
failed = this.install.addon.appDisabled
|
||||
break;
|
||||
case AddonManager.STATE_CANCELLED:
|
||||
// Just ignore cancelled downloads
|
||||
return;
|
||||
default:
|
||||
logger.warn(`Download of ${this.install.sourceURI.spec} in unexpected state ${this.install.state}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isDownloading = false;
|
||||
|
||||
if (failed) {
|
||||
// Stop listening and cancel any installs that are failed because of
|
||||
// compatibility reasons.
|
||||
if (this.install.state == AddonManager.STATE_DOWNLOADED) {
|
||||
this.install.removeListener(this);
|
||||
this.install.cancel();
|
||||
}
|
||||
installNotifyObservers("addon-install-failed", this.browser, this.url, this.install);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for a custom installation prompt that may be provided by the
|
||||
// applicaton
|
||||
if ("@mozilla.org/addons/web-install-prompt;1" in Cc) {
|
||||
try {
|
||||
let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"].
|
||||
getService(Ci.amIWebInstallPrompt);
|
||||
prompt.confirm(this.browser, this.url, [this.install]);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
|
||||
installNotifyObservers("addon-install-confirmation", this.browser, this.url, this.install);
|
||||
return;
|
||||
}
|
||||
|
||||
let args = {};
|
||||
args.url = this.url;
|
||||
args.installs = [this.install];
|
||||
args.wrappedJSObject = args;
|
||||
|
||||
try {
|
||||
Cc["@mozilla.org/base/telemetry;1"].
|
||||
getService(Ci.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI").
|
||||
add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL);
|
||||
let parentWindow = null;
|
||||
if (this.browser) {
|
||||
parentWindow = this.browser.ownerDocument.defaultView;
|
||||
PromptUtils.fireDialogEvent(parentWindow, "DOMWillOpenModalDialog", this.browser);
|
||||
}
|
||||
Services.ww.openWindow(parentWindow, this.URI_XPINSTALL_DIALOG,
|
||||
null, "chrome,modal,centerscreen", args);
|
||||
} catch (e) {
|
||||
logger.warn("Exception showing install confirmation dialog", e);
|
||||
this.install.removeListener(this);
|
||||
// Cancel the install, as currently there is no way to make it fail
|
||||
// from here.
|
||||
this.install.cancel();
|
||||
|
||||
installNotifyObservers("addon-install-cancelled", this.browser, this.url,
|
||||
this.install);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if install is now complete and if so notifies observers.
|
||||
*/
|
||||
checkInstalled() {
|
||||
switch (this.install.state) {
|
||||
case AddonManager.STATE_DOWNLOADED:
|
||||
case AddonManager.STATE_INSTALLING:
|
||||
// Exit early if the add-on hasn't started installing yet or is
|
||||
// still installing
|
||||
return;
|
||||
case AddonManager.STATE_INSTALL_FAILED:
|
||||
installNotifyObservers("addon-install-failed", this.browser, this.url, this.install);
|
||||
break;
|
||||
default:
|
||||
installNotifyObservers("addon-install-complete", this.browser, this.url, this.install);
|
||||
}
|
||||
}
|
||||
|
||||
// InstallListener methods:
|
||||
onDownloadCancelled(aInstall) {
|
||||
aInstall.removeListener(this);
|
||||
this.checkDownloaded();
|
||||
}
|
||||
|
||||
onDownloadFailed(aInstall) {
|
||||
aInstall.removeListener(this);
|
||||
this.checkDownloaded();
|
||||
}
|
||||
|
||||
onDownloadEnded(aInstall) {
|
||||
this.checkDownloaded();
|
||||
return false;
|
||||
}
|
||||
|
||||
onInstallCancelled(aInstall) {
|
||||
aInstall.removeListener(this);
|
||||
this.checkInstalled();
|
||||
}
|
||||
|
||||
onInstallFailed(aInstall) {
|
||||
aInstall.removeListener(this);
|
||||
this.checkInstalled();
|
||||
}
|
||||
|
||||
onInstallEnded(aInstall) {
|
||||
aInstall.removeListener(this);
|
||||
|
||||
// If installing a theme that is disabled and can be enabled then enable it
|
||||
if (aInstall.addon.type == "theme" &&
|
||||
aInstall.addon.userDisabled == true &&
|
||||
aInstall.addon.appDisabled == false) {
|
||||
aInstall.addon.userDisabled = false;
|
||||
}
|
||||
|
||||
this.checkInstalled();
|
||||
}
|
||||
}
|
||||
|
||||
const weblistener = {
|
||||
onWebInstallDisabled(aBrowser, aUri, aInstall) {
|
||||
installNotifyObservers("addon-install-disabled", aBrowser, aUri, aInstall);
|
||||
},
|
||||
|
||||
onWebInstallOriginBlocked(aBrowser, aUri, aInstall) {
|
||||
installNotifyObservers("addon-install-origin-blocked", aBrowser, aUri, aInstall);
|
||||
return false;
|
||||
},
|
||||
|
||||
onWebInstallBlocked(aBrowser, aUri, aInstall) {
|
||||
installNotifyObservers("addon-install-blocked", aBrowser, aUri, aInstall,
|
||||
function() { new Installer(this.browser, this.originatingURI, aInstall); });
|
||||
return false;
|
||||
},
|
||||
|
||||
onWebInstallRequested(aBrowser, aUri, aInstall) {
|
||||
new Installer(aBrowser, aUri, aInstall);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* This represents an author of an add-on (e.g. creator or developer)
|
||||
*
|
||||
|
@ -2023,70 +2240,6 @@ var AddonManagerInternal = {
|
|||
return false;
|
||||
},
|
||||
|
||||
installNotifyObservers(aTopic, aBrowser, aUri, aInstall, aInstallFn) {
|
||||
let info = {
|
||||
wrappedJSObject: {
|
||||
browser: aBrowser,
|
||||
originatingURI: aUri,
|
||||
installs: [aInstall],
|
||||
install: aInstallFn,
|
||||
},
|
||||
};
|
||||
Services.obs.notifyObservers(info, aTopic, null);
|
||||
},
|
||||
|
||||
startInstall(browser, url, install) {
|
||||
this.installNotifyObservers("addon-install-started", browser, url, install);
|
||||
|
||||
let self = this;
|
||||
let listener = {
|
||||
onDownloadCancelled() {
|
||||
install.removeListener(listener);
|
||||
},
|
||||
|
||||
onDownloadFailed() {
|
||||
install.removeListener(listener);
|
||||
self.installNotifyObservers("addon-install-failed", browser, url, install);
|
||||
},
|
||||
|
||||
onDownloadEnded() {
|
||||
if (install.addon.appDisabled) {
|
||||
// App disabled items are not compatible and so fail to install
|
||||
install.removeListener(listener);
|
||||
install.cancel();
|
||||
self.installNotifyObservers("addon-install-failed", browser, url, install);
|
||||
}
|
||||
},
|
||||
|
||||
onInstallCancelled() {
|
||||
install.removeListener(listener);
|
||||
},
|
||||
|
||||
onInstallFailed() {
|
||||
install.removeListener(listener);
|
||||
self.installNotifyObservers("addon-install-failed", browser, url, install);
|
||||
},
|
||||
|
||||
onInstallEnded() {
|
||||
install.removeListener(listener);
|
||||
|
||||
// If installing a theme that is disabled and can be enabled
|
||||
// then enable it
|
||||
if (install.addon.type == "theme" &&
|
||||
install.addon.userDisabled == true &&
|
||||
install.addon.appDisabled == false) {
|
||||
install.addon.userDisabled = false;
|
||||
}
|
||||
self.installNotifyObservers("addon-install-complete", browser, url, install);
|
||||
},
|
||||
};
|
||||
|
||||
install.addListener(listener);
|
||||
|
||||
// Start downloading if it hasn't already begun
|
||||
install.install();
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts installation of an AddonInstall notifying the registered
|
||||
* web install listener of blocked or started installs.
|
||||
|
@ -2135,14 +2288,14 @@ var AddonManagerInternal = {
|
|||
if (!this.isInstallEnabled(aMimetype)) {
|
||||
aInstall.cancel();
|
||||
|
||||
this.installNotifyObservers("addon-install-disabled", topBrowser,
|
||||
aInstallingPrincipal.URI, aInstall);
|
||||
weblistener.onWebInstallDisabled(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstall);
|
||||
return;
|
||||
} else if (!aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) {
|
||||
aInstall.cancel();
|
||||
|
||||
this.installNotifyObservers("addon-install-origin-blocked", topBrowser,
|
||||
aInstallingPrincipal.URI, aInstall);
|
||||
weblistener.onWebInstallOriginBlocked(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstall);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2151,17 +2304,12 @@ var AddonManagerInternal = {
|
|||
// install in that case.
|
||||
new BrowserListener(aBrowser, aInstallingPrincipal, aInstall);
|
||||
|
||||
AddonManagerInternal.setupPromptHandler(aBrowser, aInstallingPrincipal.URI, aInstall, true);
|
||||
|
||||
let startInstall = () => {
|
||||
AddonManagerInternal.startInstall(aBrowser, aInstallingPrincipal.URI, aInstall);
|
||||
};
|
||||
if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) {
|
||||
this.installNotifyObservers("addon-install-blocked", topBrowser,
|
||||
aInstallingPrincipal.URI, aInstall,
|
||||
startInstall);
|
||||
weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstall);
|
||||
} else {
|
||||
startInstall();
|
||||
weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstall);
|
||||
}
|
||||
} catch (e) {
|
||||
// In the event that the weblistener throws during instantiation or when
|
||||
|
@ -2188,8 +2336,7 @@ var AddonManagerInternal = {
|
|||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
AddonManagerInternal.setupPromptHandler(browser, uri, install, true);
|
||||
AddonManagerInternal.startInstall(browser, uri, install);
|
||||
weblistener.onWebInstallRequested(browser, uri, install);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2785,117 +2932,6 @@ var AddonManagerInternal = {
|
|||
return gHotfixID;
|
||||
},
|
||||
|
||||
setupPromptHandler(browser, url, install, requireConfirm) {
|
||||
install.promptHandler = info => new Promise((resolve, _reject) => {
|
||||
let reject = () => {
|
||||
this.installNotifyObservers("addon-install-cancelled",
|
||||
browser, url, install);
|
||||
_reject();
|
||||
};
|
||||
|
||||
// All installs end up in this callback when the add-on is available
|
||||
// for installation. There are numerous different things that can
|
||||
// happen from here though. For webextensions, if the application
|
||||
// implements webextension permission prompts, those always take
|
||||
// precedence.
|
||||
// If this add-on is not a webextension or if the application does not
|
||||
// implement permission prompts, no confirmation is displayed for
|
||||
// installs created with mozAddonManager (in which case requireConfirm
|
||||
// is false).
|
||||
// In the remaining cases, a confirmation prompt is displayed but the
|
||||
// application may override it either by implementing the
|
||||
// "@mozilla.org/addons/web-install-prompt;1" contract or by setting
|
||||
// the customConfirmationUI preference and responding to the
|
||||
// "addon-install-confirmation" notification. If the application
|
||||
// does not implement its own prompt, use the built-in xul dialog.
|
||||
if (info.addon.userPermissions && WEBEXT_PERMISSION_PROMPTS) {
|
||||
const observer = {
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "webextension-permission-response"
|
||||
&& subject.wrappedJSObject.info.addon == info.addon) {
|
||||
let answer = JSON.parse(data);
|
||||
Services.obs.removeObserver(observer, "webextension-permission-response");
|
||||
if (answer) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "webextension-permission-response", false);
|
||||
|
||||
let subject = {wrappedJSObject: {target: browser, info}};
|
||||
Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
|
||||
} else if (requireConfirm) {
|
||||
// The methods below all want to call the install() or cancel()
|
||||
// method on the provided AddonInstall object to either accept
|
||||
// or reject the confirmation. Fit that into our promise-based
|
||||
// control flow by wrapping the install object. However,
|
||||
// xpInstallConfirm.xul matches the install object it is passed
|
||||
// with the argument passed to an InstallListener, so give it
|
||||
// access to the underlying object through the .wrapped property.
|
||||
let proxy = new Proxy(install, {
|
||||
get(target, property) {
|
||||
if (property == "install") {
|
||||
return resolve;
|
||||
} else if (property == "cancel") {
|
||||
return reject;
|
||||
} else if (property == "wrapped") {
|
||||
return target;
|
||||
}
|
||||
let result = target[property];
|
||||
return (typeof result == "function") ? result.bind(target) : result;
|
||||
}
|
||||
});
|
||||
|
||||
// Check for a custom installation prompt that may be provided by the
|
||||
// applicaton
|
||||
if ("@mozilla.org/addons/web-install-prompt;1" in Cc) {
|
||||
try {
|
||||
let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"].
|
||||
getService(Ci.amIWebInstallPrompt);
|
||||
prompt.confirm(browser, url, [proxy]);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
|
||||
this.installNotifyObservers("addon-install-confirmation",
|
||||
browser, url, proxy);
|
||||
return;
|
||||
}
|
||||
|
||||
let args = {};
|
||||
args.url = url;
|
||||
args.installs = [proxy];
|
||||
args.wrappedJSObject = args;
|
||||
|
||||
try {
|
||||
Cc["@mozilla.org/base/telemetry;1"].
|
||||
getService(Ci.nsITelemetry).
|
||||
getHistogramById("SECURITY_UI").
|
||||
add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL);
|
||||
let parentWindow = null;
|
||||
if (browser) {
|
||||
parentWindow = browser.ownerDocument.defaultView;
|
||||
PromptUtils.fireDialogEvent(parentWindow, "DOMWillOpenModalDialog", browser);
|
||||
}
|
||||
Services.ww.openWindow(parentWindow, URI_XPINSTALL_DIALOG,
|
||||
null, "chrome,modal,centerscreen", args);
|
||||
} catch (e) {
|
||||
logger.warn("Exception showing install confirmation dialog", e);
|
||||
// Cancel the install, as currently there is no way to make it fail
|
||||
// from here.
|
||||
reject();
|
||||
}
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
webAPI: {
|
||||
// installs maps integer ids to AddonInstall instances.
|
||||
installs: new Map(),
|
||||
|
@ -2979,7 +3015,29 @@ var AddonManagerInternal = {
|
|||
|
||||
return AddonManagerInternal.getInstallForURL(options.url, "application/x-xpinstall",
|
||||
options.hash).then(install => {
|
||||
AddonManagerInternal.setupPromptHandler(target, null, install, false);
|
||||
if (Preferences.get(PREF_WEBEXT_PREF_PROMPTS, false)) {
|
||||
install.promptHandler = info => new Promise((resolve, reject) => {
|
||||
const observer = {
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "webextension-permission-response" &&
|
||||
subject.wrappedJSObject.info.addon == info.addon) {
|
||||
let answer = JSON.parse(data);
|
||||
Services.obs.removeObserver(this, "webextension-permission-response");
|
||||
if (answer) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "webextension-permission-response", false);
|
||||
|
||||
let subject = {wrappedJSObject: {target, info}};
|
||||
Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
|
||||
});
|
||||
}
|
||||
|
||||
let id = this.nextInstall++;
|
||||
let listener = this.makeListener(id, target.messageManager);
|
||||
|
|
|
@ -67,7 +67,7 @@ XPInstallConfirm.init = function() {
|
|||
}
|
||||
installItem.signed = install.certName ? "true" : "false";
|
||||
|
||||
installMap.set(install.wrapped, installItem);
|
||||
installMap.set(install, installItem);
|
||||
install.addListener(installListener);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,8 +108,6 @@ var Harness = {
|
|||
Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
|
||||
Services.obs.addObserver(this, "addon-install-started", false);
|
||||
Services.obs.addObserver(this, "addon-install-disabled", false);
|
||||
// XXX this breaks a bunch of stuff, see comment in onInstallCancelled
|
||||
// Services.obs.addObserver(this, "addon-install-cancelled", false);
|
||||
Services.obs.addObserver(this, "addon-install-origin-blocked", false);
|
||||
Services.obs.addObserver(this, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(this, "addon-install-failed", false);
|
||||
|
@ -125,7 +123,6 @@ var Harness = {
|
|||
Services.prefs.clearUserPref(PREF_INSTALL_REQUIRESECUREORIGIN);
|
||||
Services.obs.removeObserver(self, "addon-install-started");
|
||||
Services.obs.removeObserver(self, "addon-install-disabled");
|
||||
// Services.obs.removeObserver(self, "addon-install-cancelled");
|
||||
Services.obs.removeObserver(self, "addon-install-origin-blocked");
|
||||
Services.obs.removeObserver(self, "addon-install-blocked");
|
||||
Services.obs.removeObserver(self, "addon-install-failed");
|
||||
|
@ -370,23 +367,6 @@ var Harness = {
|
|||
this.checkTestEnded();
|
||||
},
|
||||
|
||||
onInstallCancelled(install) {
|
||||
// This is ugly. We have a bunch of tests that cancel installs
|
||||
// but don't expect this event to be raised (they also don't
|
||||
// expecte addon-install-cancelled to be raised but even though
|
||||
// we have code to handle that, it is never attached, see setup() above)
|
||||
// For at least one test (browser_whitelist3.js), we used to generate
|
||||
// onDownloadCancelled when the user cancelled the installation at the
|
||||
// confirmation prompt. We're now generating onInstallCancelled instead
|
||||
// of onDownloadCancelled but making this code unconditional breaks a
|
||||
// bunch of other tests. Ugh.
|
||||
let idx = this.runningInstalls.indexOf(install);
|
||||
if (idx != -1) {
|
||||
this.runningInstalls.splice(this.runningInstalls.indexOf(install), 1);
|
||||
this.checkTestEnded();
|
||||
}
|
||||
},
|
||||
|
||||
checkTestEnded() {
|
||||
if (--this.pendingCount == 0 && !this.waitingForEvent)
|
||||
this.endTest();
|
||||
|
|
Загрузка…
Ссылка в новой задаче