diff options
Diffstat (limited to 'extensions/permissions/test/unit/test_permmanager_defaults.js')
-rw-r--r-- | extensions/permissions/test/unit/test_permmanager_defaults.js | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/extensions/permissions/test/unit/test_permmanager_defaults.js b/extensions/permissions/test/unit/test_permmanager_defaults.js new file mode 100644 index 0000000000..5a817a813b --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_defaults.js @@ -0,0 +1,489 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// The origin we use in most of the tests. +const TEST_ORIGIN = NetUtil.newURI("http://example.org"); +const TEST_ORIGIN_HTTPS = NetUtil.newURI("https://example.org"); +const TEST_ORIGIN_2 = NetUtil.newURI("http://example.com"); +const TEST_ORIGIN_3 = NetUtil.newURI("https://example2.com:8080"); +const TEST_PERMISSION = "test-permission"; + +function promiseTimeout(delay) { + return new Promise(resolve => { + do_timeout(delay, resolve); + }); +} + +add_task(async function do_test() { + // setup a profile. + do_get_profile(); + + // create a file in the temp directory with the defaults. + let file = do_get_tempdir(); + file.append("test_default_permissions"); + + // write our test data to it. + let ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance( + Ci.nsIFileOutputStream + ); + ostream.init(file, -1, 0o666, 0); + let conv = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance( + Ci.nsIConverterOutputStream + ); + conv.init(ostream, "UTF-8"); + + conv.writeString("# this is a comment\n"); + conv.writeString("\n"); // a blank line! + conv.writeString( + "host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN.host + "\n" + ); + conv.writeString( + "host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN_2.host + "\n" + ); + conv.writeString( + "origin\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN_3.spec + "\n" + ); + conv.writeString( + "origin\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN.spec + "^inBrowser=1\n" + ); + ostream.close(); + + // Set the preference used by the permission manager so the file is read. + Services.prefs.setCharPref( + "permissions.manager.defaultsUrl", + "file://" + file.path + ); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + let permIsolateUserContext = Services.prefs.getBoolPref( + "permissions.isolateBy.userContext" + ); + let permIsolatePrivateBrowsing = Services.prefs.getBoolPref( + "permissions.isolateBy.privateBrowsing" + ); + + let pm = Services.perms; + + // test the default permission was applied. + let principal = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN, + {} + ); + let principalHttps = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN_HTTPS, + {} + ); + let principal2 = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN_2, + {} + ); + let principal3 = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN_3, + {} + ); + + let attrs = { inIsolatedMozBrowser: true }; + let principal4 = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN, + attrs + ); + let principal5 = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN_3, + attrs + ); + + attrs = { userContextId: 1 }; + let principal1UserContext = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN, + attrs + ); + attrs = { privateBrowsingId: 1 }; + let principal1PrivateBrowsing = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN, + attrs + ); + attrs = { firstPartyDomain: "cnn.com" }; + let principal7 = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN, + attrs + ); + attrs = { userContextId: 1, firstPartyDomain: "cnn.com" }; + let principal8 = Services.scriptSecurityManager.createContentPrincipal( + TEST_ORIGIN, + attrs + ); + + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principalHttps, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal3, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal4, TEST_PERMISSION) + ); + // Depending on the prefs there are two scenarios here: + // 1. We isolate by private browsing: The permission mgr should + // add default permissions for these principals too. + // 2. We don't isolate by private browsing: The permission + // check will strip the private browsing origin attribute. + // In this case the used internally for the lookup is always principal1. + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal1PrivateBrowsing, TEST_PERMISSION) + ); + + // Didn't add + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal5, TEST_PERMISSION) + ); + + // the permission should exist in the enumerator. + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + findCapabilityViaEnum(TEST_ORIGIN) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + findCapabilityViaEnum(TEST_ORIGIN_3) + ); + + // but should not have been written to the DB + await checkCapabilityViaDB(null); + + // remove all should not throw and the default should remain + pm.removeAll(); + + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal3, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal4, TEST_PERMISSION) + ); + // Default permission should have also been added for private browsing. + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal1PrivateBrowsing, TEST_PERMISSION) + ); + // make sure principals with userContextId use the same / different permissions + // depending on pref state + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal1UserContext, TEST_PERMISSION) + ); + // make sure principals with a firstPartyDomain use different permissions + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION) + ); + + // Asking for this permission to be removed should result in that permission + // having UNKNOWN_ACTION + pm.removeFromPrincipal(principal, TEST_PERMISSION); + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + // make sure principals with userContextId use the correct permissions + // (Should be unknown with and without OA stripping ) + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal1UserContext, TEST_PERMISSION) + ); + // If we isolate by private browsing, the permission should still be present + // for the private browsing principal. + Assert.equal( + permIsolatePrivateBrowsing + ? Ci.nsIPermissionManager.ALLOW_ACTION + : Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal1PrivateBrowsing, TEST_PERMISSION) + ); + // and we should have this UNKNOWN_ACTION reflected in the DB + await checkCapabilityViaDB(Ci.nsIPermissionManager.UNKNOWN_ACTION); + // but the permission should *not* appear in the enumerator. + Assert.equal(null, findCapabilityViaEnum()); + + // and a subsequent RemoveAll should restore the default + pm.removeAll(); + + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + // Make sure default imports work for private browsing after removeAll. + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal1PrivateBrowsing, TEST_PERMISSION) + ); + // make sure principals with userContextId share permissions depending on pref state + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal1UserContext, TEST_PERMISSION) + ); + // make sure principals with firstPartyDomain use different permissions + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION) + ); + // and allow it to again be seen in the enumerator. + Assert.equal(Ci.nsIPermissionManager.ALLOW_ACTION, findCapabilityViaEnum()); + + // now explicitly add a permission - this too should override the default. + pm.addFromPrincipal( + principal, + TEST_PERMISSION, + Ci.nsIPermissionManager.DENY_ACTION + ); + + // it should be reflected in a permission check, in the enumerator and the DB + Assert.equal( + Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + // make sure principals with userContextId use the same / different permissions + // depending on pref state + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal1UserContext, TEST_PERMISSION) + ); + // If we isolate by private browsing, we should still have the default perm + // for the private browsing principal. + Assert.equal( + permIsolatePrivateBrowsing + ? Ci.nsIPermissionManager.ALLOW_ACTION + : Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal1PrivateBrowsing, TEST_PERMISSION) + ); + // make sure principals with firstPartyDomain use different permissions + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION) + ); + Assert.equal(Ci.nsIPermissionManager.DENY_ACTION, findCapabilityViaEnum()); + await checkCapabilityViaDB(Ci.nsIPermissionManager.DENY_ACTION); + + // explicitly add a different permission - in this case we are no longer + // replacing the default, but instead replacing the replacement! + pm.addFromPrincipal( + principal, + TEST_PERMISSION, + Ci.nsIPermissionManager.PROMPT_ACTION + ); + + // it should be reflected in a permission check, in the enumerator and the DB + Assert.equal( + Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + // make sure principals with userContextId use the same / different permissions + // depending on pref state + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principal1UserContext, TEST_PERMISSION) + ); + // If we isolate by private browsing, we should still have the default perm + // for the private browsing principal. + Assert.equal( + permIsolatePrivateBrowsing + ? Ci.nsIPermissionManager.ALLOW_ACTION + : Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principal1PrivateBrowsing, TEST_PERMISSION) + ); + // make sure principals with firstPartyDomain use different permissions + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal7, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(principal8, TEST_PERMISSION) + ); + Assert.equal(Ci.nsIPermissionManager.PROMPT_ACTION, findCapabilityViaEnum()); + await checkCapabilityViaDB(Ci.nsIPermissionManager.PROMPT_ACTION); + + // -------------------------------------------------------------- + // check default permissions and removeAllSince work as expected. + pm.removeAll(); // ensure only defaults are there. + + // default for both principals is allow. + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION) + ); + + // Add a default override for TEST_ORIGIN_2 - this one should *not* be + // restored in removeAllSince() + pm.addFromPrincipal( + principal2, + TEST_PERMISSION, + Ci.nsIPermissionManager.DENY_ACTION + ); + Assert.equal( + Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION) + ); + await promiseTimeout(20); + + let since = Number(Date.now()); + await promiseTimeout(20); + + // explicitly add a permission which overrides the default for the first + // principal - this one *should* be removed by removeAllSince. + pm.addFromPrincipal( + principal, + TEST_PERMISSION, + Ci.nsIPermissionManager.DENY_ACTION + ); + Assert.equal( + Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + + // do a removeAllSince. + pm.removeAllSince(since); + + // the default for the first principal should re-appear as we modified it + // later then |since| + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + + // but the permission for principal2 should remain as we added that before |since|. + Assert.equal( + Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal2, TEST_PERMISSION) + ); + + // remove the temp file we created. + file.remove(false); +}); + +// use an enumerator to find the requested permission. Returns the permission +// value (ie, the "capability" in nsIPermission parlance) or null if it can't +// be found. +function findCapabilityViaEnum(origin = TEST_ORIGIN, type = TEST_PERMISSION) { + let result = undefined; + for (let perm of Services.perms.all) { + if (perm.matchesURI(origin, true) && perm.type == type) { + if (result !== undefined) { + // we've already found one previously - that's bad! + do_throw("enumerator found multiple entries"); + } + result = perm.capability; + } + } + return result || null; +} + +// A function to check the DB has the specified capability. As the permission +// manager uses async DB operations without a completion callback, the +// distinct possibility exists that our checking of the DB will happen before +// the permission manager update has completed - so we just retry a few times. +// Returns a promise. +function checkCapabilityViaDB( + expected, + origin = TEST_ORIGIN, + type = TEST_PERMISSION +) { + return new Promise(resolve => { + let count = 0; + let max = 20; + let do_check = () => { + let got = findCapabilityViaDB(origin, type); + if (got == expected) { + // the do_check_eq() below will succeed - which is what we want. + Assert.equal(got, expected, "The database has the expected value"); + resolve(); + return; + } + // value isn't correct - see if we've retried enough + if (count++ == max) { + // the do_check_eq() below will fail - which is what we want. + Assert.equal( + got, + expected, + "The database wasn't updated with the expected value" + ); + resolve(); + return; + } + // we can retry... + do_timeout(100, do_check); + }; + do_check(); + }); +} + +// use the DB to find the requested permission. Returns the permission +// value (ie, the "capability" in nsIPermission parlance) or null if it can't +// be found. +function findCapabilityViaDB(origin = TEST_ORIGIN, type = TEST_PERMISSION) { + let principal = Services.scriptSecurityManager.createContentPrincipal( + origin, + {} + ); + let originStr = principal.origin; + + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); + file.append("permissions.sqlite"); + + let connection = Services.storage.openDatabase(file); + + let query = connection.createStatement( + "SELECT permission FROM moz_perms WHERE origin = :origin AND type = :type" + ); + query.bindByName("origin", originStr); + query.bindByName("type", type); + + if (!query.executeStep()) { + // no row + return null; + } + let result = query.getInt32(0); + if (query.executeStep()) { + // this is bad - we never expect more than 1 row here. + do_throw("More than 1 row found!"); + } + return result; +} |