summaryrefslogtreecommitdiffstats
path: root/mobile/android/actors/GeckoViewPermissionChild.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/actors/GeckoViewPermissionChild.sys.mjs')
-rw-r--r--mobile/android/actors/GeckoViewPermissionChild.sys.mjs118
1 files changed, 118 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..f0224de2e9
--- /dev/null
+++ b/mobile/android/actors/GeckoViewPermissionChild.sys.mjs
@@ -0,0 +1,118 @@
+/* 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";
+
+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,
+ });
+ }
+
+ 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);
+ 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"
+);