1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 var EXPORTED_SYMBOLS = ["PermissionUI"];
10 * PermissionUI is responsible for exposing both a prototype
11 * PermissionPrompt that can be used by arbitrary browser
12 * components and add-ons, but also hosts the implementations of
13 * built-in permission prompts.
15 * If you're developing a feature that requires web content to ask
16 * for special permissions from the user, this module is for you.
18 * Suppose a system add-on wants to add a new prompt for a new request
19 * for getting more low-level access to the user's sound card, and the
20 * permission request is coming up from content by way of the
21 * nsContentPermissionHelper. The system add-on could then do the following:
23 * Cu.import("resource://gre/modules/Integration.jsm");
24 * Cu.import("resource:///modules/PermissionUI.jsm");
26 * const SoundCardIntegration = (base) => ({
28 * createPermissionPrompt(type, request) {
29 * if (type != "sound-api") {
30 * return super.createPermissionPrompt(...arguments);
34 * __proto__: PermissionUI.PermissionPromptForRequestPrototype,
35 * get permissionKey() {
36 * return "sound-permission";
38 * // etc - see the documentation for PermissionPrompt for
39 * // a better idea of what things one can and should override.
45 * Integration.contentPermission.register(SoundCardIntegration);
48 * Integration.contentPermission.unregister(SoundCardIntegration);
50 * Note that PermissionPromptForRequestPrototype must be used as the
51 * prototype, since the prompt is wrapping an nsIContentPermissionRequest,
52 * and going through nsIContentPermissionPrompt.
54 * It is, however, possible to take advantage of PermissionPrompt without
55 * having to go through nsIContentPermissionPrompt or with a
56 * nsIContentPermissionRequest. The PermissionPromptPrototype can be
57 * imported, subclassed, and have prompt() called directly, without
58 * the caller having called into createPermissionPrompt.
60 const { XPCOMUtils } = ChromeUtils.import(
61 "resource://gre/modules/XPCOMUtils.jsm"
64 ChromeUtils.defineModuleGetter(
67 "resource://gre/modules/Services.jsm"
69 ChromeUtils.defineModuleGetter(
72 "resource:///modules/SitePermissions.jsm"
74 ChromeUtils.defineModuleGetter(
76 "PrivateBrowsingUtils",
77 "resource://gre/modules/PrivateBrowsingUtils.jsm"
80 XPCOMUtils.defineLazyServiceGetter(
83 "@mozilla.org/network/idn-service;1",
87 XPCOMUtils.defineLazyServiceGetter(
89 "ContentPrefService2",
90 "@mozilla.org/content-pref/service;1",
91 "nsIContentPrefService2"
94 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
95 return Services.strings.createBundle(
96 "chrome://browser/locale/browser.properties"
100 var PermissionUI = {};
103 * PermissionPromptPrototype should be subclassed by callers that
104 * want to display prompts to the user. See each method and property
105 * below for guidance on what to override.
107 * Note that if you're creating a prompt for an
108 * nsIContentPermissionRequest, you'll want to subclass
109 * PermissionPromptForRequestPrototype instead.
111 var PermissionPromptPrototype = {
113 * Returns the associated <xul:browser> for the request. This should
114 * work for the e10s and non-e10s case.
116 * Subclasses must override this.
118 * @return {<xul:browser>}
121 throw new Error("Not implemented.");
125 * Returns the nsIPrincipal associated with the request.
127 * Subclasses must override this.
129 * @return {nsIPrincipal}
132 throw new Error("Not implemented.");
136 * Indicates the type of the permission request from content. This type might
137 * be different from the permission key used in the permissions database.
144 * If the nsIPermissionManager is being queried and written
145 * to for this permission request, set this to the key to be
146 * used. If this is undefined, no integration with temporary
147 * permissions infrastructure will be provided.
149 * Note that if a permission is set, in any follow-up
150 * prompting within the expiry window of that permission,
151 * the prompt will be skipped and the allow or deny choice
152 * will be selected automatically.
154 get permissionKey() {
159 * If true, user permissions will be read from and written to.
160 * When this is false, we still provide integration with
161 * infrastructure such as temporary permissions. permissionKey should
162 * still return a valid name in those cases for that integration to work.
164 get usePermissionManager() {
169 * These are the options that will be passed to the PopupNotification when it
170 * is shown. See the documentation of `PopupNotifications_show` in
171 * PopupNotifications.jsm for details.
173 * Note that prompt() will automatically set displayURI to
174 * be the URI of the requesting pricipal, unless the displayURI is exactly
182 * If true, automatically denied permission requests will
183 * spawn a "post-prompt" that allows the user to correct the
184 * automatic denial by giving permanent permission access to
187 * Note that if this function returns true, the permissionKey
188 * and postPromptActions attributes must be implemented.
190 get postPromptEnabled() {
195 * If true, the prompt will be cancelled automatically unless
196 * request.isHandlingUserInput is true.
198 get requiresUserInput() {
203 * PopupNotification requires a unique ID to open the notification.
204 * You must return a unique ID string here, for which PopupNotification
205 * will then create a <xul:popupnotification> node with the ID
206 * "<notificationID>-notification".
208 * If there's a custom <xul:popupnotification> you're hoping to show,
209 * then you need to make sure its ID has the "-notification" suffix,
210 * and then return the prefix here.
212 * See PopupNotifications.jsm for more details.
215 * The unique ID that will be used to as the
216 * "<unique ID>-notification" ID for the <xul:popupnotification>
219 get notificationID() {
220 throw new Error("Not implemented.");
224 * The ID of the element to anchor the PopupNotification to.
229 return "default-notification-icon";
233 * The message to show to the user in the PopupNotification, see
234 * `PopupNotifications_show` in PopupNotifications.jsm.
236 * Subclasses must override this.
241 throw new Error("Not implemented.");
245 * Provides the preferred name to use in the permission popups,
246 * based on the principal URI (the URI.hostPort for any URI scheme
247 * besides the moz-extension one which should default to the
250 getPrincipalName(principal = this.principal) {
251 if (principal.addonPolicy) {
252 return principal.addonPolicy.name;
255 return principal.hostPort;
259 * This will be called if the request is to be cancelled.
261 * Subclasses only need to override this if they provide a
265 throw new Error("Not implemented.");
269 * This will be called if the request is to be allowed.
271 * Subclasses only need to override this if they provide a
275 throw new Error("Not implemented.");
279 * The actions that will be displayed in the PopupNotification
280 * via a dropdown menu. The first item in this array will be
281 * the default selection. Each action is an Object with the
282 * following properties:
285 * The label that will be displayed for this choice.
286 * accessKey (string):
287 * The access key character that will be used for this choice.
288 * action (SitePermissions state)
289 * The action that will be associated with this choice.
290 * This should be either SitePermissions.ALLOW or SitePermissions.BLOCK.
291 * scope (SitePermissions scope)
292 * The scope of the associated action (e.g. SitePermissions.SCOPE_PERSISTENT)
294 * callback (function, optional)
295 * A callback function that will fire if the user makes this choice, with
296 * a single parameter, state. State is an Object that contains the property
297 * checkboxChecked, which identifies whether the checkbox to remember this
298 * decision was checked.
300 get promptActions() {
305 * The actions that will be displayed in the PopupNotification
306 * for post-prompt notifications via a dropdown menu.
307 * The first item in this array will be the default selection.
308 * Each action is an Object with the following properties:
311 * The label that will be displayed for this choice.
312 * accessKey (string):
313 * The access key character that will be used for this choice.
314 * action (SitePermissions state)
315 * The action that will be associated with this choice.
316 * This should be either SitePermissions.ALLOW or SitePermissions.BLOCK.
317 * Note that the scope of this action will always be persistent.
319 * callback (function, optional)
320 * A callback function that will fire if the user makes this choice.
322 get postPromptActions() {
327 * If the prompt will be shown to the user, this callback will
328 * be called just before. Subclasses may want to override this
329 * in order to, for example, bump a counter Telemetry probe for
330 * how often a particular permission request is seen.
332 * If this returns false, it cancels the process of showing the prompt. In
333 * that case, it is the responsibility of the onBeforeShow() implementation
334 * to ensure that allow() or cancel() are called on the object appropriately.
341 * If the prompt was shown to the user, this callback will be called just
342 * after it's been shown.
347 * If the prompt was shown to the user, this callback will be called just
348 * after it's been hidden.
353 * Will determine if a prompt should be shown to the user, and if so,
356 * If a permissionKey is defined prompt() might automatically
357 * allow or cancel itself based on the user's current
358 * permission settings without displaying the prompt.
360 * If the permission is not already set and the <xul:browser> that the request
361 * is associated with does not belong to a browser window with the
362 * PopupNotifications global set, the prompt request is ignored.
365 // We ignore requests from non-nsIStandardURLs
366 let requestingURI = this.principal.URI;
367 if (!(requestingURI instanceof Ci.nsIStandardURL)) {
371 if (this.usePermissionManager && this.permissionKey) {
372 // If we're reading and setting permissions, then we need
373 // to check to see if we already have a permission setting
374 // for this particular principal.
375 let { state } = SitePermissions.getForPrincipal(
381 if (state == SitePermissions.BLOCK) {
382 // If this block was done based on a global user setting, we want to show
383 // a post prompt to give the user some more granular control without
384 // annoying them too much.
386 this.postPromptEnabled &&
387 SitePermissions.getDefault(this.permissionKey) ==
388 SitePermissions.BLOCK
397 state == SitePermissions.ALLOW &&
398 !this.request.maybeUnsafePermissionDelegate
403 } else if (this.permissionKey) {
404 // If we're reading a permission which already has a temporary value,
405 // see if we can use the temporary value.
406 let { state } = SitePermissions.getForPrincipal(
412 if (state == SitePermissions.BLOCK) {
418 if (this.requiresUserInput && !this.request.isHandlingUserInput) {
419 if (this.postPromptEnabled) {
426 let chromeWin = this.browser.ownerGlobal;
427 if (!chromeWin.PopupNotifications) {
432 // Transform the PermissionPrompt actions into PopupNotification actions.
433 let popupNotificationActions = [];
434 for (let promptAction of this.promptActions) {
436 label: promptAction.label,
437 accessKey: promptAction.accessKey,
439 if (promptAction.callback) {
440 promptAction.callback();
443 if (this.usePermissionManager && this.permissionKey) {
445 (state && state.checkboxChecked && state.source != "esc-press") ||
446 promptAction.scope == SitePermissions.SCOPE_PERSISTENT
448 // Permanently store permission.
449 let scope = SitePermissions.SCOPE_PERSISTENT;
450 // Only remember permission for session if in PB mode.
451 if (PrivateBrowsingUtils.isBrowserPrivate(this.browser)) {
452 scope = SitePermissions.SCOPE_SESSION;
454 SitePermissions.setForPrincipal(
460 } else if (promptAction.action == SitePermissions.BLOCK) {
461 // Temporarily store BLOCK permissions only
462 // SitePermissions does not consider subframes when storing temporary
463 // permissions on a tab, thus storing ALLOW could be exploited.
464 SitePermissions.setForPrincipal(
468 SitePermissions.SCOPE_TEMPORARY,
473 // Grant permission if action is ALLOW.
474 if (promptAction.action == SitePermissions.ALLOW) {
479 } else if (this.permissionKey) {
480 // TODO: Add support for permitTemporaryAllow
481 if (promptAction.action == SitePermissions.BLOCK) {
482 // Temporarily store BLOCK permissions.
483 // We don't consider subframes when storing temporary
484 // permissions on a tab, thus storing ALLOW could be exploited.
485 SitePermissions.setForPrincipal(
489 SitePermissions.SCOPE_TEMPORARY,
496 if (promptAction.dismiss) {
497 action.dismiss = promptAction.dismiss;
500 popupNotificationActions.push(action);
503 this._showNotification(popupNotificationActions);
507 let browser = this.browser;
508 let principal = this.principal;
509 let chromeWin = browser.ownerGlobal;
510 if (!chromeWin.PopupNotifications) {
514 if (!this.permissionKey) {
515 throw new Error("permissionKey is required to show a post-prompt");
518 if (!this.postPromptActions) {
519 throw new Error("postPromptActions are required to show a post-prompt");
522 // Transform the PermissionPrompt actions into PopupNotification actions.
523 let popupNotificationActions = [];
524 for (let promptAction of this.postPromptActions) {
526 label: promptAction.label,
527 accessKey: promptAction.accessKey,
529 if (promptAction.callback) {
530 promptAction.callback();
533 // Post-prompt permissions are stored permanently by default.
534 // Since we can not reply to the original permission request anymore,
535 // the page will need to listen for permission changes which are triggered
536 // by permanent entries in the permission manager.
537 let scope = SitePermissions.SCOPE_PERSISTENT;
538 // Only remember permission for session if in PB mode.
539 if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
540 scope = SitePermissions.SCOPE_SESSION;
542 SitePermissions.setForPrincipal(
550 popupNotificationActions.push(action);
553 // Post-prompt animation
554 if (!chromeWin.gReduceMotion) {
555 let anchor = chromeWin.document.getElementById(this.anchorID);
556 // Only show the animation on the first request, not after e.g. tab switching.
557 anchor.addEventListener(
559 () => anchor.removeAttribute("animate"),
562 anchor.setAttribute("animate", "true");
565 this._showNotification(popupNotificationActions, true);
568 _showNotification(actions, postPrompt = false) {
569 let chromeWin = this.browser.ownerGlobal;
570 let mainAction = actions.length ? actions[0] : null;
571 let secondaryActions = actions.splice(1);
573 let options = this.popupOptions;
575 if (!options.hasOwnProperty("displayURI") || options.displayURI) {
576 options.displayURI = this.principal.URI;
580 // Permission prompts are always persistent; the close button is controlled by a pref.
581 options.persistent = true;
582 options.hideClose = true;
585 options.eventCallback = (topic, nextRemovalReason, isCancel) => {
586 // When the docshell of the browser is aboout to be swapped to another one,
587 // the "swapping" event is called. Returning true causes the notification
588 // to be moved to the new browser.
589 if (topic == "swapping") {
592 // The prompt has been shown, notify the PermissionUI.
593 // onShown() is currently not called for post-prompts,
594 // because there is no prompt that would make use of this.
595 // You can remove this restriction if you need it, but be
596 // mindful of other consumers.
597 if (topic == "shown" && !postPrompt) {
600 // The prompt has been removed, notify the PermissionUI.
601 // onAfterShow() is currently not called for post-prompts,
602 // because there is no prompt that would make use of this.
603 // You can remove this restriction if you need it, but be
604 // mindful of other consumers.
605 if (topic == "removed" && !postPrompt) {
614 // Post-prompts show up as dismissed.
615 options.dismissed = postPrompt;
617 // onBeforeShow() is currently not called for post-prompts,
618 // because there is no prompt that would make use of this.
619 // You can remove this restriction if you need it, but be
620 // mindful of other consumers.
621 if (postPrompt || this.onBeforeShow() !== false) {
622 chromeWin.PopupNotifications.show(
635 PermissionUI.PermissionPromptPrototype = PermissionPromptPrototype;
638 * A subclass of PermissionPromptPrototype that assumes
639 * that this.request is an nsIContentPermissionRequest
640 * and fills in some of the required properties on the
641 * PermissionPrompt. For callers that are wrapping an
642 * nsIContentPermissionRequest, this should be subclassed
643 * rather than PermissionPromptPrototype.
645 var PermissionPromptForRequestPrototype = {
646 __proto__: PermissionPromptPrototype,
649 // In the e10s-case, the <xul:browser> will be at request.element.
650 // In the single-process case, we have to use some XPCOM incantations
651 // to resolve to the <xul:browser>.
652 if (this.request.element) {
653 return this.request.element;
655 return this.request.window.docShell.chromeEventHandler;
659 let request = this.request.QueryInterface(Ci.nsIContentPermissionRequest);
660 return request.getDelegatePrincipal(this.type);
664 this.request.cancel();
668 this.request.allow(choices);
672 PermissionUI.PermissionPromptForRequestPrototype = PermissionPromptForRequestPrototype;
675 * Creates a PermissionPrompt for a nsIContentPermissionRequest for
676 * the GeoLocation API.
678 * @param request (nsIContentPermissionRequest)
679 * The request for a permission from content.
681 function GeolocationPermissionPrompt(request) {
682 this.request = request;
685 GeolocationPermissionPrompt.prototype = {
686 __proto__: PermissionPromptForRequestPrototype,
692 get permissionKey() {
697 let pref = "browser.geolocation.warning.infoURL";
699 learnMoreURL: Services.urlFormatter.formatURLPref(pref),
701 name: this.getPrincipalName(),
704 if (this.principal.schemeIs("file")) {
705 options.checkbox = { show: false };
707 // Don't offer "always remember" action in PB mode
709 show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal),
713 if (this.request.maybeUnsafePermissionDelegate) {
714 // Second name should be the third party origin
715 options.secondName = this.getPrincipalName(this.request.principal);
716 options.checkbox = { show: false };
719 if (options.checkbox.show) {
720 options.checkbox.label = gBrowserBundle.GetStringFromName(
721 "geolocation.remember"
728 get notificationID() {
729 return "geolocation";
733 return "geo-notification-icon";
737 if (this.principal.schemeIs("file")) {
738 return gBrowserBundle.GetStringFromName("geolocation.shareWithFile4");
741 if (this.request.maybeUnsafePermissionDelegate) {
742 return gBrowserBundle.formatStringFromName(
743 "geolocation.shareWithSiteUnsafeDelegation2",
748 return gBrowserBundle.formatStringFromName("geolocation.shareWithSite4", [
753 get promptActions() {
756 label: gBrowserBundle.GetStringFromName("geolocation.allow"),
757 accessKey: gBrowserBundle.GetStringFromName(
758 "geolocation.allow.accesskey"
760 action: SitePermissions.ALLOW,
763 label: gBrowserBundle.GetStringFromName("geolocation.block"),
764 accessKey: gBrowserBundle.GetStringFromName(
765 "geolocation.block.accesskey"
767 action: SitePermissions.BLOCK,
772 _updateGeoSharing(state) {
773 let gBrowser = this.browser.ownerGlobal.gBrowser;
774 if (gBrowser == null) {
777 gBrowser.updateBrowserSharing(this.browser, { geo: state });
779 // Update last access timestamp
782 host = this.browser.currentURI.host;
786 if (host == null || host == "") {
789 ContentPrefService2.set(
790 this.browser.currentURI.host,
791 "permissions.geoLocation.lastAccess",
792 new Date().toString(),
793 this.browser.loadContext
798 this._updateGeoSharing(true);
799 PermissionPromptForRequestPrototype.allow.apply(this, args);
803 this._updateGeoSharing(false);
804 PermissionPromptForRequestPrototype.cancel.apply(this, args);
808 PermissionUI.GeolocationPermissionPrompt = GeolocationPermissionPrompt;
811 * Creates a PermissionPrompt for a nsIContentPermissionRequest for
814 * @param request (nsIContentPermissionRequest)
815 * The request for a permission from content.
817 function XRPermissionPrompt(request) {
818 this.request = request;
821 XRPermissionPrompt.prototype = {
822 __proto__: PermissionPromptForRequestPrototype,
828 get permissionKey() {
833 let pref = "browser.xr.warning.infoURL";
835 learnMoreURL: Services.urlFormatter.formatURLPref(pref),
837 name: this.getPrincipalName(),
840 if (this.principal.schemeIs("file")) {
841 options.checkbox = { show: false };
843 // Don't offer "always remember" action in PB mode
845 show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal),
849 if (options.checkbox.show) {
850 options.checkbox.label = gBrowserBundle.GetStringFromName("xr.remember");
856 get notificationID() {
861 return "xr-notification-icon";
865 if (this.principal.schemeIs("file")) {
866 return gBrowserBundle.GetStringFromName("xr.shareWithFile4");
869 return gBrowserBundle.formatStringFromName("xr.shareWithSite4", ["<>"]);
872 get promptActions() {
875 label: gBrowserBundle.GetStringFromName("xr.allow2"),
876 accessKey: gBrowserBundle.GetStringFromName("xr.allow2.accesskey"),
877 action: SitePermissions.ALLOW,
880 label: gBrowserBundle.GetStringFromName("xr.block"),
881 accessKey: gBrowserBundle.GetStringFromName("xr.block.accesskey"),
882 action: SitePermissions.BLOCK,
887 _updateXRSharing(state) {
888 let gBrowser = this.browser.ownerGlobal.gBrowser;
889 if (gBrowser == null) {
892 gBrowser.updateBrowserSharing(this.browser, { xr: state });
894 let devicePermOrigins = this.browser.getDevicePermissionOrigins("xr");
896 devicePermOrigins.delete(this.principal.origin);
899 devicePermOrigins.add(this.principal.origin);
903 this._updateXRSharing(true);
904 PermissionPromptForRequestPrototype.allow.apply(this, args);
908 this._updateXRSharing(false);
909 PermissionPromptForRequestPrototype.cancel.apply(this, args);
913 PermissionUI.XRPermissionPrompt = XRPermissionPrompt;
916 * Creates a PermissionPrompt for a nsIContentPermissionRequest for
917 * the Desktop Notification API.
919 * @param request (nsIContentPermissionRequest)
920 * The request for a permission from content.
921 * @return {PermissionPrompt} (see documentation in header)
923 function DesktopNotificationPermissionPrompt(request) {
924 this.request = request;
926 XPCOMUtils.defineLazyPreferenceGetter(
929 "dom.webnotifications.requireuserinteraction"
931 XPCOMUtils.defineLazyPreferenceGetter(
934 "permissions.desktop-notification.postPrompt.enabled"
936 XPCOMUtils.defineLazyPreferenceGetter(
939 "permissions.desktop-notification.notNow.enabled"
943 DesktopNotificationPermissionPrompt.prototype = {
944 __proto__: PermissionPromptForRequestPrototype,
947 return "desktop-notification";
950 get permissionKey() {
951 return "desktop-notification";
956 Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
961 name: this.getPrincipalName(),
965 get notificationID() {
966 return "web-notifications";
970 return "web-notifications-notification-icon";
974 return gBrowserBundle.formatStringFromName(
975 "webNotifications.receiveFromSite3",
980 get promptActions() {
983 label: gBrowserBundle.GetStringFromName("webNotifications.allow2"),
984 accessKey: gBrowserBundle.GetStringFromName(
985 "webNotifications.allow2.accesskey"
987 action: SitePermissions.ALLOW,
988 scope: SitePermissions.SCOPE_PERSISTENT,
991 if (this.notNowEnabled) {
993 label: gBrowserBundle.GetStringFromName("webNotifications.notNow"),
994 accessKey: gBrowserBundle.GetStringFromName(
995 "webNotifications.notNow.accesskey"
997 action: SitePermissions.BLOCK,
1001 let isBrowserPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
1003 label: isBrowserPrivate
1004 ? gBrowserBundle.GetStringFromName("webNotifications.block")
1005 : gBrowserBundle.GetStringFromName("webNotifications.alwaysBlock"),
1006 accessKey: isBrowserPrivate
1007 ? gBrowserBundle.GetStringFromName("webNotifications.block.accesskey")
1008 : gBrowserBundle.GetStringFromName(
1009 "webNotifications.alwaysBlock.accesskey"
1011 action: SitePermissions.BLOCK,
1012 scope: isBrowserPrivate
1013 ? SitePermissions.SCOPE_SESSION
1014 : SitePermissions.SCOPE_PERSISTENT,
1019 get postPromptActions() {
1022 label: gBrowserBundle.GetStringFromName("webNotifications.allow2"),
1023 accessKey: gBrowserBundle.GetStringFromName(
1024 "webNotifications.allow2.accesskey"
1026 action: SitePermissions.ALLOW,
1030 let isBrowserPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
1032 label: isBrowserPrivate
1033 ? gBrowserBundle.GetStringFromName("webNotifications.block")
1034 : gBrowserBundle.GetStringFromName("webNotifications.alwaysBlock"),
1035 accessKey: isBrowserPrivate
1036 ? gBrowserBundle.GetStringFromName("webNotifications.block.accesskey")
1037 : gBrowserBundle.GetStringFromName(
1038 "webNotifications.alwaysBlock.accesskey"
1040 action: SitePermissions.BLOCK,
1046 PermissionUI.DesktopNotificationPermissionPrompt = DesktopNotificationPermissionPrompt;
1049 * Creates a PermissionPrompt for a nsIContentPermissionRequest for
1050 * the persistent-storage API.
1052 * @param request (nsIContentPermissionRequest)
1053 * The request for a permission from content.
1055 function PersistentStoragePermissionPrompt(request) {
1056 this.request = request;
1059 PersistentStoragePermissionPrompt.prototype = {
1060 __proto__: PermissionPromptForRequestPrototype,
1063 return "persistent-storage";
1066 get permissionKey() {
1067 return "persistent-storage";
1070 get popupOptions() {
1072 Services.urlFormatter.formatURLPref("app.support.baseURL") +
1073 "storage-permissions";
1077 name: this.getPrincipalName(),
1081 get notificationID() {
1082 return "persistent-storage";
1086 return "persistent-storage-notification-icon";
1090 return gBrowserBundle.formatStringFromName(
1091 "persistentStorage.allowWithSite2",
1096 get promptActions() {
1099 label: gBrowserBundle.GetStringFromName("persistentStorage.allow"),
1100 accessKey: gBrowserBundle.GetStringFromName(
1101 "persistentStorage.allow.accesskey"
1103 action: Ci.nsIPermissionManager.ALLOW_ACTION,
1104 scope: SitePermissions.SCOPE_PERSISTENT,
1107 label: gBrowserBundle.GetStringFromName(
1108 "persistentStorage.block.label"
1110 accessKey: gBrowserBundle.GetStringFromName(
1111 "persistentStorage.block.accesskey"
1113 action: SitePermissions.BLOCK,
1119 PermissionUI.PersistentStoragePermissionPrompt = PersistentStoragePermissionPrompt;
1122 * Creates a PermissionPrompt for a nsIContentPermissionRequest for
1125 * @param request (nsIContentPermissionRequest)
1126 * The request for a permission from content.
1128 function MIDIPermissionPrompt(request) {
1129 this.request = request;
1130 let types = request.types.QueryInterface(Ci.nsIArray);
1131 let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
1133 !!perm.options.length &&
1134 perm.options.queryElementAt(0, Ci.nsISupportsString) == "sysex";
1135 this.permName = "midi";
1136 if (this.isSysexPerm) {
1137 this.permName = "midi-sysex";
1141 MIDIPermissionPrompt.prototype = {
1142 __proto__: PermissionPromptForRequestPrototype,
1148 get permissionKey() {
1149 return this.permName;
1152 get popupOptions() {
1153 // TODO (bug 1433235) We need a security/permissions explanation URL for this
1156 name: this.getPrincipalName(),
1159 if (this.principal.schemeIs("file")) {
1160 options.checkbox = { show: false };
1162 // Don't offer "always remember" action in PB mode
1163 options.checkbox = {
1164 show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal),
1168 if (options.checkbox.show) {
1169 options.checkbox.label = gBrowserBundle.GetStringFromName(
1177 get notificationID() {
1182 return "midi-notification-icon";
1187 if (this.principal.schemeIs("file")) {
1188 if (this.isSysexPerm) {
1189 message = gBrowserBundle.GetStringFromName("midi.shareSysexWithFile");
1191 message = gBrowserBundle.GetStringFromName("midi.shareWithFile");
1193 } else if (this.isSysexPerm) {
1194 message = gBrowserBundle.formatStringFromName("midi.shareSysexWithSite", [
1198 message = gBrowserBundle.formatStringFromName("midi.shareWithSite", [
1205 get promptActions() {
1208 label: gBrowserBundle.GetStringFromName("midi.allow.label"),
1209 accessKey: gBrowserBundle.GetStringFromName("midi.allow.accesskey"),
1210 action: Ci.nsIPermissionManager.ALLOW_ACTION,
1213 label: gBrowserBundle.GetStringFromName("midi.block.label"),
1214 accessKey: gBrowserBundle.GetStringFromName("midi.block.accesskey"),
1215 action: Ci.nsIPermissionManager.DENY_ACTION,
1221 PermissionUI.MIDIPermissionPrompt = MIDIPermissionPrompt;
1223 function StorageAccessPermissionPrompt(request) {
1224 this.request = request;
1227 StorageAccessPermissionPrompt.prototype = {
1228 __proto__: PermissionPromptForRequestPrototype,
1230 get usePermissionManager() {
1235 return "storage-access";
1238 get permissionKey() {
1239 // Make sure this name is unique per each third-party tracker
1240 return "storage-access-" + this.principal.origin;
1243 prettifyHostPort(hostport) {
1244 let [host, port] = hostport.split(":");
1245 host = IDNService.convertToDisplayIDN(host, {});
1247 return `${host}:${port}`;
1252 get popupOptions() {
1254 Services.urlFormatter.formatURLPref("app.support.baseURL") +
1255 "third-party-cookies";
1256 let hostPort = this.prettifyHostPort(this.principal.hostPort);
1257 let hintText = gBrowserBundle.formatStringFromName(
1258 "storageAccess1.hintText",
1265 escAction: "secondarybuttoncommand",
1269 get notificationID() {
1270 return "storage-access";
1274 return "storage-access-notification-icon";
1278 return gBrowserBundle.formatStringFromName("storageAccess4.message", [
1279 this.prettifyHostPort(this.principal.hostPort),
1280 this.prettifyHostPort(this.topLevelPrincipal.hostPort),
1284 get promptActions() {
1289 label: gBrowserBundle.GetStringFromName("storageAccess1.Allow.label"),
1290 accessKey: gBrowserBundle.GetStringFromName(
1291 "storageAccess1.Allow.accesskey"
1293 action: Ci.nsIPermissionManager.ALLOW_ACTION,
1295 self.allow({ "storage-access": "allow" });
1299 label: gBrowserBundle.GetStringFromName(
1300 "storageAccess1.DontAllow.label"
1302 accessKey: gBrowserBundle.GetStringFromName(
1303 "storageAccess1.DontAllow.accesskey"
1305 action: Ci.nsIPermissionManager.DENY_ACTION,
1313 get topLevelPrincipal() {
1314 return this.request.topLevelPrincipal;
1318 PermissionUI.StorageAccessPermissionPrompt = StorageAccessPermissionPrompt;