ContentPermissionPrompt.sys.mjs (4898B)
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/. */ 4 5 const lazy = {}; 6 7 ChromeUtils.defineESModuleGetters(lazy, { 8 Integration: "resource://gre/modules/Integration.sys.mjs", 9 PermissionUI: "resource:///modules/PermissionUI.sys.mjs", 10 }); 11 /** 12 * ContentPermissionIntegration is responsible for showing the user 13 * simple permission prompts when content requests additional 14 * capabilities. 15 * 16 * While there are some built-in permission prompts, createPermissionPrompt 17 * can also be overridden by system add-ons or tests to provide new ones. 18 * 19 * This override ability is provided by Integration.sys.mjs. See 20 * PermissionUI.sys.mjs for an example of how to provide a new prompt 21 * from an add-on. 22 */ 23 const ContentPermissionIntegration = { 24 /** 25 * Creates a PermissionPrompt for a given permission type and 26 * nsIContentPermissionRequest. 27 * 28 * @param {string} type 29 * The type of the permission request from content. This normally 30 * matches the "type" field of an nsIContentPermissionType, but it 31 * can be something else if the permission does not use the 32 * nsIContentPermissionRequest model. Note that this type might also 33 * be different from the permission key used in the permissions 34 * database. 35 * Example: "geolocation" 36 * @param {nsIContentPermissionRequest} request 37 * The request for a permission from content. 38 * @returns {PermissionPrompt?} (see PermissionUI.sys.mjs), 39 * or undefined if the type cannot be handled. 40 */ 41 createPermissionPrompt(type, request) { 42 switch (type) { 43 case "geolocation": { 44 return new lazy.PermissionUI.GeolocationPermissionPrompt(request); 45 } 46 case "xr": { 47 return new lazy.PermissionUI.XRPermissionPrompt(request); 48 } 49 case "desktop-notification": { 50 return new lazy.PermissionUI.DesktopNotificationPermissionPrompt( 51 request 52 ); 53 } 54 case "persistent-storage": { 55 return new lazy.PermissionUI.PersistentStoragePermissionPrompt(request); 56 } 57 case "midi": { 58 return new lazy.PermissionUI.MIDIPermissionPrompt(request); 59 } 60 case "storage-access": { 61 return new lazy.PermissionUI.StorageAccessPermissionPrompt(request); 62 } 63 case "localhost": { 64 return new lazy.PermissionUI.LocalHostPermissionPrompt(request); 65 } 66 case "local-network": { 67 return new lazy.PermissionUI.LocalNetworkPermissionPrompt(request); 68 } 69 } 70 return undefined; 71 }, 72 }; 73 74 export function ContentPermissionPrompt() {} 75 76 ContentPermissionPrompt.prototype = { 77 classID: Components.ID("{d8903bf6-68d5-4e97-bcd1-e4d3012f721a}"), 78 79 QueryInterface: ChromeUtils.generateQI(["nsIContentPermissionPrompt"]), 80 81 /** 82 * This implementation of nsIContentPermissionPrompt.prompt ensures 83 * that there's only one nsIContentPermissionType in the request, 84 * and that it's of type nsIContentPermissionType. Failing to 85 * satisfy either of these conditions will result in this method 86 * throwing NS_ERRORs. If the combined ContentPermissionIntegration 87 * cannot construct a prompt for this particular request, an 88 * NS_ERROR_FAILURE will be thrown. 89 * 90 * Any time an error is thrown, the nsIContentPermissionRequest is 91 * cancelled automatically. 92 * 93 * @param {nsIContentPermissionRequest} request 94 * The request that we're to show a prompt for. 95 */ 96 prompt(request) { 97 if (request.element && request.element.fxrPermissionPrompt) { 98 // For Firefox Reality on Desktop, switch to a different mechanism to 99 // prompt the user since fewer permissions are available and since many 100 // UI dependencies are not availabe. 101 request.element.fxrPermissionPrompt(request); 102 return; 103 } 104 105 let type; 106 try { 107 // Only allow exactly one permission request here. 108 let types = request.types.QueryInterface(Ci.nsIArray); 109 if (types.length != 1) { 110 throw Components.Exception( 111 "Expected an nsIContentPermissionRequest with only 1 type.", 112 Cr.NS_ERROR_UNEXPECTED 113 ); 114 } 115 116 type = types.queryElementAt(0, Ci.nsIContentPermissionType).type; 117 let combinedIntegration = lazy.Integration.contentPermission.getCombined( 118 ContentPermissionIntegration 119 ); 120 121 let permissionPrompt = combinedIntegration.createPermissionPrompt( 122 type, 123 request 124 ); 125 if (!permissionPrompt) { 126 throw Components.Exception( 127 `Failed to handle permission of type ${type}`, 128 Cr.NS_ERROR_FAILURE 129 ); 130 } 131 132 permissionPrompt.prompt(); 133 } catch (ex) { 134 console.error(ex); 135 request.cancel(); 136 throw ex; 137 } 138 }, 139 };