summaryrefslogtreecommitdiffstats
path: root/browser/modules/test/unit/test_SitePermissions.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/modules/test/unit/test_SitePermissions.js')
-rw-r--r--browser/modules/test/unit/test_SitePermissions.js401
1 files changed, 401 insertions, 0 deletions
diff --git a/browser/modules/test/unit/test_SitePermissions.js b/browser/modules/test/unit/test_SitePermissions.js
new file mode 100644
index 0000000000..e982cf6e99
--- /dev/null
+++ b/browser/modules/test/unit/test_SitePermissions.js
@@ -0,0 +1,401 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+"use strict";
+
+const { SitePermissions } = ChromeUtils.importESModule(
+ "resource:///modules/SitePermissions.sys.mjs"
+);
+
+const RESIST_FINGERPRINTING_ENABLED = Services.prefs.getBoolPref(
+ "privacy.resistFingerprinting"
+);
+const MIDI_ENABLED = Services.prefs.getBoolPref("dom.webmidi.enabled");
+
+const EXT_PROTOCOL_ENABLED = Services.prefs.getBoolPref(
+ "security.external_protocol_requires_permission"
+);
+
+const SPEAKER_SELECTION_ENABLED = Services.prefs.getBoolPref(
+ "media.setsinkid.enabled"
+);
+
+add_task(async function testPermissionsListing() {
+ let expectedPermissions = [
+ "autoplay-media",
+ "camera",
+ "cookie",
+ "desktop-notification",
+ "focus-tab-by-prompt",
+ "geo",
+ "install",
+ "microphone",
+ "popup",
+ "screen",
+ "shortcuts",
+ "persistent-storage",
+ "storage-access",
+ "xr",
+ "3rdPartyStorage",
+ ];
+ if (RESIST_FINGERPRINTING_ENABLED) {
+ // Canvas permission should be hidden unless privacy.resistFingerprinting
+ // is true.
+ expectedPermissions.push("canvas");
+ }
+ if (MIDI_ENABLED) {
+ // Should remove this checking and add it as default after it is fully pref'd-on.
+ expectedPermissions.push("midi");
+ expectedPermissions.push("midi-sysex");
+ }
+ if (EXT_PROTOCOL_ENABLED) {
+ expectedPermissions.push("open-protocol-handler");
+ }
+ if (SPEAKER_SELECTION_ENABLED) {
+ expectedPermissions.push("speaker");
+ }
+ Assert.deepEqual(
+ SitePermissions.listPermissions().sort(),
+ expectedPermissions.sort(),
+ "Correct list of all permissions"
+ );
+});
+
+add_task(async function testGetAllByPrincipal() {
+ // check that it returns an empty array on an invalid principal
+ // like a principal with an about URI, which doesn't support site permissions
+ let wrongPrincipal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "about:config"
+ );
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(wrongPrincipal), []);
+
+ let principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "https://example.com"
+ );
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), []);
+
+ SitePermissions.setForPrincipal(principal, "camera", SitePermissions.ALLOW);
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), [
+ {
+ id: "camera",
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ ]);
+
+ SitePermissions.setForPrincipal(
+ principal,
+ "microphone",
+ SitePermissions.ALLOW,
+ SitePermissions.SCOPE_SESSION
+ );
+ SitePermissions.setForPrincipal(
+ principal,
+ "desktop-notification",
+ SitePermissions.BLOCK
+ );
+
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), [
+ {
+ id: "camera",
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ {
+ id: "microphone",
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_SESSION,
+ },
+ {
+ id: "desktop-notification",
+ state: SitePermissions.BLOCK,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ ]);
+
+ SitePermissions.removeFromPrincipal(principal, "microphone");
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), [
+ {
+ id: "camera",
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ {
+ id: "desktop-notification",
+ state: SitePermissions.BLOCK,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ ]);
+
+ SitePermissions.removeFromPrincipal(principal, "camera");
+ SitePermissions.removeFromPrincipal(principal, "desktop-notification");
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), []);
+
+ Assert.equal(Services.prefs.getIntPref("permissions.default.shortcuts"), 0);
+ SitePermissions.setForPrincipal(
+ principal,
+ "shortcuts",
+ SitePermissions.BLOCK
+ );
+
+ // Customized preference should have been enabled, but the default should not.
+ Assert.equal(Services.prefs.getIntPref("permissions.default.shortcuts"), 0);
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), [
+ {
+ id: "shortcuts",
+ state: SitePermissions.BLOCK,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ ]);
+
+ SitePermissions.removeFromPrincipal(principal, "shortcuts");
+ Services.prefs.clearUserPref("permissions.default.shortcuts");
+});
+
+add_task(async function testGetAvailableStates() {
+ Assert.deepEqual(SitePermissions.getAvailableStates("camera"), [
+ SitePermissions.UNKNOWN,
+ SitePermissions.ALLOW,
+ SitePermissions.BLOCK,
+ ]);
+
+ // Test available states with a default permission set.
+ Services.prefs.setIntPref(
+ "permissions.default.camera",
+ SitePermissions.ALLOW
+ );
+ Assert.deepEqual(SitePermissions.getAvailableStates("camera"), [
+ SitePermissions.PROMPT,
+ SitePermissions.ALLOW,
+ SitePermissions.BLOCK,
+ ]);
+ Services.prefs.clearUserPref("permissions.default.camera");
+
+ Assert.deepEqual(SitePermissions.getAvailableStates("cookie"), [
+ SitePermissions.ALLOW,
+ SitePermissions.ALLOW_COOKIES_FOR_SESSION,
+ SitePermissions.BLOCK,
+ ]);
+
+ Assert.deepEqual(SitePermissions.getAvailableStates("popup"), [
+ SitePermissions.ALLOW,
+ SitePermissions.BLOCK,
+ ]);
+});
+
+add_task(async function testExactHostMatch() {
+ let principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "https://example.com"
+ );
+ let subPrincipal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "https://test1.example.com"
+ );
+
+ let exactHostMatched = [
+ "autoplay-media",
+ "desktop-notification",
+ "focus-tab-by-prompt",
+ "camera",
+ "microphone",
+ "screen",
+ "geo",
+ "xr",
+ "persistent-storage",
+ ];
+ if (RESIST_FINGERPRINTING_ENABLED) {
+ // Canvas permission should be hidden unless privacy.resistFingerprinting
+ // is true.
+ exactHostMatched.push("canvas");
+ }
+ if (MIDI_ENABLED) {
+ // WebMIDI is only pref'd on in nightly.
+ // Should remove this checking and add it as default after it is fully pref-on.
+ exactHostMatched.push("midi");
+ exactHostMatched.push("midi-sysex");
+ }
+ if (EXT_PROTOCOL_ENABLED) {
+ exactHostMatched.push("open-protocol-handler");
+ }
+ if (SPEAKER_SELECTION_ENABLED) {
+ exactHostMatched.push("speaker");
+ }
+ let nonExactHostMatched = [
+ "cookie",
+ "popup",
+ "install",
+ "shortcuts",
+ "storage-access",
+ "3rdPartyStorage",
+ ];
+
+ let permissions = SitePermissions.listPermissions();
+ for (let permission of permissions) {
+ SitePermissions.setForPrincipal(
+ principal,
+ permission,
+ SitePermissions.ALLOW
+ );
+
+ if (exactHostMatched.includes(permission)) {
+ // Check that the sub-origin does not inherit the permission from its parent.
+ Assert.equal(
+ SitePermissions.getForPrincipal(subPrincipal, permission).state,
+ SitePermissions.getDefault(permission),
+ `${permission} should exact-host match`
+ );
+ } else if (nonExactHostMatched.includes(permission)) {
+ // Check that the sub-origin does inherit the permission from its parent.
+ Assert.equal(
+ SitePermissions.getForPrincipal(subPrincipal, permission).state,
+ SitePermissions.ALLOW,
+ `${permission} should not exact-host match`
+ );
+ } else {
+ Assert.ok(
+ false,
+ `Found an unknown permission ${permission} in exact host match test.` +
+ "Please add new permissions from SitePermissions.sys.mjs to this test."
+ );
+ }
+
+ // Check that the permission can be made specific to the sub-origin.
+ SitePermissions.setForPrincipal(
+ subPrincipal,
+ permission,
+ SitePermissions.PROMPT
+ );
+ Assert.equal(
+ SitePermissions.getForPrincipal(subPrincipal, permission).state,
+ SitePermissions.PROMPT
+ );
+ Assert.equal(
+ SitePermissions.getForPrincipal(principal, permission).state,
+ SitePermissions.ALLOW
+ );
+
+ SitePermissions.removeFromPrincipal(subPrincipal, permission);
+ SitePermissions.removeFromPrincipal(principal, permission);
+ }
+});
+
+add_task(async function testDefaultPrefs() {
+ let principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "https://example.com"
+ );
+
+ // Check that without a pref the default return value is UNKNOWN.
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "camera"), {
+ state: SitePermissions.UNKNOWN,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+
+ // Check that the default return value changed after setting the pref.
+ Services.prefs.setIntPref(
+ "permissions.default.camera",
+ SitePermissions.BLOCK
+ );
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "camera"), {
+ state: SitePermissions.BLOCK,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+
+ // Check that other permissions still return UNKNOWN.
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "microphone"), {
+ state: SitePermissions.UNKNOWN,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+
+ // Check that the default return value changed after changing the pref.
+ Services.prefs.setIntPref(
+ "permissions.default.camera",
+ SitePermissions.ALLOW
+ );
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "camera"), {
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+
+ // Check that the preference is ignored if there is a value.
+ SitePermissions.setForPrincipal(principal, "camera", SitePermissions.BLOCK);
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "camera"), {
+ state: SitePermissions.BLOCK,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+
+ // The preference should be honored again, after resetting the permissions.
+ SitePermissions.removeFromPrincipal(principal, "camera");
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "camera"), {
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+
+ // Should be UNKNOWN after clearing the pref.
+ Services.prefs.clearUserPref("permissions.default.camera");
+ Assert.deepEqual(SitePermissions.getForPrincipal(principal, "camera"), {
+ state: SitePermissions.UNKNOWN,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ });
+});
+
+add_task(async function testCanvasPermission() {
+ let resistFingerprinting = Services.prefs.getBoolPref(
+ "privacy.resistFingerprinting",
+ false
+ );
+ let principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "https://example.com"
+ );
+
+ SitePermissions.setForPrincipal(principal, "canvas", SitePermissions.ALLOW);
+
+ // Canvas permission is hidden when privacy.resistFingerprinting is false.
+ Services.prefs.setBoolPref("privacy.resistFingerprinting", false);
+ Assert.equal(SitePermissions.listPermissions().indexOf("canvas"), -1);
+ Assert.equal(
+ SitePermissions.getAllByPrincipal(principal).filter(
+ permission => permission.id === "canvas"
+ ).length,
+ 0
+ );
+
+ // Canvas permission is visible when privacy.resistFingerprinting is true.
+ Services.prefs.setBoolPref("privacy.resistFingerprinting", true);
+ Assert.notEqual(SitePermissions.listPermissions().indexOf("canvas"), -1);
+ Assert.notEqual(
+ SitePermissions.getAllByPrincipal(principal).filter(
+ permission => permission.id === "canvas"
+ ).length,
+ 0
+ );
+
+ SitePermissions.removeFromPrincipal(principal, "canvas");
+ Services.prefs.setBoolPref(
+ "privacy.resistFingerprinting",
+ resistFingerprinting
+ );
+});
+
+add_task(async function testFilePermissions() {
+ let principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "file:///example.js"
+ );
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), []);
+
+ SitePermissions.setForPrincipal(principal, "camera", SitePermissions.ALLOW);
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), [
+ {
+ id: "camera",
+ state: SitePermissions.ALLOW,
+ scope: SitePermissions.SCOPE_PERSISTENT,
+ },
+ ]);
+ SitePermissions.removeFromPrincipal(principal, "camera");
+ Assert.deepEqual(SitePermissions.getAllByPrincipal(principal), []);
+});