firefox-desktop/browser/components/permissions/ContentPermissionPrompt.sys.mjs
2025-04-18 20:22:16 +02:00

133 lines
4.6 KiB
JavaScript

/* 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/. */
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
Integration: "resource://gre/modules/Integration.sys.mjs",
PermissionUI: "resource:///modules/PermissionUI.sys.mjs",
});
/**
* ContentPermissionIntegration is responsible for showing the user
* simple permission prompts when content requests additional
* capabilities.
*
* While there are some built-in permission prompts, createPermissionPrompt
* can also be overridden by system add-ons or tests to provide new ones.
*
* This override ability is provided by Integration.sys.mjs. See
* PermissionUI.sys.mjs for an example of how to provide a new prompt
* from an add-on.
*/
const ContentPermissionIntegration = {
/**
* Creates a PermissionPrompt for a given permission type and
* nsIContentPermissionRequest.
*
* @param {string} type
* The type of the permission request from content. This normally
* matches the "type" field of an nsIContentPermissionType, but it
* can be something else if the permission does not use the
* nsIContentPermissionRequest model. Note that this type might also
* be different from the permission key used in the permissions
* database.
* Example: "geolocation"
* @param {nsIContentPermissionRequest} request
* The request for a permission from content.
* @returns {PermissionPrompt?} (see PermissionUI.sys.mjs),
* or undefined if the type cannot be handled.
*/
createPermissionPrompt(type, request) {
switch (type) {
case "geolocation": {
return new lazy.PermissionUI.GeolocationPermissionPrompt(request);
}
case "xr": {
return new lazy.PermissionUI.XRPermissionPrompt(request);
}
case "desktop-notification": {
return new lazy.PermissionUI.DesktopNotificationPermissionPrompt(
request
);
}
case "persistent-storage": {
return new lazy.PermissionUI.PersistentStoragePermissionPrompt(request);
}
case "midi": {
return new lazy.PermissionUI.MIDIPermissionPrompt(request);
}
case "storage-access": {
return new lazy.PermissionUI.StorageAccessPermissionPrompt(request);
}
}
return undefined;
},
};
export function ContentPermissionPrompt() {}
ContentPermissionPrompt.prototype = {
classID: Components.ID("{d8903bf6-68d5-4e97-bcd1-e4d3012f721a}"),
QueryInterface: ChromeUtils.generateQI(["nsIContentPermissionPrompt"]),
/**
* This implementation of nsIContentPermissionPrompt.prompt ensures
* that there's only one nsIContentPermissionType in the request,
* and that it's of type nsIContentPermissionType. Failing to
* satisfy either of these conditions will result in this method
* throwing NS_ERRORs. If the combined ContentPermissionIntegration
* cannot construct a prompt for this particular request, an
* NS_ERROR_FAILURE will be thrown.
*
* Any time an error is thrown, the nsIContentPermissionRequest is
* cancelled automatically.
*
* @param {nsIContentPermissionRequest} request
* The request that we're to show a prompt for.
*/
prompt(request) {
if (request.element && request.element.fxrPermissionPrompt) {
// For Firefox Reality on Desktop, switch to a different mechanism to
// prompt the user since fewer permissions are available and since many
// UI dependencies are not availabe.
request.element.fxrPermissionPrompt(request);
return;
}
let type;
try {
// Only allow exactly one permission request here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
throw Components.Exception(
"Expected an nsIContentPermissionRequest with only 1 type.",
Cr.NS_ERROR_UNEXPECTED
);
}
type = types.queryElementAt(0, Ci.nsIContentPermissionType).type;
let combinedIntegration = lazy.Integration.contentPermission.getCombined(
ContentPermissionIntegration
);
let permissionPrompt = combinedIntegration.createPermissionPrompt(
type,
request
);
if (!permissionPrompt) {
throw Components.Exception(
`Failed to handle permission of type ${type}`,
Cr.NS_ERROR_FAILURE
);
}
permissionPrompt.prompt();
} catch (ex) {
console.error(ex);
request.cancel();
throw ex;
}
},
};