diff --git a/remote/marionette/driver.sys.mjs b/remote/marionette/driver.sys.mjs
index 2ffe17e84279..95b1352ab351 100644
--- a/remote/marionette/driver.sys.mjs
+++ b/remote/marionette/driver.sys.mjs
@@ -3357,22 +3357,16 @@ GeckoDriver.prototype.setPermission = async function (cmd) {
const { descriptor, state, oneRealm = false } = cmd.parameters;
const browsingContext = lazy.assert.open(this.getBrowsingContext());
- // XXX: We currently depend on camera/microphone tests throwing UnsupportedOperationError,
- // the fix is ongoing in bug 1609427.
- if (["camera", "microphone"].includes(descriptor.name)) {
- throw new lazy.error.UnsupportedOperationError(
- "setPermission: camera and microphone permissions are currently unsupported"
- );
- }
+ lazy.permissions.validatePermission(descriptor.name);
- // XXX: Allowing this permission causes timing related Android crash, see also bug 1878741
+ // Bug 1878741: Allowing this permission causes timing related Android crash.
if (descriptor.name === "notifications") {
if (Services.prefs.getBoolPref("notification.prompt.testing", false)) {
// Okay, do nothing. The notifications module will work without permission.
return;
}
throw new lazy.error.UnsupportedOperationError(
- "setPermission: expected notification.prompt.testing to be set"
+ `Setting "descriptor.name" "notifications" expected "notification.prompt.testing" preference to be set`
);
}
@@ -3389,7 +3383,26 @@ GeckoDriver.prototype.setPermission = async function (cmd) {
lazy.assert.boolean(oneRealm);
- lazy.permissions.set(params.type, params.state, oneRealm, browsingContext);
+ if (!lazy.MarionettePrefs.setPermissionEnabled) {
+ throw new lazy.error.UnsupportedOperationError(
+ "'Set Permission' is not available"
+ );
+ }
+
+ let origin = browsingContext.currentURI.prePath;
+
+ // storage-access is a special case.
+ if (descriptor.name === "storage-access") {
+ origin = browsingContext.top.currentURI.prePath;
+
+ params = {
+ type: lazy.permissions.getStorageAccessPermissionsType(
+ browsingContext.currentWindowGlobal.documentURI
+ ),
+ };
+ }
+
+ lazy.permissions.set(params, state, origin);
};
/**
diff --git a/remote/shared/Permissions.sys.mjs b/remote/shared/Permissions.sys.mjs
index 5238bf834700..50996bf7019a 100644
--- a/remote/shared/Permissions.sys.mjs
+++ b/remote/shared/Permissions.sys.mjs
@@ -6,71 +6,48 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
- MarionettePrefs: "chrome://remote/content/marionette/prefs.sys.mjs",
});
/** @namespace */
export const permissions = {};
-function mapToInternalPermissionParameters(browsingContext, permissionType) {
- const currentURI = browsingContext.currentWindowGlobal.documentURI;
-
- // storage-access is quite special...
- if (permissionType === "storage-access") {
- const thirdPartyPrincipalSite = Services.eTLD.getSite(currentURI);
-
- const topLevelURI = browsingContext.top.currentWindowGlobal.documentURI;
- const topLevelPrincipal =
- Services.scriptSecurityManager.createContentPrincipal(topLevelURI, {});
-
- return {
- name: "3rdPartyFrameStorage^" + thirdPartyPrincipalSite,
- principal: topLevelPrincipal,
- };
- }
-
- const currentPrincipal =
- Services.scriptSecurityManager.createContentPrincipal(currentURI, {});
-
- return {
- name: permissionType,
- principal: currentPrincipal,
- };
-}
+/**
+ * Get a permission type for the "storage-access" permission.
+ *
+ * @param {nsIURI} uri
+ * The URI to use for building the permission type.
+ *
+ * @returns {string} permissionType
+ * The permission type for the "storage-access" permission.
+ */
+permissions.getStorageAccessPermissionsType = function (uri) {
+ const thirdPartyPrincipalSite = Services.eTLD.getSite(uri);
+ return "3rdPartyFrameStorage^" + thirdPartyPrincipalSite;
+};
/**
- * Set a permission's state.
- * Note: Currently just a shim to support testdriver's set_permission.
+ * Set a permission given a permission descriptor, a permission state,
+ * an origin.
*
- * @param {object} permissionType
- * The Gecko internal permission type
+ * @param {PermissionDescriptor} descriptor
+ * The descriptor of the permission which will be updated.
* @param {string} state
* State of the permission. It can be `granted`, `denied` or `prompt`.
- * @param {boolean} oneRealm
- * Currently ignored
- * @param {browsingContext=} browsingContext
- * Current browsing context object
+ * @param {string} origin
+ * The origin which is used as a target for permission update.
+ *
* @throws {UnsupportedOperationError}
- * If `marionette.setpermission.enabled` is not set or
- * an unsupported permission is used.
+ * If state has unsupported value.
*/
-permissions.set = function (permissionType, state, oneRealm, browsingContext) {
- if (!lazy.MarionettePrefs.setPermissionEnabled) {
- throw new lazy.error.UnsupportedOperationError(
- "'Set Permission' is not available"
- );
- }
-
- const { name, principal } = mapToInternalPermissionParameters(
- browsingContext,
- permissionType
- );
+permissions.set = function (descriptor, state, origin) {
+ const principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin);
switch (state) {
case "granted": {
Services.perms.addFromPrincipal(
principal,
- name,
+ descriptor.type,
Services.perms.ALLOW_ACTION
);
return;
@@ -78,13 +55,13 @@ permissions.set = function (permissionType, state, oneRealm, browsingContext) {
case "denied": {
Services.perms.addFromPrincipal(
principal,
- name,
+ descriptor.type,
Services.perms.DENY_ACTION
);
return;
}
case "prompt": {
- Services.perms.removeFromPrincipal(principal, name);
+ Services.perms.removeFromPrincipal(principal, descriptor.type);
return;
}
default:
@@ -93,3 +70,21 @@ permissions.set = function (permissionType, state, oneRealm, browsingContext) {
);
}
};
+
+/**
+ * Validate the permission.
+ *
+ * @param {string} permissionName
+ * The name of the permission which will be validated.
+ *
+ * @throws {UnsupportedOperationError}
+ * If permissionName is not supported.
+ */
+permissions.validatePermission = function (permissionName) {
+ // Bug 1609427: PermissionDescriptor for "camera" and "microphone" are not yet implemented.
+ if (["camera", "microphone"].includes(permissionName)) {
+ throw new lazy.error.UnsupportedOperationError(
+ `"descriptor.name" "${permissionName}" is currently unsupported`
+ );
+ }
+};
diff --git a/remote/test/puppeteer/test/TestExpectations.json b/remote/test/puppeteer/test/TestExpectations.json
index 008a15fd1303..9f021882f556 100644
--- a/remote/test/puppeteer/test/TestExpectations.json
+++ b/remote/test/puppeteer/test/TestExpectations.json
@@ -1028,6 +1028,13 @@
"expectations": ["FAIL"],
"comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
},
+ {
+ "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should deny permission when not listed",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"],
+ "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1894217"
+ },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should fail when bad permission is given",
"platforms": ["darwin", "linux", "win32"],
@@ -1041,6 +1048,13 @@
"expectations": ["FAIL"],
"comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
},
+ {
+ "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant permission when listed",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"],
+ "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1894217"
+ },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant persistent-storage",
"platforms": ["darwin", "linux", "win32"],
@@ -1048,6 +1062,13 @@
"expectations": ["FAIL"],
"comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
},
+ {
+ "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should grant persistent-storage",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"],
+ "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1894217"
+ },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should isolate permissions between browser contexts",
"platforms": ["darwin", "linux", "win32"],
@@ -1055,6 +1076,13 @@
"expectations": ["FAIL"],
"comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
},
+ {
+ "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should isolate permissions between browser contexts",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"],
+ "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1894217"
+ },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should reset permissions",
"platforms": ["darwin", "linux", "win32"],
@@ -1062,12 +1090,26 @@
"expectations": ["FAIL"],
"comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
},
+ {
+ "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should reset permissions",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["firefox", "webDriverBiDi"],
+ "expectations": ["FAIL"],
+ "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1894217"
+ },
+ {
+ "testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should trigger permission onchange",
+ "platforms": ["darwin", "linux", "win32"],
+ "parameters": ["cdp", "firefox"],
+ "expectations": ["FAIL"],
+ "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
+ },
{
"testIdPattern": "[browsercontext.spec] BrowserContext BrowserContext.overridePermissions should trigger permission onchange",
"platforms": ["darwin", "linux", "win32"],
- "parameters": ["cdp", "firefox"],
+ "parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"],
- "comment": "TODO: add a comment explaining why this expectation is required (include links to issues)"
+ "comment": "https://bugzilla.mozilla.org/show_bug.cgi?id=1894217"
},
{
"testIdPattern": "[browsercontext.spec] BrowserContext should fire target events",
diff --git a/remote/webdriver-bidi/jar.mn b/remote/webdriver-bidi/jar.mn
index 6f0b2493d8b2..ed28fda6ba66 100644
--- a/remote/webdriver-bidi/jar.mn
+++ b/remote/webdriver-bidi/jar.mn
@@ -21,6 +21,7 @@ remote.jar:
content/webdriver-bidi/modules/root/input.sys.mjs (modules/root/input.sys.mjs)
content/webdriver-bidi/modules/root/log.sys.mjs (modules/root/log.sys.mjs)
content/webdriver-bidi/modules/root/network.sys.mjs (modules/root/network.sys.mjs)
+ content/webdriver-bidi/modules/root/permissions.sys.mjs (modules/root/permissions.sys.mjs)
content/webdriver-bidi/modules/root/script.sys.mjs (modules/root/script.sys.mjs)
content/webdriver-bidi/modules/root/session.sys.mjs (modules/root/session.sys.mjs)
content/webdriver-bidi/modules/root/storage.sys.mjs (modules/root/storage.sys.mjs)
diff --git a/remote/webdriver-bidi/modules/ModuleRegistry.sys.mjs b/remote/webdriver-bidi/modules/ModuleRegistry.sys.mjs
index 63713f1f02a9..145e227fc751 100644
--- a/remote/webdriver-bidi/modules/ModuleRegistry.sys.mjs
+++ b/remote/webdriver-bidi/modules/ModuleRegistry.sys.mjs
@@ -18,6 +18,8 @@ ChromeUtils.defineESModuleGetters(modules.root, {
log: "chrome://remote/content/webdriver-bidi/modules/root/log.sys.mjs",
network:
"chrome://remote/content/webdriver-bidi/modules/root/network.sys.mjs",
+ permissions:
+ "chrome://remote/content/webdriver-bidi/modules/root/permissions.sys.mjs",
script: "chrome://remote/content/webdriver-bidi/modules/root/script.sys.mjs",
session:
"chrome://remote/content/webdriver-bidi/modules/root/session.sys.mjs",
diff --git a/remote/webdriver-bidi/modules/root/permissions.sys.mjs b/remote/webdriver-bidi/modules/root/permissions.sys.mjs
new file mode 100644
index 000000000000..7c66b113b035
--- /dev/null
+++ b/remote/webdriver-bidi/modules/root/permissions.sys.mjs
@@ -0,0 +1,140 @@
+/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
+ error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
+ permissions: "chrome://remote/content/shared/Permissions.sys.mjs",
+});
+
+export const PermissionState = {
+ denied: "denied",
+ granted: "granted",
+ prompt: "prompt",
+};
+
+class PermissionsModule extends Module {
+ constructor(messageHandler) {
+ super(messageHandler);
+ }
+
+ destroy() {}
+
+ /**
+ * An object that holds the information about permission descriptor
+ * for Webdriver BiDi permissions.setPermission command.
+ *
+ * @typedef PermissionDescriptor
+ *
+ * @property {string} name
+ * The name of the permission.
+ */
+
+ /**
+ * Set to a given permission descriptor a given state on a provided origin.
+ *
+ * @param {object=} options
+ * @param {PermissionDescriptor} options.descriptor
+ * The descriptor of the permission which will be updated.
+ * @param {PermissionState} options.state
+ * The state which will be set to the permission.
+ * @param {string} options.origin
+ * The origin which is used as a target for permission update.
+ * @param {string=} options.userContext [unsupported]
+ * The id of the user context which should be used as a target
+ * for permission update.
+ *
+ * @throws {InvalidArgumentError}
+ * Raised if an argument is of an invalid type or value.
+ * @throws {UnsupportedOperationError}
+ * Raised when unsupported permissions are set or userContext
+ * argument is used.
+ */
+ async setPermission(options = {}) {
+ const {
+ descriptor,
+ state,
+ origin,
+ userContext: userContextId = null,
+ } = options;
+
+ lazy.assert.object(
+ descriptor,
+ `Expected "descriptor" to be an object, got ${descriptor}`
+ );
+ const permissionName = descriptor.name;
+ lazy.assert.string(
+ permissionName,
+ `Expected "descriptor.name" to be a string, got ${permissionName}`
+ );
+
+ lazy.permissions.validatePermission(permissionName);
+
+ // Bug 1878741: Allowing this permission causes timing related Android crash.
+ if (descriptor.name === "notifications") {
+ if (Services.prefs.getBoolPref("notification.prompt.testing", false)) {
+ // Okay, do nothing. The notifications module will work without permission.
+ return;
+ }
+ throw new lazy.error.UnsupportedOperationError(
+ `Setting "descriptor.name" "notifications" expected "notification.prompt.testing" preference to be set`
+ );
+ }
+
+ if (permissionName === "storage-access") {
+ // TODO: Bug 1895457. Add support for "storage-access" permission.
+ throw new lazy.error.UnsupportedOperationError(
+ `"descriptor.name" "${permissionName}" is currently unsupported`
+ );
+ }
+
+ const permissionStateTypes = Object.keys(PermissionState);
+ lazy.assert.that(
+ state => permissionStateTypes.includes(state),
+ `Expected "state" to be one of ${permissionStateTypes}, got ${state}`
+ )(state);
+
+ lazy.assert.string(
+ origin,
+ `Expected "origin" to be a string, got ${origin}`
+ );
+ lazy.assert.that(
+ origin => URL.canParse(origin),
+ `Expected "origin" to be a valid URL, got ${origin}`
+ )(origin);
+
+ if (userContextId !== null) {
+ lazy.assert.string(
+ userContextId,
+ `Expected "userContext" to be a string, got ${userContextId}`
+ );
+
+ // TODO: Bug 1894217. Add support for "userContext" argument.
+ throw new lazy.error.UnsupportedOperationError(
+ `"userContext" is not supported yet`
+ );
+ }
+
+ const activeWindow = Services.wm.getMostRecentBrowserWindow();
+ let typedDescriptor;
+ try {
+ typedDescriptor = activeWindow.navigator.permissions.parseSetParameters({
+ descriptor,
+ state,
+ });
+ } catch (err) {
+ throw new lazy.error.InvalidArgumentError(
+ `The conversion of "descriptor" was not successful: ${err.message}`
+ );
+ }
+
+ lazy.permissions.set(typedDescriptor, state, origin);
+ }
+}
+
+export const permissions = PermissionsModule;
diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_set_permission.py b/testing/marionette/harness/marionette_harness/tests/unit/test_set_permission.py
index 476d9c5729b3..ba35bd6b990b 100644
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_set_permission.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_set_permission.py
@@ -48,3 +48,7 @@ class TestSetPermission(MarionetteTestCase):
self.assertEqual(
self.query_permission({"name": "midi", "sysex": True}), "prompt"
)
+
+ def test_storage_access(self):
+ self.marionette.set_permission({"name": "storage-access"}, "granted")
+ self.assertEqual(self.query_permission({"name": "storage-access"}), "granted")
diff --git a/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/invalid.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/invalid.py.ini
deleted file mode 100644
index 4c807f188ff0..000000000000
--- a/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/invalid.py.ini
+++ /dev/null
@@ -1,68 +0,0 @@
-[invalid.py]
- expected:
- if (processor == "x86") and not debug: [OK, TIMEOUT]
- [test_params_descriptor_invalid_type[False\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[SOME_STRING\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[42\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[descriptor3\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[descriptor4\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[descriptor5\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[None\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_type[descriptor7\]]
- expected: FAIL
-
- [test_params_descriptor_invalid_value[descriptor0\]]
- expected: FAIL
-
- [test_params_state_invalid_type[False\]]
- expected: FAIL
-
- [test_params_state_invalid_type[42\]]
- expected: FAIL
-
- [test_params_state_invalid_type[state2\]]
- expected: FAIL
-
- [test_params_state_invalid_type[state3\]]
- expected: FAIL
-
- [test_params_state_invalid_type[None\]]
- expected: FAIL
-
- [test_params_state_invalid_type[state5\]]
- expected: FAIL
-
- [test_params_state_invalid_value[Granted\]]
- expected: FAIL
-
- [test_params_origin_invalid_type[False\]]
- expected: FAIL
-
- [test_params_origin_invalid_type[42\]]
- expected: FAIL
-
- [test_params_origin_invalid_type[None\]]
- expected: FAIL
-
- [test_params_state_invalid_value[UNKNOWN\]]
- expected: FAIL
-
- [test_params_origin_invalid_type[user_context2\]]
- expected: FAIL
-
- [test_params_origin_invalid_type[user_context3\]]
- expected: FAIL
diff --git a/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py.ini b/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py.ini
index 789600d42655..1de0c86fe07e 100644
--- a/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py.ini
+++ b/testing/web-platform/meta/webdriver/tests/bidi/external/permissions/set_permission/set_permission.py.ini
@@ -1,13 +1,4 @@
[set_permission.py]
- [test_set_permission]
- expected: FAIL
-
- [test_set_permission_insecure_context]
- expected: FAIL
-
- [test_set_permission_new_context]
- expected: FAIL
-
[test_set_permission_origin_unknown[UNKNOWN\]]
expected: FAIL
@@ -16,3 +7,6 @@
[test_set_permission_user_context]
expected: FAIL
+ bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1894217
+ disabled:
+ if os == "android": bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1877953