From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../permissions/test/PermissionTestUtils.sys.mjs | 111 +++++ extensions/permissions/test/browser.ini | 8 + .../permissions/test/browser_permmgr_sync.js | 448 +++++++++++++++++++ .../permissions/test/browser_permmgr_viewsrc.js | 28 ++ .../test/gtest/PermissionManagerTest.cpp | 52 +++ extensions/permissions/test/gtest/moz.build | 11 + extensions/permissions/test/moz.build | 15 + extensions/permissions/test/unit/head.js | 26 ++ .../test/unit/test_permmanager_cleardata.js | 93 ++++ .../test/unit/test_permmanager_default_pref.js | 76 ++++ .../test/unit/test_permmanager_defaults.js | 485 +++++++++++++++++++++ .../test/unit/test_permmanager_expiration.js | 189 ++++++++ .../unit/test_permmanager_getAllByTypeSince.js | 79 ++++ .../test/unit/test_permmanager_getAllByTypes.js | 124 ++++++ .../unit/test_permmanager_getAllForPrincipal.js | 72 +++ .../unit/test_permmanager_getAllWithTypePrefix.js | 84 ++++ .../unit/test_permmanager_getPermissionObject.js | 98 +++++ .../permissions/test/unit/test_permmanager_idn.js | 75 ++++ .../permissions/test/unit/test_permmanager_ipc.js | 89 ++++ .../unit/test_permmanager_load_invalid_entries.js | 264 +++++++++++ .../test/unit/test_permmanager_local_files.js | 74 ++++ .../test/unit/test_permmanager_matches.js | 203 +++++++++ .../test/unit/test_permmanager_matchesuri.js | 252 +++++++++++ .../test/unit/test_permmanager_migrate_10-11.js | 196 +++++++++ .../test/unit/test_permmanager_migrate_11-12.js | 230 ++++++++++ .../test/unit/test_permmanager_migrate_4-7.js | 264 +++++++++++ .../test_permmanager_migrate_4-7_no_history.js | 279 ++++++++++++ .../test/unit/test_permmanager_migrate_5-7a.js | 365 ++++++++++++++++ .../test/unit/test_permmanager_migrate_5-7b.js | 203 +++++++++ .../test/unit/test_permmanager_migrate_6-7a.js | 366 ++++++++++++++++ .../test/unit/test_permmanager_migrate_6-7b.js | 199 +++++++++ .../test/unit/test_permmanager_migrate_7-8.js | 328 ++++++++++++++ .../test/unit/test_permmanager_migrate_9-10.js | 262 +++++++++++ .../test/unit/test_permmanager_notifications.js | 139 ++++++ .../test/unit/test_permmanager_oa_strip.js | 220 ++++++++++ .../unit/test_permmanager_remove_add_update.js | 84 ++++ .../test/unit/test_permmanager_removeall.js | 47 ++ .../test/unit/test_permmanager_removebytype.js | 76 ++++ .../unit/test_permmanager_removebytypesince.js | 89 ++++ .../test/unit/test_permmanager_removepermission.js | 58 +++ .../test/unit/test_permmanager_removesince.js | 83 ++++ .../test/unit/test_permmanager_site_scope.js | 116 +++++ .../test/unit/test_permmanager_subdomains.js | 106 +++++ extensions/permissions/test/unit/xpcshell.ini | 60 +++ 44 files changed, 6726 insertions(+) create mode 100644 extensions/permissions/test/PermissionTestUtils.sys.mjs create mode 100644 extensions/permissions/test/browser.ini create mode 100644 extensions/permissions/test/browser_permmgr_sync.js create mode 100644 extensions/permissions/test/browser_permmgr_viewsrc.js create mode 100644 extensions/permissions/test/gtest/PermissionManagerTest.cpp create mode 100644 extensions/permissions/test/gtest/moz.build create mode 100644 extensions/permissions/test/moz.build create mode 100644 extensions/permissions/test/unit/head.js create mode 100644 extensions/permissions/test/unit/test_permmanager_cleardata.js create mode 100644 extensions/permissions/test/unit/test_permmanager_default_pref.js create mode 100644 extensions/permissions/test/unit/test_permmanager_defaults.js create mode 100644 extensions/permissions/test/unit/test_permmanager_expiration.js create mode 100644 extensions/permissions/test/unit/test_permmanager_getAllByTypeSince.js create mode 100644 extensions/permissions/test/unit/test_permmanager_getAllByTypes.js create mode 100644 extensions/permissions/test/unit/test_permmanager_getAllForPrincipal.js create mode 100644 extensions/permissions/test/unit/test_permmanager_getAllWithTypePrefix.js create mode 100644 extensions/permissions/test/unit/test_permmanager_getPermissionObject.js create mode 100644 extensions/permissions/test/unit/test_permmanager_idn.js create mode 100644 extensions/permissions/test/unit/test_permmanager_ipc.js create mode 100644 extensions/permissions/test/unit/test_permmanager_load_invalid_entries.js create mode 100644 extensions/permissions/test/unit/test_permmanager_local_files.js create mode 100644 extensions/permissions/test/unit/test_permmanager_matches.js create mode 100644 extensions/permissions/test/unit/test_permmanager_matchesuri.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_10-11.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_11-12.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_4-7.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_4-7_no_history.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_5-7a.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_5-7b.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_6-7a.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_6-7b.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_7-8.js create mode 100644 extensions/permissions/test/unit/test_permmanager_migrate_9-10.js create mode 100644 extensions/permissions/test/unit/test_permmanager_notifications.js create mode 100644 extensions/permissions/test/unit/test_permmanager_oa_strip.js create mode 100644 extensions/permissions/test/unit/test_permmanager_remove_add_update.js create mode 100644 extensions/permissions/test/unit/test_permmanager_removeall.js create mode 100644 extensions/permissions/test/unit/test_permmanager_removebytype.js create mode 100644 extensions/permissions/test/unit/test_permmanager_removebytypesince.js create mode 100644 extensions/permissions/test/unit/test_permmanager_removepermission.js create mode 100644 extensions/permissions/test/unit/test_permmanager_removesince.js create mode 100644 extensions/permissions/test/unit/test_permmanager_site_scope.js create mode 100644 extensions/permissions/test/unit/test_permmanager_subdomains.js create mode 100644 extensions/permissions/test/unit/xpcshell.ini (limited to 'extensions/permissions/test') diff --git a/extensions/permissions/test/PermissionTestUtils.sys.mjs b/extensions/permissions/test/PermissionTestUtils.sys.mjs new file mode 100644 index 0000000000..84601376ba --- /dev/null +++ b/extensions/permissions/test/PermissionTestUtils.sys.mjs @@ -0,0 +1,111 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Utility module for tests to access the PermissionManager + * with uri or origin string parameters. + */ + +let pm = Services.perms; + +let secMan = Services.scriptSecurityManager; + +/** + * Convert origin string or uri to principal. + * If passed an nsIPrincipal it will be returned without conversion. + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject - Subject to convert to principal + * @returns {Ci.nsIPrincipal} Principal created from subject + */ +function convertToPrincipal(subject) { + if (subject instanceof Ci.nsIPrincipal) { + return subject; + } + if (typeof subject === "string") { + return secMan.createContentPrincipalFromOrigin(subject); + } + if (subject === null || subject instanceof Ci.nsIURI) { + return secMan.createContentPrincipal(subject, {}); + } + throw new Error( + "subject parameter must be an nsIURI an origin string or a principal." + ); +} + +export let PermissionTestUtils = { + /** + * Add permission information for a given subject. + * Subject can be a principal, uri or origin string. + * + * @see nsIPermissionManager for documentation + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject + * @param {*} args + */ + add(subject, ...args) { + return pm.addFromPrincipal(convertToPrincipal(subject), ...args); + }, + /** + * Get all custom permissions for a given subject. + * Subject can be a principal, uri or origin string. + * + * @see nsIPermissionManager for documentation + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject + * @param {*} args + */ + getAll(subject, ...args) { + return pm.getAllForPrincipal(convertToPrincipal(subject), ...args); + }, + /** + * Remove permission information for a given subject and permission type + * Subject can be a principal, uri or origin string. + * + * @see nsIPermissionManager for documentation + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject + * @param {*} args + */ + remove(subject, ...args) { + return pm.removeFromPrincipal(convertToPrincipal(subject), ...args); + }, + /** + * Test whether a website has permission to perform the given action. + * Subject can be a principal, uri or origin string. + * + * @see nsIPermissionManager for documentation + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject + * @param {*} args + */ + testPermission(subject, ...args) { + return pm.testPermissionFromPrincipal(convertToPrincipal(subject), ...args); + }, + /** + * Test whether a website has permission to perform the given action. + * Subject can be a principal, uri or origin string. + * + * @see nsIPermissionManager for documentation + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject + * @param {*} args + */ + testExactPermission(subject, ...args) { + return pm.testExactPermissionFromPrincipal( + convertToPrincipal(subject), + ...args + ); + }, + /** + * Get the permission object associated with the given subject and action. + * Subject can be a principal, uri or origin string. + * + * @see nsIPermissionManager for documentation + * + * @param {Ci.nsIPrincipal|Ci.nsIURI|string} subject + * @param {*} args + */ + getPermissionObject(subject, type, exactHost = false) { + return pm.getPermissionObject(convertToPrincipal(subject), type, exactHost); + }, +}; diff --git a/extensions/permissions/test/browser.ini b/extensions/permissions/test/browser.ini new file mode 100644 index 0000000000..b71b10dfaf --- /dev/null +++ b/extensions/permissions/test/browser.ini @@ -0,0 +1,8 @@ +[DEFAULT] + +[browser_permmgr_sync.js] +# The browser_permmgr_sync test runs code +# paths which would hit the debug only assertion in +# PermissionManager::PermissionKey::CreateFromPrincipal. +skip-if = debug +[browser_permmgr_viewsrc.js] diff --git a/extensions/permissions/test/browser_permmgr_sync.js b/extensions/permissions/test/browser_permmgr_sync.js new file mode 100644 index 0000000000..619c29842c --- /dev/null +++ b/extensions/permissions/test/browser_permmgr_sync.js @@ -0,0 +1,448 @@ +function addPerm(aOrigin, aName) { + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin(aOrigin); + Services.perms.addFromPrincipal( + principal, + aName, + Services.perms.ALLOW_ACTION + ); +} + +add_task(async function () { + // Make sure that we get a new process for the tab which we create. This is + // important, because we want to assert information about the initial state + // of the local permissions cache. + + addPerm("http://example.com", "perm1"); + addPerm("http://foo.bar.example.com", "perm2"); + addPerm("about:home", "perm3"); + addPerm("https://example.com", "perm4"); + // NOTE: This permission is a preload permission, so it should be available in + // the content process from startup. + addPerm("https://somerandomwebsite.com", "cookie"); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank", forceNewProcess: true }, + async function (aBrowser) { + await SpecialPowers.spawn(aBrowser, [], async function () { + // Before the load http URIs shouldn't have been sent down yet + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "perm1" + ), + Services.perms.UNKNOWN_ACTION, + "perm1-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "perm2" + ), + Services.perms.UNKNOWN_ACTION, + "perm2-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "about:home" + ), + "perm3" + ), + Services.perms.ALLOW_ACTION, + "perm3-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "perm4" + ), + Services.perms.UNKNOWN_ACTION, + "perm4-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://somerandomwebsite.com" + ), + "cookie" + ), + Services.perms.ALLOW_ACTION, + "cookie-1" + ); + + let iframe = content.document.createElement("iframe"); + + // Perform a load of example.com + await new Promise(resolve => { + iframe.setAttribute("src", "http://example.com"); + iframe.onload = resolve; + content.document.body.appendChild(iframe); + }); + + // After the load finishes, the iframe process should know about example.com, but not foo.bar.example.com + await content.SpecialPowers.spawn(iframe, [], async function () { + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "perm1" + ), + Services.perms.ALLOW_ACTION, + "perm1-2" + ); + + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "perm2" + ), + Services.perms.UNKNOWN_ACTION, + "perm2-2" + ); + + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "about:home" + ), + "perm3" + ), + Services.perms.ALLOW_ACTION, + "perm3-2" + ); + + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "perm4" + ), + Services.perms.UNKNOWN_ACTION, + "perm4-2" + ); + + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://somerandomwebsite.com" + ), + "cookie" + ), + Services.perms.ALLOW_ACTION, + "cookie-2" + ); + }); + + // In Fission only, the parent process should have no knowledge about the child + // process permissions + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "perm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "perm1-3" + ); + + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "perm2" + ), + Services.perms.UNKNOWN_ACTION, + "perm2-3" + ); + + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "perm4" + ), + Services.perms.UNKNOWN_ACTION, + "perm4-3" + ); + }); + + addPerm("http://example.com", "newperm1"); + addPerm("http://foo.bar.example.com", "newperm2"); + addPerm("about:home", "newperm3"); + addPerm("https://example.com", "newperm4"); + addPerm("https://someotherrandomwebsite.com", "cookie"); + + await SpecialPowers.spawn(aBrowser, [], async function () { + // The new permissions should be available, but only for + // http://example.com (without Fission), and about:home. + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "perm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "perm1-4" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "newperm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "newperm1-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "perm2" + ), + Services.perms.UNKNOWN_ACTION, + "perm2-4" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "newperm2" + ), + Services.perms.UNKNOWN_ACTION, + "newperm2-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "about:home" + ), + "perm3" + ), + Services.perms.ALLOW_ACTION, + "perm3-3" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "about:home" + ), + "newperm3" + ), + Services.perms.ALLOW_ACTION, + "newperm3-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "perm4" + ), + Services.perms.UNKNOWN_ACTION, + "perm4-4" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "newperm4" + ), + Services.perms.UNKNOWN_ACTION, + "newperm4-1" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://somerandomwebsite.com" + ), + "cookie" + ), + Services.perms.ALLOW_ACTION, + "cookie-3" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://someotherrandomwebsite.com" + ), + "cookie" + ), + Services.perms.ALLOW_ACTION, + "othercookie-3" + ); + + let iframe = content.document.createElement("iframe"); + // Loading a subdomain now, on https + await new Promise(resolve => { + iframe.setAttribute("src", "https://sub1.test1.example.com"); + iframe.onload = resolve; + content.document.body.appendChild(iframe); + }); + + // After the load finishes, the iframe process should not know about + // the permissions of its base domain. + await content.SpecialPowers.spawn(iframe, [], async function () { + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "perm4" + ), + Services.perms.ALLOW_ACTION, + "perm4-5" + ); + + // In Fission not across schemes, though. + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "perm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "perm1-5" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "newperm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "newperm1-2" + ); + }); + + // The parent process should still have no permission under Fission. + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "perm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "perm1-4" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ), + "newperm1" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "newperm1-3" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ), + "perm4" + ), + SpecialPowers.useRemoteSubframes + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + "perm4-6" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "perm2" + ), + Services.perms.UNKNOWN_ACTION, + "perm2-5" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://foo.bar.example.com" + ), + "newperm2" + ), + Services.perms.UNKNOWN_ACTION, + "newperm2-2" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "about:home" + ), + "perm3" + ), + Services.perms.ALLOW_ACTION, + "perm3-4" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "about:home" + ), + "newperm3" + ), + Services.perms.ALLOW_ACTION, + "newperm3-2" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://somerandomwebsite.com" + ), + "cookie" + ), + Services.perms.ALLOW_ACTION, + "cookie-4" + ); + is( + Services.perms.testPermissionFromPrincipal( + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://someotherrandomwebsite.com" + ), + "cookie" + ), + Services.perms.ALLOW_ACTION, + "othercookie-4" + ); + }); + } + ); +}); diff --git a/extensions/permissions/test/browser_permmgr_viewsrc.js b/extensions/permissions/test/browser_permmgr_viewsrc.js new file mode 100644 index 0000000000..64dcb0413c --- /dev/null +++ b/extensions/permissions/test/browser_permmgr_viewsrc.js @@ -0,0 +1,28 @@ +add_task(async function () { + // Add a permission for example.com, start a new content process, and make + // sure that the permission has been sent down. + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.com" + ); + Services.perms.addFromPrincipal( + principal, + "viewsourceTestingPerm", + Services.perms.ALLOW_ACTION + ); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "view-source:https://example.com", + /* waitForLoad */ true, + /* waitForStateStop */ false, + /* forceNewProcess */ true + ); + await SpecialPowers.spawn(tab.linkedBrowser, [principal], async function (p) { + is( + Services.perms.testPermissionFromPrincipal(p, "viewsourceTestingPerm"), + Services.perms.ALLOW_ACTION + ); + }); + BrowserTestUtils.removeTab(tab); +}); diff --git a/extensions/permissions/test/gtest/PermissionManagerTest.cpp b/extensions/permissions/test/gtest/PermissionManagerTest.cpp new file mode 100644 index 0000000000..b69a7d46f2 --- /dev/null +++ b/extensions/permissions/test/gtest/PermissionManagerTest.cpp @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "nsNetUtil.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/OriginAttributes.h" +#include "mozilla/PermissionManager.h" +#include "mozilla/RefPtr.h" +#include "mozilla/Unused.h" +#include "gtest/gtest.h" +#include "gtest/MozGTestBench.h" + +using namespace mozilla; + +class PermissionManagerTester : public ::testing::Test { + protected: + PermissionManagerTester() + : mNonExistentType("permissionTypeThatIsGuaranteedToNeverExist"_ns) {} + void SetUp() override { + mPermissionManager = PermissionManager::GetInstance(); + nsCOMPtr uri; + nsresult rv = + NS_NewURI(getter_AddRefs(uri), + "https://test.origin.with.subdomains.example.com"_ns); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + mPrincipal = + mozilla::BasePrincipal::CreateContentPrincipal(uri, OriginAttributes()); + } + + void TearDown() override { + mPermissionManager = nullptr; + mPrincipal = nullptr; + } + + static const unsigned kNumIterations = 100000; + + nsLiteralCString mNonExistentType; + RefPtr mPermissionManager; + nsCOMPtr mPrincipal; +}; + +MOZ_GTEST_BENCH_F(PermissionManagerTester, + TestNonExistentPermissionFromPrincipal, [this] { + for (unsigned i = 0; i < kNumIterations; ++i) { + uint32_t result = 0; + Unused << mPermissionManager->TestPermissionFromPrincipal( + mPrincipal, mNonExistentType, &result); + } + }); diff --git a/extensions/permissions/test/gtest/moz.build b/extensions/permissions/test/gtest/moz.build new file mode 100644 index 0000000000..132c384597 --- /dev/null +++ b/extensions/permissions/test/gtest/moz.build @@ -0,0 +1,11 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +UNIFIED_SOURCES += [ + "PermissionManagerTest.cpp", +] + +FINAL_LIBRARY = "xul-gtest" diff --git a/extensions/permissions/test/moz.build b/extensions/permissions/test/moz.build new file mode 100644 index 0000000000..5c68459575 --- /dev/null +++ b/extensions/permissions/test/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +TEST_DIRS += [ + "gtest", +] + +XPCSHELL_TESTS_MANIFESTS += [ + "unit/xpcshell.ini", +] + +BROWSER_CHROME_MANIFESTS += ["browser.ini"] diff --git a/extensions/permissions/test/unit/head.js b/extensions/permissions/test/unit/head.js new file mode 100644 index 0000000000..b5b2518e22 --- /dev/null +++ b/extensions/permissions/test/unit/head.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +// Helper to step a generator function and catch a StopIteration exception. +function do_run_generator(generator) { + try { + generator.next(); + } catch (e) { + do_throw("caught exception " + e, Components.stack.caller); + } +} + +// Helper to finish a generator function test. +function do_finish_generator_test(generator) { + executeSoon(function () { + generator.return(); + do_test_finished(); + }); +} + +function do_count_array(all) { + return all.length; +} diff --git a/extensions/permissions/test/unit/test_permmanager_cleardata.js b/extensions/permissions/test/unit/test_permmanager_cleardata.js new file mode 100644 index 0000000000..2bd4d11319 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_cleardata.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var pm; + +// Create a principal based on the { origin, originAttributes }. +function createPrincipal(aOrigin, aOriginAttributes) { + return Services.scriptSecurityManager.createContentPrincipal( + NetUtil.newURI(aOrigin), + aOriginAttributes + ); +} + +function getData(aPattern) { + return JSON.stringify(aPattern); +} + +// Use aEntries to create principals, add permissions to them and check that they have them. +// Then, it is removing origin attributes with the given aData and check if the permissions +// of principals[i] matches the permission in aResults[i]. +function test(aEntries, aData, aResults) { + let principals = []; + + for (const entry of aEntries) { + principals.push(createPrincipal(entry.origin, entry.originAttributes)); + } + + for (const principal of principals) { + Assert.equal( + pm.testPermissionFromPrincipal(principal, "test/clear-origin"), + pm.UNKNOWN_ACTION + ); + pm.addFromPrincipal( + principal, + "test/clear-origin", + pm.ALLOW_ACTION, + pm.EXPIRE_NEVER, + 0 + ); + Assert.equal( + pm.testPermissionFromPrincipal(principal, "test/clear-origin"), + pm.ALLOW_ACTION + ); + } + + // `clear-origin-attributes-data` notification is removed from permission + // manager + pm.removePermissionsWithAttributes(aData); + + var length = aEntries.length; + for (let i = 0; i < length; ++i) { + Assert.equal( + pm.testPermissionFromPrincipal(principals[i], "test/clear-origin"), + aResults[i] + ); + + // Remove allowed actions. + if (aResults[i] == pm.ALLOW_ACTION) { + pm.removeFromPrincipal(principals[i], "test/clear-origin"); + } + } +} + +function run_test() { + do_get_profile(); + + pm = Services.perms; + + let entries = [ + { origin: "http://example.com", originAttributes: {} }, + { + origin: "http://example.com", + originAttributes: { inIsolatedMozBrowser: true }, + }, + ]; + + // In that case, all permissions should be removed. + test(entries, getData({}), [ + pm.UNKNOWN_ACTION, + pm.UNKNOWN_ACTION, + pm.ALLOW_ACTION, + pm.ALLOW_ACTION, + ]); + + // In that case, only the permissions related to a browserElement should be removed. + // All the other permissions should stay. + test(entries, getData({ inIsolatedMozBrowser: true }), [ + pm.ALLOW_ACTION, + pm.UNKNOWN_ACTION, + pm.ALLOW_ACTION, + pm.ALLOW_ACTION, + ]); +} diff --git a/extensions/permissions/test/unit/test_permmanager_default_pref.js b/extensions/permissions/test/unit/test_permmanager_default_pref.js new file mode 100644 index 0000000000..3759594bf5 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_default_pref.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://example.org" + ); + + // Check that without a pref the default return value is UNKNOWN. + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "camera"), + Services.perms.UNKNOWN_ACTION + ); + + // Check that the default return value changed after setting the pref. + Services.prefs.setIntPref( + "permissions.default.camera", + Services.perms.DENY_ACTION + ); + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "camera"), + Services.perms.DENY_ACTION + ); + + // Check that functions that do not directly return a permission value still + // consider the permission as being set to its default. + Assert.equal( + null, + Services.perms.getPermissionObject(principal, "camera", false) + ); + + // Check that other permissions still return UNKNOWN. + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "geo"), + Services.perms.UNKNOWN_ACTION + ); + + // Check that the default return value changed after changing the pref. + Services.prefs.setIntPref( + "permissions.default.camera", + Services.perms.ALLOW_ACTION + ); + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "camera"), + Services.perms.ALLOW_ACTION + ); + + // Check that the preference is ignored if there is a value. + Services.perms.addFromPrincipal( + principal, + "camera", + Services.perms.DENY_ACTION + ); + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "camera"), + Services.perms.DENY_ACTION + ); + Assert.ok( + Services.perms.getPermissionObject(principal, "camera", false) != null + ); + + // The preference should be honored again, after resetting the permissions. + Services.perms.removeAll(); + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "camera"), + Services.perms.ALLOW_ACTION + ); + + // Should be UNKNOWN after clearing the pref. + Services.prefs.clearUserPref("permissions.default.camera"); + Assert.equal( + Services.perms.testPermissionFromPrincipal(principal, "camera"), + Services.perms.UNKNOWN_ACTION + ); +} 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..0f608e2151 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_defaults.js @@ -0,0 +1,485 @@ +/* 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; +} diff --git a/extensions/permissions/test/unit/test_permmanager_expiration.js b/extensions/permissions/test/unit/test_permmanager_expiration.js new file mode 100644 index 0000000000..24ff366730 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_expiration.js @@ -0,0 +1,189 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that permissions with specific expiry times behave as expected. +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function continue_test() { + do_run_generator(test_generator); +} + +function* do_run_test() { + let pm = Services.perms; + let permURI = NetUtil.newURI("http://example.com"); + let principal = Services.scriptSecurityManager.createContentPrincipal( + permURI, + {} + ); + + let now = Number(Date.now()); + + // add a permission with *now* expiration + pm.addFromPrincipal( + principal, + "test/expiration-perm-exp", + 1, + pm.EXPIRE_TIME, + now + ); + pm.addFromPrincipal( + principal, + "test/expiration-session-exp", + 1, + pm.EXPIRE_SESSION, + now + ); + + // add a permission with future expiration (100 milliseconds) + pm.addFromPrincipal( + principal, + "test/expiration-perm-exp2", + 1, + pm.EXPIRE_TIME, + now + 100 + ); + pm.addFromPrincipal( + principal, + "test/expiration-session-exp2", + 1, + pm.EXPIRE_SESSION, + now + 100 + ); + + // add a permission with future expiration (1000 seconds) + pm.addFromPrincipal( + principal, + "test/expiration-perm-exp3", + 1, + pm.EXPIRE_TIME, + now + 1e6 + ); + pm.addFromPrincipal( + principal, + "test/expiration-session-exp3", + 1, + pm.EXPIRE_SESSION, + now + 1e6 + ); + + // add a permission without expiration + pm.addFromPrincipal( + principal, + "test/expiration-perm-nexp", + 1, + pm.EXPIRE_NEVER, + 0 + ); + + // check that the second two haven't expired yet + Assert.equal( + 1, + pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp3") + ); + Assert.equal( + 1, + pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp3") + ); + Assert.equal( + 1, + pm.testPermissionFromPrincipal(principal, "test/expiration-perm-nexp") + ); + Assert.equal(1, pm.getAllWithTypePrefix("test/expiration-perm-exp3").length); + Assert.equal( + 1, + pm.getAllWithTypePrefix("test/expiration-session-exp3").length + ); + Assert.equal(1, pm.getAllWithTypePrefix("test/expiration-perm-nexp").length); + Assert.equal(5, pm.getAllForPrincipal(principal).length); + + // ... and the first one has + do_timeout(10, continue_test); + yield; + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp") + ); + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp") + ); + + // ... and that the short-term one will + do_timeout(200, continue_test); + yield; + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal, "test/expiration-perm-exp2") + ); + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal, "test/expiration-session-exp2") + ); + Assert.equal(0, pm.getAllWithTypePrefix("test/expiration-perm-exp2").length); + Assert.equal( + 0, + pm.getAllWithTypePrefix("test/expiration-session-exp2").length + ); + + Assert.equal(3, pm.getAllForPrincipal(principal).length); + + // Check that .getPermission returns a matching result + Assert.equal( + null, + pm.getPermissionObject(principal, "test/expiration-perm-exp", false) + ); + Assert.equal( + null, + pm.getPermissionObject(principal, "test/expiration-session-exp", false) + ); + Assert.equal( + null, + pm.getPermissionObject(principal, "test/expiration-perm-exp2", false) + ); + Assert.equal( + null, + pm.getPermissionObject(principal, "test/expiration-session-exp2", false) + ); + + // Add a persistent permission for private browsing + let principalPB = Services.scriptSecurityManager.createContentPrincipal( + permURI, + { privateBrowsingId: 1 } + ); + pm.addFromPrincipal( + principalPB, + "test/expiration-session-pb", + pm.ALLOW_ACTION + ); + + // The permission should be set to session expiry + let perm = pm.getPermissionObject( + principalPB, + "test/expiration-session-pb", + true + ); + Assert.equal(perm.expireType, pm.EXPIRE_SESSION); + + // Add a persistent permission for private browsing using + // addFromPrincipalAndPersistInPrivateBrowsing + pm.addFromPrincipalAndPersistInPrivateBrowsing( + principalPB, + "test/expiration-session-pb", + pm.ALLOW_ACTION + ); + + // The permission should be set to never expire + perm = pm.getPermissionObject( + principalPB, + "test/expiration-session-pb", + true + ); + Assert.equal(perm.expireType, pm.EXPIRE_NEVER); + + do_finish_generator_test(test_generator); +} diff --git a/extensions/permissions/test/unit/test_permmanager_getAllByTypeSince.js b/extensions/permissions/test/unit/test_permmanager_getAllByTypeSince.js new file mode 100644 index 0000000000..918f184673 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_getAllByTypeSince.js @@ -0,0 +1,79 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function check_enumerator(prefix, from, permissions) { + let pm = Services.perms; + + let array = pm.getAllByTypeSince(prefix, from); + Assert.equal(array.length, permissions.length); + for (let [principal, type, capability] of permissions) { + let perm = array.find(p => p.principal.equals(principal)); + Assert.ok(perm != null); + Assert.equal(perm.type, type); + Assert.equal(perm.capability, capability); + Assert.equal(perm.expireType, pm.EXPIRE_NEVER); + } +} + +add_task(async function test() { + let pm = Services.perms; + + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ); + let subPrincipal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://sub.example.com" + ); + + check_enumerator("test/", 0, []); + + pm.addFromPrincipal(principal, "test/getAllByTypeSince", pm.ALLOW_ACTION); + + // These shouldn't show up anywhere, the name doesn't match. + pm.addFromPrincipal( + subPrincipal, + "other-test/getAllByTypeSince", + pm.PROMPT_ACTION + ); + pm.addFromPrincipal(principal, "test/getAllByTypeSince1", pm.PROMPT_ACTION); + + check_enumerator("test/getAllByTypeSince", 0, [ + [principal, "test/getAllByTypeSince", pm.ALLOW_ACTION], + ]); + + // Add some time in between taking the snapshot of the timestamp + // to avoid flakyness. + await new Promise(c => do_timeout(100, c)); + let timestamp = Date.now(); + await new Promise(c => do_timeout(100, c)); + + pm.addFromPrincipal(subPrincipal, "test/getAllByTypeSince", pm.DENY_ACTION); + + check_enumerator("test/getAllByTypeSince", 0, [ + [subPrincipal, "test/getAllByTypeSince", pm.DENY_ACTION], + [principal, "test/getAllByTypeSince", pm.ALLOW_ACTION], + ]); + + check_enumerator("test/getAllByTypeSince", timestamp, [ + [subPrincipal, "test/getAllByTypeSince", pm.DENY_ACTION], + ]); + + // check that UNKNOWN_ACTION permissions are ignored + pm.addFromPrincipal( + subPrincipal, + "test/getAllByTypeSince", + pm.UNKNOWN_ACTION + ); + + check_enumerator("test/getAllByTypeSince", 0, [ + [principal, "test/getAllByTypeSince", pm.ALLOW_ACTION], + ]); + + // check that permission removals are reflected + pm.removeFromPrincipal(principal, "test/getAllByTypeSince"); + check_enumerator("test/", 0, []); + + pm.removeAll(); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_getAllByTypes.js b/extensions/permissions/test/unit/test_permmanager_getAllByTypes.js new file mode 100644 index 0000000000..ab40c4b12a --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_getAllByTypes.js @@ -0,0 +1,124 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function check_enumerator(permissionTypes, expectedPermissions) { + const permissions = Services.perms.getAllByTypes(permissionTypes); + + Assert.equal( + permissions.length, + expectedPermissions.length, + `getAllByTypes returned the expected number of permissions for ${JSON.stringify( + permissionTypes + )}` + ); + + for (const perm of permissions) { + Assert.ok(perm != null); + + // For some reason, the order in which we get the permissions doesn't seem to be + // stable when running the test with --verify. As a result, we need to retrieve the + // expected permission for the origin and type. + const expectedPermission = expectedPermissions.find( + ([expectedPrincipal, expectedType]) => + perm.principal.equals(expectedPrincipal) && perm.type === expectedType + ); + + Assert.ok(expectedPermission !== null, "Found the expected permission"); + Assert.equal(perm.capability, expectedPermission[2]); + Assert.equal(perm.expireType, Services.perms.EXPIRE_NEVER); + } +} + +function run_test() { + let pm = Services.perms; + + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ); + let subPrincipal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://sub.example.com" + ); + + const PERM_TYPE_1 = "test/getallbytypes_1"; + const PERM_TYPE_2 = "test/getallbytypes_2"; + + info("check default state"); + check_enumerator([], []); + check_enumerator([PERM_TYPE_1], []); + check_enumerator([PERM_TYPE_2], []); + check_enumerator([PERM_TYPE_1, PERM_TYPE_2], []); + + info("check that expected permissions are retrieved"); + pm.addFromPrincipal(principal, PERM_TYPE_1, pm.ALLOW_ACTION); + pm.addFromPrincipal( + subPrincipal, + "other-test/getallbytypes_1", + pm.PROMPT_ACTION + ); + check_enumerator([PERM_TYPE_1], [[principal, PERM_TYPE_1, pm.ALLOW_ACTION]]); + check_enumerator( + [PERM_TYPE_1, PERM_TYPE_2], + [[principal, PERM_TYPE_1, pm.ALLOW_ACTION]] + ); + check_enumerator([], []); + check_enumerator([PERM_TYPE_2], []); + + pm.addFromPrincipal(subPrincipal, PERM_TYPE_1, pm.PROMPT_ACTION); + check_enumerator( + [PERM_TYPE_1], + [ + [subPrincipal, PERM_TYPE_1, pm.PROMPT_ACTION], + [principal, PERM_TYPE_1, pm.ALLOW_ACTION], + ] + ); + check_enumerator( + [PERM_TYPE_1, PERM_TYPE_2], + [ + [subPrincipal, PERM_TYPE_1, pm.PROMPT_ACTION], + [principal, PERM_TYPE_1, pm.ALLOW_ACTION], + ] + ); + check_enumerator([], []); + check_enumerator([PERM_TYPE_2], []); + + pm.addFromPrincipal(principal, PERM_TYPE_2, pm.PROMPT_ACTION); + check_enumerator( + [PERM_TYPE_1, PERM_TYPE_2], + [ + [subPrincipal, PERM_TYPE_1, pm.PROMPT_ACTION], + [principal, PERM_TYPE_1, pm.ALLOW_ACTION], + [principal, PERM_TYPE_2, pm.PROMPT_ACTION], + ] + ); + check_enumerator([], []); + check_enumerator([PERM_TYPE_2], [[principal, PERM_TYPE_2, pm.PROMPT_ACTION]]); + + info("check that UNKNOWN_ACTION permissions are ignored"); + pm.addFromPrincipal(subPrincipal, PERM_TYPE_2, pm.UNKNOWN_ACTION); + check_enumerator([PERM_TYPE_2], [[principal, PERM_TYPE_2, pm.PROMPT_ACTION]]); + + info("check that permission updates are reflected"); + pm.addFromPrincipal(subPrincipal, PERM_TYPE_2, pm.PROMPT_ACTION); + check_enumerator( + [PERM_TYPE_2], + [ + [subPrincipal, PERM_TYPE_2, pm.PROMPT_ACTION], + [principal, PERM_TYPE_2, pm.PROMPT_ACTION], + ] + ); + + info("check that permission removals are reflected"); + pm.removeFromPrincipal(principal, PERM_TYPE_1); + check_enumerator( + [PERM_TYPE_1], + [[subPrincipal, PERM_TYPE_1, pm.PROMPT_ACTION]] + ); + + pm.removeAll(); + check_enumerator([], []); + check_enumerator([PERM_TYPE_1], []); + check_enumerator([PERM_TYPE_2], []); + check_enumerator([PERM_TYPE_1, PERM_TYPE_2], []); +} diff --git a/extensions/permissions/test/unit/test_permmanager_getAllForPrincipal.js b/extensions/permissions/test/unit/test_permmanager_getAllForPrincipal.js new file mode 100644 index 0000000000..ad9db37c91 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_getAllForPrincipal.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function check_enumerator(principal, permissions) { + let perms = Services.perms.getAllForPrincipal(principal); + for (let [type, capability] of permissions) { + let perm = perms.shift(); + Assert.ok(perm != null); + Assert.equal(perm.type, type); + Assert.equal(perm.capability, capability); + Assert.equal(perm.expireType, Services.perms.EXPIRE_NEVER); + } + Assert.ok(!perms.length); +} + +function run_test() { + let pm = Services.perms; + + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ); + let subPrincipal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://sub.example.com" + ); + + check_enumerator(principal, []); + + pm.addFromPrincipal(principal, "test/getallforuri", pm.ALLOW_ACTION); + check_enumerator(principal, [["test/getallforuri", pm.ALLOW_ACTION]]); + + // check that uris are matched exactly + check_enumerator(subPrincipal, []); + + pm.addFromPrincipal(subPrincipal, "test/getallforuri", pm.PROMPT_ACTION); + pm.addFromPrincipal(subPrincipal, "test/getallforuri2", pm.DENY_ACTION); + + check_enumerator(subPrincipal, [ + ["test/getallforuri", pm.PROMPT_ACTION], + ["test/getallforuri2", pm.DENY_ACTION], + ]); + + // check that the original uri list has not changed + check_enumerator(principal, [["test/getallforuri", pm.ALLOW_ACTION]]); + + // check that UNKNOWN_ACTION permissions are ignored + pm.addFromPrincipal(principal, "test/getallforuri2", pm.UNKNOWN_ACTION); + pm.addFromPrincipal(principal, "test/getallforuri3", pm.DENY_ACTION); + + check_enumerator(principal, [ + ["test/getallforuri", pm.ALLOW_ACTION], + ["test/getallforuri3", pm.DENY_ACTION], + ]); + + // check that permission updates are reflected + pm.addFromPrincipal(principal, "test/getallforuri", pm.PROMPT_ACTION); + + check_enumerator(principal, [ + ["test/getallforuri", pm.PROMPT_ACTION], + ["test/getallforuri3", pm.DENY_ACTION], + ]); + + // check that permission removals are reflected + pm.removeFromPrincipal(principal, "test/getallforuri"); + + check_enumerator(principal, [["test/getallforuri3", pm.DENY_ACTION]]); + + pm.removeAll(); + check_enumerator(principal, []); + check_enumerator(subPrincipal, []); +} diff --git a/extensions/permissions/test/unit/test_permmanager_getAllWithTypePrefix.js b/extensions/permissions/test/unit/test_permmanager_getAllWithTypePrefix.js new file mode 100644 index 0000000000..e3708cf445 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_getAllWithTypePrefix.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function check_enumerator(prefix, permissions) { + let pm = Services.perms; + + let array = pm.getAllWithTypePrefix(prefix); + for (let [principal, type, capability] of permissions) { + let perm = array.shift(); + Assert.ok(perm != null); + Assert.ok(perm.principal.equals(principal)); + Assert.equal(perm.type, type); + Assert.equal(perm.capability, capability); + Assert.equal(perm.expireType, pm.EXPIRE_NEVER); + } + Assert.equal(array.length, 0); +} + +function run_test() { + let pm = Services.perms; + + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ); + let subPrincipal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://sub.example.com" + ); + + check_enumerator("test/", []); + + pm.addFromPrincipal(principal, "test/getallwithtypeprefix", pm.ALLOW_ACTION); + pm.addFromPrincipal( + subPrincipal, + "other-test/getallwithtypeprefix", + pm.PROMPT_ACTION + ); + check_enumerator("test/", [ + [principal, "test/getallwithtypeprefix", pm.ALLOW_ACTION], + ]); + + pm.addFromPrincipal( + subPrincipal, + "test/getallwithtypeprefix", + pm.PROMPT_ACTION + ); + check_enumerator("test/", [ + [subPrincipal, "test/getallwithtypeprefix", pm.PROMPT_ACTION], + [principal, "test/getallwithtypeprefix", pm.ALLOW_ACTION], + ]); + + check_enumerator("test/getallwithtypeprefix", [ + [subPrincipal, "test/getallwithtypeprefix", pm.PROMPT_ACTION], + [principal, "test/getallwithtypeprefix", pm.ALLOW_ACTION], + ]); + + // check that UNKNOWN_ACTION permissions are ignored + pm.addFromPrincipal( + principal, + "test/getallwithtypeprefix2", + pm.UNKNOWN_ACTION + ); + check_enumerator("test/", [ + [subPrincipal, "test/getallwithtypeprefix", pm.PROMPT_ACTION], + [principal, "test/getallwithtypeprefix", pm.ALLOW_ACTION], + ]); + + // check that permission updates are reflected + pm.addFromPrincipal(principal, "test/getallwithtypeprefix", pm.PROMPT_ACTION); + check_enumerator("test/", [ + [subPrincipal, "test/getallwithtypeprefix", pm.PROMPT_ACTION], + [principal, "test/getallwithtypeprefix", pm.PROMPT_ACTION], + ]); + + // check that permission removals are reflected + pm.removeFromPrincipal(principal, "test/getallwithtypeprefix"); + check_enumerator("test/", [ + [subPrincipal, "test/getallwithtypeprefix", pm.PROMPT_ACTION], + ]); + + pm.removeAll(); + check_enumerator("test/", []); +} diff --git a/extensions/permissions/test/unit/test_permmanager_getPermissionObject.js b/extensions/permissions/test/unit/test_permmanager_getPermissionObject.js new file mode 100644 index 0000000000..78ef9ab08a --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_getPermissionObject.js @@ -0,0 +1,98 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function getPrincipalFromURI(aURI) { + let ssm = Services.scriptSecurityManager; + let uri = NetUtil.newURI(aURI); + return ssm.createContentPrincipal(uri, {}); +} + +function getSystemPrincipal() { + return Services.scriptSecurityManager.getSystemPrincipal(); +} + +function run_test() { + var pm = Services.perms; + + Assert.equal( + null, + pm.getPermissionObject(getSystemPrincipal(), "test/pobject", false) + ); + + let principal = getPrincipalFromURI("http://example.com"); + let subPrincipal = getPrincipalFromURI("http://sub.example.com"); + let subSubPrincipal = getPrincipalFromURI("http://sub.sub.example.com"); + + Assert.equal(null, pm.getPermissionObject(principal, "test/pobject", false)); + Assert.equal(null, pm.getPermissionObject(principal, "test/pobject", true)); + + pm.addFromPrincipal(principal, "test/pobject", pm.ALLOW_ACTION); + var rootPerm = pm.getPermissionObject(principal, "test/pobject", false); + Assert.ok(rootPerm != null); + Assert.equal(rootPerm.principal.origin, "http://example.com"); + Assert.equal(rootPerm.type, "test/pobject"); + Assert.equal(rootPerm.capability, pm.ALLOW_ACTION); + Assert.equal(rootPerm.expireType, pm.EXPIRE_NEVER); + + Assert.ok(rootPerm != null); + Assert.equal(rootPerm.principal.origin, "http://example.com"); + + var subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true); + Assert.equal(null, subPerm); + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false); + Assert.ok(subPerm != null); + Assert.equal(subPerm.principal.origin, "http://example.com"); + Assert.equal(subPerm.type, "test/pobject"); + Assert.equal(subPerm.capability, pm.ALLOW_ACTION); + + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true); + Assert.equal(null, subPerm); + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false); + Assert.ok(subPerm != null); + Assert.equal(subPerm.principal.origin, "http://example.com"); + + pm.addFromPrincipal( + principal, + "test/pobject", + pm.DENY_ACTION, + pm.EXPIRE_SESSION + ); + + // make sure permission objects are not dynamic + Assert.equal(rootPerm.capability, pm.ALLOW_ACTION); + + // but do update on change + rootPerm = pm.getPermissionObject(principal, "test/pobject", true); + Assert.equal(rootPerm.capability, pm.DENY_ACTION); + Assert.equal(rootPerm.expireType, pm.EXPIRE_SESSION); + + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false); + Assert.equal(subPerm.principal.origin, "http://example.com"); + Assert.equal(subPerm.capability, pm.DENY_ACTION); + Assert.equal(subPerm.expireType, pm.EXPIRE_SESSION); + + pm.addFromPrincipal(subPrincipal, "test/pobject", pm.PROMPT_ACTION); + rootPerm = pm.getPermissionObject(principal, "test/pobject", true); + Assert.equal(rootPerm.principal.origin, "http://example.com"); + Assert.equal(rootPerm.capability, pm.DENY_ACTION); + + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true); + Assert.equal(subPerm.principal.origin, "http://sub.example.com"); + Assert.equal(subPerm.capability, pm.PROMPT_ACTION); + + subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false); + Assert.equal(subPerm.principal.origin, "http://sub.example.com"); + Assert.equal(subPerm.capability, pm.PROMPT_ACTION); + + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true); + Assert.equal(null, subPerm); + + subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false); + Assert.equal(subPerm.principal.origin, "http://sub.example.com"); + Assert.equal(subPerm.capability, pm.PROMPT_ACTION); + + pm.removeFromPrincipal(principal, "test/pobject"); + + rootPerm = pm.getPermissionObject(principal, "test/pobject", true); + Assert.equal(null, rootPerm); +} diff --git a/extensions/permissions/test/unit/test_permmanager_idn.js b/extensions/permissions/test/unit/test_permmanager_idn.js new file mode 100644 index 0000000000..5719131245 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_idn.js @@ -0,0 +1,75 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function getPrincipalFromDomain(aDomain) { + let ssm = Services.scriptSecurityManager; + let uri = NetUtil.newURI("http://" + aDomain); + return ssm.createContentPrincipal(uri, {}); +} + +function run_test() { + let pm = Services.perms; + let perm = "test-idn"; + + // We create three principal linked to IDN. + // One with just a domain, one with a subdomain and one with the TLD + // containing a UTF-8 character. + let mainDomainPrincipal = getPrincipalFromDomain("fôû.com"); + let subDomainPrincipal = getPrincipalFromDomain("fôô.bàr.com"); + let tldPrincipal = getPrincipalFromDomain("fôû.bàr.côm"); + + // We add those to the permission manager. + pm.addFromPrincipal(mainDomainPrincipal, perm, pm.ALLOW_ACTION, 0, 0); + pm.addFromPrincipal(subDomainPrincipal, perm, pm.ALLOW_ACTION, 0, 0); + pm.addFromPrincipal(tldPrincipal, perm, pm.ALLOW_ACTION, 0, 0); + + // They should obviously be there now.. + Assert.equal( + pm.testPermissionFromPrincipal(mainDomainPrincipal, perm), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subDomainPrincipal, perm), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(tldPrincipal, perm), + pm.ALLOW_ACTION + ); + + // We do the same thing with the puny-encoded versions of the IDN. + let punyMainDomainPrincipal = getPrincipalFromDomain("xn--f-xgav.com"); + let punySubDomainPrincipal = getPrincipalFromDomain( + "xn--f-xgaa.xn--br-jia.com" + ); + let punyTldPrincipal = getPrincipalFromDomain( + "xn--f-xgav.xn--br-jia.xn--cm-8ja" + ); + + // Those principals should have the permission granted too. + Assert.equal( + pm.testPermissionFromPrincipal(punyMainDomainPrincipal, perm), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(punySubDomainPrincipal, perm), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(punyTldPrincipal, perm), + pm.ALLOW_ACTION + ); + + // However, those two principals shouldn't be allowed because they are like + // the IDN but without the UT8-8 characters. + let witnessPrincipal = getPrincipalFromDomain("foo.com"); + Assert.equal( + pm.testPermissionFromPrincipal(witnessPrincipal, perm), + pm.UNKNOWN_ACTION + ); + witnessPrincipal = getPrincipalFromDomain("foo.bar.com"); + Assert.equal( + pm.testPermissionFromPrincipal(witnessPrincipal, perm), + pm.UNKNOWN_ACTION + ); +} diff --git a/extensions/permissions/test/unit/test_permmanager_ipc.js b/extensions/permissions/test/unit/test_permmanager_ipc.js new file mode 100644 index 0000000000..239cc5aeaf --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_ipc.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { ExtensionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/ExtensionXPCShellUtils.sys.mjs" +); + +add_task(async function test_permissions_sent_over_ipc_on_bloburl() { + const ssm = Services.scriptSecurityManager; + const pm = Services.perms; + + // setup a profile. + do_get_profile(); + + async function assertExpectedContentPage(contentPage) { + const [processType, remoteType, principalSpec] = await page.spawn( + [], + async () => { + return [ + Services.appinfo.processType, + Services.appinfo.remoteType, + this.content.document.nodePrincipal.spec, + ]; + } + ); + + equal( + processType, + Services.appinfo.PROCESS_TYPE_CONTENT, + "Got a content process" + ); + equal(remoteType, "file", "Got a file child process"); + equal(principalSpec, principal.spec, "Got the expected document principal"); + } + + function getChildProcessID(contentPage) { + return contentPage.spawn([], () => Services.appinfo.processID); + } + + async function assertHasAllowedPermission(contentPage, perm) { + const isPermissionAllowed = await contentPage.spawn( + [perm], + permName => + Services.perms.getPermissionObject( + this.content.document.nodePrincipal, + permName, + true + )?.capability === Services.perms.ALLOW_ACTION + ); + ok(isPermissionAllowed, `Permission "${perm}" allowed as expected`); + } + + let file = do_get_file(".", true); + let fileURI = Services.io.newFileURI(file); + const principal = ssm.createContentPrincipal(fileURI, {}); + info(`Add a test permission to the document principal: ${principal.spec}`); + pm.addFromPrincipal(principal, "test/perm", pm.ALLOW_ACTION); + + info("Test expected permission is propagated into the child process"); + let page = await ExtensionTestUtils.loadContentPage(fileURI.spec); + const childID1 = await getChildProcessID(page); + await assertExpectedContentPage(page); + await assertHasAllowedPermission(page, "test/perm"); + await page.close(); + + // Ensure this blob url does not prevent permissions to be propagated + // to a new child process. + info("Create a blob url for a non http/https principal"); + const blob = new Blob(); + const blobURL = URL.createObjectURL(blob); + ok(blobURL, "Got a blob URL"); + + info("Test expected permission is still propagated"); + page = await ExtensionTestUtils.loadContentPage(fileURI.spec); + const childID2 = await getChildProcessID(page); + await assertExpectedContentPage(page); + Assert.notEqual(childID1, childID2, "Got a new child process as expected"); + await assertHasAllowedPermission(page, "test/perm"); + await page.close(); + + URL.revokeObjectURL(blobURL); + + page = await ExtensionTestUtils.loadContentPage(fileURI.spec); + const childID3 = await getChildProcessID(page); + await assertExpectedContentPage(page); + Assert.notEqual(childID2, childID3, "Got a new child process as expected"); + await assertHasAllowedPermission(page, "test/perm"); + await page.close(); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_load_invalid_entries.js b/extensions/permissions/test/unit/test_permmanager_load_invalid_entries.js new file mode 100644 index 0000000000..decbce81a0 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_load_invalid_entries.js @@ -0,0 +1,264 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +var DEBUG_TEST = false; + +function run_test() { + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + // Setup a profile directory. + var dir = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + // Get the db file. + var file = dir.clone(); + file.append("permissions.sqlite"); + + var storage = Services.storage; + + // Create database. + var connection = storage.openDatabase(file); + // The file should now exist. + Assert.ok(file.exists()); + + connection.schemaVersion = 3; + connection.executeSimpleSQL("DROP TABLE moz_hosts"); + connection.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + // Now we can inject garbadge in the database. + var garbadge = [ + // Regular entry. + { + host: "42", + type: "0", + permission: 1, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + + // Special values in host (some being invalid). + { + host: "scheme:file", + type: "1", + permission: 0, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + { + host: "192.168.0.1", + type: "2", + permission: 0, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + { + host: "2001:0db8:0000:0000:0000:ff00:0042:8329", + type: "3", + permission: 0, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + { + host: "::1", + type: "4", + permission: 0, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + + // Permission is UNKNOWN_ACTION. + { + host: "42", + type: "5", + permission: Ci.nsIPermissionManager.UNKNOWN_ACTION, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + + // Permission is out of range. + { + host: "42", + type: "6", + permission: 100, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + { + host: "42", + type: "7", + permission: -100, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + + // ExpireType is out of range. + { + host: "42", + type: "8", + permission: 1, + expireType: -100, + expireTime: 0, + isInBrowserElement: 0, + }, + { + host: "42", + type: "9", + permission: 1, + expireType: 100, + expireTime: 0, + isInBrowserElement: 0, + }, + + // ExpireTime is at 0 with ExpireType = Time. + { + host: "42", + type: "10", + permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_TIME, + expireTime: 0, + isInBrowserElement: 0, + }, + + // ExpireTime has a value with ExpireType != Time + { + host: "42", + type: "11", + permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_SESSION, + expireTime: 1000, + isInBrowserElement: 0, + }, + { + host: "42", + type: "12", + permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_NEVER, + expireTime: 1000, + isInBrowserElement: 0, + }, + + // ExpireTime is negative. + { + host: "42", + type: "13", + permission: 1, + expireType: Ci.nsIPermissionManager.EXPIRE_TIME, + expireTime: -1, + isInBrowserElement: 0, + }, + + // IsInBrowserElement is negative or higher than 1. + { + host: "42", + type: "15", + permission: 1, + expireType: 0, + expireTime: 0, + isInBrowserElement: -1, + }, + { + host: "42", + type: "16", + permission: 1, + expireType: 0, + expireTime: 0, + isInBrowserElement: 10, + }, + + // This insertion should be the last one. It is used to make sure we always + // load it regardless of the previous entries validities. + { + host: "example.org", + type: "test-load-invalid-entries", + permission: Ci.nsIPermissionManager.ALLOW_ACTION, + expireType: 0, + expireTime: 0, + isInBrowserElement: 0, + }, + ]; + + for (var i = 0; i < garbadge.length; ++i) { + if (DEBUG_TEST) { + dump("\n value #" + i + "\n\n"); + } + var data = garbadge[i]; + connection.executeSimpleSQL( + "INSERT INTO moz_hosts " + + " (id, host, type, permission, expireType, expireTime, isInBrowserElement, appId) " + + "VALUES (" + + i + + ", '" + + data.host + + "', '" + + data.type + + "', " + + data.permission + + ", " + + data.expireType + + ", " + + data.expireTime + + ", " + + data.isInBrowserElement + + ", 0)" + ); + } + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Let's do something in order to be sure the DB is read. + Assert.greater(pm.all.length, 0); + + // The schema should be upgraded to 11, and a 'modificationTime' column should + // exist with all records having a value of 0. + Assert.equal(connection.schemaVersion, 12); + + let select = connection.createStatement( + "SELECT modificationTime FROM moz_perms" + ); + let numMigrated = 0; + while (select.executeStep()) { + let thisModTime = select.getInt64(0); + Assert.ok( + thisModTime > 0, + "new modifiedTime field is correct (but it's not 0!)" + ); + numMigrated += 1; + } + // check we found at least 1 record that was migrated. + Assert.greater( + numMigrated, + 0, + "we found at least 1 record that was migrated" + ); + + // This permission should always be there. + let ssm = Services.scriptSecurityManager; + let uri = NetUtil.newURI("http://example.org"); + let principal = ssm.createContentPrincipal(uri, {}); + Assert.equal( + pm.testPermissionFromPrincipal(principal, "test-load-invalid-entries"), + Ci.nsIPermissionManager.ALLOW_ACTION + ); +} diff --git a/extensions/permissions/test/unit/test_permmanager_local_files.js b/extensions/permissions/test/unit/test_permmanager_local_files.js new file mode 100644 index 0000000000..389eb77916 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_local_files.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that permissions work for file:// URIs (aka local files). + +function getPrincipalFromURIString(uriStr) { + let uri = NetUtil.newURI(uriStr); + return Services.scriptSecurityManager.createContentPrincipal(uri, {}); +} + +function run_test() { + let pm = Services.perms; + + // If we add a permission to a file:// URI, the test should return true. + let principal = getPrincipalFromURIString("file:///foo/bar"); + pm.addFromPrincipal(principal, "test/local-files", pm.ALLOW_ACTION, 0, 0); + Assert.equal( + pm.testPermissionFromPrincipal(principal, "test/local-files"), + pm.ALLOW_ACTION + ); + + // Another file:// URI should have the same permission. + let witnessPrincipal = getPrincipalFromURIString("file:///bar/foo"); + Assert.equal( + pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), + pm.UNKNOWN_ACTION + ); + + // Giving "file:///" a permission shouldn't give it to all file:// URIs. + let rootPrincipal = getPrincipalFromURIString("file:///"); + pm.addFromPrincipal(rootPrincipal, "test/local-files", pm.ALLOW_ACTION, 0, 0); + Assert.equal( + pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), + pm.UNKNOWN_ACTION + ); + + // Giving "file://" a permission shouldn't give it to all file:// URIs. + let schemeRootPrincipal = getPrincipalFromURIString("file://"); + pm.addFromPrincipal( + schemeRootPrincipal, + "test/local-files", + pm.ALLOW_ACTION, + 0, + 0 + ); + Assert.equal( + pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), + pm.UNKNOWN_ACTION + ); + + // Giving 'node' a permission shouldn't give it to its 'children'. + let fileInDirPrincipal = getPrincipalFromURIString( + "file:///foo/bar/foobar.txt" + ); + Assert.equal( + pm.testPermissionFromPrincipal(fileInDirPrincipal, "test/local-files"), + pm.UNKNOWN_ACTION + ); + + // Revert "file:///foo/bar" permission and check that it has been correctly taken into account. + pm.removeFromPrincipal(principal, "test/local-files"); + Assert.equal( + pm.testPermissionFromPrincipal(principal, "test/local-files"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(witnessPrincipal, "test/local-files"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(fileInDirPrincipal, "test/local-files"), + pm.UNKNOWN_ACTION + ); +} diff --git a/extensions/permissions/test/unit/test_permmanager_matches.js b/extensions/permissions/test/unit/test_permmanager_matches.js new file mode 100644 index 0000000000..937a1ce750 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_matches.js @@ -0,0 +1,203 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var attrs; + +function matches_always(perm, principals) { + principals.forEach(principal => { + Assert.ok( + perm.matches(principal, true), + "perm: " + perm.principal.origin + ", princ: " + principal.origin + ); + Assert.ok( + perm.matches(principal, false), + "perm: " + perm.principal.origin + ", princ: " + principal.origin + ); + }); +} + +function matches_weak(perm, principals) { + principals.forEach(principal => { + Assert.ok( + !perm.matches(principal, true), + "perm: " + perm.principal.origin + ", princ: " + principal.origin + ); + Assert.ok( + perm.matches(principal, false), + "perm: " + perm.principal.origin + ", princ: " + principal.origin + ); + }); +} + +function matches_never(perm, principals) { + principals.forEach(principal => { + Assert.ok( + !perm.matches(principal, true), + "perm: " + perm.principal.origin + ", princ: " + principal.origin + ); + Assert.ok( + !perm.matches(principal, false), + "perm: " + perm.principal.origin + ", princ: " + principal.origin + ); + }); +} + +function run_test() { + // initialize the permission manager service + let pm = Services.perms; + + let secMan = Services.scriptSecurityManager; + + // Add some permissions + let uri0 = NetUtil.newURI("http://google.com/search?q=foo#hashtag"); + let uri1 = NetUtil.newURI("http://hangouts.google.com/subdir"); + let uri2 = NetUtil.newURI("http://google.org/"); + let uri3 = NetUtil.newURI("https://google.com/some/random/subdirectory"); + let uri4 = NetUtil.newURI("https://hangouts.google.com/#!/hangout"); + let uri5 = NetUtil.newURI("http://google.com:8096/"); + + let uri0_n = secMan.createContentPrincipal(uri0, {}); + let uri1_n = secMan.createContentPrincipal(uri1, {}); + let uri2_n = secMan.createContentPrincipal(uri2, {}); + let uri3_n = secMan.createContentPrincipal(uri3, {}); + let uri4_n = secMan.createContentPrincipal(uri4, {}); + let uri5_n = secMan.createContentPrincipal(uri5, {}); + + attrs = { inIsolatedMozBrowser: true }; + let uri0_y_ = secMan.createContentPrincipal(uri0, attrs); + let uri1_y_ = secMan.createContentPrincipal(uri1, attrs); + let uri2_y_ = secMan.createContentPrincipal(uri2, attrs); + let uri3_y_ = secMan.createContentPrincipal(uri3, attrs); + let uri4_y_ = secMan.createContentPrincipal(uri4, attrs); + let uri5_y_ = secMan.createContentPrincipal(uri5, attrs); + + attrs = { userContextId: 1 }; + let uri0_1 = secMan.createContentPrincipal(uri0, attrs); + let uri1_1 = secMan.createContentPrincipal(uri1, attrs); + let uri2_1 = secMan.createContentPrincipal(uri2, attrs); + let uri3_1 = secMan.createContentPrincipal(uri3, attrs); + let uri4_1 = secMan.createContentPrincipal(uri4, attrs); + let uri5_1 = secMan.createContentPrincipal(uri5, attrs); + + attrs = { firstPartyDomain: "cnn.com" }; + let uri0_cnn = secMan.createContentPrincipal(uri0, attrs); + let uri1_cnn = secMan.createContentPrincipal(uri1, attrs); + let uri2_cnn = secMan.createContentPrincipal(uri2, attrs); + let uri3_cnn = secMan.createContentPrincipal(uri3, attrs); + let uri4_cnn = secMan.createContentPrincipal(uri4, attrs); + let uri5_cnn = secMan.createContentPrincipal(uri5, attrs); + + pm.addFromPrincipal(uri0_n, "test/matches", pm.ALLOW_ACTION); + let perm_n = pm.getPermissionObject(uri0_n, "test/matches", true); + pm.addFromPrincipal(uri0_y_, "test/matches", pm.ALLOW_ACTION); + let perm_y_ = pm.getPermissionObject(uri0_y_, "test/matches", true); + pm.addFromPrincipal(uri0_1, "test/matches", pm.ALLOW_ACTION); + let perm_1 = pm.getPermissionObject(uri0_n, "test/matches", true); + pm.addFromPrincipal(uri0_cnn, "test/matches", pm.ALLOW_ACTION); + let perm_cnn = pm.getPermissionObject(uri0_n, "test/matches", true); + + matches_always(perm_n, [uri0_n, uri0_1]); + matches_weak(perm_n, [uri1_n, uri1_1]); + matches_never(perm_n, [ + uri2_n, + uri3_n, + uri4_n, + uri5_n, + uri0_y_, + uri1_y_, + uri2_y_, + uri3_y_, + uri4_y_, + uri5_y_, + uri2_1, + uri3_1, + uri4_1, + uri5_1, + uri0_cnn, + uri1_cnn, + uri2_cnn, + uri3_cnn, + uri4_cnn, + uri5_cnn, + ]); + + matches_always(perm_y_, [uri0_y_]); + matches_weak(perm_y_, [uri1_y_]); + matches_never(perm_y_, [ + uri2_y_, + uri3_y_, + uri4_y_, + uri5_y_, + uri0_n, + uri1_n, + uri2_n, + uri3_n, + uri4_n, + uri5_n, + uri0_1, + uri1_1, + uri2_1, + uri3_1, + uri4_1, + uri5_1, + uri0_cnn, + uri1_cnn, + uri2_cnn, + uri3_cnn, + uri4_cnn, + uri5_cnn, + ]); + + matches_always(perm_1, [uri0_n, uri0_1]); + matches_weak(perm_1, [uri1_n, uri1_1]); + matches_never(perm_1, [ + uri2_n, + uri3_n, + uri4_n, + uri5_n, + uri0_y_, + uri1_y_, + uri2_y_, + uri3_y_, + uri4_y_, + uri5_y_, + uri2_1, + uri3_1, + uri4_1, + uri5_1, + uri0_cnn, + uri1_cnn, + uri2_cnn, + uri3_cnn, + uri4_cnn, + uri5_cnn, + ]); + + matches_always(perm_cnn, [uri0_n, uri0_1]); + matches_weak(perm_cnn, [uri1_n, uri1_1]); + matches_never(perm_cnn, [ + uri2_n, + uri3_n, + uri4_n, + uri5_n, + uri0_y_, + uri1_y_, + uri2_y_, + uri3_y_, + uri4_y_, + uri5_y_, + uri2_1, + uri3_1, + uri4_1, + uri5_1, + uri0_cnn, + uri1_cnn, + uri2_cnn, + uri3_cnn, + uri4_cnn, + uri5_cnn, + ]); + + // Clean up! + pm.removeAll(); +} diff --git a/extensions/permissions/test/unit/test_permmanager_matchesuri.js b/extensions/permissions/test/unit/test_permmanager_matchesuri.js new file mode 100644 index 0000000000..1218fbf9ca --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_matchesuri.js @@ -0,0 +1,252 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function matches_always(perm, uris) { + uris.forEach(uri => { + Assert.ok( + perm.matchesURI(uri, true), + "perm: " + perm.principal.origin + ", URI: " + uri.spec + ); + Assert.ok( + perm.matchesURI(uri, false), + "perm: " + perm.principal.origin + ", URI: " + uri.spec + ); + }); +} + +function matches_weak(perm, uris) { + uris.forEach(uri => { + Assert.ok( + !perm.matchesURI(uri, true), + "perm: " + perm.principal.origin + ", URI: " + uri.spec + ); + Assert.ok( + perm.matchesURI(uri, false), + "perm: " + perm.principal.origin + ", URI: " + uri.spec + ); + }); +} + +function matches_never(perm, uris) { + uris.forEach(uri => { + Assert.ok( + !perm.matchesURI(uri, true), + "perm: " + perm.principal.origin + ", URI: " + uri.spec + ); + Assert.ok( + !perm.matchesURI(uri, false), + "perm: " + perm.principal.origin + ", URI: " + uri.spec + ); + }); +} + +function mk_permission(uri) { + let pm = Services.perms; + + let secMan = Services.scriptSecurityManager; + + // Get the permission from the principal! + let principal = secMan.createContentPrincipal(uri, {}); + + pm.addFromPrincipal(principal, "test/matchesuri", pm.ALLOW_ACTION); + let permission = pm.getPermissionObject(principal, "test/matchesuri", true); + + return permission; +} + +function run_test() { + // initialize the permission manager service + let pm = Services.perms; + + let fileprefix = "file:///"; + if (Services.appinfo.OS == "WINNT") { + // Windows rejects files if they don't have a drive. See Bug 1180870 + fileprefix += "c:/"; + } + + // Add some permissions + let uri0 = NetUtil.newURI("http://google.com:9091/just/a/path"); + let uri1 = NetUtil.newURI("http://hangouts.google.com:9091/some/path"); + let uri2 = NetUtil.newURI("http://google.com:9091/"); + let uri3 = NetUtil.newURI("http://google.org:9091/"); + let uri4 = NetUtil.newURI("http://deeper.hangouts.google.com:9091/"); + let uri5 = NetUtil.newURI("https://google.com/just/a/path"); + let uri6 = NetUtil.newURI("https://hangouts.google.com"); + let uri7 = NetUtil.newURI("https://google.com/"); + + let fileuri1 = NetUtil.newURI(fileprefix + "a/file/path"); + let fileuri2 = NetUtil.newURI(fileprefix + "a/file/path/deeper"); + let fileuri3 = NetUtil.newURI(fileprefix + "a/file/otherpath"); + + { + let perm = mk_permission(uri0); + matches_always(perm, [uri0, uri2]); + matches_weak(perm, [uri1, uri4]); + matches_never(perm, [uri3, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri1); + matches_always(perm, [uri1]); + matches_weak(perm, [uri4]); + matches_never(perm, [ + uri0, + uri2, + uri3, + uri5, + uri6, + uri7, + fileuri1, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(uri2); + matches_always(perm, [uri0, uri2]); + matches_weak(perm, [uri1, uri4]); + matches_never(perm, [uri3, uri5, uri6, uri7, fileuri1, fileuri2, fileuri3]); + } + + { + let perm = mk_permission(uri3); + matches_always(perm, [uri3]); + matches_weak(perm, []); + matches_never(perm, [ + uri1, + uri2, + uri4, + uri5, + uri6, + uri7, + fileuri1, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(uri4); + matches_always(perm, [uri4]); + matches_weak(perm, []); + matches_never(perm, [ + uri1, + uri2, + uri3, + uri5, + uri6, + uri7, + fileuri1, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(uri5); + matches_always(perm, [uri5, uri7]); + matches_weak(perm, [uri6]); + matches_never(perm, [ + uri0, + uri1, + uri2, + uri3, + uri4, + fileuri1, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(uri6); + matches_always(perm, [uri6]); + matches_weak(perm, []); + matches_never(perm, [ + uri0, + uri1, + uri2, + uri3, + uri4, + uri5, + uri7, + fileuri1, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(uri7); + matches_always(perm, [uri5, uri7]); + matches_weak(perm, [uri6]); + matches_never(perm, [ + uri0, + uri1, + uri2, + uri3, + uri4, + fileuri1, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(fileuri1); + matches_always(perm, [fileuri1]); + matches_weak(perm, []); + matches_never(perm, [ + uri0, + uri1, + uri2, + uri3, + uri4, + uri5, + uri6, + uri7, + fileuri2, + fileuri3, + ]); + } + + { + let perm = mk_permission(fileuri2); + matches_always(perm, [fileuri2]); + matches_weak(perm, []); + matches_never(perm, [ + uri0, + uri1, + uri2, + uri3, + uri4, + uri5, + uri6, + uri7, + fileuri1, + fileuri3, + ]); + } + + { + let perm = mk_permission(fileuri3); + matches_always(perm, [fileuri3]); + matches_weak(perm, []); + matches_never(perm, [ + uri0, + uri1, + uri2, + uri3, + uri4, + uri5, + uri6, + uri7, + fileuri1, + fileuri2, + ]); + } + + // Clean up! + pm.removeAll(); +} diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_10-11.js b/extensions/permissions/test/unit/test_permmanager_migrate_10-11.js new file mode 100644 index 0000000000..c0d30865ee --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_10-11.js @@ -0,0 +1,196 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 10; + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + let id = 0; + + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + try { + stmt6Insert.execute(); + } finally { + stmt6Insert.reset(); + } + + return { + id: thisId, + origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + insertOrigin( + "https://foo.com", + "storageAccessAPI^https://foo.com", + 2, + 0, + 0, + 0 + ); + insertOrigin( + "http://foo.com", + "storageAccessAPI^https://bar.com^https://foo.com", + 2, + 0, + 0, + 0 + ); + insertOrigin( + "http://foo.com", + "storageAccessAPI^https://bar.com^https://baz.com", + 2, + 0, + 0, + 0 + ); + insertOrigin("http://foo.com^inBrowser=1", "A", 2, 0, 0, 0); + + // CLose the db connection + stmt6Insert.finalize(); + db.close(); + db = null; + + let expected = [ + ["https://foo.com", "storageAccessAPI^https://foo.com", 2, 0, 0, 0], + ["http://foo.com", "storageAccessAPI^https://bar.com", 2, 0, 0, 0], + ["http://foo.com", "storageAccessAPI^https://bar.com", 2, 0, 0, 0], + ["http://foo.com^inBrowser=1", "A", 2, 0, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + await PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080")); + await PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080")); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms"); + try { + mozPermsCount.executeStep(); + Assert.equal(mozPermsCount.getInt64(0), expected.length); + } finally { + mozPermsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_11-12.js b/extensions/permissions/test/unit/test_permmanager_migrate_11-12.js new file mode 100644 index 0000000000..97170a9240 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_11-12.js @@ -0,0 +1,230 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 11; + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + let id = 0; + + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + try { + stmt6Insert.execute(); + } finally { + stmt6Insert.reset(); + } + + return { + id: thisId, + origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + insertOrigin("https://a.com", "3rdPartyStorage^https://b.com", 2, 0, 0, 0); + insertOrigin( + "https://www.a.com", + "3rdPartyStorage^https://www.c.com", + 2, + 0, + 0, + 0 + ); + insertOrigin( + "https://localhost", + "3rdPartyStorage^http://www.c.com", + 2, + 0, + 0, + 0 + ); + + insertOrigin( + "https://www.b.co.uk", + "3rdPartyStorage^https://www.a.co.uk", + 2, + 0, + 0, + 0 + ); + + insertOrigin( + "https://sub.www.b.co.uk", + "3rdPartyStorage^https://sub.www.a.co.uk", + 2, + 0, + 0, + 0 + ); + + insertOrigin( + "https://example.b.co.uk", + "3rdPartyStorage^https://www.a.co.uk", + 2, + 0, + 0, + 0 + ); + + insertOrigin( + "https://[::1]", + "3rdPartyStorage^https://www.a.co.uk", + 2, + 0, + 0, + 0 + ); + // Close the db connection + stmt6Insert.finalize(); + db.close(); + db = null; + info(Services.perms.all); + + let expected = [ + ["https://a.com", "3rdPartyStorage^https://b.com", 2, 0, 0, 0], + ["https://a.com", "3rdPartyStorage^https://www.c.com", 2, 0, 0, 0], + ["https://localhost", "3rdPartyStorage^http://www.c.com", 2, 0, 0, 0], + ["https://b.co.uk", "3rdPartyStorage^https://www.a.co.uk", 2, 0, 0, 0], + ["https://b.co.uk", "3rdPartyStorage^https://sub.www.a.co.uk", 2, 0, 0, 0], + ["https://[::1]", "3rdPartyStorage^https://www.a.co.uk", 2, 0, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + await PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080")); + await PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080")); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + info(Services.perms.all); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + info(expected); + info(found); + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms"); + try { + mozPermsCount.executeStep(); + Assert.equal(mozPermsCount.getInt64(0), expected.length); + } finally { + mozPermsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_4-7.js b/extensions/permissions/test/unit/test_permmanager_migrate_4-7.js new file mode 100644 index 0000000000..857e0a462c --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_4-7.js @@ -0,0 +1,264 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 4; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")" + ); + + let id = 0; + + function insertHost( + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement + ) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + try { + stmtInsert.execute(); + } finally { + stmtInsert.reset(); + } + + return { + id: thisId, + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement, + }; + } + + // Add some rows to the database + // eslint-disable-next-line no-unused-vars + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost( + "moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", + "A", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost( + "moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", + "B", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // The http:// entries under foo.com won't be inserted, as there are history entries for foo.com, + // and http://foo.com or a subdomain are never visited. + // ["http://foo.com", "A", 1, 0, 0], + // ["http://foo.com^inBrowser=1", "A", 1, 0, 0], + // + // Because we search for port/scheme combinations under eTLD+1, we should not have http:// entries + // for subdomains of foo.com either + // ["http://sub.foo.com", "B", 1, 0, 0], + // ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Because we put ftp://some.subdomain.of.foo.com:8000/some/subdirectory in the history, we should + // also have these entries + ["ftp://foo.com:8000", "A", 1, 0, 0], + ["ftp://foo.com:8000", "C", 1, 0, 0], + ["ftp://foo.com:8000^inBrowser=1", "A", 1, 0, 0], + + // In addition, because we search for port/scheme combinations under eTLD+1, we should have the + // following entries + ["ftp://sub.foo.com:8000", "B", 1, 0, 0], + ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_4-7_no_history.js b/extensions/permissions/test/unit/test_permmanager_migrate_4-7_no_history.js new file mode 100644 index 0000000000..aa735e534a --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_4-7_no_history.js @@ -0,0 +1,279 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +/* + * Prevent the nsINavHistoryService from being avaliable for the migration + */ + +var CONTRACT_ID = "@mozilla.org/browser/nav-history-service;1"; +var factory = { + createInstance() { + throw new Error("There is no history service"); + }, + QueryInterface: ChromeUtils.generateQI(["nsIFactory"]), +}; + +var newClassID = Services.uuid.generateUUID(); + +var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); +var oldClassID = registrar.contractIDToCID(CONTRACT_ID); +// TODO: There was a var oldFactory = here causing linter errors as it +// was unused. We should check if this function call is needed at all. +Components.manager.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory); +registrar.registerFactory(newClassID, "", CONTRACT_ID, factory); + +function cleanupFactory() { + registrar.unregisterFactory(newClassID, factory); + registrar.registerFactory(oldClassID, "", CONTRACT_ID, null); +} + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +/* + * Done nsINavHistoryService code + */ + +add_task(function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // Make sure that we can't resolve the nsINavHistoryService + try { + Cc["@mozilla.org/browser/nav-history-service;1"].getService( + Ci.nsINavHistoryService + ); + Assert.ok(false, "There shouldn't have been a nsINavHistoryService"); + } catch (e) { + Assert.ok(true, "There wasn't a nsINavHistoryService"); + } + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.ok(pm.all.length >= 0, "Permission manager not initialized?"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 4; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")" + ); + + let id = 0; + + function insertHost( + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement + ) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + try { + stmtInsert.execute(); + } finally { + stmtInsert.reset(); + } + + return { + id: thisId, + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement, + }; + } + + // Add some rows to the database + // eslint-disable-next-line no-unused-vars + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("263.123.555.676", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost( + "moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", + "A", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost( + "moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", + "B", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + ["http://foo.com", "A", 1, 0, 0], + ["http://foo.com", "C", 1, 0, 0], + ["http://foo.com^inBrowser=1", "A", 1, 0, 0], + ["http://sub.foo.com", "B", 1, 0, 0], + ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://263.123.555.676", "A", 1, 0, 0], + ["https://263.123.555.676", "A", 1, 0, 0], + ]; + + let found = expected.map(it => 0); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + db.close(); + } + + cleanupFactory(); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_5-7a.js b/extensions/permissions/test/unit/test_permmanager_migrate_5-7a.js new file mode 100644 index 0000000000..8ea03d5e16 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_5-7a.js @@ -0,0 +1,365 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 5; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")" + ); + + let stmt5Insert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts_v4 (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts_v4 (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")" + ); + + let id = 0; + + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt5Insert.bindByName("id", thisId); + stmt5Insert.bindByName("origin", origin); + stmt5Insert.bindByName("type", type); + stmt5Insert.bindByName("permission", permission); + stmt5Insert.bindByName("expireType", expireType); + stmt5Insert.bindByName("expireTime", expireTime); + stmt5Insert.bindByName("modificationTime", modificationTime); + + try { + stmt5Insert.execute(); + } finally { + stmt5Insert.reset(); + } + + return { + id: thisId, + origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + function insertHost( + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement + ) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + try { + stmtInsert.execute(); + } finally { + stmtInsert.reset(); + } + + return { + id: thisId, + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement, + }; + } + + let created5 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^inBrowser=1", "A", 2, 0, 0, 0), + ]; + + // Add some rows to the database + // eslint-disable-next-line no-unused-vars + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost( + "moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", + "A", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost( + "moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", + "B", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmt5Insert.finalize(); + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // The http:// entries under foo.com won't be inserted, as there are history entries for foo.com, + // and http://foo.com or a subdomain are never visited. + // ["http://foo.com", "A", 1, 0, 0], + // ["http://foo.com^inBrowser=1", "A", 1, 0, 0], + // + // Because we search for port/scheme combinations under eTLD+1, we should not have http:// entries + // for subdomains of foo.com either + // ["http://sub.foo.com", "B", 1, 0, 0], + // ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Because we put ftp://some.subdomain.of.foo.com:8000/some/subdirectory in the history, we should + // also have these entries + ["ftp://foo.com:8000", "A", 1, 0, 0], + ["ftp://foo.com:8000", "C", 1, 0, 0], + ["ftp://foo.com:8000^inBrowser=1", "A", 1, 0, 0], + + // In addition, because we search for port/scheme combinations under eTLD+1, we should have the + // following entries + ["ftp://sub.foo.com:8000", "B", 1, 0, 0], + ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + // Check that the moz_perms_v6 table contains the backup of the entry we created + let mozPermsV6Stmt = db.createStatement( + "SELECT " + + "origin, type, permission, expireType, expireTime, modificationTime " + + "FROM moz_perms_v6 WHERE id = :id" + ); + try { + // Check that the moz_hosts table still contains the correct values. + created5.forEach(it => { + mozPermsV6Stmt.reset(); + mozPermsV6Stmt.bindByName("id", it.id); + mozPermsV6Stmt.executeStep(); + Assert.equal(mozPermsV6Stmt.getUTF8String(0), it.origin); + Assert.equal(mozPermsV6Stmt.getUTF8String(1), it.type); + Assert.equal(mozPermsV6Stmt.getInt64(2), it.permission); + Assert.equal(mozPermsV6Stmt.getInt64(3), it.expireType); + Assert.equal(mozPermsV6Stmt.getInt64(4), it.expireTime); + Assert.equal(mozPermsV6Stmt.getInt64(5), it.modificationTime); + }); + } finally { + mozPermsV6Stmt.finalize(); + } + + // Check that there are the right number of values + let mozPermsV6Count = db.createStatement( + "SELECT count(*) FROM moz_perms_v6" + ); + try { + mozPermsV6Count.executeStep(); + Assert.equal(mozPermsV6Count.getInt64(0), created5.length); + } finally { + mozPermsV6Count.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_5-7b.js b/extensions/permissions/test/unit/test_permmanager_migrate_5-7b.js new file mode 100644 index 0000000000..8c330effa9 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_5-7b.js @@ -0,0 +1,203 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 5; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")" + ); + + let stmt5Insert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + let id = 0; + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt5Insert.bindByName("id", thisId); + stmt5Insert.bindByName("origin", origin); + stmt5Insert.bindByName("type", type); + stmt5Insert.bindByName("permission", permission); + stmt5Insert.bindByName("expireType", expireType); + stmt5Insert.bindByName("expireTime", expireTime); + stmt5Insert.bindByName("modificationTime", modificationTime); + + try { + stmt5Insert.execute(); + } finally { + stmt5Insert.reset(); + } + + return { + id: thisId, + host: origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + // eslint-disable-next-line no-unused-vars + let created5 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + + insertOrigin("http://127.0.0.1", "B", 2, 0, 0, 0), + insertOrigin("http://localhost", "B", 2, 0, 0, 0), + ]; + + let created4 = []; // Didn't create any v4 entries, so the DB should be empty + + // CLose the db connection + stmt5Insert.finalize(); + db.close(); + stmt5Insert = null; + db = null; + + let expected = [ + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^inBrowser=1", "A", 2, 0, 0, 0], + + ["http://127.0.0.1", "B", 2, 0, 0, 0], + ["http://localhost", "B", 2, 0, 0, 0], + ]; + + let found = expected.map(it => 0); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + let mozHostsStmt = db.createStatement( + "SELECT " + + "host, type, permission, expireType, expireTime, " + + "modificationTime, isInBrowserElement " + + "FROM moz_hosts WHERE id = :id" + ); + try { + // Check that the moz_hosts table still contains the correct values. + created4.forEach(it => { + mozHostsStmt.reset(); + mozHostsStmt.bindByName("id", it.id); + mozHostsStmt.executeStep(); + Assert.equal(mozHostsStmt.getUTF8String(0), it.host); + Assert.equal(mozHostsStmt.getUTF8String(1), it.type); + Assert.equal(mozHostsStmt.getInt64(2), it.permission); + Assert.equal(mozHostsStmt.getInt64(3), it.expireType); + Assert.equal(mozHostsStmt.getInt64(4), it.expireTime); + Assert.equal(mozHostsStmt.getInt64(5), it.modificationTime); + Assert.equal(mozHostsStmt.getInt64(6), it.isInBrowserElement); + }); + } finally { + mozHostsStmt.finalize(); + } + + // Check that there are the right number of values + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), created4.length); + } finally { + mozHostsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_6-7a.js b/extensions/permissions/test/unit/test_permmanager_migrate_6-7a.js new file mode 100644 index 0000000000..93b78e6478 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_6-7a.js @@ -0,0 +1,366 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 6; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")" + ); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")" + ); + + let id = 0; + + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + try { + stmt6Insert.execute(); + } finally { + stmt6Insert.reset(); + } + + return { + id: thisId, + origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + function insertHost( + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement + ) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + try { + stmtInsert.execute(); + } finally { + stmtInsert.reset(); + } + + return { + id: thisId, + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement, + }; + } + + let created6 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^inBrowser=1", "A", 2, 0, 0, 0), + ]; + + // Add some rows to the database + // eslint-disable-next-line no-unused-vars + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost( + "moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", + "A", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost( + "moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", + "B", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmt6Insert.finalize(); + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // The http:// entries under foo.com won't be inserted, as there are history entries for foo.com, + // and http://foo.com or a subdomain are never visited. + // ["http://foo.com", "A", 1, 0, 0], + // ["http://foo.com^inBrowser=1", "A", 1, 0, 0], + // + // Because we search for port/scheme combinations under eTLD+1, we should not have http:// entries + // for subdomains of foo.com either + // ["http://sub.foo.com", "B", 1, 0, 0], + // ["http://subber.sub.foo.com", "B", 1, 0, 0], + + ["https://foo.com", "A", 1, 0, 0], + ["https://foo.com", "C", 1, 0, 0], + ["https://foo.com^inBrowser=1", "A", 1, 0, 0], + ["https://sub.foo.com", "B", 1, 0, 0], + ["https://subber.sub.foo.com", "B", 1, 0, 0], + + // bar.ca will have both http:// and https:// for all entries, because there are no associated history entries + ["http://bar.ca", "B", 1, 0, 0], + ["https://bar.ca", "B", 1, 0, 0], + ["http://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["https://bar.ca^inBrowser=1", "A", 1, 0, 0], + ["file:///some/path/to/file.html", "A", 1, 0, 0], + ["file:///another/file.html", "A", 1, 0, 0], + + // Because we put ftp://some.subdomain.of.foo.com:8000/some/subdirectory in the history, we should + // also have these entries + ["ftp://foo.com:8000", "A", 1, 0, 0], + ["ftp://foo.com:8000", "C", 1, 0, 0], + ["ftp://foo.com:8000^inBrowser=1", "A", 1, 0, 0], + + // In addition, because we search for port/scheme combinations under eTLD+1, we should have the + // following entries + ["ftp://sub.foo.com:8000", "B", 1, 0, 0], + ["ftp://subber.sub.foo.com:8000", "B", 1, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["http://localhost", "A", 1, 0, 0], + ["https://localhost", "A", 1, 0, 0], + ["http://127.0.0.1", "A", 1, 0, 0], + ["https://127.0.0.1", "A", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + ["https://192.0.2.235", "A", 1, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + // Check that the moz_perms_v6 table contains the backup of the entry we created + let mozPermsV6Stmt = db.createStatement( + "SELECT " + + "origin, type, permission, expireType, expireTime, modificationTime " + + "FROM moz_perms_v6 WHERE id = :id" + ); + try { + // Check that the moz_hosts table still contains the correct values. + created6.forEach(it => { + mozPermsV6Stmt.reset(); + mozPermsV6Stmt.bindByName("id", it.id); + mozPermsV6Stmt.executeStep(); + Assert.equal(mozPermsV6Stmt.getUTF8String(0), it.origin); + Assert.equal(mozPermsV6Stmt.getUTF8String(1), it.type); + Assert.equal(mozPermsV6Stmt.getInt64(2), it.permission); + Assert.equal(mozPermsV6Stmt.getInt64(3), it.expireType); + Assert.equal(mozPermsV6Stmt.getInt64(4), it.expireTime); + Assert.equal(mozPermsV6Stmt.getInt64(5), it.modificationTime); + }); + } finally { + mozPermsV6Stmt.finalize(); + } + + // Check that there are the right number of values + let mozPermsV6Count = db.createStatement( + "SELECT count(*) FROM moz_perms_v6" + ); + try { + mozPermsV6Count.executeStep(); + Assert.equal(mozPermsV6Count.getInt64(0), created6.length); + } finally { + mozPermsV6Count.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_6-7b.js b/extensions/permissions/test/unit/test_permmanager_migrate_6-7b.js new file mode 100644 index 0000000000..feed156d29 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_6-7b.js @@ -0,0 +1,199 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 6; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")" + ); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + let id = 0; + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + try { + stmt6Insert.execute(); + } finally { + stmt6Insert.reset(); + } + + return { + id: thisId, + host: origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + // eslint-disable-next-line no-unused-vars + let created6 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^appId=1000&inBrowser=1", "A", 2, 0, 0, 0), + ]; + + let created4 = []; // Didn't create any v4 entries, so the DB should be empty + + // CLose the db connection + stmt6Insert.finalize(); + db.close(); + stmt6Insert = null; + db = null; + + let expected = [ + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^inBrowser=1", "A", 2, 0, 0, 0], + ]; + + let found = expected.map(it => 0); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + let mozHostsStmt = db.createStatement( + "SELECT " + + "host, type, permission, expireType, expireTime, " + + "modificationTime, isInBrowserElement " + + "FROM moz_hosts WHERE id = :id" + ); + try { + // Check that the moz_hosts table still contains the correct values. + created4.forEach(it => { + mozHostsStmt.reset(); + mozHostsStmt.bindByName("id", it.id); + mozHostsStmt.executeStep(); + Assert.equal(mozHostsStmt.getUTF8String(0), it.host); + Assert.equal(mozHostsStmt.getUTF8String(1), it.type); + Assert.equal(mozHostsStmt.getInt64(2), it.permission); + Assert.equal(mozHostsStmt.getInt64(3), it.expireType); + Assert.equal(mozHostsStmt.getInt64(4), it.expireTime); + Assert.equal(mozHostsStmt.getInt64(5), it.modificationTime); + Assert.equal(mozHostsStmt.getInt64(6), it.isInBrowserElement); + }); + } finally { + mozHostsStmt.finalize(); + } + + // Check that there are the right number of values + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), created4.length); + } finally { + mozHostsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_7-8.js b/extensions/permissions/test/unit/test_permmanager_migrate_7-8.js new file mode 100644 index 0000000000..cd8b0f86cc --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_7-8.js @@ -0,0 +1,328 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 7; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE moz_hosts"); + + /* + * V5 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")" + ); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + /* + * V4 table + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")" + ); + + /* + * The v4 table is a backup + */ + db.executeSimpleSQL( + "CREATE TABLE moz_hosts_is_backup (dummy INTEGER PRIMARY KEY)" + ); + + let id = 0; + + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + try { + stmt6Insert.execute(); + } finally { + stmt6Insert.reset(); + } + + return { + id: thisId, + origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + function insertHost( + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement + ) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + try { + stmtInsert.execute(); + } finally { + stmtInsert.reset(); + } + + return { + id: thisId, + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement, + }; + } + // eslint-disable-next-line no-unused-vars + let created7 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^inBrowser=1", "A", 2, 0, 0, 0), + insertOrigin("https://192.0.2.235", "A", 2, 0, 0), + ]; + + // Add some rows to the database + // eslint-disable-next-line no-unused-vars + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "A", 1, 0, 0, 0, 2000, true), + insertHost("sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("subber.sub.foo.com", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 0, false), + insertHost("bar.ca", "B", 1, 0, 0, 0, 1000, false), + insertHost("bar.ca", "A", 1, 0, 0, 0, 1000, true), + insertHost("localhost", "A", 1, 0, 0, 0, 0, false), + insertHost("127.0.0.1", "A", 1, 0, 0, 0, 0, false), + insertHost("192.0.2.235", "A", 1, 0, 0, 0, 0, false), + // Although ipv6 addresses are written with [] around the IP address, + // the .host property doesn't contain these []s, which means that we + // write it like this + insertHost("2001:db8::ff00:42:8329", "C", 1, 0, 0, 0, 0, false), + insertHost("file:///some/path/to/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost("file:///another/file.html", "A", 1, 0, 0, 0, 0, false), + insertHost( + "moz-nullprincipal:{8695105a-adbe-4e4e-8083-851faa5ca2d7}", + "A", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost( + "moz-nullprincipal:{12ahjksd-akjs-asd3-8393-asdu2189asdu}", + "B", + 1, + 0, + 0, + 0, + 0, + false + ), + insertHost("", "A", 1, 0, 0, 0, 0, false), + insertHost("", "B", 1, 0, 0, 0, 0, false), + ]; + + // CLose the db connection + stmt6Insert.finalize(); + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + // We should have kept the previously migrated entries + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^inBrowser=1", "A", 2, 0, 0, 0], + + // Make sure that we also support localhost, and IP addresses + ["https://localhost:8080", "A", 1, 0, 0], + ["ftp://127.0.0.1:8080", "A", 1, 0, 0], + + ["http://[2001:db8::ff00:42:8329]", "C", 1, 0, 0], + ["https://[2001:db8::ff00:42:8329]", "C", 1, 0, 0], + ["http://192.0.2.235", "A", 1, 0, 0], + + // There should only be one entry of this type in the database + ["https://192.0.2.235", "A", 2, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + await PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080")); + await PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080")); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_hosts_is_backup")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + // The moz_hosts table should still exist but be empty + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 0); + } finally { + mozHostsCount.finalize(); + } + + // Check that there are the right number of values in the permissions database + let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms"); + try { + mozPermsCount.executeStep(); + Assert.equal(mozPermsCount.getInt64(0), expected.length); + } finally { + mozPermsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_migrate_9-10.js b/extensions/permissions/test/unit/test_permmanager_migrate_9-10.js new file mode 100644 index 0000000000..02aa3bb467 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_migrate_9-10.js @@ -0,0 +1,262 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +var PERMISSIONS_FILE_NAME = "permissions.sqlite"; + +function GetPermissionsFile(profile) { + let file = profile.clone(); + file.append(PERMISSIONS_FILE_NAME); + return file; +} + +add_task(async function test() { + // Create and set up the permissions database. + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + let profile = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.equal(pm.all.length, 0, "No cookies"); + + let db = Services.storage.openDatabase(GetPermissionsFile(profile)); + db.schemaVersion = 9; + db.executeSimpleSQL("DROP TABLE moz_perms"); + db.executeSimpleSQL("DROP TABLE IF EXISTS moz_hosts"); + + db.executeSimpleSQL( + "CREATE TABLE moz_perms (" + + " id INTEGER PRIMARY KEY" + + ",origin TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ")" + ); + + let stmt6Insert = db.createStatement( + "INSERT INTO moz_perms (" + + "id, origin, type, permission, expireType, expireTime, modificationTime" + + ") VALUES (" + + ":id, :origin, :type, :permission, :expireType, :expireTime, :modificationTime" + + ")" + ); + + db.executeSimpleSQL( + "CREATE TABLE moz_hosts (" + + " id INTEGER PRIMARY KEY" + + ",host TEXT" + + ",type TEXT" + + ",permission INTEGER" + + ",expireType INTEGER" + + ",expireTime INTEGER" + + ",modificationTime INTEGER" + + ",appId INTEGER" + + ",isInBrowserElement INTEGER" + + ")" + ); + + let stmtInsert = db.createStatement( + "INSERT INTO moz_hosts (" + + "id, host, type, permission, expireType, expireTime, modificationTime, appId, isInBrowserElement" + + ") VALUES (" + + ":id, :host, :type, :permission, :expireType, :expireTime, :modificationTime, :appId, :isInBrowserElement" + + ")" + ); + + let id = 0; + + function insertOrigin( + origin, + type, + permission, + expireType, + expireTime, + modificationTime + ) { + let thisId = id++; + + stmt6Insert.bindByName("id", thisId); + stmt6Insert.bindByName("origin", origin); + stmt6Insert.bindByName("type", type); + stmt6Insert.bindByName("permission", permission); + stmt6Insert.bindByName("expireType", expireType); + stmt6Insert.bindByName("expireTime", expireTime); + stmt6Insert.bindByName("modificationTime", modificationTime); + + try { + stmt6Insert.execute(); + } finally { + stmt6Insert.reset(); + } + + return { + id: thisId, + origin, + type, + permission, + expireType, + expireTime, + modificationTime, + }; + } + + function insertHost( + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement + ) { + let thisId = id++; + + stmtInsert.bindByName("id", thisId); + stmtInsert.bindByName("host", host); + stmtInsert.bindByName("type", type); + stmtInsert.bindByName("permission", permission); + stmtInsert.bindByName("expireType", expireType); + stmtInsert.bindByName("expireTime", expireTime); + stmtInsert.bindByName("modificationTime", modificationTime); + stmtInsert.bindByName("appId", appId); + stmtInsert.bindByName("isInBrowserElement", isInBrowserElement); + + try { + stmtInsert.execute(); + } finally { + stmtInsert.reset(); + } + + return { + id: thisId, + host, + type, + permission, + expireType, + expireTime, + modificationTime, + appId, + isInBrowserElement, + }; + } + // eslint-disable-next-line no-unused-vars + let created7 = [ + insertOrigin("https://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com", "A", 2, 0, 0, 0), + insertOrigin("http://foo.com^inBrowser=1", "A", 2, 0, 0, 0), + ]; + + // Add some rows to the database + // eslint-disable-next-line no-unused-vars + let created = [ + insertHost("foo.com", "A", 1, 0, 0, 0, 0, false), + insertHost("foo.com", "B", 1, 0, 0, 0, 1000, false), + insertHost("foo.com", "C", 1, 0, 0, 0, 2000, true), + ]; + + // CLose the db connection + stmt6Insert.finalize(); + stmtInsert.finalize(); + db.close(); + stmtInsert = null; + db = null; + + let expected = [ + ["https://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com", "A", 2, 0, 0, 0], + ["http://foo.com^inBrowser=1", "A", 2, 0, 0, 0], + ]; + + let found = expected.map(it => 0); + + // Add some places to the places database + await PlacesTestUtils.addVisits( + Services.io.newURI("https://foo.com/some/other/subdirectory") + ); + await PlacesTestUtils.addVisits( + Services.io.newURI("ftp://some.subdomain.of.foo.com:8000/some/subdirectory") + ); + await PlacesTestUtils.addVisits(Services.io.newURI("ftp://127.0.0.1:8080")); + await PlacesTestUtils.addVisits(Services.io.newURI("https://localhost:8080")); + + // This will force the permission-manager to reload the data. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Force initialization of the PermissionManager + for (let permission of Services.perms.all) { + let isExpected = false; + + expected.forEach((it, i) => { + if ( + permission.principal.origin == it[0] && + permission.type == it[1] && + permission.capability == it[2] && + permission.expireType == it[3] && + permission.expireTime == it[4] + ) { + isExpected = true; + found[i]++; + } + }); + + Assert.ok( + isExpected, + "Permission " + + (isExpected ? "should" : "shouldn't") + + " be in permission database: " + + permission.principal.origin + + ", " + + permission.type + + ", " + + permission.capability + + ", " + + permission.expireType + + ", " + + permission.expireTime + ); + } + + found.forEach((count, i) => { + Assert.ok( + count == 1, + "Expected count = 1, got count = " + + count + + " for permission " + + expected[i] + ); + }); + + // Check to make sure that all of the tables which we care about are present + { + db = Services.storage.openDatabase(GetPermissionsFile(profile)); + Assert.ok(db.tableExists("moz_perms")); + Assert.ok(db.tableExists("moz_hosts")); + Assert.ok(!db.tableExists("moz_perms_v6")); + + let mozHostsCount = db.createStatement("SELECT count(*) FROM moz_hosts"); + try { + mozHostsCount.executeStep(); + Assert.equal(mozHostsCount.getInt64(0), 3); + } finally { + mozHostsCount.finalize(); + } + + let mozPermsCount = db.createStatement("SELECT count(*) FROM moz_perms"); + try { + mozPermsCount.executeStep(); + Assert.equal(mozPermsCount.getInt64(0), expected.length); + } finally { + mozPermsCount.finalize(); + } + + db.close(); + } +}); diff --git a/extensions/permissions/test/unit/test_permmanager_notifications.js b/extensions/permissions/test/unit/test_permmanager_notifications.js new file mode 100644 index 0000000000..fb851aa04b --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_notifications.js @@ -0,0 +1,139 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that the permissionmanager 'added', 'changed', 'deleted', and 'cleared' +// notifications behave as expected. + +var test_generator = do_run_test(); + +function run_test() { + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + do_test_pending(); + test_generator.next(); +} + +function* do_run_test() { + let pm = Services.perms; + let now = Number(Date.now()); + let permType = "test/expiration-perm"; + let ssm = Services.scriptSecurityManager; + let uri = NetUtil.newURI("http://example.com"); + let principal = ssm.createContentPrincipal(uri, {}); + + let observer = new permission_observer(test_generator, now, permType); + Services.obs.addObserver(observer, "perm-changed"); + + // Add a permission, to test the 'add' notification. Note that we use + // do_execute_soon() so that we can use our generator to continue the test + // where we left off. + executeSoon(function () { + pm.addFromPrincipal( + principal, + permType, + pm.ALLOW_ACTION, + pm.EXPIRE_TIME, + now + 100000 + ); + }); + yield; + + // Alter a permission, to test the 'changed' notification. + executeSoon(function () { + pm.addFromPrincipal( + principal, + permType, + pm.ALLOW_ACTION, + pm.EXPIRE_TIME, + now + 200000 + ); + }); + yield; + + // Remove a permission, to test the 'deleted' notification. + executeSoon(function () { + pm.removeFromPrincipal(principal, permType); + }); + yield; + + // Clear permissions, to test the 'cleared' notification. + executeSoon(function () { + pm.removeAll(); + }); + yield; + + Services.obs.removeObserver(observer, "perm-changed"); + Assert.equal(observer.adds, 1); + Assert.equal(observer.changes, 1); + Assert.equal(observer.deletes, 1); + Assert.ok(observer.cleared); + + do_finish_generator_test(test_generator); +} + +function permission_observer(generator, now, type) { + // Set up our observer object. + this.generator = generator; + this.pm = Services.perms; + this.now = now; + this.type = type; + this.adds = 0; + this.changes = 0; + this.deletes = 0; + this.cleared = false; +} + +permission_observer.prototype = { + observe(subject, topic, data) { + Assert.equal(topic, "perm-changed"); + + // "deleted" means a permission was deleted. aPermission is the deleted permission. + // "added" means a permission was added. aPermission is the added permission. + // "changed" means a permission was altered. aPermission is the new permission. + // "cleared" means the entire permission list was cleared. aPermission is null. + if (data == "added") { + let perm = subject.QueryInterface(Ci.nsIPermission); + this.adds++; + switch (this.adds) { + case 1: + Assert.equal(this.type, perm.type); + Assert.equal(this.pm.EXPIRE_TIME, perm.expireType); + Assert.equal(this.now + 100000, perm.expireTime); + break; + default: + do_throw("too many add notifications posted."); + } + } else if (data == "changed") { + let perm = subject.QueryInterface(Ci.nsIPermission); + this.changes++; + switch (this.changes) { + case 1: + Assert.equal(this.type, perm.type); + Assert.equal(this.pm.EXPIRE_TIME, perm.expireType); + Assert.equal(this.now + 200000, perm.expireTime); + break; + default: + do_throw("too many change notifications posted."); + } + } else if (data == "deleted") { + let perm = subject.QueryInterface(Ci.nsIPermission); + this.deletes++; + switch (this.deletes) { + case 1: + Assert.equal(this.type, perm.type); + break; + default: + do_throw("too many delete notifications posted."); + } + } else if (data == "cleared") { + // only clear once: at the end + Assert.ok(!this.cleared); + Assert.equal(do_count_array(Services.perms.all), 0); + this.cleared = true; + } else { + do_throw("unexpected data '" + data + "'!"); + } + + // Continue the test. + do_run_generator(this.generator); + }, +}; diff --git a/extensions/permissions/test/unit/test_permmanager_oa_strip.js b/extensions/permissions/test/unit/test_permmanager_oa_strip.js new file mode 100644 index 0000000000..d6c15bd807 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_oa_strip.js @@ -0,0 +1,220 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TEST_URI = Services.io.newURI("http://example.com"); +const TEST_PERMISSION = "test/oastrip"; +const TEST_PERMISSION2 = "test/oastrip2"; +const TEST_PERMISSION3 = "test/oastrip3"; + +// List of permissions which are not isolated by private browsing or user context +// as per array kStripOAPermissions in PermissionManager.cpp +const STRIPPED_PERMS = ["cookie"]; + +let principal = Services.scriptSecurityManager.createContentPrincipal( + TEST_URI, + {} +); +let principalPrivateBrowsing = + Services.scriptSecurityManager.createContentPrincipal(TEST_URI, { + privateBrowsingId: 1, + }); +let principalUserContext1 = + Services.scriptSecurityManager.createContentPrincipal(TEST_URI, { + userContextId: 1, + }); +let principalUserContext2 = + Services.scriptSecurityManager.createContentPrincipal(TEST_URI, { + userContextId: 2, + }); + +function testOAIsolation(permIsolateUserContext, permIsolatePrivateBrowsing) { + info( + `testOAIsolation: permIsolateUserContext: ${permIsolateUserContext}; permIsolatePrivateBrowsing: ${permIsolatePrivateBrowsing}` + ); + + let pm = Services.perms; + + Services.prefs.setBoolPref( + "permissions.isolateBy.userContext", + permIsolateUserContext + ); + Services.prefs.setBoolPref( + "permissions.isolateBy.privateBrowsing", + permIsolatePrivateBrowsing + ); + + // Set test permission for normal browsing + pm.addFromPrincipal(principal, TEST_PERMISSION, pm.ALLOW_ACTION); + + // Check normal browsing permission + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + // normal browsing => user context 1 + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principalUserContext1, TEST_PERMISSION) + ); + // normal browsing => user context 2 + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principalUserContext2, TEST_PERMISSION) + ); + // normal browsing => private browsing + Assert.equal( + permIsolatePrivateBrowsing + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principalPrivateBrowsing, TEST_PERMISSION) + ); + + // Set permission for private browsing + pm.addFromPrincipal( + principalPrivateBrowsing, + TEST_PERMISSION2, + pm.DENY_ACTION + ); + + // Check private browsing permission + Assert.equal( + Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principalPrivateBrowsing, TEST_PERMISSION2) + ); + // private browsing => normal browsing + Assert.equal( + permIsolatePrivateBrowsing + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION2) + ); + // private browsing => user context 1 + Assert.equal( + permIsolatePrivateBrowsing || permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principalUserContext1, TEST_PERMISSION2) + ); + // private browsing => user context 2 + Assert.equal( + permIsolatePrivateBrowsing || permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.DENY_ACTION, + pm.testPermissionFromPrincipal(principalUserContext2, TEST_PERMISSION2) + ); + + // Set permission for user context 1 + pm.addFromPrincipal( + principalUserContext1, + TEST_PERMISSION3, + pm.PROMPT_ACTION + ); + + // Check user context 1 permission + Assert.equal( + Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principalUserContext1, TEST_PERMISSION3) + ); + + // user context 1 => normal browsing + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION3) + ); + // user context 1 => user context 2 + Assert.equal( + permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principalUserContext2, TEST_PERMISSION3) + ); + // user context 1 => private browsing + Assert.equal( + permIsolatePrivateBrowsing || permIsolateUserContext + ? Ci.nsIPermissionManager.UNKNOWN_ACTION + : Ci.nsIPermissionManager.PROMPT_ACTION, + pm.testPermissionFromPrincipal(principalPrivateBrowsing, TEST_PERMISSION3) + ); + + pm.removeAll(); + + // Modifying an non-isolated/stripped permission should affect all browsing contexts, + // independently of permission isolation pref state + STRIPPED_PERMS.forEach(perm => { + info("Testing stripped permission " + perm); + + // Add a permission for the normal window + pm.addFromPrincipal(principal, perm, pm.ALLOW_ACTION); + Assert.equal( + pm.testPermissionFromPrincipal(principalPrivateBrowsing, perm), + Ci.nsIPermissionManager.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(principalUserContext1, perm), + Ci.nsIPermissionManager.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(principalUserContext2, perm), + Ci.nsIPermissionManager.ALLOW_ACTION + ); + + // Remove the permission from private window + pm.removeFromPrincipal(principalPrivateBrowsing, perm); + Assert.equal( + pm.testPermissionFromPrincipal(principal, perm), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(principalUserContext1, perm), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(principalUserContext2, perm), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + + // Set a permission for a normal window and then override it by adding it to container 2 again + pm.addFromPrincipal(principal, perm, pm.PROMPT_ACTION); + pm.addFromPrincipal(principal, TEST_PERMISSION, pm.ALLOW_ACTION); + pm.addFromPrincipal(principalUserContext2, perm, pm.DENY_ACTION); + + let principalPerms = pm.getAllForPrincipal(principalPrivateBrowsing, perm); + + Assert.ok( + principalPerms.some(p => p.type == perm && p.capability == pm.DENY_ACTION) + ); + if (permIsolatePrivateBrowsing) { + Assert.equal(principalPerms.length, 1); + Assert.ok( + principalPerms.some( + p => p.type == perm && p.capability == pm.DENY_ACTION + ) + ); + } else { + Assert.equal(principalPerms.length, 2); + Assert.ok( + principalPerms.some( + p => p.type == TEST_PERMISSION && p.capability == pm.ALLOW_ACTION + ) + ); + } + }); + + // Cleanup + pm.removeAll(); +} + +add_task(async function do_test() { + // Test all pref combinations and check if principals with different origin attributes + // are isolated. + testOAIsolation(true, true); + testOAIsolation(true, false); + testOAIsolation(false, true); + testOAIsolation(false, false); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_remove_add_update.js b/extensions/permissions/test/unit/test_permmanager_remove_add_update.js new file mode 100644 index 0000000000..6ec7b1f6e5 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_remove_add_update.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function check_enumerator(principal, permissions) { + let perms = Services.perms.getAllForPrincipal(principal); + for (let [type, capability, expireType] of permissions) { + let perm = perms.shift(); + Assert.ok(perm != null); + Assert.equal(perm.type, type); + Assert.equal(perm.capability, capability); + Assert.equal(perm.expireType, expireType); + } + Assert.ok(!perms.length); +} + +add_task(async function test() { + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + + // setup a profile directory + do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.ok(pm.all.length === 0); + + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://example.com" + ); + + info("From session to persistent"); + pm.addFromPrincipal( + principal, + "test/foo", + pm.ALLOW_ACTION, + pm.EXPIRE_SESSION + ); + + check_enumerator(principal, [ + ["test/foo", pm.ALLOW_ACTION, pm.EXPIRE_SESSION], + ]); + + pm.addFromPrincipal(principal, "test/foo", pm.ALLOW_ACTION, pm.EXPIRE_NEVER); + + check_enumerator(principal, [["test/foo", pm.ALLOW_ACTION, pm.EXPIRE_NEVER]]); + + // Let's reload the DB. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + Assert.ok(pm.all.length === 1); + check_enumerator(principal, [["test/foo", pm.ALLOW_ACTION, pm.EXPIRE_NEVER]]); + + info("From persistent to session"); + pm.addFromPrincipal( + principal, + "test/foo", + pm.ALLOW_ACTION, + pm.EXPIRE_SESSION + ); + + check_enumerator(principal, [ + ["test/foo", pm.ALLOW_ACTION, pm.EXPIRE_SESSION], + ]); + + // Let's reload the DB. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + Assert.ok(pm.all.length === 0); + + info("From persistent to persistent"); + pm.addFromPrincipal(principal, "test/foo", pm.ALLOW_ACTION, pm.EXPIRE_NEVER); + pm.addFromPrincipal(principal, "test/foo", pm.DENY_ACTION, pm.EXPIRE_NEVER); + + check_enumerator(principal, [["test/foo", pm.DENY_ACTION, pm.EXPIRE_NEVER]]); + + // Let's reload the DB. + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + Assert.ok(pm.all.length === 1); + check_enumerator(principal, [["test/foo", pm.DENY_ACTION, pm.EXPIRE_NEVER]]); + + info("Cleanup"); + pm.removeAll(); + check_enumerator(principal, []); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_removeall.js b/extensions/permissions/test/unit/test_permmanager_removeall.js new file mode 100644 index 0000000000..e6faea1369 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_removeall.js @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function test() { + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + // setup a profile directory + var dir = do_get_profile(); + + // We need to execute a pm method to be sure that the DB is fully + // initialized. + var pm = Services.perms; + Assert.ok(pm.all.length === 0); + + Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); + + // Let's force the completion of the DB reading. + Assert.ok(pm.all.length === 0); + + // get the db file + var file = dir.clone(); + file.append("permissions.sqlite"); + + Assert.ok(file.exists()); + + // corrupt the file + var ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance( + Ci.nsIFileOutputStream + ); + ostream.init(file, 0x02, 0o666, 0); + var conv = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance( + Ci.nsIConverterOutputStream + ); + conv.init(ostream, "UTF-8"); + for (var i = 0; i < file.fileSize; ++i) { + conv.writeString("a"); + } + conv.close(); + + // prepare an empty hostperm.1 file so that it can be used for importing + var hostperm = dir.clone(); + hostperm.append("hostperm.1"); + ostream.init(hostperm, 0x02 | 0x08, 0o666, 0); + ostream.close(); + + // remove all should not throw + pm.removeAll(); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_removebytype.js b/extensions/permissions/test/unit/test_permmanager_removebytype.js new file mode 100644 index 0000000000..127e0de6ec --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_removebytype.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + + // initialize the permission manager service + let pm = Services.perms; + + Assert.equal(pm.all.length, 0); + + // add some permissions + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://amazon.com:8080" + ); + let principal2 = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://google.com:2048" + ); + let principal3 = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://google.com" + ); + + pm.addFromPrincipal(principal, "apple", 3); + pm.addFromPrincipal(principal, "pear", 1); + pm.addFromPrincipal(principal, "cucumber", 1); + + pm.addFromPrincipal(principal2, "apple", 2); + pm.addFromPrincipal(principal2, "pear", 2); + + pm.addFromPrincipal(principal3, "cucumber", 3); + pm.addFromPrincipal(principal3, "apple", 1); + + Assert.equal(pm.all.length, 7); + + pm.removeByType("apple"); + Assert.equal(pm.all.length, 4); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "pear"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "pear"), 2); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "apple"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "cucumber"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "cucumber"), 3); + + pm.removeByType("cucumber"); + Assert.equal(pm.all.length, 2); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "pear"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "pear"), 2); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "apple"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "cucumber"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "cucumber"), 0); + + pm.removeByType("pear"); + Assert.equal(pm.all.length, 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "pear"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "pear"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "apple"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "cucumber"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "cucumber"), 0); +} diff --git a/extensions/permissions/test/unit/test_permmanager_removebytypesince.js b/extensions/permissions/test/unit/test_permmanager_removebytypesince.js new file mode 100644 index 0000000000..4c392501d7 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_removebytypesince.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function test() { + Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + + // initialize the permission manager service + let pm = Services.perms; + + Assert.equal(pm.all.length, 0); + + // add some permissions + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://amazon.com:8080" + ); + let principal2 = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://google.com:2048" + ); + let principal3 = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "https://google.com" + ); + + pm.addFromPrincipal(principal, "apple", 3); + pm.addFromPrincipal(principal, "pear", 1); + pm.addFromPrincipal(principal, "cucumber", 1); + + // sleep briefly, then record the time - we'll remove some permissions since then. + await new Promise(resolve => do_timeout(20, resolve)); + + let since = Date.now(); + + // *sob* - on Windows at least, the now recorded by PermissionManager.cpp + // might be a couple of ms *earlier* than what JS sees. So another sleep + // to ensure our |since| is greater than the time of the permissions we + // are now adding. Sadly this means we'll never be able to test when since + // exactly equals the modTime, but there you go... + await new Promise(resolve => do_timeout(20, resolve)); + + pm.addFromPrincipal(principal2, "apple", 2); + pm.addFromPrincipal(principal2, "pear", 2); + + pm.addFromPrincipal(principal3, "cucumber", 3); + pm.addFromPrincipal(principal3, "apple", 1); + + Assert.equal(pm.all.length, 7); + + pm.removeByTypeSince("apple", since); + + Assert.equal(pm.all.length, 5); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "pear"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "pear"), 2); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "apple"), 3); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "apple"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "cucumber"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "cucumber"), 3); + + pm.removeByTypeSince("cucumber", since); + Assert.equal(pm.all.length, 4); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "pear"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "pear"), 2); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "apple"), 3); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "apple"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "cucumber"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "cucumber"), 0); + + pm.removeByTypeSince("pear", since); + Assert.equal(pm.all.length, 3); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "pear"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "pear"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "apple"), 3); + Assert.equal(pm.testPermissionFromPrincipal(principal2, "apple"), 0); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "apple"), 0); + + Assert.equal(pm.testPermissionFromPrincipal(principal, "cucumber"), 1); + Assert.equal(pm.testPermissionFromPrincipal(principal3, "cucumber"), 0); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_removepermission.js b/extensions/permissions/test/unit/test_permmanager_removepermission.js new file mode 100644 index 0000000000..50b2c3105b --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_removepermission.js @@ -0,0 +1,58 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + // initialize the permission manager service + let pm = Services.perms; + + Assert.equal(pm.all.length, 0); + + // add some permissions + let principal = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://amazon.com:8080" + ); + let principal2 = + Services.scriptSecurityManager.createContentPrincipalFromOrigin( + "http://google.com:2048" + ); + + pm.addFromPrincipal(principal, "apple", 0); + pm.addFromPrincipal(principal, "apple", 3); + pm.addFromPrincipal(principal, "pear", 3); + pm.addFromPrincipal(principal, "pear", 1); + pm.addFromPrincipal(principal, "cucumber", 1); + pm.addFromPrincipal(principal, "cucumber", 1); + pm.addFromPrincipal(principal, "cucumber", 1); + + pm.addFromPrincipal(principal2, "apple", 2); + pm.addFromPrincipal(principal2, "pear", 0); + pm.addFromPrincipal(principal2, "pear", 2); + + // Make sure that removePermission doesn't remove more than one permission each time + Assert.equal(pm.all.length, 5); + + remove_one_by_type("apple"); + Assert.equal(pm.all.length, 4); + + remove_one_by_type("apple"); + Assert.equal(pm.all.length, 3); + + remove_one_by_type("pear"); + Assert.equal(pm.all.length, 2); + + remove_one_by_type("cucumber"); + Assert.equal(pm.all.length, 1); + + remove_one_by_type("pear"); + Assert.equal(pm.all.length, 0); + + function remove_one_by_type(type) { + for (let perm of pm.all) { + if (perm.type == type) { + pm.removePermission(perm); + break; + } + } + } +} diff --git a/extensions/permissions/test/unit/test_permmanager_removesince.js b/extensions/permissions/test/unit/test_permmanager_removesince.js new file mode 100644 index 0000000000..c33d02b08b --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_removesince.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that removing permissions since a specified time behaves as expected. + +var test_generator = do_run_test(); + +function run_test() { + do_test_pending(); + test_generator.next(); +} + +function continue_test() { + do_run_generator(test_generator); +} + +function* do_run_test() { + let pm = Services.perms; + + // to help with testing edge-cases, we will arrange for .removeAllSince to + // remove *all* permissions from one principal and one permission from another. + let permURI1 = NetUtil.newURI("http://example.com"); + let principal1 = Services.scriptSecurityManager.createContentPrincipal( + permURI1, + {} + ); + + let permURI2 = NetUtil.newURI("http://example.org"); + let principal2 = Services.scriptSecurityManager.createContentPrincipal( + permURI2, + {} + ); + + // add a permission now - this isn't going to be removed. + pm.addFromPrincipal(principal1, "test/remove-since", 1); + + // sleep briefly, then record the time - we'll remove all since then. + do_timeout(20, continue_test); + yield; + + let since = Number(Date.now()); + + // *sob* - on Windows at least, the now recorded by PermissionManager.cpp + // might be a couple of ms *earlier* than what JS sees. So another sleep + // to ensure our |since| is greater than the time of the permissions we + // are now adding. Sadly this means we'll never be able to test when since + // exactly equals the modTime, but there you go... + do_timeout(20, continue_test); + yield; + + // add another item - this second one should get nuked. + pm.addFromPrincipal(principal1, "test/remove-since-2", 1); + + // add 2 items for the second principal - both will be removed. + pm.addFromPrincipal(principal2, "test/remove-since", 1); + pm.addFromPrincipal(principal2, "test/remove-since-2", 1); + + // do the removal. + pm.removeAllSince(since); + + // principal1 - the first one should remain. + Assert.equal( + 1, + pm.testPermissionFromPrincipal(principal1, "test/remove-since") + ); + // but the second should have been removed. + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal1, "test/remove-since-2") + ); + + // principal2 - both should have been removed. + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal2, "test/remove-since") + ); + Assert.equal( + 0, + pm.testPermissionFromPrincipal(principal2, "test/remove-since-2") + ); + + do_finish_generator_test(test_generator); +} diff --git a/extensions/permissions/test/unit/test_permmanager_site_scope.js b/extensions/permissions/test/unit/test_permmanager_site_scope.js new file mode 100644 index 0000000000..2944fa2623 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_site_scope.js @@ -0,0 +1,116 @@ +const TEST_SITE_URI = Services.io.newURI("http://example.com"); +const TEST_FQDN_1_URI = Services.io.newURI("http://test1.example.com"); +const TEST_FQDN_2_URI = Services.io.newURI("http://test2.example.com"); +const TEST_OTHER_URI = Services.io.newURI("http://example.net"); +const TEST_PERMISSION = "3rdPartyStorage^https://example.org"; + +add_task(async function do_test() { + let pm = Services.perms; + + let principal = Services.scriptSecurityManager.createContentPrincipal( + TEST_SITE_URI, + {} + ); + + let subdomain1Principal = + Services.scriptSecurityManager.createContentPrincipal(TEST_FQDN_1_URI, {}); + + let subdomain2Principal = + Services.scriptSecurityManager.createContentPrincipal(TEST_FQDN_2_URI, {}); + + let otherPrincipal = Services.scriptSecurityManager.createContentPrincipal( + TEST_OTHER_URI, + {} + ); + + // Set test permission for site + pm.addFromPrincipal(principal, TEST_PERMISSION, pm.ALLOW_ACTION); + + // Check normal site permission + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + + // Check subdomain permission + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(subdomain1Principal, TEST_PERMISSION) + ); + + // Check other site permission + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(otherPrincipal, TEST_PERMISSION) + ); + + // Remove the permission from the site + pm.removeFromPrincipal(principal, TEST_PERMISSION); + Assert.equal( + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subdomain1Principal, TEST_PERMISSION), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + + // Set test permission for subdomain + pm.addFromPrincipal(subdomain1Principal, TEST_PERMISSION, pm.ALLOW_ACTION); + + // Check normal site permission + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION) + ); + + // Check subdomain permission + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(subdomain1Principal, TEST_PERMISSION) + ); + + // Check other subdomain permission + Assert.equal( + Ci.nsIPermissionManager.ALLOW_ACTION, + pm.testPermissionFromPrincipal(subdomain2Principal, TEST_PERMISSION) + ); + + // Check other site permission + Assert.equal( + Ci.nsIPermissionManager.UNKNOWN_ACTION, + pm.testPermissionFromPrincipal(otherPrincipal, TEST_PERMISSION) + ); + + // Check that subdomains include the site-scoped in the getAllForPrincipal + let sitePerms = pm.getAllForPrincipal(principal, TEST_PERMISSION); + let subdomain1Perms = pm.getAllForPrincipal( + subdomain1Principal, + TEST_PERMISSION + ); + let subdomain2Perms = pm.getAllForPrincipal( + subdomain2Principal, + TEST_PERMISSION + ); + let otherSitePerms = pm.getAllForPrincipal(otherPrincipal, TEST_PERMISSION); + + Assert.equal(sitePerms.length, 1); + Assert.equal(subdomain1Perms.length, 1); + Assert.equal(subdomain2Perms.length, 1); + Assert.equal(otherSitePerms.length, 0); + + // Remove the permission from the subdomain + pm.removeFromPrincipal(subdomain1Principal, TEST_PERMISSION); + Assert.equal( + pm.testPermissionFromPrincipal(principal, TEST_PERMISSION), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subdomain1Principal, TEST_PERMISSION), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subdomain2Principal, TEST_PERMISSION), + Ci.nsIPermissionManager.UNKNOWN_ACTION + ); +}); diff --git a/extensions/permissions/test/unit/test_permmanager_subdomains.js b/extensions/permissions/test/unit/test_permmanager_subdomains.js new file mode 100644 index 0000000000..4d30372332 --- /dev/null +++ b/extensions/permissions/test/unit/test_permmanager_subdomains.js @@ -0,0 +1,106 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function getPrincipalFromURI(aURI) { + let ssm = Services.scriptSecurityManager; + let uri = NetUtil.newURI(aURI); + return ssm.createContentPrincipal(uri, {}); +} + +function run_test() { + var pm = Services.perms; + + // Adds a permission to a sub-domain. Checks if it is working. + let sub1Principal = getPrincipalFromURI("http://sub1.example.com"); + pm.addFromPrincipal(sub1Principal, "test/subdomains", pm.ALLOW_ACTION, 0, 0); + Assert.equal( + pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), + pm.ALLOW_ACTION + ); + + // A sub-sub-domain should get the permission. + let subsubPrincipal = getPrincipalFromURI("http://sub.sub1.example.com"); + Assert.equal( + pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), + pm.ALLOW_ACTION + ); + + // Another sub-domain shouldn't get the permission. + let sub2Principal = getPrincipalFromURI("http://sub2.example.com"); + Assert.equal( + pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + + // Remove current permissions. + pm.removeFromPrincipal(sub1Principal, "test/subdomains"); + Assert.equal( + pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + + // Adding the permission to the main domain. Checks if it is working. + let mainPrincipal = getPrincipalFromURI("http://example.com"); + pm.addFromPrincipal(mainPrincipal, "test/subdomains", pm.ALLOW_ACTION, 0, 0); + Assert.equal( + pm.testPermissionFromPrincipal(mainPrincipal, "test/subdomains"), + pm.ALLOW_ACTION + ); + + // All sub-domains should have the permission now. + Assert.equal( + pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), + pm.ALLOW_ACTION + ); + + // Remove current permissions. + pm.removeFromPrincipal(mainPrincipal, "test/subdomains"); + Assert.equal( + pm.testPermissionFromPrincipal(mainPrincipal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + + // A sanity check that the previous implementation wasn't passing... + let crazyPrincipal = getPrincipalFromURI("http://com"); + pm.addFromPrincipal(crazyPrincipal, "test/subdomains", pm.ALLOW_ACTION, 0, 0); + Assert.equal( + pm.testPermissionFromPrincipal(crazyPrincipal, "test/subdomains"), + pm.ALLOW_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(mainPrincipal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(sub1Principal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(sub2Principal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); + Assert.equal( + pm.testPermissionFromPrincipal(subsubPrincipal, "test/subdomains"), + pm.UNKNOWN_ACTION + ); +} diff --git a/extensions/permissions/test/unit/xpcshell.ini b/extensions/permissions/test/unit/xpcshell.ini new file mode 100644 index 0000000000..294d7c47a3 --- /dev/null +++ b/extensions/permissions/test/unit/xpcshell.ini @@ -0,0 +1,60 @@ +[DEFAULT] +head = head.js + +[test_permmanager_default_pref.js] +[test_permmanager_defaults.js] +[test_permmanager_expiration.js] +skip-if = + win10_2004 # Bug 1718292 + win10_2009 # Bug 1718292 + win11_2009 # Bug 1797751 + os == "win" && os_version == "6.1" # Skip on Azure - frequent failure +[test_permmanager_getAllByTypes.js] +[test_permmanager_getAllByTypeSince.js] +[test_permmanager_getAllForPrincipal.js] +[test_permmanager_getAllWithTypePrefix.js] +[test_permmanager_getPermissionObject.js] +[test_permmanager_notifications.js] +[test_permmanager_removeall.js] +[test_permmanager_removebytype.js] +[test_permmanager_removebytypesince.js] +[test_permmanager_removesince.js] +[test_permmanager_load_invalid_entries.js] +skip-if = debug == true +[test_permmanager_idn.js] +[test_permmanager_subdomains.js] +[test_permmanager_local_files.js] +[test_permmanager_cleardata.js] +[test_permmanager_removepermission.js] +[test_permmanager_matchesuri.js] +[test_permmanager_matches.js] +[test_permmanager_migrate_4-7.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_5-7a.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_5-7b.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_6-7a.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_6-7b.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_4-7_no_history.js] +skip-if = + apple_silicon || toolkit == 'android' # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs +[test_permmanager_migrate_7-8.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_9-10.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_10-11.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_migrate_11-12.js] +skip-if = toolkit == 'android' # Android doesn't use places +[test_permmanager_oa_strip.js] +[test_permmanager_site_scope.js] +[test_permmanager_remove_add_update.js] +skip-if = win10_2004 && bits == 64 # Bug 1718292 +[test_permmanager_ipc.js] +# This test is meant to run on a multi process mode +# and with file urls loaded in their own child process. +skip-if = !e10s +firefox-appdir = browser -- cgit v1.2.3