diff options
Diffstat (limited to 'application/basilisk/modules/PermissionUI.jsm')
-rw-r--r-- | application/basilisk/modules/PermissionUI.jsm | 601 |
1 files changed, 0 insertions, 601 deletions
diff --git a/application/basilisk/modules/PermissionUI.jsm b/application/basilisk/modules/PermissionUI.jsm deleted file mode 100644 index b4856a007..000000000 --- a/application/basilisk/modules/PermissionUI.jsm +++ /dev/null @@ -1,601 +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/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ - "PermissionUI", -]; - -/** - * PermissionUI is responsible for exposing both a prototype - * PermissionPrompt that can be used by arbitrary browser - * components and add-ons, but also hosts the implementations of - * built-in permission prompts. - * - * If you're developing a feature that requires web content to ask - * for special permissions from the user, this module is for you. - * - * Suppose a system add-on wants to add a new prompt for a new request - * for getting more low-level access to the user's sound card, and the - * permission request is coming up from content by way of the - * nsContentPermissionHelper. The system add-on could then do the following: - * - * Cu.import("resource://gre/modules/Integration.jsm"); - * Cu.import("resource:///modules/PermissionUI.jsm"); - * - * const SoundCardIntegration = (base) => ({ - * __proto__: base, - * createPermissionPrompt(type, request) { - * if (type != "sound-api") { - * return super.createPermissionPrompt(...arguments); - * } - * - * return { - * __proto__: PermissionUI.PermissionPromptForRequestPrototype, - * get permissionKey() { - * return "sound-permission"; - * } - * // etc - see the documentation for PermissionPrompt for - * // a better idea of what things one can and should override. - * } - * }, - * }); - * - * // Add-on startup: - * Integration.contentPermission.register(SoundCardIntegration); - * // ... - * // Add-on shutdown: - * Integration.contentPermission.unregister(SoundCardIntegration); - * - * Note that PermissionPromptForRequestPrototype must be used as the - * prototype, since the prompt is wrapping an nsIContentPermissionRequest, - * and going through nsIContentPermissionPrompt. - * - * It is, however, possible to take advantage of PermissionPrompt without - * having to go through nsIContentPermissionPrompt or with a - * nsIContentPermissionRequest. The PermissionPromptPrototype can be - * imported, subclassed, and have prompt() called directly, without - * the caller having called into createPermissionPrompt. - */ -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Services", - "resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "SitePermissions", - "resource:///modules/SitePermissions.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() { - return Services.strings - .createBundle("chrome://branding/locale/brand.properties"); -}); - -XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() { - return Services.strings - .createBundle("chrome://browser/locale/browser.properties"); -}); - -this.PermissionUI = {}; - -/** - * PermissionPromptPrototype should be subclassed by callers that - * want to display prompts to the user. See each method and property - * below for guidance on what to override. - * - * Note that if you're creating a prompt for an - * nsIContentPermissionRequest, you'll want to subclass - * PermissionPromptForRequestPrototype instead. - */ -this.PermissionPromptPrototype = { - /** - * Returns the associated <xul:browser> for the request. This should - * work for the e10s and non-e10s case. - * - * Subclasses must override this. - * - * @return {<xul:browser>} - */ - get browser() { - throw new Error("Not implemented."); - }, - - /** - * Returns the nsIPrincipal associated with the request. - * - * Subclasses must override this. - * - * @return {nsIPrincipal} - */ - get principal() { - throw new Error("Not implemented."); - }, - - /** - * If the nsIPermissionManager is being queried and written - * to for this permission request, set this to the key to be - * used. If this is undefined, user permissions will not be - * read from or written to. - * - * Note that if a permission is set, in any follow-up - * prompting within the expiry window of that permission, - * the prompt will be skipped and the allow or deny choice - * will be selected automatically. - */ - get permissionKey() { - return undefined; - }, - - /** - * These are the options that will be passed to the - * PopupNotification when it is shown. See the documentation - * for PopupNotification for more details. - * - * Note that prompt() will automatically set displayURI to - * be the URI of the requesting pricipal, unless the displayURI is exactly - * set to false. - */ - get popupOptions() { - return {}; - }, - - /** - * PopupNotification requires a unique ID to open the notification. - * You must return a unique ID string here, for which PopupNotification - * will then create a <xul:popupnotification> node with the ID - * "<notificationID>-notification". - * - * If there's a custom <xul:popupnotification> you're hoping to show, - * then you need to make sure its ID has the "-notification" suffix, - * and then return the prefix here. - * - * See PopupNotification.jsm for more details. - * - * @return {string} - * The unique ID that will be used to as the - * "<unique ID>-notification" ID for the <xul:popupnotification> - * to use or create. - */ - get notificationID() { - throw new Error("Not implemented."); - }, - - /** - * The ID of the element to anchor the PopupNotification to. - * - * @return {string} - */ - get anchorID() { - return "default-notification-icon"; - }, - - /** - * The message to show the user in the PopupNotification. This - * is usually a string describing the permission that is being - * requested. - * - * Subclasses must override this. - * - * @return {string} - */ - get message() { - throw new Error("Not implemented."); - }, - - /** - * This will be called if the request is to be cancelled. - * - * Subclasses only need to override this if they provide a - * permissionKey. - */ - cancel() { - throw new Error("Not implemented.") - }, - - /** - * This will be called if the request is to be allowed. - * - * Subclasses only need to override this if they provide a - * permissionKey. - */ - allow() { - throw new Error("Not implemented."); - }, - - /** - * The actions that will be displayed in the PopupNotification - * via a dropdown menu. The first item in this array will be - * the default selection. Each action is an Object with the - * following properties: - * - * label (string): - * The label that will be displayed for this choice. - * accessKey (string): - * The access key character that will be used for this choice. - * action (SitePermissions state) - * The action that will be associated with this choice. - * This should be either SitePermissions.ALLOW or SitePermissions.BLOCK. - * - * callback (function, optional) - * A callback function that will fire if the user makes this choice, with - * a single parameter, state. State is an Object that contains the property - * checkboxChecked, which identifies whether the checkbox to remember this - * decision was checked. - */ - get promptActions() { - return []; - }, - - /** - * If the prompt will be shown to the user, this callback will - * be called just before. Subclasses may want to override this - * in order to, for example, bump a counter Telemetry probe for - * how often a particular permission request is seen. - */ - onBeforeShow() {}, - - /** - * Will determine if a prompt should be shown to the user, and if so, - * will show it. - * - * If a permissionKey is defined prompt() might automatically - * allow or cancel itself based on the user's current - * permission settings without displaying the prompt. - * - * If the <xul:browser> that the request is associated with - * does not belong to a browser window with the PopupNotifications - * global set, the prompt request is ignored. - */ - prompt() { - let chromeWin = this.browser.ownerGlobal; - if (!chromeWin.PopupNotifications) { - return; - } - - // We ignore requests from non-nsIStandardURLs - let requestingURI = this.principal.URI; - if (!(requestingURI instanceof Ci.nsIStandardURL)) { - return; - } - - if (this.permissionKey) { - // If we're reading and setting permissions, then we need - // to check to see if we already have a permission setting - // for this particular principal. - let {state} = SitePermissions.get(requestingURI, - this.permissionKey, - this.browser); - - if (state == SitePermissions.BLOCK) { - this.cancel(); - return; - } - - if (state == SitePermissions.ALLOW) { - this.allow(); - return; - } - - // Tell the browser to refresh the identity block display in case there - // are expired permission states. - this.browser.dispatchEvent(new this.browser.ownerGlobal - .CustomEvent("PermissionStateChange")); - } - - // Transform the PermissionPrompt actions into PopupNotification actions. - let popupNotificationActions = []; - for (let promptAction of this.promptActions) { - let action = { - label: promptAction.label, - accessKey: promptAction.accessKey, - callback: state => { - if (promptAction.callback) { - promptAction.callback(); - } - - if (this.permissionKey) { - - // Permanently store permission. - if (state && state.checkboxChecked) { - let scope = SitePermissions.SCOPE_PERSISTENT; - // Only remember permission for session if in PB mode. - if (PrivateBrowsingUtils.isBrowserPrivate(this.browser)) { - scope = SitePermissions.SCOPE_SESSION; - } - SitePermissions.set(this.principal.URI, - this.permissionKey, - promptAction.action, - scope); - } else if (promptAction.action == SitePermissions.BLOCK) { - // Temporarily store BLOCK permissions only. - // SitePermissions does not consider subframes when storing temporary - // permissions on a tab, thus storing ALLOW could be exploited. - SitePermissions.set(this.principal.URI, - this.permissionKey, - promptAction.action, - SitePermissions.SCOPE_TEMPORARY, - this.browser); - } - - // Grant permission if action is ALLOW. - if (promptAction.action == SitePermissions.ALLOW) { - this.allow(); - } else { - this.cancel(); - } - } - }, - }; - if (promptAction.dismiss) { - action.dismiss = promptAction.dismiss - } - - popupNotificationActions.push(action); - } - - let mainAction = popupNotificationActions.length ? - popupNotificationActions[0] : null; - let secondaryActions = popupNotificationActions.splice(1); - - let options = this.popupOptions; - - if (!options.hasOwnProperty("displayURI") || options.displayURI) { - options.displayURI = this.principal.URI; - } - // Permission prompts are always persistent; the close button is controlled by a pref. - options.persistent = true; - options.hideClose = !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"); - // When the docshell of the browser is aboout to be swapped to another one, - // the "swapping" event is called. Returning true causes the notification - // to be moved to the new browser. - options.eventCallback = topic => topic == "swapping"; - - this.onBeforeShow(); - chromeWin.PopupNotifications.show(this.browser, - this.notificationID, - this.message, - this.anchorID, - mainAction, - secondaryActions, - options); - }, -}; - -PermissionUI.PermissionPromptPrototype = PermissionPromptPrototype; - -/** - * A subclass of PermissionPromptPrototype that assumes - * that this.request is an nsIContentPermissionRequest - * and fills in some of the required properties on the - * PermissionPrompt. For callers that are wrapping an - * nsIContentPermissionRequest, this should be subclassed - * rather than PermissionPromptPrototype. - */ -this.PermissionPromptForRequestPrototype = { - __proto__: PermissionPromptPrototype, - - get browser() { - // In the e10s-case, the <xul:browser> will be at request.element. - // In the single-process case, we have to use some XPCOM incantations - // to resolve to the <xul:browser>. - if (this.request.element) { - return this.request.element; - } - return this.request - .window - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler; - }, - - get principal() { - return this.request.principal; - }, - - cancel() { - this.request.cancel(); - }, - - allow() { - this.request.allow(); - }, -}; - -PermissionUI.PermissionPromptForRequestPrototype = - PermissionPromptForRequestPrototype; - -/** - * Creates a PermissionPrompt for a nsIContentPermissionRequest for - * the GeoLocation API. - * - * @param request (nsIContentPermissionRequest) - * The request for a permission from content. - */ -function GeolocationPermissionPrompt(request) { - this.request = request; -} - -GeolocationPermissionPrompt.prototype = { - __proto__: PermissionPromptForRequestPrototype, - - get permissionKey() { - return "geo"; - }, - - get popupOptions() { - let pref = "browser.geolocation.warning.infoURL"; - let options = { - learnMoreURL: Services.urlFormatter.formatURLPref(pref), - displayURI: false - }; - - if (this.principal.URI.schemeIs("file")) { - options.checkbox = { show: false }; - } else { - // Don't offer "always remember" action in PB mode - options.checkbox = { - show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal) - }; - } - - if (options.checkbox.show) { - options.checkbox.label = gBrowserBundle.GetStringFromName("geolocation.remember"); - } - - return options; - }, - - get notificationID() { - return "geolocation"; - }, - - get anchorID() { - return "geo-notification-icon"; - }, - - get message() { - let message; - if (this.principal.URI.schemeIs("file")) { - message = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3"); - } else { - let hostPort = "<>"; - try { - hostPort = this.principal.URI.hostPort; - } catch (ex) { } - message = gBrowserBundle.formatStringFromName("geolocation.shareWithSite3", - [hostPort], 1); - } - return message; - }, - - get promptActions() { - // We collect Telemetry data on Geolocation prompts and how users - // respond to them. The probe keys are a bit verbose, so let's alias them. - const SHARE_LOCATION = - Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_SHARE_LOCATION; - const ALWAYS_SHARE = - Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_ALWAYS_SHARE; - const NEVER_SHARE = - Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_NEVER_SHARE; - - let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI"); - - return [{ - label: gBrowserBundle.GetStringFromName("geolocation.allowLocation"), - accessKey: - gBrowserBundle.GetStringFromName("geolocation.allowLocation.accesskey"), - action: SitePermissions.ALLOW, - callback(state) { - if (state && state.checkboxChecked) { - secHistogram.add(ALWAYS_SHARE); - } else { - secHistogram.add(SHARE_LOCATION); - } - }, - }, { - label: gBrowserBundle.GetStringFromName("geolocation.dontAllowLocation"), - accessKey: - gBrowserBundle.GetStringFromName("geolocation.dontAllowLocation.accesskey"), - action: SitePermissions.BLOCK, - callback(state) { - if (state && state.checkboxChecked) { - secHistogram.add(NEVER_SHARE); - } - }, - }]; - }, - - onBeforeShow() { - let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI"); - const SHOW_REQUEST = Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST; - secHistogram.add(SHOW_REQUEST); - }, -}; - -PermissionUI.GeolocationPermissionPrompt = GeolocationPermissionPrompt; - -/** - * Creates a PermissionPrompt for a nsIContentPermissionRequest for - * the Desktop Notification API. - * - * @param request (nsIContentPermissionRequest) - * The request for a permission from content. - * @return {PermissionPrompt} (see documentation in header) - */ -function DesktopNotificationPermissionPrompt(request) { - this.request = request; -} - -DesktopNotificationPermissionPrompt.prototype = { - __proto__: PermissionPromptForRequestPrototype, - - get permissionKey() { - return "desktop-notification"; - }, - - get popupOptions() { - let learnMoreURL = - Services.urlFormatter.formatURLPref("app.support.baseURL") + "push"; - - let checkbox = { - show: true, - checked: true, - label: gBrowserBundle.GetStringFromName("webNotifications.remember") - }; - - // In PB mode, the "always remember" checkbox should only remember for the - // session. - if (PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)) { - checkbox.label = - gBrowserBundle.GetStringFromName("webNotifications.rememberForSession"); - } - - return { - learnMoreURL, - checkbox, - displayURI: false - }; - }, - - get notificationID() { - return "web-notifications"; - }, - - get anchorID() { - return "web-notifications-notification-icon"; - }, - - get message() { - let hostPort = "<>"; - try { - hostPort = this.principal.URI.hostPort; - } catch (ex) { } - return gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2", - [hostPort], 1); - }, - - get promptActions() { - return [ - { - label: gBrowserBundle.GetStringFromName("webNotifications.allow"), - accessKey: - gBrowserBundle.GetStringFromName("webNotifications.allow.accesskey"), - action: SitePermissions.ALLOW, - }, - { - label: gBrowserBundle.GetStringFromName("webNotifications.dontAllow"), - accessKey: - gBrowserBundle.GetStringFromName("webNotifications.dontAllow.accesskey"), - action: SitePermissions.BLOCK, - }, - ]; - }, -}; - -PermissionUI.DesktopNotificationPermissionPrompt = - DesktopNotificationPermissionPrompt; |