diff --git a/extensions/permissions/PermissionManager.cpp b/extensions/permissions/PermissionManager.cpp index 5a38bb50e88c..80c7fefbffbe 100644 --- a/extensions/permissions/PermissionManager.cpp +++ b/extensions/permissions/PermissionManager.cpp @@ -6,9 +6,6 @@ #include "mozilla/AbstractThread.h" #include "mozilla/AppShutdown.h" -#ifdef MOZ_BACKGROUNDTASKS -# include "mozilla/BackgroundTasks.h" -#endif #include "mozilla/BasePrincipal.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/ContentPrincipal.h" @@ -406,10 +403,8 @@ nsresult UpgradeHostToOriginAndInsert( // subdomain of this host), and try to add it as a principal. bool foundHistory = false; - nsCOMPtr histSrv = nullptr; - if (NS_IsMainThread()) { - histSrv = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID); - } + nsCOMPtr histSrv = + do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID); if (histSrv) { nsCOMPtr histQuery; @@ -1709,68 +1704,6 @@ PermissionManager::AddFromPrincipalAndPersistInPrivateBrowsing( /* aAllowPersistInPrivateBrowsing */ true); } -NS_IMETHODIMP -PermissionManager::AddDefaultFromPrincipal(nsIPrincipal* aPrincipal, - const nsACString& aType, - uint32_t aPermission) { - ENSURE_NOT_CHILD_PROCESS; - MOZ_ASSERT(mState == eReady); - - bool isValidPermissionPrincipal = false; - nsresult rv = ShouldHandlePrincipalForPermission(aPrincipal, - isValidPermissionPrincipal); - NS_ENSURE_SUCCESS(rv, rv); - if (!isValidPermissionPrincipal) { - // return early if the principal is invalid for permissions - return rv; - } - - nsCString origin; - rv = GetOriginFromPrincipal(aPrincipal, IsOAForceStripPermission(aType), - origin); - NS_ENSURE_SUCCESS(rv, rv); - - DefaultEntry entry; - { - // Lock for mDefaultEntriesForImport - MonitorAutoLock lock(mMonitor); - - // Try to update existing entry in mDefaultEntriesForImport, which will - // later be used to restore the default permissions when permissions are - // cleared - bool updatedExistingEntry = false; - nsTArray::iterator defaultEntry = - mDefaultEntriesForImport.begin(); - while (defaultEntry != mDefaultEntriesForImport.end()) { - if (defaultEntry->mType == aType && defaultEntry->mOrigin == origin) { - defaultEntry->mPermission = aPermission; - entry = *defaultEntry; - if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) { - mDefaultEntriesForImport.RemoveElementAt(defaultEntry); - } - updatedExistingEntry = true; - break; - } - ++defaultEntry; - } - - // Or add a new entry if there wasn't already one and we aren't deleting the - // default permission - if (!updatedExistingEntry) { - entry.mOrigin = origin; - entry.mPermission = aPermission; - entry.mType = aType; - if (aPermission != nsIPermissionManager::UNKNOWN_ACTION) { - mDefaultEntriesForImport.AppendElement(entry); - } - } - } - - // So far, we have only updated mDefaultEntriesForImport for later recovery. - // Now, we actually need to import this change into the permission manager. - return ImportDefaultEntry(entry); -} - NS_IMETHODIMP PermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, const nsACString& aType, @@ -1836,9 +1769,6 @@ nsresult PermissionManager::AddInternal( const bool aAllowPersistInPrivateBrowsing) { MOZ_ASSERT(NS_IsMainThread()); - // If this is a default permission, no changes should not be written to disk. - MOZ_ASSERT((aID != cIDPermissionIsDefault) || (aDBOperation != eWriteToDB)); - EnsureReadCompleted(); nsresult rv = NS_OK; @@ -1949,26 +1879,23 @@ nsresult PermissionManager::AddInternal( if (aPermission == oldPermissionEntry.mPermission && aExpireType == oldPermissionEntry.mExpireType && (aExpireType == nsIPermissionManager::EXPIRE_NEVER || - aExpireTime == oldPermissionEntry.mExpireTime)) { + aExpireTime == oldPermissionEntry.mExpireTime)) op = eOperationNone; - } else if (oldPermissionEntry.mID == cIDPermissionIsDefault && - aID != cIDPermissionIsDefault) { - // An existing default permission already exists, but the new permission - // isn't a default permission. This case requires some special handing. + else if (oldPermissionEntry.mID == cIDPermissionIsDefault) + // The existing permission is one added as a default and the new + // permission doesn't exactly match so we are replacing the default. This + // is true even if the new permission is UNKNOWN_ACTION (which means a + // "logical remove" of the default) op = eOperationReplacingDefault; - } else if (oldPermissionEntry.mID != cIDPermissionIsDefault && - aID == cIDPermissionIsDefault) { + else if (aID == cIDPermissionIsDefault) // We are adding a default permission but a "real" permission already - // exists. This means we don't have to do anything here. + // exists. This almost-certainly means we just did a removeAllSince and + // are re-importing defaults - so we can ignore this. op = eOperationNone; - } else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) { - // At this point, both the old and new permission are either both default - // permissions, or both not default permissions. Now we only need to check - // wether to change or remove the old permission. + else if (aPermission == nsIPermissionManager::UNKNOWN_ACTION) op = eOperationRemoving; - } else { + else op = eOperationChanging; - } } // child processes should *always* be passed a modificationTime of zero. @@ -2046,20 +1973,6 @@ nsresult PermissionManager::AddInternal( mPermissionTable.RemoveEntry(entry); } - // If the entry we are removing is not a default, restore the potential - // default entry in-memory - if (oldPermissionEntry.mID != cIDPermissionIsDefault) { - for (const DefaultEntry& defaultEntry : mDefaultEntriesForImport) { - if (defaultEntry.mType == aType && defaultEntry.mOrigin == origin && - defaultEntry.mPermission != - nsIPermissionManager::UNKNOWN_ACTION) { - rv = ImportDefaultEntry(defaultEntry); - NS_ENSURE_SUCCESS(rv, rv); - break; - } - } - } - break; } @@ -2290,6 +2203,9 @@ nsresult PermissionManager::RemovePermissionEntries(T aCondition) { PermissionManager::eWriteToDB, false, &std::get<2>(i)); } + // now re-import any defaults as they may now be required if we just deleted + // an override. + ImportLatestDefaults(); return NS_OK; } @@ -2798,13 +2714,10 @@ NS_IMETHODIMP PermissionManager::Observe(nsISupports* aSubject, const char16_t* someData) { ENSURE_NOT_CHILD_PROCESS; - if (!nsCRT::strcmp(aTopic, "profile-do-change")) { - if (!mPermissionsFile) { - // profile startup is complete, and we didn't have the permissions file - // before; init the db from the new location - InitDB(false); - } - InitRemotePermissionService(); + if (!nsCRT::strcmp(aTopic, "profile-do-change") && !mPermissionsFile) { + // profile startup is complete, and we didn't have the permissions file + // before; init the db from the new location + InitDB(false); } else if (!nsCRT::strcmp(aTopic, "testonly-reload-permissions-from-disk")) { // Testing mechanism to reload all permissions from disk. Because the // permission manager automatically initializes itself at startup, tests @@ -2816,7 +2729,6 @@ NS_IMETHODIMP PermissionManager::Observe(nsISupports* aSubject, RemoveAllFromMemory(); CloseDB(eNone); InitDB(false); - InitRemotePermissionService(); } else if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY)) { PerformIdleDailyMaintenance(); } @@ -3263,33 +3175,6 @@ void PermissionManager::CompleteRead() { } } -void PermissionManager::InitRemotePermissionService() { - // Check if this service is disabled by pref, and abort if it is. - if (!StaticPrefs::permissions_manager_remote_enabled()) { - return; - } - - // Also abort if we are in a background task. We do not want to call remote - // settings there, because we do not want to pollute the background task - // profile, and because we don't need the remote permissions there anyways. -#ifdef MOZ_BACKGROUNDTASKS - if (BackgroundTasks::IsBackgroundTaskMode()) { - return; - } -#endif - - NS_DispatchToCurrentThreadQueue( - NS_NewRunnableFunction( - "RemotePermissionService::Init", - [&] { - nsCOMPtr remotePermissionService = - do_GetService(NS_REMOTEPERMISSIONSERVICE_CONTRACTID); - NS_ENSURE_TRUE_VOID(remotePermissionService); - remotePermissionService->Init(); - }), - EventQueuePriority::Idle); -} - void PermissionManager::MaybeAddReadEntryFromMigration( const nsACString& aOrigin, const nsCString& aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime, @@ -3785,7 +3670,7 @@ void PermissionManager::ConsumeDefaultsInputStream( constexpr char kMatchTypeHost[] = "host"; constexpr char kMatchTypeOrigin[] = "origin"; - mDefaultEntriesForImport.Clear(); + mDefaultEntries.Clear(); if (!aInputStream) { return; @@ -3829,99 +3714,128 @@ void PermissionManager::ConsumeDefaultsInputStream( continue; } - const nsCString& hostOrOrigin = lineArray[3]; - const nsCString& type = lineArray[1]; + DefaultEntry::Op op; if (lineArray[0].EqualsLiteral(kMatchTypeHost)) { - UpgradeHostToOriginAndInsert( - hostOrOrigin, type, permission, nsIPermissionManager::EXPIRE_NEVER, 0, - 0, - [&](const nsACString& aOrigin, const nsCString& aType, - uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime) { - AddDefaultEntryForImport(aOrigin, aType, aPermission, aProofOfLock); - return NS_OK; - }); + op = DefaultEntry::eImportMatchTypeHost; } else if (lineArray[0].EqualsLiteral(kMatchTypeOrigin)) { - AddDefaultEntryForImport(hostOrOrigin, type, permission, aProofOfLock); + op = DefaultEntry::eImportMatchTypeOrigin; } else { continue; } + DefaultEntry* entry = mDefaultEntries.AppendElement(); + MOZ_ASSERT(entry); + + entry->mOp = op; + entry->mPermission = permission; + entry->mHostOrOrigin = lineArray[3]; + entry->mType = lineArray[1]; } while (isMore); } -void PermissionManager::AddDefaultEntryForImport( - const nsACString& aOrigin, const nsCString& aType, uint32_t aPermission, - const MonitorAutoLock& aProofOfLock) { - DefaultEntry* entry = mDefaultEntriesForImport.AppendElement(); - MOZ_ASSERT(entry); - - entry->mPermission = aPermission; - entry->mOrigin = aOrigin; - entry->mType = aType; -} - -nsresult PermissionManager::ImportDefaultEntry( - const DefaultEntry& aDefaultEntry) { - nsCOMPtr principal; - nsresult rv = GetPrincipalFromOrigin( - aDefaultEntry.mOrigin, IsOAForceStripPermission(aDefaultEntry.mType), - getter_AddRefs(principal)); - if (NS_FAILED(rv)) { - NS_WARNING("Couldn't import an origin permission - malformed origin"); - return rv; - } - - // the import file format doesn't handle modification times, so we use - // 0, which AddInternal will convert to now() - int64_t modificationTime = 0; - - rv = AddInternal(principal, aDefaultEntry.mType, aDefaultEntry.mPermission, - cIDPermissionIsDefault, nsIPermissionManager::EXPIRE_NEVER, - 0, modificationTime, eDontNotify, eNoDBOperation); - if (NS_FAILED(rv)) { - NS_WARNING("There was a problem importing an origin permission"); - return rv; - } - - if (StaticPrefs::permissions_isolateBy_privateBrowsing() && - !IsOAForceStripPermission(aDefaultEntry.mType)) { - // Also import the permission for private browsing. - OriginAttributes attrs = OriginAttributes(principal->OriginAttributesRef()); - attrs.mPrivateBrowsingId = 1; - nsCOMPtr pbPrincipal = - BasePrincipal::Cast(principal)->CloneForcingOriginAttributes(attrs); - // May return nullptr if clone fails. - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = - AddInternal(pbPrincipal, aDefaultEntry.mType, aDefaultEntry.mPermission, - cIDPermissionIsDefault, nsIPermissionManager::EXPIRE_NEVER, - 0, modificationTime, eDontNotify, eNoDBOperation); - if (NS_FAILED(rv)) { - NS_WARNING( - "There was a problem importing an origin permission for private " - "browsing"); - return rv; - } - } - - return NS_OK; -} - -// ImportLatestDefaults will import the latest default permissions read during -// the last DB initialization. +// ImportLatestDefaults will import the latest default cookies read during the +// last DB initialization. nsresult PermissionManager::ImportLatestDefaults() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mState == eReady); + nsresult rv; + MonitorAutoLock lock(mMonitor); - for (const DefaultEntry& entry : mDefaultEntriesForImport) { - Unused << ImportDefaultEntry(entry); + for (const DefaultEntry& entry : mDefaultEntries) { + if (entry.mOp == DefaultEntry::eImportMatchTypeHost) { + // the import file format doesn't handle modification times, so we use + // 0, which AddInternal will convert to now() + int64_t modificationTime = 0; + + rv = UpgradeHostToOriginAndInsert( + entry.mHostOrOrigin, entry.mType, entry.mPermission, + nsIPermissionManager::EXPIRE_NEVER, 0, modificationTime, + [&](const nsACString& aOrigin, const nsCString& aType, + uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime) { + nsCOMPtr principal; + nsresult rv = + GetPrincipalFromOrigin(aOrigin, IsOAForceStripPermission(aType), + getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + rv = + AddInternal(principal, aType, aPermission, + cIDPermissionIsDefault, aExpireType, aExpireTime, + aModificationTime, PermissionManager::eDontNotify, + PermissionManager::eNoDBOperation, false, &aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (StaticPrefs::permissions_isolateBy_privateBrowsing()) { + // Also import the permission for private browsing. + OriginAttributes attrs = + OriginAttributes(principal->OriginAttributesRef()); + attrs.mPrivateBrowsingId = 1; + nsCOMPtr pbPrincipal = + BasePrincipal::Cast(principal)->CloneForcingOriginAttributes( + attrs); + + rv = AddInternal( + pbPrincipal, aType, aPermission, cIDPermissionIsDefault, + aExpireType, aExpireTime, aModificationTime, + PermissionManager::eDontNotify, + PermissionManager::eNoDBOperation, false, &aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + }); + + if (NS_FAILED(rv)) { + NS_WARNING("There was a problem importing a host permission"); + } + continue; + } + + MOZ_ASSERT(entry.mOp == DefaultEntry::eImportMatchTypeOrigin); + + nsCOMPtr principal; + rv = GetPrincipalFromOrigin(entry.mHostOrOrigin, + IsOAForceStripPermission(entry.mType), + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + NS_WARNING("Couldn't import an origin permission - malformed origin"); + continue; + } + + // the import file format doesn't handle modification times, so we use + // 0, which AddInternal will convert to now() + int64_t modificationTime = 0; + + rv = AddInternal(principal, entry.mType, entry.mPermission, + cIDPermissionIsDefault, nsIPermissionManager::EXPIRE_NEVER, + 0, modificationTime, eDontNotify, eNoDBOperation); + if (NS_FAILED(rv)) { + NS_WARNING("There was a problem importing an origin permission"); + } + + if (StaticPrefs::permissions_isolateBy_privateBrowsing()) { + // Also import the permission for private browsing. + OriginAttributes attrs = + OriginAttributes(principal->OriginAttributesRef()); + attrs.mPrivateBrowsingId = 1; + nsCOMPtr pbPrincipal = + BasePrincipal::Cast(principal)->CloneForcingOriginAttributes(attrs); + // May return nullptr if clone fails. + NS_ENSURE_TRUE(pbPrincipal, NS_ERROR_FAILURE); + + rv = AddInternal(pbPrincipal, entry.mType, entry.mPermission, + cIDPermissionIsDefault, + nsIPermissionManager::EXPIRE_NEVER, 0, modificationTime, + eDontNotify, eNoDBOperation); + if (NS_FAILED(rv)) { + NS_WARNING( + "There was a problem importing an origin permission for private " + "browsing"); + } + } } return NS_OK; diff --git a/extensions/permissions/PermissionManager.h b/extensions/permissions/PermissionManager.h index aad994ae2c80..97011167e0be 100644 --- a/extensions/permissions/PermissionManager.h +++ b/extensions/permissions/PermissionManager.h @@ -10,7 +10,6 @@ #include "nsIPermissionManager.h" #include "nsIAsyncShutdown.h" #include "nsIObserver.h" -#include "nsIRemotePermissionService.h" #include "nsWeakReference.h" #include "nsCOMPtr.h" #include "nsIURI.h" @@ -621,35 +620,29 @@ class PermissionManager final : public nsIPermissionManager, // A single entry from the defaults URL. struct DefaultEntry { - nsCString mOrigin; + DefaultEntry() : mOp(eImportMatchTypeHost), mPermission(0) {} + + enum Op { + eImportMatchTypeHost, + eImportMatchTypeOrigin, + }; + + Op mOp; + + nsCString mHostOrOrigin; nsCString mType; - uint32_t mPermission = 0; + uint32_t mPermission; }; // List of entries read from the default settings. // This array is protected by the monitor. - nsTArray mDefaultEntriesForImport; - // Adds a default permission entry to AddDefaultEntryForImport for given - // origin, type and value - void AddDefaultEntryForImport(const nsACString& aOrigin, - const nsCString& aType, uint32_t aPermission, - const MonitorAutoLock& aProofOfLock); - // Given a default entry, import it as a default permission (id = -1) into the - // permission manager without storing it to disk. If permission isolation for - // private browsing is enabled (which is the default), and the permission type - // is not exempt from it, this will also create a separate default permission - // for private browsing - nsresult ImportDefaultEntry(const DefaultEntry& aDefaultEntry); + nsTArray mDefaultEntries; nsresult Read(const MonitorAutoLock& aProofOfLock); void CompleteRead(); void CompleteMigrations(); - // Initialize service used for importing default permissions from remote - // settings - void InitRemotePermissionService(); - bool mMemoryOnlyDB; nsTHashtable mPermissionTable; diff --git a/extensions/permissions/RemotePermissionService.sys.mjs b/extensions/permissions/RemotePermissionService.sys.mjs deleted file mode 100644 index b1cd015cf449..000000000000 --- a/extensions/permissions/RemotePermissionService.sys.mjs +++ /dev/null @@ -1,191 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -import { RemoteSettings } from "resource://services-settings/remote-settings.sys.mjs"; - -const COLLECTION_NAME = "remote-permissions"; - -/** - * Allowlist of permission types and values allowed to be set through remote - * settings. In this map, the key is the permission type, while the value is an - * array of allowed permission values/capabilities allowed to be set. Possible - * values for most permissions are: - * - * - Ci.nsIPermissionManager.ALLOW_ACTION - * - Ci.nsIPermissionManager.DENY_ACTION - * - Ci.nsIPermissionManager.PROMPT_ACTION - * - "*" (Allows all values) - * - * Permission types with custom permission values (like - * https-only-load-insecure) may include different values. Only change this - * value with a review from #permissions-reviewers. - */ -const ALLOWED_PERMISSION_VALUES = { - "https-only-load-insecure": [ - Ci.nsIHttpsOnlyModePermission.HTTPSFIRST_LOAD_INSECURE_ALLOW, - ], -}; - -/** - * See nsIRemotePermissionService.idl - */ -export class RemotePermissionService { - classId = Components.ID("{a4b1b3b1-b68a-4129-aa2f-eb086162a8c7}"); - QueryInterface = ChromeUtils.generateQI(["nsIRemotePermissionService"]); - - #rs = RemoteSettings(COLLECTION_NAME); - #onSyncCallback = null; - #initialized = Promise.withResolvers(); - #allowedPermissionValues = ALLOWED_PERMISSION_VALUES; - - /** - * Asynchonously import all default permissions from remote settings into the - * permission manager. Also, if not already done, set up remote settings event - * listener to keep remote permissions in sync. - */ - async init() { - try { - if (Services.startup.shuttingDown) { - return; - } - - if ( - !Services.prefs.getBoolPref("permissions.manager.remote.enabled", false) - ) { - throw Error( - "Tried to initialize remote permission service despite being disabled by pref" - ); - } - - let remotePermissions = await this.#rs.get(); - for (const permission of remotePermissions) { - this.#addDefaultPermission(permission); - } - - // Init could be called multiple times if the permission manager is - // reinitializing itself due to "testonly-reload-permissions-from-disk" - // being emitted. In that case, we don't shouldn't set up the RS listener - // again. We may also land in that situtation when "profile-do-change" is - // emitted. - if (!this.#onSyncCallback) { - this.#onSyncCallback = this.#onSync.bind(this); - this.#rs.on("sync", this.#onSyncCallback); - } - - this.#initialized.resolve(); - } catch (e) { - this.#initialized.reject(e); - throw e; - } - } - - get isInitialized() { - return this.#initialized.promise; - } - - get testAllowedPermissionValues() { - return this.#allowedPermissionValues; - } - - set testAllowedPermissionValues(allowedPermissionValues) { - Cu.crashIfNotInAutomation(); - this.#allowedPermissionValues = allowedPermissionValues; - } - - // eslint-disable-next-line jsdoc/require-param - /** - * Callback for the "sync" event from remote settings. This function will - * receive the created, updated and deleted permissions from remote settings, - * and will update the permission manager accordingly. - */ - #onSync({ data: { created = [], updated = [], deleted = [] } }) { - const toBeDeletedPermissions = [ - // Delete permissions that got deleted in remote settings. - ...deleted, - // If an existing entry got updated in remote settings, but the origin or - // type changed, we can not just update it, as permissions are identified - // by origin and type in the permission manager. Instead, we need to - // remove the old permission and add a new one. - ...updated - .filter( - ({ - old: { origin: oldOrigin, type: oldType }, - new: { origin: newOrigin, type: newType }, - }) => oldOrigin != newOrigin || oldType != newType - ) - .map(({ old }) => old), - ]; - - const toBeAddedPermissions = [ - // Add newly created permissions. - ...created, - // "Add" permissions updated in remote settings (the permission manager - // will automatically update the existing default permission instead of - // creating a new one if the permission origin and type match). - ...updated.map(({ new: newPermission }) => newPermission), - // Delete permissions by "adding" them with value UNKNOWN_ACTION. - ...toBeDeletedPermissions.map(({ origin, type }) => ({ - origin, - type, - capability: Ci.nsIPermissionManager.UNKNOWN_ACTION, - })), - ]; - - for (const permission of toBeAddedPermissions) { - this.#addDefaultPermission(permission); - } - } - - /** - * Check if a permission type and value is allowed to be set through remote - * settings, based on the ALLOWED_PERMISSION_VALUES allowlist. - * - * @param {string} type Permission type to check - * @param {string} capability Permission capability to check - * @returns {boolean} - */ - #isAllowed(type, capability) { - if (!this.#allowedPermissionValues[type]) { - if (this.#allowedPermissionValues["*"]) { - this.#allowedPermissionValues[type] = - this.#allowedPermissionValues["*"]; - } else { - return false; - } - } - - return ( - this.#allowedPermissionValues[type].includes("*") || - this.#allowedPermissionValues[type].includes(capability) || - capability === Ci.nsIPermissionManager.UNKNOWN_ACTION - ); - } - - /** - * Add a default permission to the permission manager. - * - * @param {object} permission The permission to add - * @param {string} permission.origin Origin string of the permission - * @param {string} permission.type Type of the permission - * @param {number} permission.capability Capability of the permission - */ - #addDefaultPermission({ origin, type, capability }) { - if (!this.#isAllowed(type, capability)) { - console.error( - `Remote Settings contain default permission of disallowed type '${type}' with value '${capability}' for origin '${origin}', skipping import` - ); - return; - } - - try { - let principal = Services.scriptSecurityManager.createContentPrincipal( - Services.io.newURI(origin), - {} - ); - Services.perms.addDefaultFromPrincipal(principal, type, capability); - } catch (e) { - console.error(e); - } - } -} diff --git a/extensions/permissions/components.conf b/extensions/permissions/components.conf index 759686c0c84b..62f4f7ba1c56 100644 --- a/extensions/permissions/components.conf +++ b/extensions/permissions/components.conf @@ -22,12 +22,4 @@ Classes = [ 'type': 'PermissionDelegateHandler', 'headers': ['/extensions/permissions/PermissionDelegateHandler.h'], }, - { - 'cid': '{a4b1b3b1-b68a-4129-aa2f-eb086162a8c7}', - 'contract_ids': ['@mozilla.org/remote-permission-service;1'], - 'esModule': 'resource://gre/modules/RemotePermissionService.sys.mjs', - 'constructor': 'RemotePermissionService', - 'singleton': True, - 'processes': ProcessSelector.MAIN_PROCESS_ONLY, - }, ] diff --git a/extensions/permissions/moz.build b/extensions/permissions/moz.build index a8565b90fec2..6cdac6092644 100644 --- a/extensions/permissions/moz.build +++ b/extensions/permissions/moz.build @@ -27,16 +27,6 @@ XPCOM_MANIFESTS += [ "components.conf", ] -XPIDL_MODULE = "permissions" - -XPIDL_SOURCES += [ - "nsIRemotePermissionService.idl", -] - -EXTRA_JS_MODULES += [ - "RemotePermissionService.sys.mjs", -] - LOCAL_INCLUDES += [ "/caps", ] diff --git a/extensions/permissions/nsIRemotePermissionService.idl b/extensions/permissions/nsIRemotePermissionService.idl deleted file mode 100644 index 0c0d9cd65374..000000000000 --- a/extensions/permissions/nsIRemotePermissionService.idl +++ /dev/null @@ -1,41 +0,0 @@ -/* 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 "nsISupports.idl" - -interface nsIPrincipal; - -/** - * Service to import default permissions from Remote Settings. Will be - * initialized by permission manager after it itself has completed its - * initialization, and will then import default permissions from Remote Settings - * asynchronously. This also means default permissions aren't guranteed to be - * available directly after startup. - */ -[scriptable, uuid(a4b1b3b1-b68a-4129-aa2f-eb086162a8c7)] -interface nsIRemotePermissionService : nsISupports { - /** - * Asynchonously import all default permissions from remote settings into - * the permission manager. Also, if not already done, set up remote settings - * event listener to keep remote permissions in sync. - */ - void init(); - /** - * Promise that is resolved when the remote permission service has been - * fully initialized, meaning all intial permissions have been imported and - * the remote settings sync event listener has been set up. If any errors - * are encountered during inizialization, this promise will be rejected. - */ - readonly attribute Promise isInitialized; - /** - * Allowed permission types and values to be set through remote settings. - * See RemotePermissionService.sys.mjs for further documentation. Exposed - * only for testing purposes. - */ - attribute jsval testAllowedPermissionValues; -}; - -%{C++ -#define NS_REMOTEPERMISSIONSERVICE_CONTRACTID "@mozilla.org/remote-permission-service;1" -%} diff --git a/extensions/permissions/test/unit/test_permmanager_remote.js b/extensions/permissions/test/unit/test_permmanager_remote.js deleted file mode 100644 index 2131114a92b4..000000000000 --- a/extensions/permissions/test/unit/test_permmanager_remote.js +++ /dev/null @@ -1,480 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. -https://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -ChromeUtils.defineESModuleGetters(this, { - RemoteSettings: "resource://services-settings/remote-settings.sys.mjs", -}); - -const COLLECTION_NAME = "remote-permissions"; -const ORIGIN_1 = "https://example.com"; -const PRINCIPAL_1 = Services.scriptSecurityManager.createContentPrincipal( - Services.io.newURI(ORIGIN_1), - {} -); -const PRINCIPAL_1_PB = Services.scriptSecurityManager.createContentPrincipal( - Services.io.newURI(ORIGIN_1), - { privateBrowsingId: 1 } -); -const ORIGIN_2 = "https://example.org"; -const PRINCIPAL_2 = Services.scriptSecurityManager.createContentPrincipal( - Services.io.newURI(ORIGIN_2), - {} -); -const PRINCIPAL_2_PB = Services.scriptSecurityManager.createContentPrincipal( - Services.io.newURI(ORIGIN_2), - { privateBrowsingId: 1 } -); -const ORIGIN_INVALID = "not a valid origin"; -const TEST_PERMISSION_1 = "test-permission-1"; -const TEST_PERMISSION_2 = "test-permission-2"; - -let rs = RemoteSettings(COLLECTION_NAME); -let pm = Services.perms; -let rps = Cc["@mozilla.org/remote-permission-service;1"].getService( - Ci.nsIRemotePermissionService -); - -async function remoteSettingsSync({ created, updated, deleted }) { - await rs.emit("sync", { - data: { - created, - updated, - deleted, - }, - }); -} - -function expectPermissions(perms) { - Assert.deepEqual( - pm.all - .map(({ principal, type, capability }) => ({ - principal: principal.siteOrigin, - type, - capability, - })) - .sort((a, b) => a.principal.localeCompare(b.principal)), - perms - .map(({ principal, type, capability }) => ({ - principal: principal.siteOrigin, - type, - capability, - })) - .sort((a, b) => a.principal.localeCompare(b.principal)), - "Permission manager should have expected permissions" - ); -} - -add_setup(async function () { - do_get_profile(); - - // This needs to be restored on cleanup - let originalPermissionValues = structuredClone( - rps.testAllowedPermissionValues - ); - - // Initialize remote permission service - let permObserver = Services.perms.QueryInterface(Ci.nsIObserver); - permObserver.observe(null, "profile-do-change", ""); - await rps.isInitialized; - - registerCleanupFunction(async () => { - info("Cleaning up"); - rps.testAllowedPermissionValues = originalPermissionValues; - Services.prefs.clearUserPref("permissions.manager.defaultsUrl"); - Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); - Services.perms.removeAll(); - }); - - // Allow setting everything - rps.testAllowedPermissionValues = { - "*": ["*"], - }; -}); - -add_task(async function test_create_permission() { - info("Creating permission"); - - await remoteSettingsSync({ - created: [ - { - origin: ORIGIN_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - ], - }); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - ]); -}); - -add_task(async function test_update_permission_value() { - info("Updating permission value"); - - await remoteSettingsSync({ - updated: [ - { - old: { - origin: ORIGIN_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - new: { - origin: ORIGIN_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - }, - ], - }); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); -}); - -add_task(async function test_update_permission_origin() { - info("Updating permission origin"); - - await remoteSettingsSync({ - updated: [ - { - old: { - origin: ORIGIN_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - new: { - origin: ORIGIN_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - }, - ], - }); - - expectPermissions([ - { - principal: PRINCIPAL_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - { - principal: PRINCIPAL_2_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); -}); - -add_task(async function test_user_permission_restoration() { - info("Overriding with user permission"); - - pm.addFromPrincipal( - PRINCIPAL_2, - TEST_PERMISSION_1, - Ci.nsIPermissionManager.ALLOW_ACTION - ); - - expectPermissions([ - { - principal: PRINCIPAL_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_2_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); - - info("Removing user permission"); - - pm.removeFromPrincipal(PRINCIPAL_2, TEST_PERMISSION_1); - - expectPermissions([ - { - principal: PRINCIPAL_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - { - principal: PRINCIPAL_2_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); -}); - -add_task(async function test_remove_all_restoration() { - info("Overriding with user permission and adding new user permission"); - - pm.addFromPrincipal( - PRINCIPAL_1, - TEST_PERMISSION_1, - Ci.nsIPermissionManager.ALLOW_ACTION - ); - pm.addFromPrincipal( - PRINCIPAL_2, - TEST_PERMISSION_1, - Ci.nsIPermissionManager.ALLOW_ACTION - ); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_2_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); - - info("Removing all permissions"); - - pm.removeAll(); - - expectPermissions([ - { - principal: PRINCIPAL_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - { - principal: PRINCIPAL_2_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); -}); - -add_task(async function test_delete_permission() { - info("Deleting permission"); - - await remoteSettingsSync({ - deleted: [ - { - origin: ORIGIN_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ], - }); - - expectPermissions([]); -}); - -add_task(async function test_allowlist() { - info("Only allowing TEST_PERMISSION_1 with value ALLOW_ACTION"); - - rps.testAllowedPermissionValues = { - [TEST_PERMISSION_1]: [Ci.nsIPermissionManager.ALLOW_ACTION], - }; - - info("Trying to add all sorts of default permissions"); - - await remoteSettingsSync({ - created: [ORIGIN_1, ORIGIN_2].flatMap(origin => - [TEST_PERMISSION_1, TEST_PERMISSION_2].flatMap(type => - [ - Ci.nsIPermissionManager.ALLOW_ACTION, - Ci.nsIPermissionManager.DENY_ACTION, - Ci.nsIPermissionManager.PROMPT_ACTION, - ].flatMap(capability => ({ origin, type, capability })) - ) - ), - }); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_2, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_2_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - ]); - - rps.testAllowedPermissionValues = { - "*": ["*"], - }; -}); - -add_task(async function test_defaults_url() { - info("Testing interaction with permissions.manager.defaultsUrl"); - - info("Setting up permissions.manager.defaultsUrl"); - - let file = do_get_tempdir(); - file.append("test_default_permissions"); - 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( - [ - "host", - TEST_PERMISSION_1, - Ci.nsIPermissionManager.ALLOW_ACTION, - ORIGIN_1, - ].join("\t") + "\n" - ); - conv.writeString( - [ - "host", - TEST_PERMISSION_2, - Ci.nsIPermissionManager.ALLOW_ACTION, - ORIGIN_1, - ].join("\t") + "\n" - ); - ostream.close(); - - Services.prefs.setCharPref( - "permissions.manager.defaultsUrl", - "file://" + file.path - ); - - info("Re-initializing permission manager"); - - // Start from a clean slate with our new default permissions from - // permissions.manager.defaultsUrl - Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); - Services.perms.removeAll(); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_2, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_2, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - ]); - - info("Overriding permissions from permissions.manager.defaultsUrl"); - - await remoteSettingsSync({ - created: [ - { - origin: ORIGIN_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - { - origin: ORIGIN_1, - type: TEST_PERMISSION_2, - capability: Ci.nsIPermissionManager.UNKNOWN_ACTION, - }, - ], - }); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.DENY_ACTION, - }, - ]); -}); - -add_task(async function test_malformed_origin() { - info( - "Testing that import will continue after encountering a malformed origin" - ); - - await remoteSettingsSync({ - created: [ - { - origin: ORIGIN_INVALID, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - // TEST_PERMISSION_1 still exists for ORIGIN_1 from the previous step, but - // for simplicity we act like it is new here. We will see if the value has - // changed from deny to allow. - { - origin: ORIGIN_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - ], - }); - - expectPermissions([ - { - principal: PRINCIPAL_1, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - { - principal: PRINCIPAL_1_PB, - type: TEST_PERMISSION_1, - capability: Ci.nsIPermissionManager.ALLOW_ACTION, - }, - ]); -}); diff --git a/extensions/permissions/test/unit/xpcshell.toml b/extensions/permissions/test/unit/xpcshell.toml index 5f3f3c918fac..93eb51d98c6c 100644 --- a/extensions/permissions/test/unit/xpcshell.toml +++ b/extensions/permissions/test/unit/xpcshell.toml @@ -77,8 +77,6 @@ skip-if = ["os == 'android'"] # Android doesn't use places ["test_permmanager_oa_strip.js"] -["test_permmanager_remote.js"] - ["test_permmanager_removeAllExceptTypes.js"] ["test_permmanager_removeAllSinceWithTypeExceptions.js"] diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index bf6b911cf9f4..5d4d11ea97f6 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -14565,13 +14565,6 @@ value: true mirror: always -# Whether default permissions should be imported from remote settings in -# addition to importing them from browser/app/permissions. -- name: permissions.manager.remote.enabled - type: bool - value: @IS_EARLY_BETA_OR_EARLIER@ - mirror: always - #--------------------------------------------------------------------------- # Prefs starting with "places." #--------------------------------------------------------------------------- diff --git a/netwerk/base/nsIPermissionManager.idl b/netwerk/base/nsIPermissionManager.idl index bc8f2104da74..db680b9d0d46 100644 --- a/netwerk/base/nsIPermissionManager.idl +++ b/netwerk/base/nsIPermissionManager.idl @@ -155,20 +155,6 @@ interface nsIPermissionManager : nsISupports in ACString type, in uint32_t permission); - /** - * Add temporary default permission information for a given principal. - * This permission will be cleared at the end of the session, will not be - * stored on disk, and will not be set if a conflicting (non-default) - * permission already exists. - * - * This function shouldn't be used by regular permission manager consumers and - * is only expected to be called by the RemotePermissionService.sys.mjs for - * the purpose of importing default permissions from remote settings. - */ - void addDefaultFromPrincipal(in nsIPrincipal principal, - in ACString type, - in uint32_t permission); - /** * Remove permission information for a given principal. * This is internally calling remove() with the host from the principal's URI. diff --git a/services/settings/dumps/main/remote-permissions.json b/services/settings/dumps/main/remote-permissions.json deleted file mode 100644 index 8c65f467207c..000000000000 --- a/services/settings/dumps/main/remote-permissions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "data": [], - "timestamp": 1730278443662 -}