summaryrefslogtreecommitdiffstats
path: root/mobile/android/actors/GeckoViewPermissionChild.sys.mjs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /mobile/android/actors/GeckoViewPermissionChild.sys.mjs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mobile/android/actors/GeckoViewPermissionChild.sys.mjs')
-rw-r--r--mobile/android/actors/GeckoViewPermissionChild.sys.mjs188
1 files changed, 188 insertions, 0 deletions
diff --git a/mobile/android/actors/GeckoViewPermissionChild.sys.mjs b/mobile/android/actors/GeckoViewPermissionChild.sys.mjs
new file mode 100644
index 0000000000..bbe9457cc5
--- /dev/null
+++ b/mobile/android/actors/GeckoViewPermissionChild.sys.mjs
@@ -0,0 +1,188 @@
+/* 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/. */
+
+import { GeckoViewActorChild } from "resource://gre/modules/GeckoViewActorChild.sys.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
+});
+
+const PERM_ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
+
+const MAPPED_TO_EXTENSION_PERMISSIONS = [
+ "persistent-storage",
+ // TODO(Bug 1336194): support geolocation manifest permission
+ // (see https://bugzilla.mozilla.org/show_bug.cgi?id=1336194#c17)l
+];
+
+export class GeckoViewPermissionChild extends GeckoViewActorChild {
+ getMediaPermission(aPermission) {
+ return this.eventDispatcher.sendRequestForResult({
+ type: "GeckoView:MediaPermission",
+ ...aPermission,
+ });
+ }
+
+ addCameraPermission() {
+ return this.sendQuery("AddCameraPermission");
+ }
+
+ getAppPermissions(aPermissions) {
+ return this.sendQuery("GetAppPermissions", aPermissions);
+ }
+
+ mediaRecordingStatusChanged(aDevices) {
+ return this.eventDispatcher.sendRequest({
+ type: "GeckoView:MediaRecordingStatusChanged",
+ devices: aDevices,
+ });
+ }
+
+ // Some WebAPI permissions can be requested and granted to extensions through the
+ // the extension manifest.json, which the user have been already prompted for
+ // (e.g. at install time for the one listed in the manifest.json permissions property,
+ // or at runtime through the optional_permissions property and the permissions.request
+ // WebExtensions API method).
+ //
+ // WebAPI permission that are expected to be mapped to extensions permissions are listed
+ // in the MAPPED_TO_EXTENSION_PERMISSIONS array.
+ //
+ // @param {nsIContentPermissionType} perm
+ // The WebAPI permission being requested
+ // @param {nsIContentPermissionRequest} aRequest
+ // The nsIContentPermissionRequest as received by the promptPermission method.
+ //
+ // @returns {null | { allow: boolean, permission: Object }
+ // Returns null if the request was not handled and should continue with the
+ // regular permission prompting flow, otherwise it returns an object to
+ // allow or disallow the permission request right away.
+ checkIfGrantedByExtensionPermissions(perm, aRequest) {
+ if (!aRequest.principal.addonPolicy) {
+ // Not an extension, continue with the regular permission prompting flow.
+ return null;
+ }
+
+ // Return earlier and continue with the regular permission prompting flow if the
+ // the permission is no one that can be requested from the extension manifest file.
+ if (!MAPPED_TO_EXTENSION_PERMISSIONS.includes(perm.type)) {
+ return null;
+ }
+
+ // Disallow if the extension is not active anymore.
+ if (!aRequest.principal.addonPolicy.active) {
+ return { allow: false };
+ }
+
+ // Check if the permission have been already granted to the extension, if it is allow it right away.
+ const isGranted =
+ Services.perms.testPermissionFromPrincipal(
+ aRequest.principal,
+ perm.type
+ ) === Services.perms.ALLOW_ACTION;
+ if (isGranted) {
+ return {
+ allow: true,
+ permission: { [perm.type]: Services.perms.ALLOW_ACTION },
+ };
+ }
+
+ // continue with the regular permission prompting flow otherwise.
+ return null;
+ }
+
+ async promptPermission(aRequest) {
+ // Only allow exactly one permission request here.
+ const types = aRequest.types.QueryInterface(Ci.nsIArray);
+ if (types.length !== 1) {
+ return { allow: false };
+ }
+
+ const perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
+
+ // Check if the request principal is an extension principal and if the permission requested
+ // should be already granted based on the extension permissions (or disallowed right away
+ // because the extension is not enabled anymore.
+ const extensionResult = this.checkIfGrantedByExtensionPermissions(
+ perm,
+ aRequest
+ );
+ if (extensionResult) {
+ return extensionResult;
+ }
+
+ if (
+ perm.type === "desktop-notification" &&
+ !aRequest.hasValidTransientUserGestureActivation &&
+ Services.prefs.getBoolPref(
+ "dom.webnotifications.requireuserinteraction",
+ true
+ )
+ ) {
+ // We need user interaction and don't have it.
+ return { allow: false };
+ }
+
+ const principal =
+ perm.type === "storage-access"
+ ? aRequest.principal
+ : aRequest.topLevelPrincipal;
+
+ let allowOrDeny;
+ try {
+ allowOrDeny = await this.eventDispatcher.sendRequestForResult({
+ type: "GeckoView:ContentPermission",
+ uri: principal.URI.displaySpec,
+ thirdPartyOrigin: aRequest.principal.origin,
+ principal: lazy.E10SUtils.serializePrincipal(principal),
+ perm: perm.type,
+ value: perm.capability,
+ contextId: principal.originAttributes.geckoViewSessionContextId ?? null,
+ privateMode: principal.privateBrowsingId != 0,
+ });
+
+ if (allowOrDeny === Services.perms.ALLOW_ACTION) {
+ // Ask for app permission after asking for content permission.
+ if (perm.type === "geolocation") {
+ const granted = await this.getAppPermissions([
+ PERM_ACCESS_FINE_LOCATION,
+ ]);
+ allowOrDeny = granted
+ ? Services.perms.ALLOW_ACTION
+ : Services.perms.DENY_ACTION;
+ }
+ }
+ } catch (error) {
+ console.error("Permission error:", error);
+ allowOrDeny = Services.perms.DENY_ACTION;
+ }
+
+ // Manually release the target request here to facilitate garbage collection.
+ aRequest = undefined;
+
+ const allow = allowOrDeny === Services.perms.ALLOW_ACTION;
+
+ // The storage access code adds itself to the perm manager; no need for us to do it.
+ if (perm.type === "storage-access") {
+ if (allow) {
+ return { allow, permission: { "storage-access": "allow" } };
+ }
+ return { allow };
+ }
+
+ Services.perms.addFromPrincipal(
+ principal,
+ perm.type,
+ allowOrDeny,
+ Services.perms.EXPIRE_NEVER
+ );
+
+ return { allow };
+ }
+}
+
+const { debug, warn } = GeckoViewPermissionChild.initLogging(
+ "GeckoViewPermissionChild"
+);