author | Razvan Maries <rmaries@mozilla.com> |
Fri, 10 Apr 2020 11:31:20 +0300 | |
changeset 523362 | 397af4c4b102f8cae9e471449e74fa3bb5f6c655 |
parent 523361 | 91d5c60ddc69aff6ef25d4bbee6f76bcc1c8872d |
child 523363 | bbef701c7a1aad1def411071ccc4bf47322bbfa1 |
push id | 37301 |
push user | aiakab@mozilla.com |
push date | Fri, 10 Apr 2020 21:37:00 +0000 |
treeherder | mozilla-central@82d84da94d8d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1363541 |
milestone | 77.0a1 |
backs out | a775f6e9eb41a272c375cdb2f1af798c2340cf9e 9212bfd89eca2fbae1669f215e56f425f4c81c8e bf41b0c139f6b558c08c8e6c1b1842a420eb5818 aa7c6668b249f4e555ea29774f749e6db1804d04 9f413a8a47bbe149eb945018e54fc2e96566b459 827a9a2866bd8900bf82d0e520dfaeec09cde629 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/app/permissions +++ b/browser/app/permissions @@ -1,15 +1,15 @@ # This file has default permissions for the permission manager. # The file-format is strict: # * matchtype \t type \t permission \t host # * "origin" should be used for matchtype, "host" is supported for legacy reasons # * type is a string that identifies the type of permission (e.g. "cookie") # * permission is an integer between 1 and 15 -# See PermissionManager.cpp for more... +# See nsPermissionManager.cpp for more... # UITour # Bug 1557153: www.mozilla.org gets a special workaround in UITourChild.jsm origin uitour 1 https://www.mozilla.org origin uitour 1 https://monitor.firefox.com origin uitour 1 https://screenshots.firefox.com origin uitour 1 https://support.mozilla.org origin uitour 1 about:home
--- a/browser/base/content/test/performance/browser_startup_mainthreadio.js +++ b/browser/base/content/test/performance/browser_startup_mainthreadio.js @@ -248,16 +248,39 @@ const startupPhases = { }, { // bug 1534745 path: "ProfD:cookies.sqlite-wal", condition: WIN, stat: 2, }, { + // bug 975996 + path: "ProfD:permissions.sqlite", + condition: WIN || MAC, + fsync: 8, + read: 2, + stat: 1, + write: 10, + }, + { + // bug 975996 + path: "ProfD:permissions.sqlite-journal", + condition: WIN || MAC, + fsync: 8, + stat: 28, + write: 40, + }, + { + // bug 975996 + path: "ProfD:permissions.sqlite-wal", + condition: WIN, + stat: 20, + }, + { // Seems done by OS X and outside of our control. path: "*.savedState/restorecount.plist", condition: MAC, ignoreIfUnused: true, write: 1, }, { path: "*ld.so.conf*",
--- a/build/clang-plugin/ThreadAllows.txt +++ b/build/clang-plugin/ThreadAllows.txt @@ -50,17 +50,16 @@ MediaTelemetry MediaTrackGrph mtransport NamedPipeSrv NetPredictClean Netlink Monitor OSKeyStore OutputDrain PaintThread -Permission PlayEventSound ProcessHangMon ProfSymbolTable ProfilerChild ProxyResolution RWLockTester RacingServMan RemVidChild
--- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -86,17 +86,17 @@ #include "nsSerializationHelper.h" #include "nsICertOverrideService.h" #include "nsIX509Cert.h" #include "nsIX509CertValidity.h" #include "nsITransportSecurityInfo.h" #include "nsINSSErrorsService.h" #include "nsISocketProvider.h" #include "nsISiteSecurityService.h" -#include "mozilla/PermissionDelegateHandler.h" +#include "PermissionDelegateHandler.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/BasicEvents.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventStateManager.h" #include "mozilla/FullscreenChange.h" #include "mozilla/PendingAnimationTracker.h" #include "mozilla/intl/LocaleService.h" @@ -169,19 +169,19 @@ #include "nsIRequestContext.h" #include "nsStyleSheetService.h" #include "nsNetUtil.h" // for NS_NewURI #include "nsIInputStreamChannel.h" #include "nsIAuthPrompt.h" #include "nsIAuthPrompt2.h" -#include "mozilla/PermissionManager.h" #include "nsIScriptSecurityManager.h" #include "nsIPermission.h" +#include "nsPermissionManager.h" #include "nsIPrincipal.h" #include "nsIPrivateBrowsingChannel.h" #include "ExpandedPrincipal.h" #include "mozilla/NullPrincipal.h" #include "nsPIDOMWindow.h" #include "nsFocusManager.h" #include "nsICookieService.h" @@ -6818,18 +6818,17 @@ void Document::SetScopeObject(nsIGlobalO mScopeObject = do_GetWeakReference(aGlobal); if (aGlobal) { mHasHadScriptHandlingObject = true; nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal); if (!window) { return; } - BrowsingContextGroup* browsingContextGroup = - window->GetBrowsingContextGroup(); + BrowsingContextGroup* browsingContextGroup = window->GetBrowsingContextGroup(); // We should already have the principal, and now that we have been added // to a window, we should be able to join a DocGroup! nsAutoCString docGroupKey; nsresult rv = mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey); if (mDocGroup) { if (NS_SUCCEEDED(rv)) { MOZ_RELEASE_ASSERT(mDocGroup->MatchesKey(docGroupKey)); @@ -15888,17 +15887,17 @@ Document::AutomaticStorageAccessCanBeGra return AutomaticStorageAccessGrantPromise::CreateAndReject(false, __func__); } bool Document::AutomaticStorageAccessCanBeGranted(nsIPrincipal* aPrincipal) { nsAutoCString prefix; AntiTrackingUtils::CreateStoragePermissionKey(aPrincipal, prefix); - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); if (NS_WARN_IF(!permManager)) { return false; } typedef nsTArray<RefPtr<nsIPermission>> Permissions; Permissions perms; nsresult rv = permManager->GetAllWithTypePrefix(prefix, perms); if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -123,33 +123,33 @@ class nsSimpleContentList; class nsTextNode; class nsWindowSizes; class nsDOMCaretPosition; class nsViewportInfo; class nsIGlobalObject; class nsIAppWindow; class nsXULPrototypeDocument; class nsXULPrototypeElement; +class PermissionDelegateHandler; class nsIPermissionDelegateHandler; struct nsFont; struct StyleUseCounters; namespace mozilla { class AbstractThread; class StyleSheet; class EditorCommand; class Encoding; class ErrorResult; class EventStates; class EventListenerManager; class FullscreenExit; class FullscreenRequest; struct LangGroupFontPrefs; class PendingAnimationTracker; -class PermissionDelegateHandler; class PresShell; class ServoStyleSet; enum class StyleOrigin : uint8_t; class SMILAnimationController; enum class StyleCursorKind : uint8_t; enum class StylePrefersColorScheme : uint8_t; template <typename> class OwningNonNull;
--- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -68,17 +68,17 @@ #include "nsStringStream.h" #include "nsComponentManagerUtils.h" #include "nsICookieService.h" #include "nsIHttpChannel.h" #include "nsStreamUtils.h" #include "WidgetUtils.h" #include "nsIScriptError.h" #include "ReferrerInfo.h" -#include "mozilla/PermissionDelegateHandler.h" +#include "PermissionDelegateHandler.h" #include "nsIExternalProtocolHandler.h" #include "BrowserChild.h" #include "URIUtils.h" #include "mozilla/dom/MediaDevices.h" #include "MediaManager.h"
--- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -505,16 +505,17 @@ LOCAL_INCLUDES += [ '/dom/html', '/dom/ipc', '/dom/storage', '/dom/svg', '/dom/u2f', '/dom/xml', '/dom/xslt/xpath', '/dom/xul', + '/extensions/permissions', '/gfx/2d', '/image', '/js/xpconnect/loader', '/js/xpconnect/src', '/js/xpconnect/wrappers', '/layout/base', '/layout/forms', '/layout/generic',
--- a/dom/base/nsContentPermissionHelper.h +++ b/dom/base/nsContentPermissionHelper.h @@ -7,17 +7,17 @@ #ifndef nsContentPermissionHelper_h #define nsContentPermissionHelper_h #include "nsIContentPermissionPrompt.h" #include "nsTArray.h" #include "nsIMutableArray.h" #include "mozilla/dom/PContentPermissionRequestChild.h" #include "mozilla/dom/ipc/IdType.h" -#include "mozilla/PermissionDelegateHandler.h" +#include "PermissionDelegateHandler.h" // Microsoft's API Name hackery sucks // XXXbz Doing this in a header is a gigantic footgun. See // https://bugzilla.mozilla.org/show_bug.cgi?id=932421#c3 for why. #undef LoadImage class nsPIDOMWindowInner; class nsContentPermissionRequestProxy;
--- a/dom/base/nsIContentPolicy.idl +++ b/dom/base/nsIContentPolicy.idl @@ -393,17 +393,17 @@ interface nsIContentPolicy : nsISupports * implementations. */ const nsContentPolicyType TYPE_INTERNAL_PAINTWORKLET = 50; /* When adding new content types, please update * NS_CP_ContentTypeName, nsCSPContext, CSP_ContentTypeToDirective, * DoContentSecurityChecks, all nsIContentPolicy implementations, the * static_assert in dom/cache/DBSchema.cpp, ChannelWrapper.webidl, - * ChannelWrapper.cpp, PermissionManager.cpp, and other things that are not + * ChannelWrapper.cpp, nsPermissionManager.cpp, and other things that are not * listed here that are related to nsIContentPolicy. */ ////////////////////////////////////////////////////////////////////// /** * Returned from shouldLoad or shouldProcess if the load or process request * is rejected based on details of the request. */
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -204,18 +204,18 @@ #include "nsIScriptSecurityManager.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #ifdef MOZ_WEBRTC # include "signaling/src/peerconnection/WebrtcGlobalChild.h" #endif -#include "mozilla/Permission.h" -#include "mozilla/PermissionManager.h" +#include "nsPermission.h" +#include "nsPermissionManager.h" #include "PermissionMessageUtils.h" #if defined(MOZ_WIDGET_ANDROID) # include "APKOpen.h" #endif #ifdef XP_WIN @@ -2464,18 +2464,18 @@ mozilla::ipc::IPCResult ContentChild::Re LocaleService::GetInstance()->AssignRequestedLocales(aRequestedLocales); return IPC_OK(); } mozilla::ipc::IPCResult ContentChild::RecvAddPermission( const IPC::Permission& permission) { nsCOMPtr<nsIPermissionManager> permissionManagerIface = services::GetPermissionManager(); - PermissionManager* permissionManager = - static_cast<PermissionManager*>(permissionManagerIface.get()); + nsPermissionManager* permissionManager = + static_cast<nsPermissionManager*>(permissionManagerIface.get()); MOZ_ASSERT(permissionManager, "We have no permissionManager in the Content process !"); // note we do not need to force mUserContextId to the default here because // the permission manager does that internally. nsAutoCString originNoSuffix; OriginAttributes attrs; bool success = attrs.PopulateFromOrigin(permission.origin, originNoSuffix); @@ -2489,26 +2489,26 @@ mozilla::ipc::IPCResult ContentChild::Re mozilla::BasePrincipal::CreateContentPrincipal(uri, attrs); // child processes don't care about modification time. int64_t modificationTime = 0; permissionManager->AddInternal( principal, nsCString(permission.type), permission.capability, 0, permission.expireType, permission.expireTime, modificationTime, - PermissionManager::eNotify, PermissionManager::eNoDBOperation); + nsPermissionManager::eNotify, nsPermissionManager::eNoDBOperation); return IPC_OK(); } mozilla::ipc::IPCResult ContentChild::RecvRemoveAllPermissions() { nsCOMPtr<nsIPermissionManager> permissionManagerIface = services::GetPermissionManager(); - PermissionManager* permissionManager = - static_cast<PermissionManager*>(permissionManagerIface.get()); + nsPermissionManager* permissionManager = + static_cast<nsPermissionManager*>(permissionManagerIface.get()); MOZ_ASSERT(permissionManager, "We have no permissionManager in the Content process !"); permissionManager->RemoveAllFromIPC(); return IPC_OK(); } mozilla::ipc::IPCResult ContentChild::RecvFlushMemory(const nsString& reason) { @@ -3341,17 +3341,17 @@ nsresult ContentChild::AsyncOpenAnonymou // Remember the association with the callback. MOZ_ASSERT(!mPendingAnonymousTemporaryFiles.Get(newID)); mPendingAnonymousTemporaryFiles.LookupOrAdd(newID, aCallback); return NS_OK; } mozilla::ipc::IPCResult ContentChild::RecvSetPermissionsWithKey( const nsCString& aPermissionKey, nsTArray<IPC::Permission>&& aPerms) { - RefPtr<PermissionManager> permManager = PermissionManager::GetInstance(); + RefPtr<nsPermissionManager> permManager = nsPermissionManager::GetInstance(); if (permManager) { permManager->SetPermissionsWithKey(aPermissionKey, aPerms); } return IPC_OK(); } mozilla::ipc::IPCResult ContentChild::RecvRefreshScreens(
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -246,17 +246,17 @@ #if defined(XP_LINUX) # include "mozilla/Hal.h" #endif #ifdef ANDROID # include "gfxAndroidPlatform.h" #endif -#include "mozilla/PermissionManager.h" +#include "nsPermissionManager.h" #ifdef MOZ_WIDGET_ANDROID # include "AndroidBridge.h" #endif #ifdef MOZ_WIDGET_GTK # include <gdk/gdk.h> #endif @@ -5451,17 +5451,17 @@ nsresult ContentParent::AboutToLoadHttpF return NS_OK; } nsresult ContentParent::TransmitPermissionsForPrincipal( nsIPrincipal* aPrincipal) { // Create the key, and send it down to the content process. nsTArray<std::pair<nsCString, nsCString>> pairs = - PermissionManager::GetAllKeysForPrincipal(aPrincipal); + nsPermissionManager::GetAllKeysForPrincipal(aPrincipal); MOZ_ASSERT(pairs.Length() >= 1); for (auto& pair : pairs) { EnsurePermissionsByKey(pair.first, pair.second); } return NS_OK; } @@ -5501,17 +5501,17 @@ void ContentParent::TransmitBlobURLsForP void ContentParent::EnsurePermissionsByKey(const nsCString& aKey, const nsCString& aOrigin) { // NOTE: Make sure to initialize the permission manager before updating the // mActivePermissionKeys list. If the permission manager is being initialized // by this call to GetPermissionManager, and we've added the key to // mActivePermissionKeys, then the permission manager will send down a // SendAddPermission before receiving the SendSetPermissionsWithKey message. - RefPtr<PermissionManager> permManager = PermissionManager::GetInstance(); + RefPtr<nsPermissionManager> permManager = nsPermissionManager::GetInstance(); if (!permManager) { return; } if (mActivePermissionKeys.Contains(aKey)) { return; } mActivePermissionKeys.PutEntry(aKey);
--- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -184,16 +184,17 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/bindings', '/dom/events', '/dom/filesystem', '/dom/geolocation', '/dom/media/webspeech/synth/ipc', '/dom/security', '/dom/storage', + '/extensions/permissions', '/extensions/spellcheck/src', '/gfx/2d', '/hal/sandbox', '/js/xpconnect/loader', '/js/xpconnect/src', '/layout/base', '/media/webrtc', '/netwerk/base',
--- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -27,17 +27,16 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/UserActivation.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/media/MediaChild.h" #include "mozilla/media/MediaTaskUtils.h" #include "mozilla/MozPromise.h" #include "mozilla/NullPrincipal.h" #include "mozilla/PeerIdentity.h" -#include "mozilla/PermissionDelegateHandler.h" #include "mozilla/Sprintf.h" #include "mozilla/StaticPrefs_media.h" #include "mozilla/Telemetry.h" #include "mozilla/Types.h" #include "nsAppDirectoryServiceDefs.h" #include "nsArray.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" @@ -51,16 +50,17 @@ #include "nsJSUtils.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsPIDOMWindow.h" #include "nspr.h" #include "nsProxyRelease.h" #include "nss.h" #include "nsVariant.h" +#include "PermissionDelegateHandler.h" #include "pk11pub.h" #include "ThreadSafeRefcountingWithMainThreadDestruction.h" #include "VideoStreamTrack.h" #include "VideoUtils.h" #include "CubebDeviceEnumerator.h" /* Using WebRTC backend on Desktops (Mac, Windows, Linux), otherwise default */ #include "MediaEngineDefault.h"
--- a/dom/permission/PermissionStatus.cpp +++ b/dom/permission/PermissionStatus.cpp @@ -1,23 +1,23 @@ /* -*- 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 "mozilla/dom/PermissionStatus.h" -#include "mozilla/PermissionDelegateHandler.h" #include "mozilla/AsyncEventDispatcher.h" -#include "mozilla/Permission.h" #include "mozilla/Services.h" #include "nsIPermissionManager.h" #include "PermissionObserver.h" #include "PermissionUtils.h" +#include "nsPermission.h" +#include "PermissionDelegateHandler.h" namespace mozilla { namespace dom { /* static */ already_AddRefed<PermissionStatus> PermissionStatus::Create( nsPIDOMWindowInner* aWindow, PermissionName aName, ErrorResult& aRv) { RefPtr<PermissionStatus> status = new PermissionStatus(aWindow, aName); @@ -100,17 +100,17 @@ already_AddRefed<nsIPrincipal> Permissio } Document* doc = window->GetExtantDoc(); if (NS_WARN_IF(!doc)) { return nullptr; } nsCOMPtr<nsIPrincipal> principal = - Permission::ClonePrincipalForPermission(doc->NodePrincipal()); + nsPermission::ClonePrincipalForPermission(doc->NodePrincipal()); NS_ENSURE_TRUE(principal, nullptr); return principal.forget(); } void PermissionStatus::PermissionChanged() { auto oldState = mState; UpdateState();
--- a/dom/permission/moz.build +++ b/dom/permission/moz.build @@ -14,13 +14,17 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'PermissionObserver.cpp', 'Permissions.cpp', 'PermissionStatus.cpp', 'PermissionUtils.cpp', ] +LOCAL_INCLUDES += [ + '/extensions/permissions', +] + MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] FINAL_LIBRARY = 'xul' include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/serviceworkers/ServiceWorkerManager.cpp +++ b/dom/serviceworkers/ServiceWorkerManager.cpp @@ -48,22 +48,22 @@ #include "mozilla/dom/SharedWorker.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/dom/WorkerScope.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/dom/ScriptLoader.h" -#include "mozilla/PermissionManager.h" #include "mozilla/Unused.h" #include "mozilla/EnumSet.h" #include "nsContentUtils.h" #include "nsNetUtil.h" +#include "nsPermissionManager.h" #include "nsProxyRelease.h" #include "nsQueryObject.h" #include "nsTArray.h" #include "ServiceWorker.h" #include "ServiceWorkerContainer.h" #include "ServiceWorkerInfo.h" #include "ServiceWorkerJobQueue.h" @@ -2282,17 +2282,18 @@ void ServiceWorkerManager::DispatchFetch new ContinueDispatchFetchEventRunnable(serviceWorker->WorkerPrivate(), aChannel, loadGroup); // When this service worker was registered, we also sent down the permissions // for the runnable. They should have arrived by now, but we still need to // wait for them if they have not. nsCOMPtr<nsIRunnable> permissionsRunnable = NS_NewRunnableFunction( "dom::ServiceWorkerManager::DispatchFetchEvent", [=]() { - RefPtr<PermissionManager> permMgr = PermissionManager::GetInstance(); + RefPtr<nsPermissionManager> permMgr = + nsPermissionManager::GetInstance(); if (permMgr) { permMgr->WhenPermissionsAvailable(serviceWorker->Principal(), continueRunnable); } else { continueRunnable->HandleError(); } });
--- a/dom/serviceworkers/moz.build +++ b/dom/serviceworkers/moz.build @@ -102,16 +102,17 @@ IPDL_SOURCES += [ 'ServiceWorkerRegistrarTypes.ipdlh', ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ + '/extensions/permissions', '/js/xpconnect/loader', ] MOCHITEST_MANIFESTS += [ 'test/mochitest.ini', ] MOCHITEST_CHROME_MANIFESTS += [
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp @@ -10,16 +10,17 @@ #include "MainThreadUtils.h" #include "nsDebug.h" #include "nsError.h" #include "nsIConsoleReportCollector.h" #include "nsIInterfaceRequestor.h" #include "nsIPrincipal.h" #include "nsNetUtil.h" +#include "nsPermissionManager.h" #include "nsProxyRelease.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" #include "RemoteWorkerService.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/BasePrincipal.h" @@ -41,17 +42,16 @@ #include "mozilla/dom/workerinternals/ScriptLoader.h" #include "mozilla/dom/WorkerError.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRef.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/URIUtils.h" #include "mozilla/net/CookieJarSettings.h" -#include "mozilla/PermissionManager.h" namespace mozilla { using namespace ipc; namespace dom { using workerinternals::ChannelFromScriptURLMainThread; @@ -460,18 +460,18 @@ nsresult RemoteWorkerChild::ExecWorkerOn isPending = lock->is<Pending>(); } if (NS_WARN_IF(!isPending || !initializeWorkerRunnable->Dispatch())) { self->TransitionStateToTerminated(); self->CreationFailedOnAnyThread(); } }); - RefPtr<PermissionManager> permissionManager = - PermissionManager::GetInstance(); + RefPtr<nsPermissionManager> permissionManager = + nsPermissionManager::GetInstance(); if (!permissionManager) { return NS_ERROR_FAILURE; } permissionManager->WhenPermissionsAvailable(principal, r); } else { if (NS_WARN_IF(!runnable->Dispatch())) { rv = NS_ERROR_FAILURE; return rv;
--- a/dom/workers/remoteworkers/moz.build +++ b/dom/workers/remoteworkers/moz.build @@ -24,16 +24,17 @@ UNIFIED_SOURCES += [ 'RemoteWorkerParent.cpp', 'RemoteWorkerService.cpp', 'RemoteWorkerServiceChild.cpp', 'RemoteWorkerServiceParent.cpp', ] LOCAL_INCLUDES += [ '/dom/serviceworkers', + '/extensions/permissions', '/xpcom/build', ] IPDL_SOURCES += [ 'PRemoteWorker.ipdl', 'PRemoteWorkerController.ipdl', 'PRemoteWorkerService.ipdl', 'RemoteWorkerTypes.ipdlh',
--- a/extensions/permissions/PermissionDelegateHandler.cpp +++ b/extensions/permissions/PermissionDelegateHandler.cpp @@ -1,31 +1,28 @@ /* -*- Mode: C++; tab-width: 2; 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 "mozilla/PermissionDelegateHandler.h" - #include "nsGlobalWindowInner.h" +#include "PermissionDelegateHandler.h" #include "nsPIDOMWindow.h" +#include "nsPermissionManager.h" #include "nsIPrincipal.h" #include "nsContentPermissionHelper.h" #include "mozilla/BasePrincipal.h" #include "mozilla/StaticPrefs_permissions.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/FeaturePolicyUtils.h" -#include "mozilla/PermissionManager.h" +using namespace mozilla; using namespace mozilla::dom; - -namespace mozilla { - typedef PermissionDelegateHandler::PermissionDelegatePolicy DelegatePolicy; typedef PermissionDelegateHandler::PermissionDelegateInfo DelegateInfo; // Particular type of permissions to care about. We decide cases by case and // give various types of controls over each of these. static const DelegateInfo sPermissionsMap[] = { // Permissions API map {"geo", u"geolocation", DelegatePolicy::eDelegateUseFeaturePolicy}, @@ -130,17 +127,17 @@ nsresult PermissionDelegateHandler::GetD } return aRequest->GetPrincipal(aResult); } bool PermissionDelegateHandler::Initialize() { MOZ_ASSERT(mDocument); - mPermissionManager = PermissionManager::GetInstance(); + mPermissionManager = nsPermissionManager::GetInstance(); if (!mPermissionManager) { return false; } mPrincipal = mDocument->NodePrincipal(); nsPIDOMWindowInner* window = mDocument->GetInnerWindow(); nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(window); if (innerWindow) { @@ -240,10 +237,8 @@ nsresult PermissionDelegateHandler::GetP return (mPermissionManager->*testPermission)(principal, aType, aPermission); } nsresult PermissionDelegateHandler::GetPermissionForPermissionsAPI( const nsACString& aType, uint32_t* aPermission) { return GetPermission(aType, aPermission, false); } - -} // namespace mozilla
--- a/extensions/permissions/PermissionDelegateHandler.h +++ b/extensions/permissions/PermissionDelegateHandler.h @@ -18,32 +18,30 @@ * denied. if the top-level origin already has access to geolocation and the * iframe has been granted access to geolocation by Feature Policy, the iframe * will also have access to geolocation. If the top-level frame did not have * access to geolocation, and the iframe has been granted access to geolocation * by Feature Policy, a request from the cross-origin iframe would trigger a * prompt using of the top-level origin. */ -#ifndef mozilla_PermissionDelegateHandler_h -#define mozilla_PermissionDelegateHandler_h +#ifndef PermissionDelegateHandler_h__ +#define PermissionDelegateHandler_h__ -#include "nsCycleCollectionParticipant.h" #include "nsISupports.h" #include "nsIPermissionDelegateHandler.h" -#include "nsCOMPtr.h" -class nsIPermissionManager; class nsIPrincipal; class nsIContentPermissionRequest; namespace mozilla { namespace dom { class Document; } +} // namespace mozilla class PermissionDelegateHandler final : public nsIPermissionDelegateHandler { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(PermissionDelegateHandler) NS_DECL_NSIPERMISSIONDELEGATEHANDLER @@ -159,11 +157,9 @@ class PermissionDelegateHandler final : // A weak pointer to our document. Nulled out by DropDocumentReference. mozilla::dom::Document* mDocument; nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsIPrincipal> mTopLevelPrincipal; RefPtr<nsIPermissionManager> mPermissionManager; }; -} // namespace mozilla - -#endif // mozilla_PermissionDelegateHandler_h +#endif // PermissionDelegateHandler_h__
--- a/extensions/permissions/components.conf +++ b/extensions/permissions/components.conf @@ -5,18 +5,18 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. Classes = [ { 'cid': '{4f6b5e00-0c36-11d5-a535-0010a401eb10}', 'contract_ids': ['@mozilla.org/permissionmanager;1'], 'singleton': True, 'type': 'nsIPermissionManager', - 'constructor': 'mozilla::PermissionManager::GetXPCOMSingleton', - 'headers': ['/extensions/permissions/PermissionManager.h'], + 'constructor': 'nsPermissionManager::GetXPCOMSingleton', + 'headers': ['/extensions/permissions/nsPermissionManager.h'], }, { 'cid': '{07611dc6-bf4d-4d8a-a64b-f3a5904dddc7}', 'contract_ids': ['@mozilla.org/permissiondelegatehandler;1'], 'type': 'PermissionDelegateHandler', 'headers': ['/extensions/permissions/PermissionDelegateHandler.h'], }, ]
--- a/extensions/permissions/moz.build +++ b/extensions/permissions/moz.build @@ -5,26 +5,24 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. TEST_DIRS += ['test'] TESTING_JS_MODULES += [ 'test/PermissionTestUtils.jsm', ] -EXPORTS.mozilla += [ - 'Permission.h', +EXPORTS += [ 'PermissionDelegateHandler.h', - 'PermissionManager.h', ] UNIFIED_SOURCES += [ - 'Permission.cpp', + 'nsPermission.cpp', + 'nsPermissionManager.cpp', 'PermissionDelegateHandler.cpp', - 'PermissionManager.cpp', ] XPCOM_MANIFESTS += [ 'components.conf', ] LOCAL_INCLUDES += [ '/caps',
rename from extensions/permissions/Permission.cpp rename to extensions/permissions/nsPermission.cpp --- a/extensions/permissions/Permission.cpp +++ b/extensions/permissions/nsPermission.cpp @@ -1,39 +1,38 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 "mozilla/Permission.h" +#include "nsPermission.h" +#include "nsContentUtils.h" #include "nsIClassInfoImpl.h" #include "nsIEffectiveTLDService.h" #include "nsNetCID.h" #include "nsNetUtil.h" #include "mozilla/BasePrincipal.h" #include "mozilla/StaticPrefs_permissions.h" -namespace mozilla { - -// Permission Implementation +// nsPermission Implementation -NS_IMPL_CLASSINFO(Permission, nullptr, 0, {0}) -NS_IMPL_ISUPPORTS_CI(Permission, nsIPermission) +NS_IMPL_CLASSINFO(nsPermission, nullptr, 0, {0}) +NS_IMPL_ISUPPORTS_CI(nsPermission, nsIPermission) -Permission::Permission(nsIPrincipal* aPrincipal, const nsACString& aType, - uint32_t aCapability, uint32_t aExpireType, - int64_t aExpireTime, int64_t aModificationTime) +nsPermission::nsPermission(nsIPrincipal* aPrincipal, const nsACString& aType, + uint32_t aCapability, uint32_t aExpireType, + int64_t aExpireTime, int64_t aModificationTime) : mPrincipal(aPrincipal), mType(aType), mCapability(aCapability), mExpireType(aExpireType), mExpireTime(aExpireTime), mModificationTime(aModificationTime) {} -already_AddRefed<nsIPrincipal> Permission::ClonePrincipalForPermission( +already_AddRefed<nsIPrincipal> nsPermission::ClonePrincipalForPermission( nsIPrincipal* aPrincipal) { MOZ_ASSERT(aPrincipal); mozilla::OriginAttributes attrs = aPrincipal->OriginAttributesRef(); if (!StaticPrefs::permissions_isolateBy_userContext()) { attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID); } @@ -43,88 +42,89 @@ already_AddRefed<nsIPrincipal> Permissio nsCOMPtr<nsIURI> uri; rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); NS_ENSURE_SUCCESS(rv, nullptr); return mozilla::BasePrincipal::CreateContentPrincipal(uri, attrs); } -already_AddRefed<Permission> Permission::Create( +already_AddRefed<nsPermission> nsPermission::Create( nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aCapability, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime) { NS_ENSURE_TRUE(aPrincipal, nullptr); nsCOMPtr<nsIPrincipal> principal = - Permission::ClonePrincipalForPermission(aPrincipal); + nsPermission::ClonePrincipalForPermission(aPrincipal); NS_ENSURE_TRUE(principal, nullptr); - RefPtr<Permission> permission = - new Permission(principal, aType, aCapability, aExpireType, aExpireTime, - aModificationTime); + RefPtr<nsPermission> permission = + new nsPermission(principal, aType, aCapability, aExpireType, aExpireTime, + aModificationTime); return permission.forget(); } NS_IMETHODIMP -Permission::GetPrincipal(nsIPrincipal** aPrincipal) { +nsPermission::GetPrincipal(nsIPrincipal** aPrincipal) { nsCOMPtr<nsIPrincipal> copy = mPrincipal; copy.forget(aPrincipal); return NS_OK; } NS_IMETHODIMP -Permission::GetType(nsACString& aType) { +nsPermission::GetType(nsACString& aType) { aType = mType; return NS_OK; } NS_IMETHODIMP -Permission::GetCapability(uint32_t* aCapability) { +nsPermission::GetCapability(uint32_t* aCapability) { *aCapability = mCapability; return NS_OK; } NS_IMETHODIMP -Permission::GetExpireType(uint32_t* aExpireType) { +nsPermission::GetExpireType(uint32_t* aExpireType) { *aExpireType = mExpireType; return NS_OK; } NS_IMETHODIMP -Permission::GetExpireTime(int64_t* aExpireTime) { +nsPermission::GetExpireTime(int64_t* aExpireTime) { *aExpireTime = mExpireTime; return NS_OK; } NS_IMETHODIMP -Permission::GetModificationTime(int64_t* aModificationTime) { +nsPermission::GetModificationTime(int64_t* aModificationTime) { *aModificationTime = mModificationTime; return NS_OK; } NS_IMETHODIMP -Permission::Matches(nsIPrincipal* aPrincipal, bool aExactHost, bool* aMatches) { +nsPermission::Matches(nsIPrincipal* aPrincipal, bool aExactHost, + bool* aMatches) { NS_ENSURE_ARG_POINTER(aPrincipal); NS_ENSURE_ARG_POINTER(aMatches); *aMatches = false; nsCOMPtr<nsIPrincipal> principal = - Permission::ClonePrincipalForPermission(aPrincipal); + nsPermission::ClonePrincipalForPermission(aPrincipal); if (!principal) { *aMatches = false; return NS_OK; } return MatchesPrincipalForPermission(principal, aExactHost, aMatches); } NS_IMETHODIMP -Permission::MatchesPrincipalForPermission(nsIPrincipal* aPrincipal, - bool aExactHost, bool* aMatches) { +nsPermission::MatchesPrincipalForPermission(nsIPrincipal* aPrincipal, + bool aExactHost, bool* aMatches) { NS_ENSURE_ARG_POINTER(aPrincipal); NS_ENSURE_ARG_POINTER(aMatches); *aMatches = false; // If the principals are equal, then they match. if (mPrincipal->Equals(aPrincipal)) { *aMatches = true; @@ -202,30 +202,29 @@ Permission::MatchesPrincipalForPermissio // This loop will not loop forever, as GetNextSubDomain will eventually fail // with NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS. while (theirHost != ourHost) { rv = tldService->GetNextSubDomain(theirHost, theirHost); if (NS_FAILED(rv)) { if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { return NS_OK; + } else { + return rv; } - return rv; } } *aMatches = true; return NS_OK; } NS_IMETHODIMP -Permission::MatchesURI(nsIURI* aURI, bool aExactHost, bool* aMatches) { +nsPermission::MatchesURI(nsIURI* aURI, bool aExactHost, bool* aMatches) { NS_ENSURE_ARG_POINTER(aURI); mozilla::OriginAttributes attrs; nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateContentPrincipal(aURI, attrs); NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); return Matches(principal, aExactHost, aMatches); } - -} // namespace mozilla
rename from extensions/permissions/Permission.h rename to extensions/permissions/nsPermission.h --- a/extensions/permissions/Permission.h +++ b/extensions/permissions/nsPermission.h @@ -1,49 +1,45 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ -#ifndef mozilla_Permission_h -#define mozilla_Permission_h +#ifndef nsPermission_h__ +#define nsPermission_h__ #include "nsIPermission.h" #include "nsCOMPtr.h" #include "nsString.h" -namespace mozilla { - //////////////////////////////////////////////////////////////////////////////// -class Permission : public nsIPermission { +class nsPermission : public nsIPermission { public: // nsISupports NS_DECL_ISUPPORTS NS_DECL_NSIPERMISSION - static already_AddRefed<Permission> Create( + static already_AddRefed<nsPermission> Create( nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aCapability, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime); // This method creates a new nsIPrincipal with a stripped OriginAttributes (no // userContextId) and a content principal equal to the origin of 'aPrincipal'. static already_AddRefed<nsIPrincipal> ClonePrincipalForPermission( nsIPrincipal* aPrincipal); protected: - Permission(nsIPrincipal* aPrincipal, const nsACString& aType, - uint32_t aCapability, uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime); + nsPermission(nsIPrincipal* aPrincipal, const nsACString& aType, + uint32_t aCapability, uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime); - virtual ~Permission() = default; + virtual ~nsPermission(){}; nsCOMPtr<nsIPrincipal> mPrincipal; nsCString mType; uint32_t mCapability; uint32_t mExpireType; int64_t mExpireTime; int64_t mModificationTime; }; -} // namespace mozilla - -#endif // mozilla_Permission_h +#endif // nsPermission_h__
rename from extensions/permissions/PermissionManager.cpp rename to extensions/permissions/nsPermissionManager.cpp --- a/extensions/permissions/PermissionManager.cpp +++ b/extensions/permissions/nsPermissionManager.cpp @@ -1,67 +1,78 @@ /* -*- Mode: C++; tab-width: 2; 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 "mozilla/AbstractThread.h" +#include "mozilla/Attributes.h" +#include "mozilla/dom/ContentParent.h" #include "mozilla/BasePrincipal.h" -#include "mozilla/ClearOnShutdown.h" #include "mozilla/ContentBlockingUserInteraction.h" #include "mozilla/ContentPrincipal.h" #include "mozilla/DebugOnly.h" -#include "mozilla/dom/ContentParent.h" -#include "mozilla/ExpandedPrincipal.h" +#include "mozilla/Services.h" +#include "nsPermissionManager.h" +#include "nsPermission.h" +#include "nsCRT.h" +#include "nsNetUtil.h" +#include "nsTArray.h" +#include "nsReadableUtils.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceDefs.h" +#include "mozIStorageCompletionCallback.h" +#include "mozIStorageService.h" +#include "mozIStorageStatementCallback.h" +#include "mozilla/storage.h" +#include "mozilla/Attributes.h" +#include "nsXULAppAPI.h" +#include "nsIIdleService.h" +#include "nsIPrincipal.h" +#include "nsIURIMutator.h" +#include "nsContentUtils.h" +#include "nsPIDOMWindow.h" +#include "mozilla/dom/Document.h" #include "mozilla/net/NeckoMessageUtils.h" -#include "mozilla/Permission.h" -#include "mozilla/PermissionManager.h" #include "mozilla/Preferences.h" #include "mozilla/StaticPrefs_permissions.h" +#include "nsReadLine.h" #include "mozilla/Telemetry.h" - -#include "mozIStorageService.h" -#include "mozIStorageConnection.h" -#include "mozIStorageStatement.h" -#include "mozStorageCID.h" - -#include "nsAppDirectoryServiceDefs.h" -#include "nsContentUtils.h" -#include "nsEffectiveTLDService.h" #include "nsIConsoleService.h" -#include "nsIIdleService.h" -#include "nsIInputStream.h" #include "nsINavHistoryService.h" -#include "nsIObserverService.h" -#include "nsIPrefBranch.h" -#include "nsIPrincipal.h" -#include "nsIURIMutator.h" -#include "nsReadLine.h" #include "nsToolkitCompsCID.h" - +#include "nsIObserverService.h" +#include "nsPrintfCString.h" +#include "mozilla/AbstractThread.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/ClearOnShutdown.h" +#include "nsEffectiveTLDService.h" + +static mozilla::StaticRefPtr<nsPermissionManager> gPermissionManager; + +// Initially, |false|. Set to |true| once shutdown has started, to avoid +// reopening the database. +static bool gIsShuttingDown = false; + +using namespace mozilla; using namespace mozilla::dom; -namespace mozilla { - -#define PERMISSIONS_FILE_NAME "permissions.sqlite" -#define HOSTS_SCHEMA_VERSION 11 - -// Default permissions are read from a URL - this is the preference we read -// to find that URL. If not set, don't use any default permissions. -constexpr char kDefaultsUrlPrefName[] = "permissions.manager.defaultsUrl"; - -constexpr char kPermissionChangeNotification[] = PERM_CHANGE_NOTIFICATION; - -// A special value for a permission ID that indicates the ID was loaded as -// a default value. These will never be written to the database, but may -// be overridden with an explicit permission (including UNKNOWN_ACTION) -constexpr int64_t cIDPermissionIsDefault = -1; - -static StaticRefPtr<PermissionManager> gPermissionManager; +static bool IsChildProcess() { return XRE_IsContentProcess(); } + +static void LogToConsole(const nsAString& aMsg) { + nsCOMPtr<nsIConsoleService> console( + do_GetService("@mozilla.org/consoleservice;1")); + if (!console) { + NS_WARNING("Failed to log message to console."); + return; + } + + nsAutoString msg(aMsg); + console->LogStringMessage(msg.get()); +} #define ENSURE_NOT_CHILD_PROCESS_(onError) \ PR_BEGIN_MACRO \ if (IsChildProcess()) { \ NS_ERROR("Cannot perform action in content process!"); \ onError \ } \ PR_END_MACRO @@ -72,51 +83,16 @@ static StaticRefPtr<PermissionManager> g #define ENSURE_NOT_CHILD_PROCESS_NORET ENSURE_NOT_CHILD_PROCESS_(;) #define EXPIRY_NOW PR_Now() / 1000 //////////////////////////////////////////////////////////////////////////////// namespace { -bool IsChildProcess() { return XRE_IsContentProcess(); } - -void LogToConsole(const nsAString& aMsg) { - nsCOMPtr<nsIConsoleService> console( - do_GetService("@mozilla.org/consoleservice;1")); - if (!console) { - NS_WARNING("Failed to log message to console."); - return; - } - - nsAutoString msg(aMsg); - console->LogStringMessage(msg.get()); -} - -// NOTE: an empty string can be passed as aType - if it is this function will -// return "false" unconditionally. -bool HasDefaultPref(const nsACString& aType) { - // A list of permissions that can have a fallback default permission - // set under the permissions.default.* pref. - static const nsLiteralCString kPermissionsWithDefaults[] = { - NS_LITERAL_CSTRING("camera"), NS_LITERAL_CSTRING("microphone"), - NS_LITERAL_CSTRING("geo"), NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("shortcuts")}; - - if (!aType.IsEmpty()) { - for (const auto& perm : kPermissionsWithDefaults) { - if (perm.Equals(aType)) { - return true; - } - } - } - - return false; -} - // These permissions are special permissions which must be transmitted to the // content process before documents with their principals have loaded within // that process. // // Permissions which are in this list are considered to have a "" permission // key, even if their principal would not normally have that key. static const nsLiteralCString kPreloadPermissions[] = { // This permission is preloaded to support properly blocking service worker @@ -216,17 +192,17 @@ nsresult GetOriginFromPrincipal(nsIPrinc if (NS_FAILED(rv)) { return rv; } nsAutoCString suffix; rv = aPrincipal->GetOriginSuffix(suffix); NS_ENSURE_SUCCESS(rv, rv); - OriginAttributes attrs; + mozilla::OriginAttributes attrs; if (!attrs.PopulateFromSuffix(suffix)) { return NS_ERROR_FAILURE; } OriginAppendOASuffix(attrs, aForceStripOA, aOrigin); return NS_OK; } @@ -243,48 +219,48 @@ nsresult GetOriginFromURIAndOA(nsIURI* a aOrigin = origin; return NS_OK; } nsresult GetPrincipalFromOrigin(const nsACString& aOrigin, bool aForceStripOA, nsIPrincipal** aPrincipal) { nsAutoCString originNoSuffix; - OriginAttributes attrs; + mozilla::OriginAttributes attrs; if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) { return NS_ERROR_FAILURE; } MaybeStripOAs(aForceStripOA, attrs); nsCOMPtr<nsIURI> uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIPrincipal> principal = - BasePrincipal::CreateContentPrincipal(uri, attrs); + mozilla::BasePrincipal::CreateContentPrincipal(uri, attrs); principal.forget(aPrincipal); return NS_OK; } nsresult GetPrincipal(nsIURI* aURI, bool aIsInIsolatedMozBrowserElement, nsIPrincipal** aPrincipal) { - OriginAttributes attrs(aIsInIsolatedMozBrowserElement); + mozilla::OriginAttributes attrs(aIsInIsolatedMozBrowserElement); nsCOMPtr<nsIPrincipal> principal = - BasePrincipal::CreateContentPrincipal(aURI, attrs); + mozilla::BasePrincipal::CreateContentPrincipal(aURI, attrs); NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); principal.forget(aPrincipal); return NS_OK; } nsresult GetPrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal) { - OriginAttributes attrs; + mozilla::OriginAttributes attrs; nsCOMPtr<nsIPrincipal> principal = - BasePrincipal::CreateContentPrincipal(aURI, attrs); + mozilla::BasePrincipal::CreateContentPrincipal(aURI, attrs); NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); principal.forget(aPrincipal); return NS_OK; } nsCString GetNextSubDomainForHost(const nsACString& aHost) { nsCString subDomain; @@ -337,37 +313,208 @@ already_AddRefed<nsIPrincipal> GetNextSu // Create a new principal which is identical to the current one, but with the // new host nsCOMPtr<nsIURI> newURI = GetNextSubDomainURI(uri); if (!newURI) { return nullptr; } // Copy the attributes over - OriginAttributes attrs = aPrincipal->OriginAttributesRef(); + mozilla::OriginAttributes attrs = aPrincipal->OriginAttributesRef(); if (!StaticPrefs::permissions_isolateBy_userContext()) { // Disable userContext for permissions. - attrs.StripAttributes(OriginAttributes::STRIP_USER_CONTEXT_ID); + attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID); } nsCOMPtr<nsIPrincipal> principal = - BasePrincipal::CreateContentPrincipal(newURI, attrs); + mozilla::BasePrincipal::CreateContentPrincipal(newURI, attrs); return principal.forget(); } +class MOZ_STACK_CLASS UpgradeHostToOriginHelper { + public: + virtual nsresult Insert(const nsACString& aOrigin, const nsCString& aType, + uint32_t aPermission, uint32_t aExpireType, + int64_t aExpireTime, int64_t aModificationTime) = 0; +}; + +class MOZ_STACK_CLASS UpgradeHostToOriginDBMigration final + : public UpgradeHostToOriginHelper { + public: + UpgradeHostToOriginDBMigration(mozIStorageConnection* aDBConn, int64_t* aID) + : mDBConn(aDBConn), mID(aID) { + mDBConn->CreateStatement( + NS_LITERAL_CSTRING("INSERT INTO moz_hosts_new " + "(id, origin, type, permission, expireType, " + "expireTime, modificationTime) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), + getter_AddRefs(mStmt)); + } + + nsresult Insert(const nsACString& aOrigin, const nsCString& aType, + uint32_t aPermission, uint32_t aExpireType, + int64_t aExpireTime, int64_t aModificationTime) final { + nsresult rv = mStmt->BindInt64ByIndex(0, *mID); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(1, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(2, aType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(3, aPermission); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(4, aExpireType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(5, aExpireTime); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(6, aModificationTime); + NS_ENSURE_SUCCESS(rv, rv); + + // Increment the working identifier, as we are about to use this one + (*mID)++; + + rv = mStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + private: + nsCOMPtr<mozIStorageStatement> mStmt; + nsCOMPtr<mozIStorageConnection> mDBConn; + int64_t* mID; +}; + +class MOZ_STACK_CLASS UpgradeHostToOriginHostfileImport final + : public UpgradeHostToOriginHelper { + public: + UpgradeHostToOriginHostfileImport( + nsPermissionManager* aPm, nsPermissionManager::DBOperationType aOperation, + int64_t aID) + : mPm(aPm), mOperation(aOperation), mID(aID) {} + + nsresult Insert(const nsACString& aOrigin, const nsCString& aType, + uint32_t aPermission, uint32_t aExpireType, + int64_t aExpireTime, int64_t aModificationTime) final { + nsCOMPtr<nsIPrincipal> principal; + nsresult rv = GetPrincipalFromOrigin( + aOrigin, IsOAForceStripPermission(aType), getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + return mPm->AddInternal(principal, aType, aPermission, mID, aExpireType, + aExpireTime, aModificationTime, + nsPermissionManager::eDontNotify, mOperation, false, + &aOrigin); + } + + private: + RefPtr<nsPermissionManager> mPm; + nsPermissionManager::DBOperationType mOperation; + int64_t mID; +}; + +class MOZ_STACK_CLASS UpgradeIPHostToOriginDB final + : public UpgradeHostToOriginHelper { + public: + UpgradeIPHostToOriginDB(mozIStorageConnection* aDBConn, int64_t* aID) + : mDBConn(aDBConn), mID(aID) { + mDBConn->CreateStatement( + NS_LITERAL_CSTRING("INSERT INTO moz_perms" + "(id, origin, type, permission, expireType, " + "expireTime, modificationTime) " + "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), + getter_AddRefs(mStmt)); + + mDBConn->CreateStatement( + NS_LITERAL_CSTRING( + "SELECT id FROM moz_perms WHERE origin = ?1 AND type = ?2"), + getter_AddRefs(mLookupStmt)); + } + + nsresult Insert(const nsACString& aOrigin, const nsCString& aType, + uint32_t aPermission, uint32_t aExpireType, + int64_t aExpireTime, int64_t aModificationTime) final { + // Every time the migration code wants to insert an origin into + // the database we need to check to see if someone has already + // created a permissions entry for that permission. If they have, + // we don't want to insert a duplicate row. + // + // We can afford to do this lookup unconditionally and not perform + // caching, as a origin type pair should only be attempted to be + // inserted once. + + nsresult rv = mLookupStmt->Reset(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mLookupStmt->BindUTF8StringByIndex(0, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mLookupStmt->BindUTF8StringByIndex(1, aType); + NS_ENSURE_SUCCESS(rv, rv); + + // Check if we already have the row in the database, if we do, then + // we don't want to be inserting it again. + bool moreStmts = false; + if (NS_FAILED(mLookupStmt->ExecuteStep(&moreStmts)) || moreStmts) { + mLookupStmt->Reset(); + NS_WARNING( + "A permissions entry was going to be re-migrated, " + "but was already found in the permissions database."); + return NS_OK; + } + + // Actually insert the statement into the database. + rv = mStmt->BindInt64ByIndex(0, *mID); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(1, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindUTF8StringByIndex(2, aType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(3, aPermission); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt32ByIndex(4, aExpireType); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(5, aExpireTime); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mStmt->BindInt64ByIndex(6, aModificationTime); + NS_ENSURE_SUCCESS(rv, rv); + + // Increment the working identifier, as we are about to use this one + (*mID)++; + + rv = mStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + private: + nsCOMPtr<mozIStorageStatement> mStmt; + nsCOMPtr<mozIStorageStatement> mLookupStmt; + nsCOMPtr<mozIStorageConnection> mDBConn; + int64_t* mID; +}; + nsresult UpgradeHostToOriginAndInsert( const nsACString& aHost, const nsCString& aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime, - bool aIsInIsolatedMozBrowserElement, - std::function<nsresult(const nsACString& aOrigin, const nsCString& aType, - uint32_t aPermission, uint32_t aExpireType, - int64_t aExpireTime, int64_t aModificationTime)>&& - aCallback) { + bool aIsInIsolatedMozBrowserElement, UpgradeHostToOriginHelper* aHelper) { if (aHost.EqualsLiteral("<file>")) { // We no longer support the magic host <file> NS_WARNING( "The magic host <file> is no longer supported. " "It is being removed from the permissions database."); return NS_OK; } @@ -389,18 +536,18 @@ nsresult UpgradeHostToOriginAndInsert( getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString origin; rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), origin); NS_ENSURE_SUCCESS(rv, rv); - aCallback(origin, aType, aPermission, aExpireType, aExpireTime, - aModificationTime); + return aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, + aModificationTime); return NS_OK; } // The user may use this host at non-standard ports or protocols, we can use // their history to guess what ports and protocols we want to add permissions // for. We find every URI which they have visited with this host (or a // subdomain of this host), and try to add it as a principal. bool foundHistory = false; @@ -511,18 +658,18 @@ nsresult UpgradeHostToOriginAndInsert( if (NS_WARN_IF(NS_FAILED(rv))) continue; // Ensure that we don't insert the same origin repeatedly if (insertedOrigins.Contains(origin)) { continue; } foundHistory = true; - rv = aCallback(origin, aType, aPermission, aExpireType, aExpireTime, - aModificationTime); + rv = aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, + aModificationTime); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Insert failed"); insertedOrigins.PutEntry(origin); } rv = histResultContainer->SetContainerOpen(false); NS_ENSURE_SUCCESS(rv, rv); } @@ -553,666 +700,703 @@ nsresult UpgradeHostToOriginAndInsert( rv = GetPrincipal(uri, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), origin); NS_ENSURE_SUCCESS(rv, rv); - aCallback(origin, aType, aPermission, aExpireType, aExpireTime, - aModificationTime); + aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, + aModificationTime); // https:// URI default rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostSegment); NS_ENSURE_SUCCESS(rv, rv); rv = GetPrincipal(uri, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); rv = GetOriginFromPrincipal(principal, IsOAForceStripPermission(aType), origin); NS_ENSURE_SUCCESS(rv, rv); - aCallback(origin, aType, aPermission, aExpireType, aExpireTime, - aModificationTime); + aHelper->Insert(origin, aType, aPermission, aExpireType, aExpireTime, + aModificationTime); } return NS_OK; } -bool IsExpandedPrincipal(nsIPrincipal* aPrincipal) { +static bool IsExpandedPrincipal(nsIPrincipal* aPrincipal) { nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal); return !!ep; } // We only want to persist permissions which don't have session or policy // expiration. -bool IsPersistentExpire(uint32_t aExpire, const nsACString& aType) { +static bool IsPersistentExpire(uint32_t aExpire, const nsACString& aType) { bool res = (aExpire != nsIPermissionManager::EXPIRE_SESSION && aExpire != nsIPermissionManager::EXPIRE_POLICY); #ifdef ANDROID for (const auto& perm : kGeckoViewRestrictedPermissions) { res = res && !perm.Equals(aType); } #endif return res; } } // namespace //////////////////////////////////////////////////////////////////////////////// -PermissionManager::PermissionKey* -PermissionManager::PermissionKey::CreateFromPrincipal(nsIPrincipal* aPrincipal, - bool aForceStripOA, - nsresult& aResult) { +nsPermissionManager::PermissionKey* +nsPermissionManager::PermissionKey::CreateFromPrincipal( + nsIPrincipal* aPrincipal, bool aForceStripOA, nsresult& aResult) { nsAutoCString origin; aResult = GetOriginFromPrincipal(aPrincipal, aForceStripOA, origin); if (NS_WARN_IF(NS_FAILED(aResult))) { return nullptr; } return new PermissionKey(origin); } -PermissionManager::PermissionKey* -PermissionManager::PermissionKey::CreateFromURIAndOriginAttributes( +nsPermissionManager::PermissionKey* +nsPermissionManager::PermissionKey::CreateFromURIAndOriginAttributes( nsIURI* aURI, const OriginAttributes* aOriginAttributes, bool aForceStripOA, nsresult& aResult) { nsAutoCString origin; aResult = GetOriginFromURIAndOA(aURI, aOriginAttributes, aForceStripOA, origin); if (NS_WARN_IF(NS_FAILED(aResult))) { return nullptr; } return new PermissionKey(origin); } -PermissionManager::PermissionKey* -PermissionManager::PermissionKey::CreateFromURI(nsIURI* aURI, - nsresult& aResult) { +nsPermissionManager::PermissionKey* +nsPermissionManager::PermissionKey::CreateFromURI(nsIURI* aURI, + nsresult& aResult) { nsAutoCString origin; aResult = ContentPrincipal::GenerateOriginNoSuffixFromURI(aURI, origin); if (NS_WARN_IF(NS_FAILED(aResult))) { return nullptr; } return new PermissionKey(origin); } +/** + * Simple callback used by |AsyncClose| to trigger a treatment once + * the database is closed. + * + * Note: Beware that, if you hold onto a |CloseDatabaseListener| from a + * |nsPermissionManager|, this will create a cycle. + * + * Note: Once the callback has been called this DeleteFromMozHostListener cannot + * be reused. + */ +class CloseDatabaseListener final : public mozIStorageCompletionCallback { + ~CloseDatabaseListener() {} + + public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGECOMPLETIONCALLBACK + /** + * @param aManager The owning manager. + * @param aRebuildOnSuccess If |true|, reinitialize the database once + * it has been closed. Otherwise, do nothing such. + */ + CloseDatabaseListener(nsPermissionManager* aManager, bool aRebuildOnSuccess); + + protected: + RefPtr<nsPermissionManager> mManager; + bool mRebuildOnSuccess; +}; + +NS_IMPL_ISUPPORTS(CloseDatabaseListener, mozIStorageCompletionCallback) + +CloseDatabaseListener::CloseDatabaseListener(nsPermissionManager* aManager, + bool aRebuildOnSuccess) + : mManager(aManager), mRebuildOnSuccess(aRebuildOnSuccess) {} + +NS_IMETHODIMP +CloseDatabaseListener::Complete(nsresult, nsISupports*) { + // Help breaking cycles + RefPtr<nsPermissionManager> manager = std::move(mManager); + if (mRebuildOnSuccess && !gIsShuttingDown) { + return manager->InitDB(true); + } + return NS_OK; +} + +/** + * Simple callback used by |RemoveAllInternal| to trigger closing + * the database and reinitializing it. + * + * Note: Beware that, if you hold onto a |DeleteFromMozHostListener| from a + * |nsPermissionManager|, this will create a cycle. + * + * Note: Once the callback has been called this DeleteFromMozHostListener cannot + * be reused. + */ +class DeleteFromMozHostListener final : public mozIStorageStatementCallback { + ~DeleteFromMozHostListener() {} + + public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGESTATEMENTCALLBACK + + /** + * @param aManager The owning manager. + */ + explicit DeleteFromMozHostListener(nsPermissionManager* aManager); + + protected: + RefPtr<nsPermissionManager> mManager; +}; + +NS_IMPL_ISUPPORTS(DeleteFromMozHostListener, mozIStorageStatementCallback) + +DeleteFromMozHostListener::DeleteFromMozHostListener( + nsPermissionManager* aManager) + : mManager(aManager) {} + +NS_IMETHODIMP DeleteFromMozHostListener::HandleResult(mozIStorageResultSet*) { + MOZ_CRASH("Should not get any results"); +} + +NS_IMETHODIMP DeleteFromMozHostListener::HandleError(mozIStorageError*) { + // Errors are handled in |HandleCompletion| + return NS_OK; +} + +NS_IMETHODIMP DeleteFromMozHostListener::HandleCompletion(uint16_t aReason) { + // Help breaking cycles + RefPtr<nsPermissionManager> manager = std::move(mManager); + + if (aReason == REASON_ERROR) { + manager->CloseDB(true); + } + + return NS_OK; +} + /* static */ -void PermissionManager::Startup() { +void nsPermissionManager::Startup() { nsCOMPtr<nsIPermissionManager> permManager = do_GetService("@mozilla.org/permissionmanager;1"); } //////////////////////////////////////////////////////////////////////////////// -// PermissionManager Implementation - -NS_IMPL_ISUPPORTS(PermissionManager, nsIPermissionManager, nsIObserver, +// nsPermissionManager Implementation + +#define PERMISSIONS_FILE_NAME "permissions.sqlite" +#define HOSTS_SCHEMA_VERSION 11 + +// Default permissions are read from a URL - this is the preference we read +// to find that URL. If not set, don't use any default permissions. +static const char kDefaultsUrlPrefName[] = "permissions.manager.defaultsUrl"; + +static const char kPermissionChangeNotification[] = PERM_CHANGE_NOTIFICATION; + +NS_IMPL_ISUPPORTS(nsPermissionManager, nsIPermissionManager, nsIObserver, nsISupportsWeakReference) -PermissionManager::PermissionManager() - : mMonitor("PermissionManager::mMonitor"), - mState(eInitializing), - mMemoryOnlyDB(false), - mLargestID(0) {} - -PermissionManager::~PermissionManager() { +nsPermissionManager::nsPermissionManager() + : mMemoryOnlyDB(false), mLargestID(0) {} + +nsPermissionManager::~nsPermissionManager() { // NOTE: Make sure to reject each of the promises in mPermissionKeyPromiseMap // before destroying. for (auto iter = mPermissionKeyPromiseMap.Iter(); !iter.Done(); iter.Next()) { if (iter.Data()) { iter.Data()->Reject(NS_ERROR_FAILURE, __func__); } } mPermissionKeyPromiseMap.Clear(); RemoveAllFromMemory(); if (gPermissionManager) { MOZ_ASSERT(gPermissionManager == this); gPermissionManager = nullptr; } - - if (mThread) { - mThread->Shutdown(); - mThread = nullptr; - } } // static -already_AddRefed<nsIPermissionManager> PermissionManager::GetXPCOMSingleton() { +already_AddRefed<nsIPermissionManager> +nsPermissionManager::GetXPCOMSingleton() { if (gPermissionManager) { return do_AddRef(gPermissionManager); } - // Create a new singleton PermissionManager. + if (gIsShuttingDown) { + return nullptr; + } + + // Create a new singleton nsPermissionManager. // We AddRef only once since XPCOM has rules about the ordering of module // teardowns - by the time our module destructor is called, it's too late to // Release our members, since GC cycles have already been completed and // would result in serious leaks. // See bug 209571. - auto permManager = MakeRefPtr<PermissionManager>(); + auto permManager = MakeRefPtr<nsPermissionManager>(); if (NS_SUCCEEDED(permManager->Init())) { - // Note: This is cleared in the PermissionManager destructor. + // Note: This is cleared in the nsPermissionManager destructor. gPermissionManager = permManager.get(); ClearOnShutdown(&gPermissionManager); return permManager.forget(); } return nullptr; } // static -PermissionManager* PermissionManager::GetInstance() { +nsPermissionManager* nsPermissionManager::GetInstance() { if (!gPermissionManager) { // Hand off the creation of the permission manager to GetXPCOMSingleton. nsCOMPtr<nsIPermissionManager> permManager = GetXPCOMSingleton(); } return gPermissionManager; } -nsresult PermissionManager::Init() { +nsresult nsPermissionManager::Init() { // If the 'permissions.memory_only' pref is set to true, then don't write any // permission settings to disk, but keep them in a memory-only database. - mMemoryOnlyDB = Preferences::GetBool("permissions.memory_only", false); + mMemoryOnlyDB = + mozilla::Preferences::GetBool("permissions.memory_only", false); nsresult rv; nsCOMPtr<nsIPrefService> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = prefService->GetBranch("permissions.default.", getter_AddRefs(mDefaultPrefBranch)); NS_ENSURE_SUCCESS(rv, rv); if (IsChildProcess()) { // Stop here; we don't need the DB in the child process. Instead we will be // sent permissions as we need them by our parent process. - mState = eReady; return NS_OK; } - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); if (observerService) { observerService->AddObserver(this, "profile-before-change", true); observerService->AddObserver(this, "profile-do-change", true); observerService->AddObserver(this, "testonly-reload-permissions-from-disk", true); } - AddIdleDailyMaintenanceJob(); - - MOZ_ASSERT(!mThread); - NS_ENSURE_SUCCESS(NS_NewNamedThread("Permission", getter_AddRefs(mThread)), - NS_ERROR_FAILURE); - - PRThread* prThread; - MOZ_ALWAYS_SUCCEEDS(mThread->GetPRThread(&prThread)); - MOZ_ASSERT(prThread); - - mThreadBoundData.Transfer(prThread); - + // ignore failure here, since it's non-fatal (we can run fine without + // persistent storage - e.g. if there's no profile). + // XXX should we tell the user about this? InitDB(false); return NS_OK; } -nsresult PermissionManager::OpenDatabase(nsIFile* aPermissionsFile) { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ACCESS_THREAD_BOUND(mThreadBoundData, data); - +nsresult nsPermissionManager::OpenDatabase(nsIFile* aPermissionsFile) { nsresult rv; nsCOMPtr<mozIStorageService> storage = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); if (!storage) { return NS_ERROR_UNEXPECTED; } // cache a connection to the hosts database if (mMemoryOnlyDB) { - rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(data->mDBConn)); + rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(mDBConn)); } else { - rv = storage->OpenDatabase(aPermissionsFile, getter_AddRefs(data->mDBConn)); + rv = storage->OpenDatabase(aPermissionsFile, getter_AddRefs(mDBConn)); } return rv; } -void PermissionManager::InitDB(bool aRemoveFile) { - mState = eInitializing; - - { - MonitorAutoLock lock(mMonitor); - mReadEntries.Clear(); - } - - auto readyIfFailed = MakeScopeExit([&]() { - // ignore failure here, since it's non-fatal (we can run fine without - // persistent storage - e.g. if there's no profile). - // XXX should we tell the user about this? - mState = eReady; - }); - - if (!mPermissionsFile) { - nsresult rv = NS_GetSpecialDirectory(NS_APP_PERMISSION_PARENT_DIR, - getter_AddRefs(mPermissionsFile)); +nsresult nsPermissionManager::InitDB(bool aRemoveFile) { + nsCOMPtr<nsIFile> permissionsFile; + nsresult rv = NS_GetSpecialDirectory(NS_APP_PERMISSION_PARENT_DIR, + getter_AddRefs(permissionsFile)); + if (NS_FAILED(rv)) { + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(permissionsFile)); if (NS_FAILED(rv)) { - rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, - getter_AddRefs(mPermissionsFile)); - if (NS_FAILED(rv)) { - return; - } + return NS_ERROR_UNEXPECTED; } - - rv = mPermissionsFile->AppendNative( - NS_LITERAL_CSTRING(PERMISSIONS_FILE_NAME)); - NS_ENSURE_SUCCESS_VOID(rv); } - nsCOMPtr<nsIInputStream> defaultsInputStream = GetDefaultsInputStream(); - - RefPtr<PermissionManager> self = this; - mThread->Dispatch(NS_NewRunnableFunction( - "PermissionManager::InitDB", [self, aRemoveFile, defaultsInputStream] { - nsresult rv = self->TryInitDB(aRemoveFile, defaultsInputStream); - Unused << NS_WARN_IF(NS_FAILED(rv)); - - // This extra runnable calls EnsureReadCompleted to finialize the - // initialization. If there is something blocked by the monitor, it will - // be NOP. - NS_DispatchToMainThread( - NS_NewRunnableFunction("PermissionManager::InitDB-MainThread", - [self] { self->EnsureReadCompleted(); })); - - self->mMonitor.Notify(); - })); - - readyIfFailed.release(); -} - -nsresult PermissionManager::TryInitDB(bool aRemoveFile, - nsIInputStream* aDefaultsInputStream) { - MOZ_ASSERT(!NS_IsMainThread()); - - MonitorAutoLock lock(mMonitor); - - auto raii = MakeScopeExit([&]() { - if (aDefaultsInputStream) { - aDefaultsInputStream->Close(); - } - - mState = eDBInitialized; - }); - - nsresult rv; + rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(PERMISSIONS_FILE_NAME)); + NS_ENSURE_SUCCESS(rv, rv); if (aRemoveFile) { bool exists = false; - rv = mPermissionsFile->Exists(&exists); + rv = permissionsFile->Exists(&exists); NS_ENSURE_SUCCESS(rv, rv); if (exists) { - rv = mPermissionsFile->Remove(false); + rv = permissionsFile->Remove(false); NS_ENSURE_SUCCESS(rv, rv); } } - rv = OpenDatabase(mPermissionsFile); + rv = OpenDatabase(permissionsFile); if (rv == NS_ERROR_FILE_CORRUPTED) { LogToConsole( NS_LITERAL_STRING("permissions.sqlite is corrupted! Try again!")); // Add telemetry probe - Telemetry::Accumulate(Telemetry::PERMISSIONS_SQL_CORRUPTED, 1); + mozilla::Telemetry::Accumulate( + mozilla::Telemetry::PERMISSIONS_SQL_CORRUPTED, 1); // delete corrupted permissions.sqlite and try again - rv = mPermissionsFile->Remove(false); + rv = permissionsFile->Remove(false); NS_ENSURE_SUCCESS(rv, rv); LogToConsole( NS_LITERAL_STRING("Corrupted permissions.sqlite has been removed.")); - rv = OpenDatabase(mPermissionsFile); + rv = OpenDatabase(permissionsFile); NS_ENSURE_SUCCESS(rv, rv); LogToConsole( NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!")); - } - - if (NS_WARN_IF(NS_FAILED(rv))) { + } else if (NS_FAILED(rv)) { return rv; } - MOZ_ACCESS_THREAD_BOUND(mThreadBoundData, data); - bool ready; - data->mDBConn->GetConnectionReady(&ready); + mDBConn->GetConnectionReady(&ready); if (!ready) { LogToConsole(NS_LITERAL_STRING( "Fail to get connection to permissions.sqlite! Try again!")); // delete and try again - rv = mPermissionsFile->Remove(false); + rv = permissionsFile->Remove(false); NS_ENSURE_SUCCESS(rv, rv); LogToConsole( NS_LITERAL_STRING("Defective permissions.sqlite has been removed.")); // Add telemetry probe - Telemetry::Accumulate(Telemetry::DEFECTIVE_PERMISSIONS_SQL_REMOVED, 1); - - rv = OpenDatabase(mPermissionsFile); + mozilla::Telemetry::Accumulate( + mozilla::Telemetry::DEFECTIVE_PERMISSIONS_SQL_REMOVED, 1); + + rv = OpenDatabase(permissionsFile); NS_ENSURE_SUCCESS(rv, rv); LogToConsole( NS_LITERAL_STRING("OpenDatabase to permissions.sqlite is successful!")); - data->mDBConn->GetConnectionReady(&ready); + mDBConn->GetConnectionReady(&ready); if (!ready) return NS_ERROR_UNEXPECTED; } bool tableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &tableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), &tableExists); if (!tableExists) { - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &tableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), &tableExists); } if (!tableExists) { rv = CreateTable(); NS_ENSURE_SUCCESS(rv, rv); } else { // table already exists; check the schema version before reading int32_t dbSchemaVersion; - rv = data->mDBConn->GetSchemaVersion(&dbSchemaVersion); + rv = mDBConn->GetSchemaVersion(&dbSchemaVersion); NS_ENSURE_SUCCESS(rv, rv); switch (dbSchemaVersion) { // upgrading. - // every time you increment the database schema, you need to - // implement the upgrading code from the previous version to the - // new one. fall through to current version + // every time you increment the database schema, you need to implement + // the upgrading code from the previous version to the new one. + // fall through to current version case 1: { - // previous non-expiry version of database. Upgrade it by adding - // the expiration columns - rv = data->mDBConn->ExecuteSimpleSQL( + // previous non-expiry version of database. Upgrade it by adding the + // expiration columns + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("ALTER TABLE moz_hosts ADD expireType INTEGER")); NS_ENSURE_SUCCESS(rv, rv); - rv = data->mDBConn->ExecuteSimpleSQL( + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("ALTER TABLE moz_hosts ADD expireTime INTEGER")); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; - // TODO: we want to make default version as version 2 in order to - // fix bug 784875. + // TODO: we want to make default version as version 2 in order to fix bug + // 784875. case 0: case 2: { // Add appId/isInBrowserElement fields. - rv = data->mDBConn->ExecuteSimpleSQL( + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("ALTER TABLE moz_hosts ADD appId INTEGER")); NS_ENSURE_SUCCESS(rv, rv); - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "ALTER TABLE moz_hosts ADD isInBrowserElement INTEGER")); NS_ENSURE_SUCCESS(rv, rv); - rv = data->mDBConn->SetSchemaVersion(3); + rv = mDBConn->SetSchemaVersion(3); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; // Version 3->4 is the creation of the modificationTime field. case 3: { - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "ALTER TABLE moz_hosts ADD modificationTime INTEGER")); NS_ENSURE_SUCCESS(rv, rv); - // We leave the modificationTime at zero for all existing records; - // using now() would mean, eg, that doing "remove all from the - // last hour" within the first hour after migration would remove - // all permissions. - - rv = data->mDBConn->SetSchemaVersion(4); + // We leave the modificationTime at zero for all existing records; using + // now() would mean, eg, that doing "remove all from the last hour" + // within the first hour after migration would remove all permissions. + + rv = mDBConn->SetSchemaVersion(4); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; - // In version 5, host appId, and isInBrowserElement were merged into - // a single origin entry + // In version 5, host appId, and isInBrowserElement were merged into a + // single origin entry // // In version 6, the tables were renamed for backwards compatability // reasons with version 4 and earlier. // // In version 7, a bug in the migration used for version 4->5 was - // discovered which could have triggered data-loss. Because of that, - // all users with a version 4, 5, or 6 database will be re-migrated - // from the backup database. (bug 1186034). This migration bug is - // not present after bug 1185340, and the re-migration ensures that - // all users have the fix. + // discovered which could have triggered data-loss. Because of that, all + // users with a version 4, 5, or 6 database will be re-migrated from the + // backup database. (bug 1186034). This migration bug is not present after + // bug 1185340, and the re-migration ensures that all users have the fix. case 5: - // This branch could also be reached via dbSchemaVersion == 3, in - // which case we want to fall through to the dbSchemaVersion == 4 - // case. The easiest way to do that is to perform this extra check - // here to make sure that we didn't get here via a fallthrough - // from v3 + // This branch could also be reached via dbSchemaVersion == 3, in which + // case we want to fall through to the dbSchemaVersion == 4 case. The + // easiest way to do that is to perform this extra check here to make + // sure that we didn't get here via a fallthrough from v3 if (dbSchemaVersion == 5) { - // In version 5, the backup database is named moz_hosts_v4. We - // perform the version 5->6 migration to get the tables to have - // consistent naming conventions. + // In version 5, the backup database is named moz_hosts_v4. We perform + // the version 5->6 migration to get the tables to have consistent + // naming conventions. // Version 5->6 is the renaming of moz_hosts to moz_perms, and // moz_hosts_v4 to moz_hosts (bug 1185343) // - // In version 5, we performed the modifications to the - // permissions database in place, this meant that if you - // upgraded to a version which used V5, and then downgraded to a - // version which used v4 or earlier, the fallback path would - // drop the table, and your permissions data would be lost. This - // migration undoes that mistake, by restoring the old moz_hosts - // table (if it was present), and instead using the new table - // moz_perms for the new permissions schema. + // In version 5, we performed the modifications to the permissions + // database in place, this meant that if you upgraded to a version + // which used V5, and then downgraded to a version which used v4 or + // earlier, the fallback path would drop the table, and your + // permissions data would be lost. This migration undoes that mistake, + // by restoring the old moz_hosts table (if it was present), and + // instead using the new table moz_perms for the new permissions + // schema. // - // NOTE: If you downgrade, store new permissions, and then - // upgrade again, these new permissions won't be migrated or - // reflected in the updated database. This migration only occurs - // once, as if moz_perms exists, it will skip creating it. In - // addition, permissions added after the migration will not be - // visible in previous versions of firefox. + // NOTE: If you downgrade, store new permissions, and then upgrade + // again, these new permissions won't be migrated or reflected in the + // updated database. This migration only occurs once, as if moz_perms + // exists, it will skip creating it. In addition, permissions added + // after the migration will not be visible in previous versions of + // firefox. bool permsTableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), - &permsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), + &permsTableExists); if (!permsTableExists) { // Move the upgraded database to moz_perms - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "ALTER TABLE moz_hosts RENAME TO moz_perms")); NS_ENSURE_SUCCESS(rv, rv); } else { NS_WARNING( "moz_hosts was not renamed to moz_perms, " "as a moz_perms table already exists"); - // In the situation where a moz_perms table already exists, - // but the schema is lower than 6, a migration has already - // previously occured to V6, but a downgrade has caused the - // moz_hosts table to be dropped. This should only occur in - // the case of a downgrade to a V5 database, which was only - // present in a few day's nightlies. As that version was - // likely used only on a temporary basis, we assume that the - // database from the previous V6 has the permissions which the - // user actually wants to use. We have to get rid of moz_hosts - // such that moz_hosts_v4 can be moved into its place if it - // exists. - rv = data->mDBConn->ExecuteSimpleSQL( + // In the situation where a moz_perms table already exists, but the + // schema is lower than 6, a migration has already previously + // occured to V6, but a downgrade has caused the moz_hosts table to + // be dropped. This should only occur in the case of a downgrade to + // a V5 database, which was only present in a few day's nightlies. + // As that version was likely used only on a temporary basis, we + // assume that the database from the previous V6 has the permissions + // which the user actually wants to use. We have to get rid of + // moz_hosts such that moz_hosts_v4 can be moved into its place if + // it exists. + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE moz_hosts")); NS_ENSURE_SUCCESS(rv, rv); } #ifdef DEBUG // The moz_hosts table shouldn't exist anymore bool hostsTableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), - &hostsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), + &hostsTableExists); MOZ_ASSERT(!hostsTableExists); #endif - // Rename moz_hosts_v4 back to it's original location, if it - // exists + // Rename moz_hosts_v4 back to it's original location, if it exists bool v4TableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_v4"), - &v4TableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_v4"), + &v4TableExists); if (v4TableExists) { - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "ALTER TABLE moz_hosts_v4 RENAME TO moz_hosts")); NS_ENSURE_SUCCESS(rv, rv); } - rv = data->mDBConn->SetSchemaVersion(6); + rv = mDBConn->SetSchemaVersion(6); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; - // At this point, the version 5 table has been migrated to a version - // 6 table We are guaranteed to have at least one of moz_hosts and + // At this point, the version 5 table has been migrated to a version 6 + // table We are guaranteed to have at least one of moz_hosts and // moz_perms. If we have moz_hosts, we will migrate moz_hosts into // moz_perms (even if we already have a moz_perms, as we need a // re-migration due to bug 1186034). // - // After this migration, we are guaranteed to have both a moz_hosts - // (for backwards compatability), and a moz_perms table. The - // moz_hosts table will have a v4 schema, and the moz_perms table - // will have a v6 schema. + // After this migration, we are guaranteed to have both a moz_hosts (for + // backwards compatability), and a moz_perms table. The moz_hosts table + // will have a v4 schema, and the moz_perms table will have a v6 schema. case 4: case 6: { bool hostsTableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), - &hostsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), + &hostsTableExists); if (hostsTableExists) { - // Both versions 4 and 6 have a version 4 formatted hosts table - // named moz_hosts. We can migrate this table to our version 7 - // table moz_perms. If moz_perms is present, then we can use it - // as a basis for comparison. - - rv = data->mDBConn->BeginTransaction(); + // Both versions 4 and 6 have a version 4 formatted hosts table named + // moz_hosts. We can migrate this table to our version 7 table + // moz_perms. If moz_perms is present, then we can use it as a basis + // for comparison. + + rv = mDBConn->BeginTransaction(); NS_ENSURE_SUCCESS(rv, rv); bool tableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_new"), - &tableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_new"), + &tableExists); if (tableExists) { NS_WARNING( - "The temporary database moz_hosts_new already exists, " - "dropping " + "The temporary database moz_hosts_new already exists, dropping " "it."); - rv = data->mDBConn->ExecuteSimpleSQL( + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE moz_hosts_new")); NS_ENSURE_SUCCESS(rv, rv); } - rv = data->mDBConn->ExecuteSimpleSQL( + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("CREATE TABLE moz_hosts_new (" " id INTEGER PRIMARY KEY" ",origin TEXT" ",type TEXT" ",permission INTEGER" ",expireType INTEGER" ",expireTime INTEGER" ",modificationTime INTEGER" ")")); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageStatement> stmt; - rv = data->mDBConn->CreateStatement( + rv = mDBConn->CreateStatement( NS_LITERAL_CSTRING( - "SELECT host, type, permission, expireType, " - "expireTime, " + "SELECT host, type, permission, expireType, expireTime, " "modificationTime, isInBrowserElement FROM moz_hosts"), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); int64_t id = 0; + nsAutoCString host, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; + bool isInBrowserElement; bool hasResult; while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { - MigrationEntry entry; - // Read in the old row - rv = stmt->GetUTF8String(0, entry.mHost); + rv = stmt->GetUTF8String(0, host); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } - rv = stmt->GetUTF8String(1, entry.mType); + rv = stmt->GetUTF8String(1, type); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } - - entry.mId = id++; - entry.mPermission = stmt->AsInt32(2); - entry.mExpireType = stmt->AsInt32(3); - entry.mExpireTime = stmt->AsInt64(4); - entry.mModificationTime = stmt->AsInt64(5); - entry.mIsInBrowserElement = static_cast<bool>(stmt->AsInt32(6)); - - mMigrationEntries.AppendElement(entry); + permission = stmt->AsInt32(2); + expireType = stmt->AsInt32(3); + expireTime = stmt->AsInt64(4); + modificationTime = stmt->AsInt64(5); + isInBrowserElement = static_cast<bool>(stmt->AsInt32(6)); + + // Perform the meat of the migration by deferring to the + // UpgradeHostToOriginAndInsert function. + UpgradeHostToOriginDBMigration upHelper(mDBConn, &id); + rv = UpgradeHostToOriginAndInsert( + host, type, permission, expireType, expireTime, + modificationTime, isInBrowserElement, &upHelper); + if (NS_FAILED(rv)) { + NS_WARNING( + "Unexpected failure when upgrading migrating permission " + "from host to origin"); + } } - // We don't drop the moz_hosts table such that it is available - // for backwards-compatability and for future migrations in case - // of migration errors in the current code. Create a marker - // empty table which will indicate that the moz_hosts table is - // intended to act as a backup. If this table is not present, + // We don't drop the moz_hosts table such that it is available for + // backwards-compatability and for future migrations in case of + // migration errors in the current code. + // Create a marker empty table which will indicate that the moz_hosts + // table is intended to act as a backup. If this table is not present, // then the moz_hosts table was created as a random empty table. - rv = data->mDBConn->ExecuteSimpleSQL( - NS_LITERAL_CSTRING("CREATE TABLE moz_hosts_is_backup (dummy " - "INTEGER PRIMARY KEY)")); + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE moz_hosts_is_backup (dummy INTEGER PRIMARY KEY)")); NS_ENSURE_SUCCESS(rv, rv); bool permsTableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), - &permsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), + &permsTableExists); if (permsTableExists) { - // The user already had a moz_perms table, and we are - // performing a re-migration. We count the rows in the old - // table for telemetry, and then back up their old database as - // moz_perms_v6 + // The user already had a moz_perms table, and we are performing a + // re-migration. We count the rows in the old table for telemetry, + // and then back up their old database as moz_perms_v6 nsCOMPtr<mozIStorageStatement> countStmt; - rv = data->mDBConn->CreateStatement( + rv = mDBConn->CreateStatement( NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_perms"), getter_AddRefs(countStmt)); bool hasResult = false; if (NS_FAILED(rv) || NS_FAILED(countStmt->ExecuteStep(&hasResult)) || !hasResult) { NS_WARNING("Could not count the rows in moz_perms"); } - // Back up the old moz_perms database as moz_perms_v6 before - // we move the new table into its position - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + // Back up the old moz_perms database as moz_perms_v6 before we + // move the new table into its position + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "ALTER TABLE moz_perms RENAME TO moz_perms_v6")); NS_ENSURE_SUCCESS(rv, rv); } - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "ALTER TABLE moz_hosts_new RENAME TO moz_perms")); NS_ENSURE_SUCCESS(rv, rv); - rv = data->mDBConn->CommitTransaction(); + rv = mDBConn->CommitTransaction(); NS_ENSURE_SUCCESS(rv, rv); } else { - // We don't have a moz_hosts table, so we create one for - // downgrading purposes. This table is empty. - rv = data->mDBConn->ExecuteSimpleSQL( + // We don't have a moz_hosts table, so we create one for downgrading + // purposes. This table is empty. + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("CREATE TABLE moz_hosts (" " id INTEGER PRIMARY KEY" ",host TEXT" ",type TEXT" ",permission INTEGER" ",expireType INTEGER" ",expireTime INTEGER" ",modificationTime INTEGER" @@ -1221,342 +1405,334 @@ nsresult PermissionManager::TryInitDB(bo ")")); NS_ENSURE_SUCCESS(rv, rv); // We are guaranteed to have a moz_perms table at this point. } #ifdef DEBUG { - // At this point, both the moz_hosts and moz_perms tables should - // exist + // At this point, both the moz_hosts and moz_perms tables should exist bool hostsTableExists = false; bool permsTableExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), - &hostsTableExists); - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), - &permsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts"), + &hostsTableExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_perms"), + &permsTableExists); MOZ_ASSERT(hostsTableExists && permsTableExists); } #endif - rv = data->mDBConn->SetSchemaVersion(7); + rv = mDBConn->SetSchemaVersion(7); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; // The version 7-8 migration is the re-migration of localhost and - // ip-address entries due to errors in the previous version 7 - // migration which caused localhost and ip-address entries to be - // incorrectly discarded. The version 7 migration logic has been - // corrected, and thus this logic only needs to execute if the user - // is currently on version 7. + // ip-address entries due to errors in the previous version 7 migration + // which caused localhost and ip-address entries to be incorrectly + // discarded. The version 7 migration logic has been corrected, and thus + // this logic only needs to execute if the user is currently on version 7. case 7: { - // This migration will be relatively expensive as we need to - // perform database lookups for each origin which we want to - // insert. Fortunately, it shouldn't be too expensive as we only - // want to insert a small number of entries created for localhost - // or IP addresses. - - // We only want to perform the re-migration if moz_hosts is a - // backup + // This migration will be relatively expensive as we need to perform + // database lookups for each origin which we want to insert. + // Fortunately, it shouldn't be too expensive as we only want to insert + // a small number of entries created for localhost or IP addresses. + + // We only want to perform the re-migration if moz_hosts is a backup bool hostsIsBackupExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), - &hostsIsBackupExists); - - // Only perform this migration if the original schema version was - // 7, and the moz_hosts table is a backup. + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), + &hostsIsBackupExists); + + // Only perform this migration if the original schema version was 7, and + // the moz_hosts table is a backup. if (dbSchemaVersion == 7 && hostsIsBackupExists) { nsCOMPtr<mozIStorageStatement> stmt; - rv = data->mDBConn->CreateStatement( + rv = mDBConn->CreateStatement( NS_LITERAL_CSTRING( - "SELECT host, type, permission, expireType, " - "expireTime, " + "SELECT host, type, permission, expireType, expireTime, " "modificationTime, isInBrowserElement FROM moz_hosts"), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageStatement> idStmt; - rv = data->mDBConn->CreateStatement( + rv = mDBConn->CreateStatement( NS_LITERAL_CSTRING("SELECT MAX(id) FROM moz_hosts"), getter_AddRefs(idStmt)); - int64_t id = 0; bool hasResult = false; if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(idStmt->ExecuteStep(&hasResult)) && hasResult) { id = idStmt->AsInt32(0) + 1; } + nsAutoCString host, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; + bool isInBrowserElement; + while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { - MigrationEntry entry; - // Read in the old row - rv = stmt->GetUTF8String(0, entry.mHost); + rv = stmt->GetUTF8String(0, host); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } nsAutoCString eTLD1; rv = nsEffectiveTLDService::GetInstance()->GetBaseDomainFromHost( - entry.mHost, 0, eTLD1); + host, 0, eTLD1); if (NS_SUCCEEDED(rv)) { - // We only care about entries which the tldService can't - // handle + // We only care about entries which the tldService can't handle continue; } - rv = stmt->GetUTF8String(1, entry.mType); + rv = stmt->GetUTF8String(1, type); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } - - entry.mId = id++; - entry.mPermission = stmt->AsInt32(2); - entry.mExpireType = stmt->AsInt32(3); - entry.mExpireTime = stmt->AsInt64(4); - entry.mModificationTime = stmt->AsInt64(5); - entry.mIsInBrowserElement = static_cast<bool>(stmt->AsInt32(6)); - - mMigrationEntries.AppendElement(entry); + permission = stmt->AsInt32(2); + expireType = stmt->AsInt32(3); + expireTime = stmt->AsInt64(4); + modificationTime = stmt->AsInt64(5); + isInBrowserElement = static_cast<bool>(stmt->AsInt32(6)); + + // Perform the meat of the migration by deferring to the + // UpgradeHostToOriginAndInsert function. + UpgradeIPHostToOriginDB upHelper(mDBConn, &id); + rv = UpgradeHostToOriginAndInsert( + host, type, permission, expireType, expireTime, + modificationTime, isInBrowserElement, &upHelper); + if (NS_FAILED(rv)) { + NS_WARNING( + "Unexpected failure when upgrading migrating permission " + "from host to origin"); + } } } - // Even if we didn't perform the migration, we want to bump the - // schema version to 8. - rv = data->mDBConn->SetSchemaVersion(8); + // Even if we didn't perform the migration, we want to bump the schema + // version to 8. + rv = mDBConn->SetSchemaVersion(8); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; - // The version 8-9 migration removes the unnecessary backup - // moz-hosts database contents. as the data no longer needs to be - // migrated + // The version 8-9 migration removes the unnecessary backup moz-hosts + // database contents. as the data no longer needs to be migrated case 8: { - // We only want to clear out the old table if it is a backup. If - // it isn't a backup, we don't need to touch it. + // We only want to clear out the old table if it is a backup. If it + // isn't a backup, we don't need to touch it. bool hostsIsBackupExists = false; - data->mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), - &hostsIsBackupExists); + mDBConn->TableExists(NS_LITERAL_CSTRING("moz_hosts_is_backup"), + &hostsIsBackupExists); if (hostsIsBackupExists) { - // Delete everything from the backup, we want to keep around the - // table so that you can still downgrade and not break things, - // but we don't need to keep the rows around. - rv = data->mDBConn->ExecuteSimpleSQL( + // Delete everything from the backup, we want to keep around the table + // so that you can still downgrade and not break things, but we don't + // need to keep the rows around. + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DELETE FROM moz_hosts")); NS_ENSURE_SUCCESS(rv, rv); // The table is no longer a backup, so get rid of it. - rv = data->mDBConn->ExecuteSimpleSQL( + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE moz_hosts_is_backup")); NS_ENSURE_SUCCESS(rv, rv); } - rv = data->mDBConn->SetSchemaVersion(9); + rv = mDBConn->SetSchemaVersion(9); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; case 9: { - rv = data->mDBConn->SetSchemaVersion(10); + rv = mDBConn->SetSchemaVersion(10); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; case 10: { // Filter out the rows with storage access API permissions with a // granted origin, and remove the granted origin part from the // permission type. - rv = data->mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "UPDATE moz_perms " - "SET type=SUBSTR(type, 0, INSTR(SUBSTR(type, INSTR(type, " - "'^') + " + "SET type=SUBSTR(type, 0, INSTR(SUBSTR(type, INSTR(type, '^') + " "1), '^') + INSTR(type, '^')) " "WHERE INSTR(SUBSTR(type, INSTR(type, '^') + 1), '^') AND " "SUBSTR(type, 0, 18) == \"storageAccessAPI^\";")); NS_ENSURE_SUCCESS(rv, rv); - rv = data->mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION); + rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION); NS_ENSURE_SUCCESS(rv, rv); } // fall through to the next upgrade [[fallthrough]]; // current version. case HOSTS_SCHEMA_VERSION: break; // downgrading. - // if columns have been added to the table, we can still use the - // ones we understand safely. if columns have been deleted or - // altered, just blow away the table and start from scratch! if you - // change the way a column is interpreted, make sure you also change - // its name so this check will catch it. + // if columns have been added to the table, we can still use the ones we + // understand safely. if columns have been deleted or altered, just + // blow away the table and start from scratch! if you change the way + // a column is interpreted, make sure you also change its name so this + // check will catch it. default: { // check if all the expected columns exist nsCOMPtr<mozIStorageStatement> stmt; - rv = data->mDBConn->CreateStatement( - NS_LITERAL_CSTRING("SELECT origin, type, permission, " - "expireType, expireTime, " - "modificationTime FROM moz_perms"), + rv = mDBConn->CreateStatement( + NS_LITERAL_CSTRING( + "SELECT origin, type, permission, expireType, expireTime, " + "modificationTime FROM moz_perms"), getter_AddRefs(stmt)); if (NS_SUCCEEDED(rv)) break; // our columns aren't there - drop the table! - rv = data->mDBConn->ExecuteSimpleSQL( + rv = mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE moz_perms")); NS_ENSURE_SUCCESS(rv, rv); rv = CreateTable(); NS_ENSURE_SUCCESS(rv, rv); } break; } } - // cache frequently used statements (for insertion, deletion, and - // updating) - rv = data->mDBConn->CreateStatement( + // cache frequently used statements (for insertion, deletion, and updating) + rv = mDBConn->CreateAsyncStatement( NS_LITERAL_CSTRING("INSERT INTO moz_perms " "(id, origin, type, permission, expireType, " "expireTime, modificationTime) " "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), - getter_AddRefs(data->mStmtInsert)); + getter_AddRefs(mStmtInsert)); NS_ENSURE_SUCCESS(rv, rv); - rv = - data->mDBConn->CreateStatement(NS_LITERAL_CSTRING("DELETE FROM moz_perms " + rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING("DELETE FROM moz_perms " "WHERE id = ?1"), - getter_AddRefs(data->mStmtDelete)); + getter_AddRefs(mStmtDelete)); NS_ENSURE_SUCCESS(rv, rv); - rv = data->mDBConn->CreateStatement( + rv = mDBConn->CreateAsyncStatement( NS_LITERAL_CSTRING("UPDATE moz_perms " "SET permission = ?2, expireType= ?3, expireTime = " "?4, modificationTime = ?5 WHERE id = ?1"), - getter_AddRefs(data->mStmtUpdate)); + getter_AddRefs(mStmtUpdate)); NS_ENSURE_SUCCESS(rv, rv); // Always import default permissions. - ConsumeDefaultsInputStream(aDefaultsInputStream, lock); - + ImportDefaults(); // check whether to import or just read in the db if (tableExists) { - rv = Read(lock); + rv = Read(); NS_ENSURE_SUCCESS(rv, rv); + + AddIdleDailyMaintenanceJob(); } return NS_OK; } -void PermissionManager::AddIdleDailyMaintenanceJob() { - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); +void nsPermissionManager::AddIdleDailyMaintenanceJob() { + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); NS_ENSURE_TRUE_VOID(observerService); nsresult rv = observerService->AddObserver(this, OBSERVER_TOPIC_IDLE_DAILY, false); NS_ENSURE_SUCCESS_VOID(rv); } -void PermissionManager::RemoveIdleDailyMaintenanceJob() { - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); +void nsPermissionManager::RemoveIdleDailyMaintenanceJob() { + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); NS_ENSURE_TRUE_VOID(observerService); nsresult rv = observerService->RemoveObserver(this, OBSERVER_TOPIC_IDLE_DAILY); NS_ENSURE_SUCCESS_VOID(rv); } -void PermissionManager::PerformIdleDailyMaintenance() { - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr<PermissionManager> self = this; - mThread->Dispatch(NS_NewRunnableFunction( - "PermissionManager::PerformIdleDailyMaintenance", [self] { - MOZ_ACCESS_THREAD_BOUND(self->mThreadBoundData, data); - - if (self->mState == eClosed || !data->mDBConn) { - return; - } - - nsCOMPtr<mozIStorageStatement> stmtDeleteExpired; - nsresult rv = data->mDBConn->CreateStatement( - NS_LITERAL_CSTRING("DELETE FROM moz_perms WHERE expireType = " - "?1 AND expireTime <= ?2"), - getter_AddRefs(stmtDeleteExpired)); - NS_ENSURE_SUCCESS_VOID(rv); - - rv = stmtDeleteExpired->BindInt32ByIndex( - 0, nsIPermissionManager::EXPIRE_TIME); - NS_ENSURE_SUCCESS_VOID(rv); - - rv = stmtDeleteExpired->BindInt64ByIndex(1, EXPIRY_NOW); - NS_ENSURE_SUCCESS_VOID(rv); - - rv = stmtDeleteExpired->Execute(); - NS_ENSURE_SUCCESS_VOID(rv); - })); +void nsPermissionManager::PerformIdleDailyMaintenance() { + if (!mDBConn) { + return; + } + + nsCOMPtr<mozIStorageAsyncStatement> stmtDeleteExpired; + nsresult rv = mDBConn->CreateAsyncStatement( + NS_LITERAL_CSTRING("DELETE FROM moz_perms WHERE expireType = " + "?1 AND expireTime <= ?2"), + getter_AddRefs(stmtDeleteExpired)); + NS_ENSURE_SUCCESS_VOID(rv); + + rv = + stmtDeleteExpired->BindInt32ByIndex(0, nsIPermissionManager::EXPIRE_TIME); + NS_ENSURE_SUCCESS_VOID(rv); + + rv = stmtDeleteExpired->BindInt64ByIndex(1, EXPIRY_NOW); + NS_ENSURE_SUCCESS_VOID(rv); + + nsCOMPtr<mozIStoragePendingStatement> pending; + rv = stmtDeleteExpired->ExecuteAsync(nullptr, getter_AddRefs(pending)); + NS_ENSURE_SUCCESS_VOID(rv); } // sets the schema version and creates the moz_perms table. -nsresult PermissionManager::CreateTable() { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ACCESS_THREAD_BOUND(mThreadBoundData, data); - +nsresult nsPermissionManager::CreateTable() { // set the schema version, before creating the table - nsresult rv = data->mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION); + nsresult rv = mDBConn->SetSchemaVersion(HOSTS_SCHEMA_VERSION); if (NS_FAILED(rv)) return rv; // create the table // SQL also lives in automation.py.in. If you change this SQL change that // one too - rv = data->mDBConn->ExecuteSimpleSQL( - NS_LITERAL_CSTRING("CREATE TABLE moz_perms (" - " id INTEGER PRIMARY KEY" - ",origin TEXT" - ",type TEXT" - ",permission INTEGER" - ",expireType INTEGER" - ",expireTime INTEGER" - ",modificationTime INTEGER" - ")")); + rv = + mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE moz_perms (" + " id INTEGER PRIMARY KEY" + ",origin TEXT" + ",type TEXT" + ",permission INTEGER" + ",expireType INTEGER" + ",expireTime INTEGER" + ",modificationTime INTEGER" + ")")); if (NS_FAILED(rv)) return rv; // We also create a legacy V4 table, for backwards compatability, // and to ensure that downgrades don't trigger a schema version change. - return data->mDBConn->ExecuteSimpleSQL( + return mDBConn->ExecuteSimpleSQL( NS_LITERAL_CSTRING("CREATE TABLE moz_hosts (" " id INTEGER PRIMARY KEY" ",host TEXT" ",type TEXT" ",permission INTEGER" ",expireType INTEGER" ",expireTime INTEGER" ",modificationTime INTEGER" ",isInBrowserElement INTEGER" ")")); } NS_IMETHODIMP -PermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, - const nsACString& aType, - uint32_t aPermission, uint32_t aExpireType, - int64_t aExpireTime) { +nsPermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, + const nsACString& aType, + uint32_t aPermission, + uint32_t aExpireType, + int64_t aExpireTime) { ENSURE_NOT_CHILD_PROCESS; NS_ENSURE_ARG_POINTER(aPrincipal); NS_ENSURE_TRUE(aExpireType == nsIPermissionManager::EXPIRE_NEVER || aExpireType == nsIPermissionManager::EXPIRE_TIME || aExpireType == nsIPermissionManager::EXPIRE_SESSION || aExpireType == nsIPermissionManager::EXPIRE_POLICY, NS_ERROR_INVALID_ARG); @@ -1588,26 +1764,22 @@ PermissionManager::AddFromPrincipal(nsIP // A modificationTime of zero will cause AddInternal to use now(). int64_t modificationTime = 0; return AddInternal(aPrincipal, aType, aPermission, 0, aExpireType, aExpireTime, modificationTime, eNotify, eWriteToDB); } -nsresult PermissionManager::AddInternal( +nsresult nsPermissionManager::AddInternal( nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aPermission, int64_t aID, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime, NotifyOperationType aNotifyOperation, DBOperationType aDBOperation, const bool aIgnoreSessionPermissions, const nsACString* aOriginString) { - MOZ_ASSERT(NS_IsMainThread()); - - EnsureReadCompleted(); - nsresult rv = NS_OK; nsAutoCString origin; // Only attempt to compute the origin string when it is going to be needed // later on in the function. if (!IsChildProcess() || (aDBOperation == eWriteToDB && IsPersistentExpire(aExpireType, aType))) { if (aOriginString) { // Use the origin string provided by the caller. @@ -1735,18 +1907,18 @@ nsresult PermissionManager::AddInternal( } entry->GetPermissions().AppendElement( PermissionEntry(id, typeIndex, aPermission, aExpireType, aExpireTime, aModificationTime)); if (aDBOperation == eWriteToDB && IsPersistentExpire(aExpireType, aType)) { - UpdateDB(op, id, origin, aType, aPermission, aExpireType, aExpireTime, - aModificationTime); + UpdateDB(op, mStmtInsert, id, origin, aType, aPermission, aExpireType, + aExpireTime, aModificationTime); } if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], aPermission, aExpireType, aExpireTime, aModificationTime, u"added"); } @@ -1764,17 +1936,17 @@ nsresult PermissionManager::AddInternal( break; } entry->GetPermissions().RemoveElementAt(index); if (aDBOperation == eWriteToDB) // We care only about the id here so we pass dummy values for all other // parameters. - UpdateDB(op, id, EmptyCString(), EmptyCString(), 0, + UpdateDB(op, mStmtDelete, id, EmptyCString(), EmptyCString(), 0, nsIPermissionManager::EXPIRE_NEVER, 0, 0); if (aNotifyOperation == eNotify) { NotifyObserversWithPermission( aPrincipal, mTypeArray[typeIndex], oldPermissionEntry.mPermission, oldPermissionEntry.mExpireType, oldPermissionEntry.mExpireTime, oldPermissionEntry.mModificationTime, u"deleted"); } @@ -1820,18 +1992,18 @@ nsresult PermissionManager::AddInternal( entry->GetPermissions()[index].mExpireTime = aExpireTime; entry->GetPermissions()[index].mModificationTime = aModificationTime; if (aDBOperation == eWriteToDB && IsPersistentExpire(aExpireType, aType)) { // We care only about the id, the permission and // expireType/expireTime/modificationTime here. We pass dummy values for // all other parameters. - UpdateDB(op, id, EmptyCString(), EmptyCString(), aPermission, - aExpireType, aExpireTime, aModificationTime); + UpdateDB(op, mStmtUpdate, id, EmptyCString(), EmptyCString(), + aPermission, aExpireType, aExpireTime, aModificationTime); } if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], aPermission, aExpireType, aExpireTime, aModificationTime, u"changed"); } @@ -1870,35 +2042,35 @@ nsresult PermissionManager::AddInternal( entry->GetPermissions()[index].mPermission = aPermission; entry->GetPermissions()[index].mExpireType = aExpireType; entry->GetPermissions()[index].mExpireTime = aExpireTime; entry->GetPermissions()[index].mModificationTime = aModificationTime; // If requested, create the entry in the DB. if (aDBOperation == eWriteToDB && IsPersistentExpire(aExpireType, aType)) { - UpdateDB(eOperationAdding, id, origin, aType, aPermission, aExpireType, - aExpireTime, aModificationTime); + UpdateDB(eOperationAdding, mStmtInsert, id, origin, aType, aPermission, + aExpireType, aExpireTime, aModificationTime); } if (aNotifyOperation == eNotify) { NotifyObserversWithPermission(aPrincipal, mTypeArray[typeIndex], aPermission, aExpireType, aExpireTime, aModificationTime, u"changed"); } } break; } return NS_OK; } NS_IMETHODIMP -PermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal, - const nsACString& aType) { +nsPermissionManager::RemoveFromPrincipal(nsIPrincipal* aPrincipal, + const nsACString& aType) { ENSURE_NOT_CHILD_PROCESS; NS_ENSURE_ARG_POINTER(aPrincipal); // System principals are never added to the database, no need to remove them. if (aPrincipal->IsSystemPrincipal()) { return NS_OK; } @@ -1909,17 +2081,17 @@ PermissionManager::RemoveFromPrincipal(n // AddInternal() handles removal, just let it do the work return AddInternal(aPrincipal, aType, nsIPermissionManager::UNKNOWN_ACTION, 0, nsIPermissionManager::EXPIRE_NEVER, 0, 0, eNotify, eWriteToDB); } NS_IMETHODIMP -PermissionManager::RemovePermission(nsIPermission* aPerm) { +nsPermissionManager::RemovePermission(nsIPermission* aPerm) { if (!aPerm) { return NS_OK; } nsCOMPtr<nsIPrincipal> principal; nsresult rv = aPerm->GetPrincipal(getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString type; @@ -1927,29 +2099,29 @@ PermissionManager::RemovePermission(nsIP NS_ENSURE_SUCCESS(rv, rv); // Permissions are uniquely identified by their principal and type. // We remove the permission using these two pieces of data. return RemoveFromPrincipal(principal, type); } NS_IMETHODIMP -PermissionManager::RemoveAll() { +nsPermissionManager::RemoveAll() { ENSURE_NOT_CHILD_PROCESS; return RemoveAllInternal(true); } NS_IMETHODIMP -PermissionManager::RemoveAllSince(int64_t aSince) { +nsPermissionManager::RemoveAllSince(int64_t aSince) { ENSURE_NOT_CHILD_PROCESS; return RemoveAllModifiedSince(aSince); } template <class T> -nsresult PermissionManager::RemovePermissionEntries(T aCondition) { +nsresult nsPermissionManager::RemovePermissionEntries(T aCondition) { Vector<Tuple<nsCOMPtr<nsIPrincipal>, nsCString, nsCString>, 10> array; for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { PermissionHashKey* entry = iter.Get(); for (const auto& permEntry : entry->GetPermissions()) { if (!aCondition(permEntry)) { continue; } @@ -1968,195 +2140,173 @@ nsresult PermissionManager::RemovePermis } } } for (auto& i : array) { // AddInternal handles removal, so let it do the work... AddInternal(Get<0>(i), Get<1>(i), nsIPermissionManager::UNKNOWN_ACTION, 0, nsIPermissionManager::EXPIRE_NEVER, 0, 0, - PermissionManager::eNotify, PermissionManager::eWriteToDB, + nsPermissionManager::eNotify, nsPermissionManager::eWriteToDB, false, &Get<2>(i)); } - // now re-import any defaults as they may now be required if we just deleted // an override. - ImportLatestDefaults(); + ImportDefaults(); return NS_OK; } NS_IMETHODIMP -PermissionManager::RemoveByType(const nsACString& aType) { +nsPermissionManager::RemoveByType(const nsACString& aType) { ENSURE_NOT_CHILD_PROCESS; int32_t typeIndex = GetTypeIndex(aType, false); // If type == -1, the type isn't known, // so just return NS_OK if (typeIndex == -1) { return NS_OK; } return RemovePermissionEntries( [typeIndex](const PermissionEntry& aPermEntry) { return static_cast<uint32_t>(typeIndex) == aPermEntry.mType; }); } NS_IMETHODIMP -PermissionManager::RemoveByTypeSince(const nsACString& aType, - int64_t aModificationTime) { +nsPermissionManager::RemoveByTypeSince(const nsACString& aType, + int64_t aModificationTime) { ENSURE_NOT_CHILD_PROCESS; int32_t typeIndex = GetTypeIndex(aType, false); // If type == -1, the type isn't known, // so just return NS_OK if (typeIndex == -1) { return NS_OK; } return RemovePermissionEntries( [typeIndex, aModificationTime](const PermissionEntry& aPermEntry) { return uint32_t(typeIndex) == aPermEntry.mType && aModificationTime <= aPermEntry.mModificationTime; }); } -void PermissionManager::CloseDB(bool aRebuildOnSuccess) { - EnsureReadCompleted(); - - mState = eClosed; - - nsCOMPtr<nsIInputStream> defaultsInputStream; - if (aRebuildOnSuccess) { - defaultsInputStream = GetDefaultsInputStream(); +void nsPermissionManager::CloseDB(bool aRebuildOnSuccess) { + // Null the statements, this will finalize them. + mStmtInsert = nullptr; + mStmtDelete = nullptr; + mStmtUpdate = nullptr; + if (mDBConn) { + mozIStorageCompletionCallback* cb = + new CloseDatabaseListener(this, aRebuildOnSuccess); + mozilla::DebugOnly<nsresult> rv = mDBConn->AsyncClose(cb); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + mDBConn = nullptr; // Avoid race conditions } - - RefPtr<PermissionManager> self = this; - mThread->Dispatch(NS_NewRunnableFunction( - "PermissionManager::CloseDB", - [self, aRebuildOnSuccess, defaultsInputStream] { - MOZ_ACCESS_THREAD_BOUND(self->mThreadBoundData, data); - // Null the statements, this will finalize them. - data->mStmtInsert = nullptr; - data->mStmtDelete = nullptr; - data->mStmtUpdate = nullptr; - if (data->mDBConn) { - DebugOnly<nsresult> rv = data->mDBConn->Close(); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - data->mDBConn = nullptr; - - if (aRebuildOnSuccess) { - self->TryInitDB(true, defaultsInputStream); - } - } - })); } -nsresult PermissionManager::RemoveAllFromIPC() { +nsresult nsPermissionManager::RemoveAllFromIPC() { MOZ_ASSERT(IsChildProcess()); // Remove from memory and notify immediately. Since the in-memory // database is authoritative, we do not need confirmation from the // on-disk database to notify observers. RemoveAllFromMemory(); return NS_OK; } -nsresult PermissionManager::RemoveAllInternal(bool aNotifyObservers) { +nsresult nsPermissionManager::RemoveAllInternal(bool aNotifyObservers) { ENSURE_NOT_CHILD_PROCESS; - EnsureReadCompleted(); - // Let's broadcast the removeAll() to any content process. nsTArray<ContentParent*> parents; ContentParent::GetAll(parents); for (ContentParent* parent : parents) { Unused << parent->SendRemoveAllPermissions(); } // Remove from memory and notify immediately. Since the in-memory // database is authoritative, we do not need confirmation from the // on-disk database to notify observers. RemoveAllFromMemory(); // Re-import the defaults - ImportLatestDefaults(); + ImportDefaults(); if (aNotifyObservers) { NotifyObservers(nullptr, u"cleared"); } - RefPtr<PermissionManager> self = this; - mThread->Dispatch( - NS_NewRunnableFunction("PermissionManager::RemoveAllInternal", [self] { - MOZ_ACCESS_THREAD_BOUND(self->mThreadBoundData, data); - - if (self->mState == eClosed || !data->mDBConn) { - return; - } - - // clear the db - nsresult rv = data->mDBConn->ExecuteSimpleSQL( - NS_LITERAL_CSTRING("DELETE FROM moz_perms")); - if (NS_WARN_IF(NS_FAILED(rv))) { - NS_DispatchToMainThread(NS_NewRunnableFunction( - "PermissionManager::RemoveAllInternal-Failure", - [self] { self->CloseDB(true); })); - } - })); + // clear the db + if (mDBConn) { + nsCOMPtr<mozIStorageAsyncStatement> removeStmt; + nsresult rv = mDBConn->CreateAsyncStatement( + NS_LITERAL_CSTRING("DELETE FROM moz_perms"), + getter_AddRefs(removeStmt)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + if (!removeStmt) { + return NS_ERROR_UNEXPECTED; + } + nsCOMPtr<mozIStoragePendingStatement> pending; + mozIStorageStatementCallback* cb = new DeleteFromMozHostListener(this); + rv = removeStmt->ExecuteAsync(cb, getter_AddRefs(pending)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + return rv; + } return NS_OK; } NS_IMETHODIMP -PermissionManager::TestExactPermissionFromPrincipal(nsIPrincipal* aPrincipal, - const nsACString& aType, - uint32_t* aPermission) { +nsPermissionManager::TestExactPermissionFromPrincipal(nsIPrincipal* aPrincipal, + const nsACString& aType, + uint32_t* aPermission) { return CommonTestPermission(aPrincipal, -1, aType, aPermission, nsIPermissionManager::UNKNOWN_ACTION, false, true, true); } NS_IMETHODIMP -PermissionManager::TestExactPermanentPermission(nsIPrincipal* aPrincipal, - const nsACString& aType, - uint32_t* aPermission) { +nsPermissionManager::TestExactPermanentPermission(nsIPrincipal* aPrincipal, + const nsACString& aType, + uint32_t* aPermission) { return CommonTestPermission(aPrincipal, -1, aType, aPermission, nsIPermissionManager::UNKNOWN_ACTION, false, true, false); } -nsresult PermissionManager::LegacyTestPermissionFromURI( - nsIURI* aURI, const OriginAttributes* aOriginAttributes, +nsresult nsPermissionManager::LegacyTestPermissionFromURI( + nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes, const nsACString& aType, uint32_t* aPermission) { return CommonTestPermission(aURI, aOriginAttributes, -1, aType, aPermission, nsIPermissionManager::UNKNOWN_ACTION, false, false, true); } NS_IMETHODIMP -PermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal, - const nsACString& aType, - uint32_t* aPermission) { +nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal, + const nsACString& aType, + uint32_t* aPermission) { return CommonTestPermission(aPrincipal, -1, aType, aPermission, nsIPermissionManager::UNKNOWN_ACTION, false, false, true); } NS_IMETHODIMP -PermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal, - const nsACString& aType, - bool aExactHostMatch, - nsIPermission** aResult) { +nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal, + const nsACString& aType, + bool aExactHostMatch, + nsIPermission** aResult) { NS_ENSURE_ARG_POINTER(aPrincipal); + *aResult = nullptr; - EnsureReadCompleted(); - if (aPrincipal->IsSystemPrincipal()) { return NS_OK; } // Querying the permission object of an nsEP is non-sensical. if (IsExpandedPrincipal(aPrincipal)) { return NS_ERROR_INVALID_ARG; } @@ -2183,44 +2333,43 @@ PermissionManager::GetPermissionObject(n nsCOMPtr<nsIPrincipal> principal; nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, IsOAForceStripPermission(aType), getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); PermissionEntry& perm = entry->GetPermissions()[idx]; - nsCOMPtr<nsIPermission> r = Permission::Create( + nsCOMPtr<nsIPermission> r = nsPermission::Create( principal, mTypeArray[perm.mType], perm.mPermission, perm.mExpireType, perm.mExpireTime, perm.mModificationTime); if (NS_WARN_IF(!r)) { return NS_ERROR_FAILURE; } r.forget(aResult); return NS_OK; } -nsresult PermissionManager::CommonTestPermissionInternal( +nsresult nsPermissionManager::CommonTestPermissionInternal( nsIPrincipal* aPrincipal, nsIURI* aURI, const OriginAttributes* aOriginAttributes, int32_t aTypeIndex, const nsACString& aType, uint32_t* aPermission, bool aExactHostMatch, bool aIncludingSession) { MOZ_ASSERT(aPrincipal || aURI); NS_ENSURE_ARG_POINTER(aPrincipal || aURI); MOZ_ASSERT_IF(aPrincipal, !aURI && !aOriginAttributes); MOZ_ASSERT_IF(aURI || aOriginAttributes, !aPrincipal); - EnsureReadCompleted(); - #ifdef DEBUG { nsCOMPtr<nsIPrincipal> prin = aPrincipal; if (!prin) { if (aURI) { - prin = BasePrincipal::CreateContentPrincipal(aURI, OriginAttributes()); + prin = mozilla::BasePrincipal::CreateContentPrincipal( + aURI, OriginAttributes()); } } MOZ_ASSERT(prin); MOZ_ASSERT(PermissionAvailable(prin, aType)); } #endif PermissionHashKey* entry = @@ -2235,288 +2384,25 @@ nsresult PermissionManager::CommonTestPe *aPermission = aIncludingSession ? entry->GetPermission(aTypeIndex).mPermission : entry->GetPermission(aTypeIndex).mNonSessionPermission; return NS_OK; } -NS_IMETHODIMP PermissionManager::GetAll( - nsTArray<RefPtr<nsIPermission>>& aResult) { - return GetAllWithTypePrefix(NS_LITERAL_CSTRING(""), aResult); -} - -NS_IMETHODIMP PermissionManager::GetAllWithTypePrefix( - const nsACString& aPrefix, nsTArray<RefPtr<nsIPermission>>& aResult) { - aResult.Clear(); - if (XRE_IsContentProcess()) { - NS_WARNING( - "PermissionManager's getAllWithTypePrefix is not available in the " - "content process, as not all permissions may be available."); - return NS_ERROR_NOT_AVAILABLE; - } - - EnsureReadCompleted(); - - for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { - PermissionHashKey* entry = iter.Get(); - for (const auto& permEntry : entry->GetPermissions()) { - // Given how "default" permissions work and the possibility of them being - // overridden with UNKNOWN_ACTION, we might see this value here - but we - // do *not* want to return them via the enumerator. - if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { - continue; - } - - if (!aPrefix.IsEmpty() && - !StringBeginsWith(mTypeArray[permEntry.mType], aPrefix)) { - continue; - } - - nsCOMPtr<nsIPrincipal> principal; - nsresult rv = GetPrincipalFromOrigin( - entry->GetKey()->mOrigin, - IsOAForceStripPermission(mTypeArray[permEntry.mType]), - getter_AddRefs(principal)); - if (NS_FAILED(rv)) { - continue; - } - - RefPtr<nsIPermission> permission = Permission::Create( - principal, mTypeArray[permEntry.mType], permEntry.mPermission, - permEntry.mExpireType, permEntry.mExpireTime, - permEntry.mModificationTime); - if (NS_WARN_IF(!permission)) { - continue; - } - aResult.AppendElement(std::move(permission)); - } - } - - return NS_OK; -} - -NS_IMETHODIMP -PermissionManager::GetAllForPrincipal( - nsIPrincipal* aPrincipal, nsTArray<RefPtr<nsIPermission>>& aResult) { - aResult.Clear(); - - MOZ_ASSERT(PermissionAvailable(aPrincipal, EmptyCString())); - - nsresult rv; - RefPtr<PermissionKey> key = - PermissionKey::CreateFromPrincipal(aPrincipal, false, rv); - if (!key) { - MOZ_ASSERT(NS_FAILED(rv)); - return rv; - } - PermissionHashKey* entry = mPermissionTable.GetEntry(key); - - nsTArray<PermissionEntry> strippedPerms; - rv = GetStripPermsForPrincipal(aPrincipal, strippedPerms); - if (NS_FAILED(rv)) { - return rv; - } - - if (entry) { - for (const auto& permEntry : entry->GetPermissions()) { - // Only return custom permissions - if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { - continue; - } - - // Stripped principal permissions overwrite regular ones - // For each permission check if there is a stripped permission we should - // use instead - PermissionEntry perm = permEntry; - nsTArray<PermissionEntry>::index_type index = 0; - for (const auto& strippedPerm : strippedPerms) { - if (strippedPerm.mType == permEntry.mType) { - perm = strippedPerm; - strippedPerms.RemoveElementAt(index); - break; - } - index++; - } - - RefPtr<nsIPermission> permission = Permission::Create( - aPrincipal, mTypeArray[perm.mType], perm.mPermission, - perm.mExpireType, perm.mExpireTime, perm.mModificationTime); - if (NS_WARN_IF(!permission)) { - continue; - } - aResult.AppendElement(permission); - } - } - - for (const auto& perm : strippedPerms) { - RefPtr<nsIPermission> permission = Permission::Create( - aPrincipal, mTypeArray[perm.mType], perm.mPermission, perm.mExpireType, - perm.mExpireTime, perm.mModificationTime); - if (NS_WARN_IF(!permission)) { - continue; - } - aResult.AppendElement(permission); - } - - return NS_OK; -} - -NS_IMETHODIMP PermissionManager::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* someData) { - ENSURE_NOT_CHILD_PROCESS; - - if (!nsCRT::strcmp(aTopic, "profile-before-change")) { - // The profile is about to change, - // or is going away because the application is shutting down. - RemoveIdleDailyMaintenanceJob(); - RemoveAllFromMemory(); - CloseDB(false); - } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) { - // the profile has already changed; 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 - // that directly manipulate the permissions database need some way to reload - // the database for their changes to have any effect. This mechanism was - // introduced when moving the permissions manager from on-demand startup to - // always being initialized. This is not guarded by a pref because it's not - // dangerous to reload permissions from disk, just bad for performance. - RemoveAllFromMemory(); - CloseDB(false); - InitDB(false); - } else if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY)) { - PerformIdleDailyMaintenance(); - } - - return NS_OK; -} - -nsresult PermissionManager::RemoveAllModifiedSince(int64_t aModificationTime) { - ENSURE_NOT_CHILD_PROCESS; - - return RemovePermissionEntries( - [aModificationTime](const PermissionEntry& aPermEntry) { - return aModificationTime <= aPermEntry.mModificationTime; - }); -} - -NS_IMETHODIMP -PermissionManager::RemovePermissionsWithAttributes(const nsAString& aPattern) { - ENSURE_NOT_CHILD_PROCESS; - OriginAttributesPattern pattern; - if (!pattern.Init(aPattern)) { - return NS_ERROR_INVALID_ARG; - } - - return RemovePermissionsWithAttributes(pattern); -} - -nsresult PermissionManager::RemovePermissionsWithAttributes( - OriginAttributesPattern& aPattern) { - Vector<Tuple<nsCOMPtr<nsIPrincipal>, nsCString, nsCString>, 10> permissions; - for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { - PermissionHashKey* entry = iter.Get(); - - nsCOMPtr<nsIPrincipal> principal; - nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, false, - getter_AddRefs(principal)); - if (NS_FAILED(rv)) { - continue; - } - - if (!aPattern.Matches(principal->OriginAttributesRef())) { - continue; - } - - for (const auto& permEntry : entry->GetPermissions()) { - if (!permissions.emplaceBack(principal, mTypeArray[permEntry.mType], - entry->GetKey()->mOrigin)) { - continue; - } - } - } - - for (auto& i : permissions) { - AddInternal(Get<0>(i), Get<1>(i), nsIPermissionManager::UNKNOWN_ACTION, 0, - nsIPermissionManager::EXPIRE_NEVER, 0, 0, - PermissionManager::eNotify, PermissionManager::eWriteToDB, - false, &Get<2>(i)); - } - - return NS_OK; -} - -nsresult PermissionManager::GetStripPermsForPrincipal( - nsIPrincipal* aPrincipal, nsTArray<PermissionEntry>& aResult) { - aResult.Clear(); - aResult.SetCapacity(kStripOAPermissions.size()); - - // No special strip permissions - if (kStripOAPermissions.empty()) { - return NS_OK; - } - - nsresult rv; - // Create a key for the principal, but strip any origin attributes - RefPtr<PermissionKey> key = - PermissionKey::CreateFromPrincipal(aPrincipal, true, rv); - if (!key) { - MOZ_ASSERT(NS_FAILED(rv)); - return rv; - } - - PermissionHashKey* hashKey = mPermissionTable.GetEntry(key); - if (!hashKey) { - return NS_OK; - } - - for (const auto& permType : kStripOAPermissions) { - int32_t index = GetTypeIndex(permType, false); - if (index == -1) { - continue; - } - PermissionEntry perm = hashKey->GetPermission(index); - if (perm.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { - continue; - } - aResult.AppendElement(perm); - } - - return NS_OK; -} - -int32_t PermissionManager::GetTypeIndex(const nsACString& aType, bool aAdd) { - for (uint32_t i = 0; i < mTypeArray.length(); ++i) { - if (mTypeArray[i].Equals(aType)) { - return i; - } - } - - if (!aAdd) { - // Not found, but that is ok - we were just looking. - return -1; - } - - // This type was not registered before. - // append it to the array, without copy-constructing the string - if (!mTypeArray.emplaceBack(aType)) { - return -1; - } - - return mTypeArray.length() - 1; -} - -PermissionManager::PermissionHashKey* PermissionManager::GetPermissionHashKey( - nsIPrincipal* aPrincipal, uint32_t aType, bool aExactHostMatch) { - EnsureReadCompleted(); - +// Returns PermissionHashKey for a given { host, isInBrowserElement } +// tuple. This is not simply using PermissionKey because we will walk-up domains +// in case of |host| contains sub-domains. Returns null if nothing found. Also +// accepts host on the format "<foo>". This will perform an exact match lookup +// as the string doesn't contain any dots. +nsPermissionManager::PermissionHashKey* +nsPermissionManager::GetPermissionHashKey(nsIPrincipal* aPrincipal, + uint32_t aType, + bool aExactHostMatch) { MOZ_ASSERT(PermissionAvailable(aPrincipal, mTypeArray[aType])); nsresult rv; RefPtr<PermissionKey> key = PermissionKey::CreateFromPrincipal( aPrincipal, IsOAForceStripPermission(mTypeArray[aType]), rv); if (!key) { return nullptr; } @@ -2551,17 +2437,23 @@ PermissionManager::PermissionHashKey* Pe return GetPermissionHashKey(principal, aType, aExactHostMatch); } } // No entry, really... return nullptr; } -PermissionManager::PermissionHashKey* PermissionManager::GetPermissionHashKey( +// Returns PermissionHashKey for a given { host, isInBrowserElement } +// tuple. This is not simply using PermissionKey because we will walk-up domains +// in case of |host| contains sub-domains. Returns null if nothing found. Also +// accepts host on the format "<foo>". This will perform an exact match lookup +// as the string doesn't contain any dots. +nsPermissionManager::PermissionHashKey* +nsPermissionManager::GetPermissionHashKey( nsIURI* aURI, const OriginAttributes* aOriginAttributes, uint32_t aType, bool aExactHostMatch) { MOZ_ASSERT(aURI); #ifdef DEBUG { nsCOMPtr<nsIPrincipal> principal; nsresult rv = NS_OK; @@ -2631,304 +2523,587 @@ PermissionManager::PermissionHashKey* Pe aExactHostMatch); } } // No entry, really... return nullptr; } -nsresult PermissionManager::RemoveAllFromMemory() { +NS_IMETHODIMP nsPermissionManager::GetAll( + nsTArray<RefPtr<nsIPermission>>& aResult) { + return GetAllWithTypePrefix(NS_LITERAL_CSTRING(""), aResult); +} + +NS_IMETHODIMP nsPermissionManager::GetAllWithTypePrefix( + const nsACString& aPrefix, nsTArray<RefPtr<nsIPermission>>& aResult) { + aResult.Clear(); + if (XRE_IsContentProcess()) { + NS_WARNING( + "nsPermissionManager's getAllWithTypePrefix is not available in the " + "content process, as not all permissions may be available."); + return NS_ERROR_NOT_AVAILABLE; + } + + for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { + PermissionHashKey* entry = iter.Get(); + for (const auto& permEntry : entry->GetPermissions()) { + // Given how "default" permissions work and the possibility of them being + // overridden with UNKNOWN_ACTION, we might see this value here - but we + // do *not* want to return them via the enumerator. + if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + continue; + } + + if (!aPrefix.IsEmpty() && + !StringBeginsWith(mTypeArray[permEntry.mType], aPrefix)) { + continue; + } + + nsCOMPtr<nsIPrincipal> principal; + nsresult rv = GetPrincipalFromOrigin( + entry->GetKey()->mOrigin, + IsOAForceStripPermission(mTypeArray[permEntry.mType]), + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + continue; + } + + RefPtr<nsIPermission> permission = nsPermission::Create( + principal, mTypeArray[permEntry.mType], permEntry.mPermission, + permEntry.mExpireType, permEntry.mExpireTime, + permEntry.mModificationTime); + if (NS_WARN_IF(!permission)) { + continue; + } + aResult.AppendElement(std::move(permission)); + } + } + + return NS_OK; +} + +nsresult nsPermissionManager::GetStripPermsForPrincipal( + nsIPrincipal* aPrincipal, nsTArray<PermissionEntry>& aResult) { + aResult.Clear(); + aResult.SetCapacity(kStripOAPermissions.size()); + + // No special strip permissions + if (kStripOAPermissions.empty()) { + return NS_OK; + } + + nsresult rv; + // Create a key for the principal, but strip any origin attributes + RefPtr<PermissionKey> key = + PermissionKey::CreateFromPrincipal(aPrincipal, true, rv); + if (!key) { + MOZ_ASSERT(NS_FAILED(rv)); + return rv; + } + + PermissionHashKey* hashKey = mPermissionTable.GetEntry(key); + if (!hashKey) { + return NS_OK; + } + + for (const auto& permType : kStripOAPermissions) { + int32_t index = GetTypeIndex(permType, false); + if (index == -1) { + continue; + } + PermissionEntry perm = hashKey->GetPermission(index); + if (perm.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + continue; + } + aResult.AppendElement(perm); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPermissionManager::GetAllForPrincipal( + nsIPrincipal* aPrincipal, nsTArray<RefPtr<nsIPermission>>& aResult) { + aResult.Clear(); + + MOZ_ASSERT(PermissionAvailable(aPrincipal, EmptyCString())); + + nsresult rv; + RefPtr<PermissionKey> key = + PermissionKey::CreateFromPrincipal(aPrincipal, false, rv); + if (!key) { + MOZ_ASSERT(NS_FAILED(rv)); + return rv; + } + PermissionHashKey* entry = mPermissionTable.GetEntry(key); + + nsTArray<PermissionEntry> strippedPerms; + rv = GetStripPermsForPrincipal(aPrincipal, strippedPerms); + if (NS_FAILED(rv)) { + return rv; + } + + if (entry) { + for (const auto& permEntry : entry->GetPermissions()) { + // Only return custom permissions + if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { + continue; + } + + // Stripped principal permissions overwrite regular ones + // For each permission check if there is a stripped permission we should + // use instead + PermissionEntry perm = permEntry; + nsTArray<PermissionEntry>::index_type index = 0; + for (const auto& strippedPerm : strippedPerms) { + if (strippedPerm.mType == permEntry.mType) { + perm = strippedPerm; + strippedPerms.RemoveElementAt(index); + break; + } + index++; + } + + RefPtr<nsIPermission> permission = nsPermission::Create( + aPrincipal, mTypeArray[perm.mType], perm.mPermission, + perm.mExpireType, perm.mExpireTime, perm.mModificationTime); + if (NS_WARN_IF(!permission)) { + continue; + } + aResult.AppendElement(permission); + } + } + + for (const auto& perm : strippedPerms) { + RefPtr<nsIPermission> permission = nsPermission::Create( + aPrincipal, mTypeArray[perm.mType], perm.mPermission, perm.mExpireType, + perm.mExpireTime, perm.mModificationTime); + if (NS_WARN_IF(!permission)) { + continue; + } + aResult.AppendElement(permission); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPermissionManager::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* someData) { + ENSURE_NOT_CHILD_PROCESS; + + if (!nsCRT::strcmp(aTopic, "profile-before-change")) { + // The profile is about to change, + // or is going away because the application is shutting down. + RemoveIdleDailyMaintenanceJob(); + gIsShuttingDown = true; + RemoveAllFromMemory(); + CloseDB(false); + } else if (!nsCRT::strcmp(aTopic, "profile-do-change")) { + // the profile has already changed; 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 + // that directly manipulate the permissions database need some way to reload + // the database for their changes to have any effect. This mechanism was + // introduced when moving the permissions manager from on-demand startup to + // always being initialized. This is not guarded by a pref because it's not + // dangerous to reload permissions from disk, just bad for performance. + RemoveAllFromMemory(); + CloseDB(false); + InitDB(false); + } else if (!nsCRT::strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY)) { + PerformIdleDailyMaintenance(); + } + + return NS_OK; +} + +nsresult nsPermissionManager::RemoveAllModifiedSince( + int64_t aModificationTime) { + ENSURE_NOT_CHILD_PROCESS; + + return RemovePermissionEntries( + [aModificationTime](const PermissionEntry& aPermEntry) { + return aModificationTime <= aPermEntry.mModificationTime; + }); +} + +NS_IMETHODIMP +nsPermissionManager::RemovePermissionsWithAttributes( + const nsAString& aPattern) { + ENSURE_NOT_CHILD_PROCESS; + mozilla::OriginAttributesPattern pattern; + if (!pattern.Init(aPattern)) { + return NS_ERROR_INVALID_ARG; + } + + return RemovePermissionsWithAttributes(pattern); +} + +nsresult nsPermissionManager::RemovePermissionsWithAttributes( + mozilla::OriginAttributesPattern& aPattern) { + Vector<Tuple<nsCOMPtr<nsIPrincipal>, nsCString, nsCString>, 10> permissions; + for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { + PermissionHashKey* entry = iter.Get(); + + nsCOMPtr<nsIPrincipal> principal; + nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, false, + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + continue; + } + + if (!aPattern.Matches(principal->OriginAttributesRef())) { + continue; + } + + for (const auto& permEntry : entry->GetPermissions()) { + if (!permissions.emplaceBack(principal, mTypeArray[permEntry.mType], + entry->GetKey()->mOrigin)) { + continue; + } + } + } + + for (auto& i : permissions) { + AddInternal(Get<0>(i), Get<1>(i), nsIPermissionManager::UNKNOWN_ACTION, 0, + nsIPermissionManager::EXPIRE_NEVER, 0, 0, + nsPermissionManager::eNotify, nsPermissionManager::eWriteToDB, + false, &Get<2>(i)); + } + + return NS_OK; +} + +//***************************************************************************** +//*** nsPermissionManager private methods +//***************************************************************************** + +nsresult nsPermissionManager::RemoveAllFromMemory() { mLargestID = 0; mTypeArray.clear(); mPermissionTable.Clear(); return NS_OK; } // wrapper function for mangling (host,type,perm,expireType,expireTime) // set into an nsIPermission. -void PermissionManager::NotifyObserversWithPermission( +void nsPermissionManager::NotifyObserversWithPermission( nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime, const char16_t* aData) { nsCOMPtr<nsIPermission> permission = - Permission::Create(aPrincipal, aType, aPermission, aExpireType, - aExpireTime, aModificationTime); + nsPermission::Create(aPrincipal, aType, aPermission, aExpireType, + aExpireTime, aModificationTime); if (permission) NotifyObservers(permission, aData); } // notify observers that the permission list changed. there are four possible // values for aData: // "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. -void PermissionManager::NotifyObservers(nsIPermission* aPermission, - const char16_t* aData) { - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); +void nsPermissionManager::NotifyObservers(nsIPermission* aPermission, + const char16_t* aData) { + nsCOMPtr<nsIObserverService> observerService = + mozilla::services::GetObserverService(); if (observerService) observerService->NotifyObservers(aPermission, kPermissionChangeNotification, aData); } -nsresult PermissionManager::Read(const MonitorAutoLock& aProofOfLock) { +nsresult nsPermissionManager::Read() { ENSURE_NOT_CHILD_PROCESS; - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ACCESS_THREAD_BOUND(mThreadBoundData, data); - nsresult rv; nsCOMPtr<mozIStorageStatement> stmt; - rv = data->mDBConn->CreateStatement( + rv = mDBConn->CreateStatement( NS_LITERAL_CSTRING( "SELECT id, origin, type, permission, expireType, " "expireTime, modificationTime " "FROM moz_perms WHERE expireType != ?1 OR expireTime > ?2"), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->BindInt32ByIndex(0, nsIPermissionManager::EXPIRE_TIME); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->BindInt64ByIndex(1, EXPIRY_NOW); NS_ENSURE_SUCCESS(rv, rv); + int64_t id; + nsAutoCString origin, type; + uint32_t permission; + uint32_t expireType; + int64_t expireTime; + int64_t modificationTime; bool hasResult; bool readError = false; while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { - ReadEntry entry; - // explicitly set our entry id counter for use in AddInternal(), // and keep track of the largest id so we know where to pick up. - entry.mId = stmt->AsInt64(0); - if (entry.mId > mLargestID) mLargestID = entry.mId; - - rv = stmt->GetUTF8String(1, entry.mOrigin); + id = stmt->AsInt64(0); + if (id > mLargestID) mLargestID = id; + + rv = stmt->GetUTF8String(1, origin); if (NS_FAILED(rv)) { readError = true; continue; } - rv = stmt->GetUTF8String(2, entry.mType); + rv = stmt->GetUTF8String(2, type); if (NS_FAILED(rv)) { readError = true; continue; } - entry.mPermission = stmt->AsInt32(3); - entry.mExpireType = stmt->AsInt32(4); + permission = stmt->AsInt32(3); + expireType = stmt->AsInt32(4); // convert into int64_t values (milliseconds) - entry.mExpireTime = stmt->AsInt64(5); - entry.mModificationTime = stmt->AsInt64(6); - - entry.mFromMigration = false; - - mReadEntries.AppendElement(entry); + expireTime = stmt->AsInt64(5); + modificationTime = stmt->AsInt64(6); + + nsCOMPtr<nsIPrincipal> principal; + nsresult rv = GetPrincipalFromOrigin(origin, IsOAForceStripPermission(type), + getter_AddRefs(principal)); + if (NS_FAILED(rv)) { + readError = true; + continue; + } + + rv = AddInternal(principal, type, permission, id, expireType, expireTime, + modificationTime, eDontNotify, eNoDBOperation, false, + &origin); + if (NS_FAILED(rv)) { + readError = true; + continue; + } } if (readError) { NS_ERROR("Error occured while reading the permissions database!"); return NS_ERROR_FAILURE; } return NS_OK; } -void PermissionManager::CompleteMigrations() { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mState == eReady); - - nsresult rv; - - nsTArray<MigrationEntry> entries; - { - MonitorAutoLock lock(mMonitor); - entries.SwapElements(mMigrationEntries); +static const char kMatchTypeHost[] = "host"; +static const char kMatchTypeOrigin[] = "origin"; + +// ImportDefaults will read a URL with default permissions and add them to the +// in-memory copy of permissions. The database is *not* written to. +nsresult nsPermissionManager::ImportDefaults() { + nsAutoCString defaultsURL; + mozilla::Preferences::GetCString(kDefaultsUrlPrefName, defaultsURL); + if (defaultsURL.IsEmpty()) { // == Don't use built-in permissions. + return NS_OK; } - for (const MigrationEntry& entry : entries) { - rv = UpgradeHostToOriginAndInsert( - entry.mHost, entry.mType, entry.mPermission, entry.mExpireType, - entry.mExpireTime, entry.mModificationTime, entry.mIsInBrowserElement, - [&](const nsACString& aOrigin, const nsCString& aType, - uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime) { - MaybeAddReadEntryFromMigration(aOrigin, aType, aPermission, - aExpireType, aExpireTime, - aModificationTime, entry.mId); - return NS_OK; - }); - Unused << NS_WARN_IF(NS_FAILED(rv)); - } + nsCOMPtr<nsIURI> defaultsURI; + nsresult rv = NS_NewURI(getter_AddRefs(defaultsURI), defaultsURL); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIChannel> channel; + rv = NS_NewChannel(getter_AddRefs(channel), defaultsURI, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, + nsIContentPolicy::TYPE_OTHER); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIInputStream> inputStream; + rv = channel->Open(getter_AddRefs(inputStream)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = _DoImport(inputStream, nullptr); + inputStream->Close(); + return rv; } -void PermissionManager::CompleteRead() { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mState == eReady); +// _DoImport reads the specified stream and adds the parsed elements. If +// |conn| is passed, the imported data will be written to the database, but if +// |conn| is null the data will be added only to the in-memory copy of the +// database. +nsresult nsPermissionManager::_DoImport(nsIInputStream* inputStream, + mozIStorageConnection* conn) { + ENSURE_NOT_CHILD_PROCESS; nsresult rv; - - nsTArray<ReadEntry> entries; - { - MonitorAutoLock lock(mMonitor); - entries.SwapElements(mReadEntries); - } - - for (const ReadEntry& entry : entries) { - nsCOMPtr<nsIPrincipal> principal; - rv = GetPrincipalFromOrigin(entry.mOrigin, - IsOAForceStripPermission(entry.mType), - getter_AddRefs(principal)); - if (NS_WARN_IF(NS_FAILED(rv))) { + // start a transaction on the storage db, to optimize insertions. + // transaction will automically commit on completion + // (note the transaction is a no-op if a null connection is passed) + mozStorageTransaction transaction(conn, true); + + // The DB operation - we only try and write if a connection was passed. + DBOperationType operation = conn ? eWriteToDB : eNoDBOperation; + // and if no DB connection was passed we assume this is a "default" + // permission, so use the special ID which indicates this. + int64_t id = conn ? 0 : cIDPermissionIsDefault; + + /* format is: + * matchtype \t type \t permission \t host + * Only "host" is supported for matchtype + * type is a string that identifies the type of permission (e.g. "cookie") + * permission is an integer between 1 and 15 + */ + + // Ideally we'd do this with nsILineInputString, but this is called with an + // nsIInputStream that comes from a resource:// URI, which doesn't support + // that interface. So NS_ReadLine to the rescue... + nsLineBuffer<char> lineBuffer; + nsCString line; + bool isMore = true; + do { + rv = NS_ReadLine(inputStream, &lineBuffer, line, &isMore); + NS_ENSURE_SUCCESS(rv, rv); + + if (line.IsEmpty() || line.First() == '#') { continue; } - DBOperationType op = entry.mFromMigration ? eWriteToDB : eNoDBOperation; - - rv = AddInternal(principal, entry.mType, entry.mPermission, entry.mId, - entry.mExpireType, entry.mExpireTime, - entry.mModificationTime, eDontNotify, op, false, - &entry.mOrigin); - Unused << NS_WARN_IF(NS_FAILED(rv)); - } + nsTArray<nsCString> lineArray; + + // Split the line at tabs + ParseString(line, '\t', lineArray); + + if (lineArray[0].EqualsLiteral(kMatchTypeHost) && lineArray.Length() == 4) { + nsresult error = NS_OK; + uint32_t permission = lineArray[2].ToInteger(&error); + if (NS_FAILED(error)) continue; + + // the import file format doesn't handle modification times, so we use + // 0, which AddInternal will convert to now() + int64_t modificationTime = 0; + + UpgradeHostToOriginHostfileImport upHelper(this, operation, id); + error = + UpgradeHostToOriginAndInsert(lineArray[3], lineArray[1], permission, + nsIPermissionManager::EXPIRE_NEVER, 0, + modificationTime, false, &upHelper); + if (NS_FAILED(error)) { + NS_WARNING("There was a problem importing a host permission"); + } + } else if (lineArray[0].EqualsLiteral(kMatchTypeOrigin) && + lineArray.Length() == 4) { + nsresult error = NS_OK; + uint32_t permission = lineArray[2].ToInteger(&error); + if (NS_FAILED(error)) continue; + + nsCOMPtr<nsIPrincipal> principal; + error = GetPrincipalFromOrigin(lineArray[3], + IsOAForceStripPermission(lineArray[1]), + getter_AddRefs(principal)); + if (NS_FAILED(error)) { + 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; + + error = AddInternal(principal, lineArray[1], permission, id, + nsIPermissionManager::EXPIRE_NEVER, 0, + modificationTime, eDontNotify, operation); + if (NS_FAILED(error)) { + NS_WARNING("There was a problem importing an origin permission"); + } + } + + } while (isMore); + + return NS_OK; } -void PermissionManager::MaybeAddReadEntryFromMigration( - const nsACString& aOrigin, const nsCString& aType, uint32_t aPermission, - uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime, - int64_t aId) { - MonitorAutoLock lock(mMonitor); - - // We convert a migration to a ReadEntry only if we don't have an existing - // ReadEntry for the same origin + type. - for (const ReadEntry& entry : mReadEntries) { - if (entry.mOrigin == aOrigin && entry.mType == aType) { - return; +void nsPermissionManager::UpdateDB( + OperationType aOp, mozIStorageAsyncStatement* aStmt, int64_t aID, + const nsACString& aOrigin, const nsACString& aType, uint32_t aPermission, + uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime) { + ENSURE_NOT_CHILD_PROCESS_NORET; + + nsresult rv; + + // no statement is ok - just means we don't have a profile + if (!aStmt) return; + + switch (aOp) { + case eOperationAdding: { + rv = aStmt->BindInt64ByIndex(0, aID); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindUTF8StringByIndex(1, aOrigin); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindUTF8StringByIndex(2, aType); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(3, aPermission); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(4, aExpireType); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(5, aExpireTime); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(6, aModificationTime); + break; + } + + case eOperationRemoving: { + rv = aStmt->BindInt64ByIndex(0, aID); + break; + } + + case eOperationChanging: { + rv = aStmt->BindInt64ByIndex(0, aID); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(1, aPermission); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt32ByIndex(2, aExpireType); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(3, aExpireTime); + if (NS_FAILED(rv)) break; + + rv = aStmt->BindInt64ByIndex(4, aModificationTime); + break; + } + + default: { + MOZ_ASSERT_UNREACHABLE("need a valid operation in UpdateDB()!"); + rv = NS_ERROR_UNEXPECTED; + break; } } - ReadEntry entry; - entry.mId = aId; - entry.mOrigin = aOrigin; - entry.mType = aType; - entry.mPermission = aPermission; - entry.mExpireType = aExpireType; - entry.mExpireTime = aExpireTime; - entry.mModificationTime = aModificationTime; - entry.mFromMigration = true; - - mReadEntries.AppendElement(entry); + if (NS_FAILED(rv)) { + NS_WARNING("db change failed!"); + return; + } + + nsCOMPtr<mozIStoragePendingStatement> pending; + rv = aStmt->ExecuteAsync(nullptr, getter_AddRefs(pending)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); } -void PermissionManager::UpdateDB(OperationType aOp, int64_t aID, - const nsACString& aOrigin, - const nsACString& aType, uint32_t aPermission, - uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime) { - ENSURE_NOT_CHILD_PROCESS_NORET; - - MOZ_ASSERT(NS_IsMainThread()); - EnsureReadCompleted(); - - nsCString origin(aOrigin); - nsCString type(aType); - - RefPtr<PermissionManager> self = this; - mThread->Dispatch(NS_NewRunnableFunction( - "PermissionManager::UpdateDB", - [self, aOp, aID, origin, type, aPermission, aExpireType, aExpireTime, - aModificationTime] { - nsresult rv; - - MOZ_ACCESS_THREAD_BOUND(self->mThreadBoundData, data); - - if (self->mState == eClosed || !data->mDBConn) { - // no statement is ok - just means we don't have a profile - return; - } - - mozIStorageStatement* stmt = nullptr; - switch (aOp) { - case eOperationAdding: { - stmt = data->mStmtInsert; - - rv = stmt->BindInt64ByIndex(0, aID); - if (NS_FAILED(rv)) break; - - rv = stmt->BindUTF8StringByIndex(1, origin); - if (NS_FAILED(rv)) break; - - rv = stmt->BindUTF8StringByIndex(2, type); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt32ByIndex(3, aPermission); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt32ByIndex(4, aExpireType); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt64ByIndex(5, aExpireTime); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt64ByIndex(6, aModificationTime); - break; - } - - case eOperationRemoving: { - stmt = data->mStmtDelete; - rv = stmt->BindInt64ByIndex(0, aID); - break; - } - - case eOperationChanging: { - stmt = data->mStmtUpdate; - - rv = stmt->BindInt64ByIndex(0, aID); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt32ByIndex(1, aPermission); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt32ByIndex(2, aExpireType); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt64ByIndex(3, aExpireTime); - if (NS_FAILED(rv)) break; - - rv = stmt->BindInt64ByIndex(4, aModificationTime); - break; - } - - default: { - MOZ_ASSERT_UNREACHABLE("need a valid operation in UpdateDB()!"); - rv = NS_ERROR_UNEXPECTED; - break; - } - } - - if (NS_FAILED(rv)) { - NS_WARNING("db change failed!"); - return; - } - - rv = stmt->Execute(); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - })); -} - -bool PermissionManager::GetPermissionsFromOriginOrKey( +bool nsPermissionManager::GetPermissionsFromOriginOrKey( const nsACString& aOrigin, const nsACString& aKey, nsTArray<IPC::Permission>& aPerms) { - EnsureReadCompleted(); - aPerms.Clear(); if (NS_WARN_IF(XRE_IsContentProcess())) { return false; } for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) { PermissionHashKey* entry = iter.Get(); @@ -2974,17 +3149,17 @@ bool PermissionManager::GetPermissionsFr permEntry.mExpireType, permEntry.mExpireTime)); } } } return true; } -void PermissionManager::SetPermissionsWithKey( +void nsPermissionManager::SetPermissionsWithKey( const nsACString& aPermissionKey, nsTArray<IPC::Permission>& aPerms) { if (NS_WARN_IF(XRE_IsParentProcess())) { return; } RefPtr<GenericNonExclusivePromise::Private> promise; bool foundKey = mPermissionKeyPromiseMap.Get(aPermissionKey, getter_AddRefs(promise)); @@ -3025,18 +3200,19 @@ void PermissionManager::SetPermissionsWi uint64_t modificationTime = 0; AddInternal(principal, perm.type, perm.capability, 0, perm.expireType, perm.expireTime, modificationTime, eNotify, eNoDBOperation, true /* ignoreSessionPermissions */); } } /* static */ -void PermissionManager::GetKeyForOrigin(const nsACString& aOrigin, - bool aForceStripOA, nsACString& aKey) { +void nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin, + bool aForceStripOA, + nsACString& aKey) { aKey.Truncate(); // We only key origins for http, https, and ftp URIs. All origins begin with // the URL which they apply to, which means that they should begin with their // scheme in the case where they are one of these interesting URIs. We don't // want to actually parse the URL here however, because this can be called on // hot paths. if (!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("http:")) && @@ -3069,44 +3245,44 @@ void PermissionManager::GetKeyForOrigin( // Append the stripped suffix to the output origin key. nsAutoCString suffix; attrs.CreateSuffix(suffix); aKey.Append(suffix); } /* static */ -void PermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, - bool aForceStripOA, - nsACString& aKey) { +void nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, + bool aForceStripOA, + nsACString& aKey) { nsAutoCString origin; nsresult rv = aPrincipal->GetOrigin(origin); if (NS_WARN_IF(NS_FAILED(rv))) { aKey.Truncate(); return; } GetKeyForOrigin(origin, aForceStripOA, aKey); } /* static */ -void PermissionManager::GetKeyForPermission(nsIPrincipal* aPrincipal, - const nsACString& aType, - nsACString& aKey) { +void nsPermissionManager::GetKeyForPermission(nsIPrincipal* aPrincipal, + const nsACString& aType, + nsACString& aKey) { // Preload permissions have the "" key. if (IsPreloadPermission(aType)) { aKey.Truncate(); return; } GetKeyForPrincipal(aPrincipal, IsOAForceStripPermission(aType), aKey); } /* static */ nsTArray<std::pair<nsCString, nsCString>> -PermissionManager::GetAllKeysForPrincipal(nsIPrincipal* aPrincipal) { +nsPermissionManager::GetAllKeysForPrincipal(nsIPrincipal* aPrincipal) { MOZ_ASSERT(aPrincipal); nsTArray<std::pair<nsCString, nsCString>> pairs; nsCOMPtr<nsIPrincipal> prin = aPrincipal; while (prin) { // Add the pair to the list std::pair<nsCString, nsCString>* pair = pairs.AppendElement(std::make_pair(EmptyCString(), EmptyCString())); @@ -3121,32 +3297,30 @@ PermissionManager::GetAllKeysForPrincipa } MOZ_ASSERT(pairs.Length() >= 1, "Every principal should have at least one pair item."); return pairs; } NS_IMETHODIMP -PermissionManager::BroadcastPermissionsForPrincipalToAllContentProcesses( +nsPermissionManager::BroadcastPermissionsForPrincipalToAllContentProcesses( nsIPrincipal* aPrincipal) { nsTArray<ContentParent*> cps; ContentParent::GetAll(cps); for (ContentParent* cp : cps) { nsresult rv = cp->TransmitPermissionsForPrincipal(aPrincipal); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; } -bool PermissionManager::PermissionAvailable(nsIPrincipal* aPrincipal, - const nsACString& aType) { - EnsureReadCompleted(); - +bool nsPermissionManager::PermissionAvailable(nsIPrincipal* aPrincipal, + const nsACString& aType) { if (XRE_IsContentProcess()) { nsAutoCString permissionKey; // NOTE: GetKeyForPermission accepts a null aType. GetKeyForPermission(aPrincipal, aType, permissionKey); // If we have a pending promise for the permission key in question, we don't // have the permission available, so report a warning and return false. RefPtr<GenericNonExclusivePromise::Private> promise; @@ -3159,18 +3333,18 @@ bool PermissionManager::PermissionAvaila permissionKey.get()) .get()); return false; } } return true; } -void PermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal, - nsIRunnable* aRunnable) { +void nsPermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal, + nsIRunnable* aRunnable) { MOZ_ASSERT(aRunnable); if (!XRE_IsContentProcess()) { aRunnable->Run(); return; } nsTArray<RefPtr<GenericNonExclusivePromise>> promises; @@ -3201,365 +3375,12 @@ void PermissionManager::WhenPermissionsA auto* thread = AbstractThread::MainThread(); RefPtr<nsIRunnable> runnable = aRunnable; GenericNonExclusivePromise::All(thread, promises) ->Then( thread, __func__, [runnable]() { runnable->Run(); }, []() { NS_WARNING( - "PermissionManager permission promise rejected. We're " + "nsPermissionManager permission promise rejected. We're " "probably shutting down."); }); } - -void PermissionManager::EnsureReadCompleted() { - MOZ_ASSERT(NS_IsMainThread()); - - if (mState == eInitializing) { - MonitorAutoLock lock(mMonitor); - - while (mState == eInitializing) { - mMonitor.Wait(); - } - } - - switch (mState) { - case eInitializing: - MOZ_CRASH("This state is impossible!"); - - case eDBInitialized: - mState = eReady; - - CompleteMigrations(); - ImportLatestDefaults(); - CompleteRead(); - - [[fallthrough]]; - - case eReady: - [[fallthrough]]; - - case eClosed: - return; - - default: - MOZ_CRASH("Invalid state"); - } -} - -already_AddRefed<nsIInputStream> PermissionManager::GetDefaultsInputStream() { - MOZ_ASSERT(NS_IsMainThread()); - - nsAutoCString defaultsURL; - Preferences::GetCString(kDefaultsUrlPrefName, defaultsURL); - if (defaultsURL.IsEmpty()) { // == Don't use built-in permissions. - return nullptr; - } - - nsCOMPtr<nsIURI> defaultsURI; - nsresult rv = NS_NewURI(getter_AddRefs(defaultsURI), defaultsURL); - NS_ENSURE_SUCCESS(rv, nullptr); - - nsCOMPtr<nsIChannel> channel; - rv = NS_NewChannel(getter_AddRefs(channel), defaultsURI, - nsContentUtils::GetSystemPrincipal(), - nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, - nsIContentPolicy::TYPE_OTHER); - NS_ENSURE_SUCCESS(rv, nullptr); - - nsCOMPtr<nsIInputStream> inputStream; - rv = channel->Open(getter_AddRefs(inputStream)); - NS_ENSURE_SUCCESS(rv, nullptr); - - return inputStream.forget(); -} - -void PermissionManager::ConsumeDefaultsInputStream( - nsIInputStream* aInputStream, const MonitorAutoLock& aProofOfLock) { - MOZ_ASSERT(!NS_IsMainThread()); - - constexpr char kMatchTypeHost[] = "host"; - constexpr char kMatchTypeOrigin[] = "origin"; - - mDefaultEntries.Clear(); - - if (!aInputStream) { - return; - } - - nsresult rv; - - /* format is: - * matchtype \t type \t permission \t host - * Only "host" is supported for matchtype - * type is a string that identifies the type of permission (e.g. "cookie") - * permission is an integer between 1 and 15 - */ - - // Ideally we'd do this with nsILineInputString, but this is called with an - // nsIInputStream that comes from a resource:// URI, which doesn't support - // that interface. So NS_ReadLine to the rescue... - nsLineBuffer<char> lineBuffer; - nsCString line; - bool isMore = true; - do { - rv = NS_ReadLine(aInputStream, &lineBuffer, line, &isMore); - NS_ENSURE_SUCCESS_VOID(rv); - - if (line.IsEmpty() || line.First() == '#') { - continue; - } - - nsTArray<nsCString> lineArray; - - // Split the line at tabs - ParseString(line, '\t', lineArray); - - if (lineArray.Length() != 4) { - continue; - } - - nsresult error = NS_OK; - uint32_t permission = lineArray[2].ToInteger(&error); - if (NS_FAILED(error)) { - continue; - } - - DefaultEntry::Op op; - - if (lineArray[0].EqualsLiteral(kMatchTypeHost)) { - op = DefaultEntry::eImportMatchTypeHost; - } else if (lineArray[0].EqualsLiteral(kMatchTypeOrigin)) { - 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); -} - -// 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 : 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, false, - [&](const nsACString& aOrigin, const nsCString& aType, - uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime) { - nsCOMPtr<nsIPrincipal> principal; - nsresult rv = - GetPrincipalFromOrigin(aOrigin, IsOAForceStripPermission(aType), - getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - - return AddInternal( - principal, aType, aPermission, cIDPermissionIsDefault, - aExpireType, aExpireTime, aModificationTime, - PermissionManager::eDontNotify, - PermissionManager::eNoDBOperation, false, &aOrigin); - }); - - if (NS_FAILED(rv)) { - NS_WARNING("There was a problem importing a host permission"); - } - continue; - } - - MOZ_ASSERT(entry.mOp == DefaultEntry::eImportMatchTypeOrigin); - - nsCOMPtr<nsIPrincipal> 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"); - } - } - - return NS_OK; -} - -/** - * Perform the early steps of a permission check and determine whether we need - * to call CommonTestPermissionInternal() for the actual permission check. - * - * @param aPrincipal optional principal argument to check the permission for, - * can be nullptr if we aren't performing a principal-based - * check. - * @param aTypeIndex if the caller isn't sure what the index of the permission - * type to check for is in the mTypeArray member variable, - * it should pass -1, otherwise this would be the index of - * the type inside mTypeArray. This would only be something - * other than -1 in recursive invocations of this function. - * @param aType the permission type to test. - * @param aPermission out argument which will be a permission type that we - * will return from this function once the function is - * done. - * @param aDefaultPermission the default permission to be used if we can't - * determine the result of the permission check. - * @param aDefaultPermissionIsValid whether the previous argument contains a - * valid value. - * @param aExactHostMatch whether to look for the exact host name or also for - * subdomains that can have the same permission. - * @param aIncludingSession whether to include session permissions when - * testing for the permission. - */ -PermissionManager::TestPreparationResult -PermissionManager::CommonPrepareToTestPermission( - nsIPrincipal* aPrincipal, int32_t aTypeIndex, const nsACString& aType, - uint32_t* aPermission, uint32_t aDefaultPermission, - bool aDefaultPermissionIsValid, bool aExactHostMatch, - bool aIncludingSession) { - auto* basePrin = BasePrincipal::Cast(aPrincipal); - if (basePrin && basePrin->IsSystemPrincipal()) { - *aPermission = ALLOW_ACTION; - return AsVariant(NS_OK); - } - - EnsureReadCompleted(); - - // For some permissions, query the default from a pref. We want to avoid - // doing this for all permissions so that permissions can opt into having - // the pref lookup overhead on each call. - int32_t defaultPermission = - aDefaultPermissionIsValid ? aDefaultPermission : UNKNOWN_ACTION; - if (!aDefaultPermissionIsValid && HasDefaultPref(aType)) { - Unused << mDefaultPrefBranch->GetIntPref(PromiseFlatCString(aType).get(), - &defaultPermission); - } - - // Set the default. - *aPermission = defaultPermission; - - int32_t typeIndex = - aTypeIndex == -1 ? GetTypeIndex(aType, false) : aTypeIndex; - - // For expanded principals, we want to iterate over the allowlist and see - // if the permission is granted for any of them. - if (basePrin && basePrin->Is<ExpandedPrincipal>()) { - auto ep = basePrin->As<ExpandedPrincipal>(); - for (auto& prin : ep->AllowList()) { - uint32_t perm; - nsresult rv = - CommonTestPermission(prin, typeIndex, aType, &perm, defaultPermission, - true, aExactHostMatch, aIncludingSession); - if (NS_WARN_IF(NS_FAILED(rv))) { - return AsVariant(rv); - } - - if (perm == nsIPermissionManager::ALLOW_ACTION) { - *aPermission = perm; - return AsVariant(NS_OK); - } - if (perm == nsIPermissionManager::PROMPT_ACTION) { - // Store it, but keep going to see if we can do better. - *aPermission = perm; - } - } - - return AsVariant(NS_OK); - } - - // If type == -1, the type isn't known, just signal that we are done. - if (typeIndex == -1) { - return AsVariant(NS_OK); - } - - return AsVariant(typeIndex); -} - -// If aTypeIndex is passed -1, we try to inder the type index from aType. -nsresult PermissionManager::CommonTestPermission( - nsIPrincipal* aPrincipal, int32_t aTypeIndex, const nsACString& aType, - uint32_t* aPermission, uint32_t aDefaultPermission, - bool aDefaultPermissionIsValid, bool aExactHostMatch, - bool aIncludingSession) { - auto preparationResult = CommonPrepareToTestPermission( - aPrincipal, aTypeIndex, aType, aPermission, aDefaultPermission, - aDefaultPermissionIsValid, aExactHostMatch, aIncludingSession); - if (preparationResult.is<nsresult>()) { - return preparationResult.as<nsresult>(); - } - - return CommonTestPermissionInternal( - aPrincipal, nullptr, nullptr, preparationResult.as<int32_t>(), aType, - aPermission, aExactHostMatch, aIncludingSession); -} - -// If aTypeIndex is passed -1, we try to inder the type index from aType. -nsresult PermissionManager::CommonTestPermission( - nsIURI* aURI, int32_t aTypeIndex, const nsACString& aType, - uint32_t* aPermission, uint32_t aDefaultPermission, - bool aDefaultPermissionIsValid, bool aExactHostMatch, - bool aIncludingSession) { - auto preparationResult = CommonPrepareToTestPermission( - nullptr, aTypeIndex, aType, aPermission, aDefaultPermission, - aDefaultPermissionIsValid, aExactHostMatch, aIncludingSession); - if (preparationResult.is<nsresult>()) { - return preparationResult.as<nsresult>(); - } - - return CommonTestPermissionInternal( - nullptr, aURI, nullptr, preparationResult.as<int32_t>(), aType, - aPermission, aExactHostMatch, aIncludingSession); -} - -nsresult PermissionManager::CommonTestPermission( - nsIURI* aURI, const OriginAttributes* aOriginAttributes, int32_t aTypeIndex, - const nsACString& aType, uint32_t* aPermission, uint32_t aDefaultPermission, - bool aDefaultPermissionIsValid, bool aExactHostMatch, - bool aIncludingSession) { - auto preparationResult = CommonPrepareToTestPermission( - nullptr, aTypeIndex, aType, aPermission, aDefaultPermission, - aDefaultPermissionIsValid, aExactHostMatch, aIncludingSession); - if (preparationResult.is<nsresult>()) { - return preparationResult.as<nsresult>(); - } - - return CommonTestPermissionInternal( - nullptr, aURI, aOriginAttributes, preparationResult.as<int32_t>(), aType, - aPermission, aExactHostMatch, aIncludingSession); -} - -nsresult PermissionManager::TestPermissionWithoutDefaultsFromPrincipal( - nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t* aPermission) { - MOZ_ASSERT(!HasDefaultPref(aType)); - - return CommonTestPermission(aPrincipal, -1, aType, aPermission, - nsIPermissionManager::UNKNOWN_ACTION, true, false, - true); -} - -} // namespace mozilla
rename from extensions/permissions/PermissionManager.h rename to extensions/permissions/nsPermissionManager.h --- a/extensions/permissions/PermissionManager.h +++ b/extensions/permissions/nsPermissionManager.h @@ -1,59 +1,57 @@ /* -*- 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/. */ -#ifndef mozilla_PermissionManager_h -#define mozilla_PermissionManager_h +#ifndef nsPermissionManager_h__ +#define nsPermissionManager_h__ #include "nsIPermissionManager.h" #include "nsIObserver.h" #include "nsWeakReference.h" #include "nsCOMPtr.h" +#include "nsIInputStream.h" #include "nsTHashtable.h" #include "nsTArray.h" #include "nsString.h" +#include "nsPermission.h" +#include "nsIPrefBranch.h" #include "nsHashKeys.h" +#include "nsCOMArray.h" +#include "nsDataHashtable.h" #include "nsRefPtrHashtable.h" -#include "mozilla/Atomics.h" -#include "mozilla/Monitor.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/ExpandedPrincipal.h" #include "mozilla/MozPromise.h" -#include "mozilla/ThreadBound.h" +#include "mozilla/Unused.h" #include "mozilla/Variant.h" #include "mozilla/Vector.h" #include <utility> -class mozIStorageConnection; -class mozIStorageStatement; -class nsIInputStream; -class nsIPermission; -class nsIPrefBranch; - namespace IPC { struct Permission; } namespace mozilla { class OriginAttributesPattern; +} -namespace dom { -class ContentChild; -} // namespace dom +class nsIPermission; +class mozIStorageConnection; +class mozIStorageAsyncStatement; //////////////////////////////////////////////////////////////////////////////// -class PermissionManager final : public nsIPermissionManager, - public nsIObserver, - public nsSupportsWeakReference { - friend class dom::ContentChild; - +class nsPermissionManager final : public nsIPermissionManager, + public nsIObserver, + public nsSupportsWeakReference { public: class PermissionEntry { public: PermissionEntry(int64_t aID, uint32_t aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime) : mID(aID), mExpireTime(aExpireTime), @@ -81,21 +79,21 @@ class PermissionManager final : public n */ class PermissionKey { public: static PermissionKey* CreateFromPrincipal(nsIPrincipal* aPrincipal, bool aForceStripOA, nsresult& aResult); static PermissionKey* CreateFromURI(nsIURI* aURI, nsresult& aResult); static PermissionKey* CreateFromURIAndOriginAttributes( - nsIURI* aURI, const OriginAttributes* aOriginAttributes, + nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes, bool aForceStripOA, nsresult& aResult); explicit PermissionKey(const nsACString& aOrigin) - : mOrigin(aOrigin), mHashCode(HashString(aOrigin)) {} + : mOrigin(aOrigin), mHashCode(mozilla::HashString(aOrigin)) {} bool operator==(const PermissionKey& aKey) const { return mOrigin.Equals(aKey.mOrigin); } PLDHashNumber GetHashCode() const { return mHashCode; } NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PermissionKey) @@ -150,58 +148,78 @@ class PermissionManager final : public n nsIPermissionManager::EXPIRE_NEVER, 0, 0); } private: AutoTArray<PermissionEntry, 1> mPermissions; }; // nsISupports - NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_ISUPPORTS NS_DECL_NSIPERMISSIONMANAGER NS_DECL_NSIOBSERVER - PermissionManager(); + nsPermissionManager(); static already_AddRefed<nsIPermissionManager> GetXPCOMSingleton(); - static PermissionManager* GetInstance(); + static nsPermissionManager* GetInstance(); nsresult Init(); // enums for AddInternal() enum OperationType { eOperationNone, eOperationAdding, eOperationRemoving, eOperationChanging, eOperationReplacingDefault }; enum DBOperationType { eNoDBOperation, eWriteToDB }; enum NotifyOperationType { eDontNotify, eNotify }; + // A special value for a permission ID that indicates the ID was loaded as + // a default value. These will never be written to the database, but may + // be overridden with an explicit permission (including UNKNOWN_ACTION) + static const int64_t cIDPermissionIsDefault = -1; + + nsresult AddInternal(nsIPrincipal* aPrincipal, const nsACString& aType, + uint32_t aPermission, int64_t aID, uint32_t aExpireType, + int64_t aExpireTime, int64_t aModificationTime, + NotifyOperationType aNotifyOperation, + DBOperationType aDBOperation, + const bool aIgnoreSessionPermissions = false, + const nsACString* aOriginString = nullptr); + // Similar to TestPermissionFromPrincipal, except that it is used only for // permissions which can never have default values. nsresult TestPermissionWithoutDefaultsFromPrincipal(nsIPrincipal* aPrincipal, const nsACString& aType, - uint32_t* aPermission); + uint32_t* aPermission) { + MOZ_ASSERT(!HasDefaultPref(aType)); + + return CommonTestPermission(aPrincipal, -1, aType, aPermission, + nsIPermissionManager::UNKNOWN_ACTION, true, + false, true); + } nsresult LegacyTestPermissionFromURI( - nsIURI* aURI, const OriginAttributes* aOriginAttributes, + nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes, const nsACString& aType, uint32_t* aPermission); /** * Initialize the permission-manager service. * The permission manager is always initialized at startup because when it * was lazy-initialized on demand, it was possible for it to be created * once shutdown had begun, resulting in the manager failing to correctly * shutdown because it missed its shutdown observer notification. */ static void Startup(); - nsresult RemovePermissionsWithAttributes(OriginAttributesPattern& aAttrs); + nsresult RemovePermissionsWithAttributes( + mozilla::OriginAttributesPattern& aAttrs); /** * See `nsIPermissionManager::GetPermissionsWithKey` for more info on * permission keys. * * Get the permission key corresponding to the given Principal. This method is * intentionally infallible, as we want to provide an permission key to every * principal. Principals which don't have meaningful URIs with http://, @@ -291,34 +309,34 @@ class PermissionManager final : public n /** * The content process doesn't have access to every permission. Instead, when * LOAD_DOCUMENT_URI channels for http://, https://, and ftp:// URIs are * opened, the permissions for those channels are sent down to the content * process before the OnStartRequest message. Permissions for principals with * other schemes are sent down at process startup. * * Permissions are keyed and grouped by "Permission Key"s. - * `PermissionManager::GetKeyForPrincipal` provides the mechanism for + * `nsPermissionManager::GetKeyForPrincipal` provides the mechanism for * determining the permission key for a given principal. * * This method may only be called in the parent process. It fills the nsTArray * argument with the IPC::Permission objects which have a matching origin. * * @param origin The origin to use to find the permissions of interest. * @param key The key to use to find the permissions of interest. Only used * when the origin argument is empty. * @param perms An array which will be filled with the permissions which * match the given origin. */ bool GetPermissionsFromOriginOrKey(const nsACString& aOrigin, const nsACString& aKey, nsTArray<IPC::Permission>& aPerms); /** - * See `PermissionManager::GetPermissionsWithKey` for more info on + * See `nsPermissionManager::GetPermissionsWithKey` for more info on * Permission keys. * * `SetPermissionsWithKey` may only be called in the Child process, and * initializes the permission manager with the permissions for a given * Permission key. marking permissions with that key as available. * * @param permissionKey The key for the permissions which have been sent * over. @@ -342,289 +360,289 @@ class PermissionManager final : public n * for. * @param aRunnable The runnable to run when permissions are available for * the given principal. */ void WhenPermissionsAvailable(nsIPrincipal* aPrincipal, nsIRunnable* aRunnable); private: - ~PermissionManager(); + virtual ~nsPermissionManager(); /** * Get all permissions for a given principal, which should not be isolated * by user context or private browsing. The principal has its origin * attributes stripped before perm db lookup. This is currently only affects * the "cookie" permission. * @param aPrincipal Used for creating the permission key. */ nsresult GetStripPermsForPrincipal(nsIPrincipal* aPrincipal, nsTArray<PermissionEntry>& aResult); - // Returns -1 on failure - int32_t GetTypeIndex(const nsACString& aType, bool aAdd); + // NOTE: nullptr can be passed as aType - if it is this function will return + // "false" unconditionally. + static bool HasDefaultPref(const nsACString& aType) { + // A list of permissions that can have a fallback default permission + // set under the permissions.default.* pref. + static const nsLiteralCString kPermissionsWithDefaults[] = { + NS_LITERAL_CSTRING("camera"), NS_LITERAL_CSTRING("microphone"), + NS_LITERAL_CSTRING("geo"), NS_LITERAL_CSTRING("desktop-notification"), + NS_LITERAL_CSTRING("shortcuts")}; + + if (!aType.IsEmpty()) { + for (const auto& perm : kPermissionsWithDefaults) { + if (perm.Equals(aType)) { + return true; + } + } + } + + return false; + } - // Returns PermissionHashKey for a given { host, isInBrowserElement } tuple. - // This is not simply using PermissionKey because we will walk-up domains in - // case of |host| contains sub-domains. Returns null if nothing found. Also - // accepts host on the format "<foo>". This will perform an exact match lookup - // as the string doesn't contain any dots. + // Returns -1 on failure + int32_t GetTypeIndex(const nsACString& aType, bool aAdd) { + for (uint32_t i = 0; i < mTypeArray.length(); ++i) { + if (mTypeArray[i].Equals(aType)) { + return i; + } + } + + if (!aAdd) { + // Not found, but that is ok - we were just looking. + return -1; + } + + // This type was not registered before. + // append it to the array, without copy-constructing the string + if (!mTypeArray.emplaceBack(aType)) { + return -1; + } + + return mTypeArray.length() - 1; + } + PermissionHashKey* GetPermissionHashKey(nsIPrincipal* aPrincipal, uint32_t aType, bool aExactHostMatch); - - // Returns PermissionHashKey for a given { host, isInBrowserElement } tuple. - // This is not simply using PermissionKey because we will walk-up domains in - // case of |host| contains sub-domains. Returns null if nothing found. Also - // accepts host on the format "<foo>". This will perform an exact match lookup - // as the string doesn't contain any dots. PermissionHashKey* GetPermissionHashKey( - nsIURI* aURI, const OriginAttributes* aOriginAttributes, uint32_t aType, - bool aExactHostMatch); + nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes, + uint32_t aType, bool aExactHostMatch); // The int32_t is the type index, the nsresult is an early bail-out return // code. - typedef Variant<int32_t, nsresult> TestPreparationResult; + typedef mozilla::Variant<int32_t, nsresult> TestPreparationResult; + /** + * Perform the early steps of a permission check and determine whether we need + * to call CommonTestPermissionInternal() for the actual permission check. + * + * @param aPrincipal optional principal argument to check the permission for, + * can be nullptr if we aren't performing a principal-based + * check. + * @param aTypeIndex if the caller isn't sure what the index of the permission + * type to check for is in the mTypeArray member variable, + * it should pass -1, otherwise this would be the index of + * the type inside mTypeArray. This would only be something + * other than -1 in recursive invocations of this function. + * @param aType the permission type to test. + * @param aPermission out argument which will be a permission type that we + * will return from this function once the function is + * done. + * @param aDefaultPermission the default permission to be used if we can't + * determine the result of the permission check. + * @param aDefaultPermissionIsValid whether the previous argument contains a + * valid value. + * @param aExactHostMatch whether to look for the exact host name or also for + * subdomains that can have the same permission. + * @param aIncludingSession whether to include session permissions when + * testing for the permission. + */ TestPreparationResult CommonPrepareToTestPermission( nsIPrincipal* aPrincipal, int32_t aTypeIndex, const nsACString& aType, uint32_t* aPermission, uint32_t aDefaultPermission, bool aDefaultPermissionIsValid, bool aExactHostMatch, - bool aIncludingSession); + bool aIncludingSession) { + using mozilla::AsVariant; + + auto* basePrin = mozilla::BasePrincipal::Cast(aPrincipal); + if (basePrin && basePrin->IsSystemPrincipal()) { + *aPermission = ALLOW_ACTION; + return AsVariant(NS_OK); + } + + // For some permissions, query the default from a pref. We want to avoid + // doing this for all permissions so that permissions can opt into having + // the pref lookup overhead on each call. + int32_t defaultPermission = + aDefaultPermissionIsValid ? aDefaultPermission : UNKNOWN_ACTION; + if (!aDefaultPermissionIsValid && HasDefaultPref(aType)) { + mozilla::Unused << mDefaultPrefBranch->GetIntPref( + PromiseFlatCString(aType).get(), &defaultPermission); + } + + // Set the default. + *aPermission = defaultPermission; + + int32_t typeIndex = + aTypeIndex == -1 ? GetTypeIndex(aType, false) : aTypeIndex; + + // For expanded principals, we want to iterate over the allowlist and see + // if the permission is granted for any of them. + if (basePrin && basePrin->Is<ExpandedPrincipal>()) { + auto ep = basePrin->As<ExpandedPrincipal>(); + for (auto& prin : ep->AllowList()) { + uint32_t perm; + nsresult rv = CommonTestPermission(prin, typeIndex, aType, &perm, + defaultPermission, true, + aExactHostMatch, aIncludingSession); + if (NS_WARN_IF(NS_FAILED(rv))) { + return AsVariant(rv); + } + + if (perm == nsIPermissionManager::ALLOW_ACTION) { + *aPermission = perm; + return AsVariant(NS_OK); + } + if (perm == nsIPermissionManager::PROMPT_ACTION) { + // Store it, but keep going to see if we can do better. + *aPermission = perm; + } + } + + return AsVariant(NS_OK); + } + + // If type == -1, the type isn't known, just signal that we are done. + if (typeIndex == -1) { + return AsVariant(NS_OK); + } + + return AsVariant(typeIndex); + } // If aTypeIndex is passed -1, we try to inder the type index from aType. nsresult CommonTestPermission(nsIPrincipal* aPrincipal, int32_t aTypeIndex, const nsACString& aType, uint32_t* aPermission, uint32_t aDefaultPermission, bool aDefaultPermissionIsValid, - bool aExactHostMatch, bool aIncludingSession); + bool aExactHostMatch, bool aIncludingSession) { + auto preparationResult = CommonPrepareToTestPermission( + aPrincipal, aTypeIndex, aType, aPermission, aDefaultPermission, + aDefaultPermissionIsValid, aExactHostMatch, aIncludingSession); + if (preparationResult.is<nsresult>()) { + return preparationResult.as<nsresult>(); + } + return CommonTestPermissionInternal( + aPrincipal, nullptr, nullptr, preparationResult.as<int32_t>(), aType, + aPermission, aExactHostMatch, aIncludingSession); + } // If aTypeIndex is passed -1, we try to inder the type index from aType. nsresult CommonTestPermission(nsIURI* aURI, int32_t aTypeIndex, const nsACString& aType, uint32_t* aPermission, uint32_t aDefaultPermission, bool aDefaultPermissionIsValid, - bool aExactHostMatch, bool aIncludingSession); + bool aExactHostMatch, bool aIncludingSession) { + auto preparationResult = CommonPrepareToTestPermission( + nullptr, aTypeIndex, aType, aPermission, aDefaultPermission, + aDefaultPermissionIsValid, aExactHostMatch, aIncludingSession); + if (preparationResult.is<nsresult>()) { + return preparationResult.as<nsresult>(); + } - nsresult CommonTestPermission(nsIURI* aURI, - const OriginAttributes* aOriginAttributes, - int32_t aTypeIndex, const nsACString& aType, - uint32_t* aPermission, - uint32_t aDefaultPermission, - bool aDefaultPermissionIsValid, - bool aExactHostMatch, bool aIncludingSession); + return CommonTestPermissionInternal( + nullptr, aURI, nullptr, preparationResult.as<int32_t>(), aType, + aPermission, aExactHostMatch, aIncludingSession); + } + nsresult CommonTestPermission( + nsIURI* aURI, const mozilla::OriginAttributes* aOriginAttributes, + int32_t aTypeIndex, const nsACString& aType, uint32_t* aPermission, + uint32_t aDefaultPermission, bool aDefaultPermissionIsValid, + bool aExactHostMatch, bool aIncludingSession) { + auto preparationResult = CommonPrepareToTestPermission( + nullptr, aTypeIndex, aType, aPermission, aDefaultPermission, + aDefaultPermissionIsValid, aExactHostMatch, aIncludingSession); + if (preparationResult.is<nsresult>()) { + return preparationResult.as<nsresult>(); + } + return CommonTestPermissionInternal( + nullptr, aURI, aOriginAttributes, preparationResult.as<int32_t>(), + aType, aPermission, aExactHostMatch, aIncludingSession); + } // Only one of aPrincipal or aURI is allowed to be passed in. nsresult CommonTestPermissionInternal( nsIPrincipal* aPrincipal, nsIURI* aURI, - const OriginAttributes* aOriginAttributes, int32_t aTypeIndex, + const mozilla::OriginAttributes* aOriginAttributes, int32_t aTypeIndex, const nsACString& aType, uint32_t* aPermission, bool aExactHostMatch, bool aIncludingSession); nsresult OpenDatabase(nsIFile* permissionsFile); - - void InitDB(bool aRemoveFile); - nsresult TryInitDB(bool aRemoveFile, nsIInputStream* aDefaultsInputStream); - + nsresult InitDB(bool aRemoveFile); void AddIdleDailyMaintenanceJob(); void RemoveIdleDailyMaintenanceJob(); void PerformIdleDailyMaintenance(); - nsresult ImportLatestDefaults(); - already_AddRefed<nsIInputStream> GetDefaultsInputStream(); - void ConsumeDefaultsInputStream(nsIInputStream* aDefaultsInputStream, - const MonitorAutoLock& aProofOfLock); - nsresult CreateTable(); + nsresult ImportDefaults(); + nsresult _DoImport(nsIInputStream* inputStream, mozIStorageConnection* aConn); + nsresult Read(); void NotifyObserversWithPermission(nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, int64_t aModificationTime, const char16_t* aData); void NotifyObservers(nsIPermission* aPermission, const char16_t* aData); // Finalize all statements, close the DB and null it. // if aRebuildOnSuccess, reinitialize database void CloseDB(bool aRebuildOnSuccess = false); nsresult RemoveAllInternal(bool aNotifyObservers); nsresult RemoveAllFromMemory(); - - void UpdateDB(OperationType aOp, int64_t aID, const nsACString& aOrigin, - const nsACString& aType, uint32_t aPermission, - uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime); + static void UpdateDB(OperationType aOp, mozIStorageAsyncStatement* aStmt, + int64_t aID, const nsACString& aOrigin, + const nsACString& aType, uint32_t aPermission, + uint32_t aExpireType, int64_t aExpireTime, + int64_t aModificationTime); /** * This method removes all permissions modified after the specified time. */ nsresult RemoveAllModifiedSince(int64_t aModificationTime); template <class T> nsresult RemovePermissionEntries(T aCondition); - // This method must be called before doing any operation to be sure that the - // DB reading has been completed. This method is also in charge to complete - // the migrations if needed. - void EnsureReadCompleted(); - - nsresult AddInternal(nsIPrincipal* aPrincipal, const nsACString& aType, - uint32_t aPermission, int64_t aID, uint32_t aExpireType, - int64_t aExpireTime, int64_t aModificationTime, - NotifyOperationType aNotifyOperation, - DBOperationType aDBOperation, - const bool aIgnoreSessionPermissions = false, - const nsACString* aOriginString = nullptr); - - void MaybeAddReadEntryFromMigration(const nsACString& aOrigin, - const nsCString& aType, - uint32_t aPermission, - uint32_t aExpireType, int64_t aExpireTime, - int64_t aModificationTime, int64_t aId); - - nsRefPtrHashtable<nsCStringHashKey, GenericNonExclusivePromise::Private> + nsRefPtrHashtable<nsCStringHashKey, + mozilla::GenericNonExclusivePromise::Private> mPermissionKeyPromiseMap; - nsCOMPtr<nsIFile> mPermissionsFile; - - // This monitor is used to ensure the database reading before any other - // operation. The reading of the database happens OMT. See |State| to know the - // steps of the database reading. - Monitor mMonitor; - - enum State { - // Initial state. The database has not been read yet. - // |TryInitDB| is called at startup time to read the database OMT. - // During the reading, |mReadEntries| will be populated with all the - // existing permissions. - eInitializing, - - // At the end of the database reading, we are in this state. A runnable is - // executed to call |EnsureReadCompleted| on the main thread. - // |EnsureReadCompleted| processes |mReadEntries| and goes to the next - // state. - eDBInitialized, - - // The permissions are fully read and any pending operation can proceed. - eReady, - - // The permission manager has been terminated. No extra database operations - // will be allowed. - eClosed, - }; - Atomic<State> mState; - - // A single entry, from the database. - struct ReadEntry { - ReadEntry() - : mId(0), - mPermission(0), - mExpireType(0), - mExpireTime(0), - mModificationTime(0) {} - - nsCString mOrigin; - nsCString mType; - int64_t mId; - uint32_t mPermission; - uint32_t mExpireType; - int64_t mExpireTime; - int64_t mModificationTime; - - // true if this entry is the result of a migration. - bool mFromMigration; - }; - - // List of entries read from the database. It will be populated OMT and - // consumed on the main-thread. - // This array is protected by the monitor. - nsTArray<ReadEntry> mReadEntries; - - // A single entry, from the database. - struct MigrationEntry { - MigrationEntry() - : mId(0), - mPermission(0), - mExpireType(0), - mExpireTime(0), - mModificationTime(0), - mIsInBrowserElement(false) {} - - nsCString mHost; - nsCString mType; - int64_t mId; - uint32_t mPermission; - uint32_t mExpireType; - int64_t mExpireTime; - int64_t mModificationTime; - - // Legacy, for migration. - bool mIsInBrowserElement; - }; - - // List of entries read from the database. It will be populated OMT and - // consumed on the main-thread. The migration entries will be converted to - // ReadEntry in |CompleteMigrations|. - // This array is protected by the monitor. - nsTArray<MigrationEntry> mMigrationEntries; - - // A single entry from the defaults URL. - struct DefaultEntry { - DefaultEntry() : mOp(eImportMatchTypeHost), mPermission(0) {} - - enum Op { - eImportMatchTypeHost, - eImportMatchTypeOrigin, - }; - - Op mOp; - - nsCString mHostOrOrigin; - nsCString mType; - uint32_t mPermission; - }; - - // List of entries read from the default settings. - // This array is protected by the monitor. - nsTArray<DefaultEntry> mDefaultEntries; - - nsresult Read(const MonitorAutoLock& aProofOfLock); - void CompleteRead(); - - void CompleteMigrations(); + nsCOMPtr<mozIStorageConnection> mDBConn; + nsCOMPtr<mozIStorageAsyncStatement> mStmtInsert; + nsCOMPtr<mozIStorageAsyncStatement> mStmtDelete; + nsCOMPtr<mozIStorageAsyncStatement> mStmtUpdate; bool mMemoryOnlyDB; nsTHashtable<PermissionHashKey> mPermissionTable; // a unique, monotonically increasing id used to identify each database entry int64_t mLargestID; nsCOMPtr<nsIPrefBranch> mDefaultPrefBranch; // NOTE: Ensure this is the last member since it has a large inline buffer. // An array to store the strings identifying the different types. - Vector<nsCString, 512> mTypeArray; - - nsCOMPtr<nsIThread> mThread; - - struct ThreadBoundData { - nsCOMPtr<mozIStorageConnection> mDBConn; - - nsCOMPtr<mozIStorageStatement> mStmtInsert; - nsCOMPtr<mozIStorageStatement> mStmtDelete; - nsCOMPtr<mozIStorageStatement> mStmtUpdate; - }; - ThreadBound<ThreadBoundData> mThreadBoundData; + mozilla::Vector<nsCString, 512> mTypeArray; friend class DeleteFromMozHostListener; friend class CloseDatabaseListener; }; // {4F6B5E00-0C36-11d5-A535-0010A401EB10} #define NS_PERMISSIONMANAGER_CID \ { \ 0x4f6b5e00, 0xc36, 0x11d5, { \ 0xa5, 0x35, 0x0, 0x10, 0xa4, 0x1, 0xeb, 0x10 \ } \ } -} // namespace mozilla - -#endif // mozilla_PermissionManager_h +#endif /* nsPermissionManager_h__ */
--- a/extensions/permissions/test/browser.ini +++ b/extensions/permissions/test/browser.ini @@ -1,10 +1,10 @@ [DEFAULT] [browser_permmgr_sync.js] fail-if = fission # The browser_permmgr_sync test tests e10s specific behavior, and runs code # paths which would hit the debug only assertion in -# PermissionManager::PermissionKey::CreateFromPrincipal. Because of this, it +# nsPermissionManager::PermissionKey::CreateFromPrincipal. Because of this, it # is only run in e10s opt builds. skip-if = debug || !e10s [browser_permmgr_viewsrc.js]
--- a/extensions/permissions/test/gtest/PermissionManagerTest.cpp +++ b/extensions/permissions/test/gtest/PermissionManagerTest.cpp @@ -1,31 +1,31 @@ /* -*- 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 "nsPermissionManager.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 { +class PermissionManager : public ::testing::Test { protected: - PermissionManagerTester() + PermissionManager() : mNonExistentType( NS_LITERAL_CSTRING("permissionTypeThatIsGuaranteedToNeverExist")) {} void SetUp() override { - mPermissionManager = PermissionManager::GetInstance(); + mPermissionManager = nsPermissionManager::GetInstance(); nsCOMPtr<nsIURI> uri; nsresult rv = NS_NewURI( getter_AddRefs(uri), NS_LITERAL_CSTRING("https://test.origin.with.subdomains.example.com")); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); mPrincipal = mozilla::BasePrincipal::CreateContentPrincipal(uri, OriginAttributes()); } @@ -33,20 +33,20 @@ class PermissionManagerTester : public : void TearDown() override { mPermissionManager = nullptr; mPrincipal = nullptr; } static const unsigned kNumIterations = 100000; nsLiteralCString mNonExistentType; - RefPtr<PermissionManager> mPermissionManager; + RefPtr<nsPermissionManager> mPermissionManager; nsCOMPtr<nsIPrincipal> mPrincipal; }; -MOZ_GTEST_BENCH_F(PermissionManagerTester, - TestNonExistentPermissionFromPrincipal, [this] { +MOZ_GTEST_BENCH_F(PermissionManager, TestNonExistentPermissionFromPrincipal, + [this] { for (unsigned i = 0; i < kNumIterations; ++i) { uint32_t result = 0; Unused << mPermissionManager->TestPermissionFromPrincipal( mPrincipal, mNonExistentType, &result); } });
--- a/extensions/permissions/test/gtest/moz.build +++ b/extensions/permissions/test/gtest/moz.build @@ -3,10 +3,14 @@ # 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', ] +LOCAL_INCLUDES += [ + '/extensions/permissions', +] + FINAL_LIBRARY = 'xul-gtest'
--- a/extensions/permissions/test/unit/test_permmanager_load_invalid_entries.js +++ b/extensions/permissions/test/unit/test_permmanager_load_invalid_entries.js @@ -218,33 +218,27 @@ function run_test() { } // This will force the permission-manager to reload the data. Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); // Initialize the permission manager service var pm = Services.perms; - // 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, 11); 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!)" - ); + Assert.ok(thisModTime == 0, "new modifiedTime field is correct"); 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" );
--- a/extensions/permissions/test/unit/test_permmanager_migrate_10-11.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_10-11.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(async function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - 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" + @@ -121,17 +116,17 @@ add_task(async function test() { 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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_4-7.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_4-7.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(async function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - 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" + @@ -195,17 +190,17 @@ add_task(async function test() { ); 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 + // Force initialization of the nsPermissionManager 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] &&
--- 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 @@ -207,17 +207,17 @@ add_task(function test() { ["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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_5-7a.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_5-7a.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(async function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - let db = Services.storage.openDatabase(GetPermissionsFile(profile)); db.schemaVersion = 5; db.executeSimpleSQL("DROP TABLE moz_perms"); db.executeSimpleSQL("DROP TABLE moz_hosts"); /* * V5 table */ @@ -262,17 +257,17 @@ add_task(async function test() { ); 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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_5-7b.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_5-7b.js @@ -15,19 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - var pm = Services.perms; - pm.removeAll(); - let db = Services.storage.openDatabase(GetPermissionsFile(profile)); db.schemaVersion = 5; db.executeSimpleSQL("DROP TABLE moz_perms"); db.executeSimpleSQL("DROP TABLE moz_hosts"); /* * V5 table */ @@ -114,17 +111,17 @@ add_task(function test() { ["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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_6-7a.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_6-7a.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(async function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - let db = Services.storage.openDatabase(GetPermissionsFile(profile)); db.schemaVersion = 6; db.executeSimpleSQL("DROP TABLE moz_perms"); db.executeSimpleSQL("DROP TABLE moz_hosts"); /* * V5 table */ @@ -263,17 +258,17 @@ add_task(async function test() { ); 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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_6-7b.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_6-7b.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - let db = Services.storage.openDatabase(GetPermissionsFile(profile)); db.schemaVersion = 6; db.executeSimpleSQL("DROP TABLE moz_perms"); db.executeSimpleSQL("DROP TABLE moz_hosts"); /* * V5 table */ @@ -110,17 +105,17 @@ add_task(function test() { ["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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_7-8.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_7-8.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(async function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - let db = Services.storage.openDatabase(GetPermissionsFile(profile)); db.schemaVersion = 7; db.executeSimpleSQL("DROP TABLE moz_perms"); db.executeSimpleSQL("DROP TABLE moz_hosts"); /* * V5 table */ @@ -250,17 +245,17 @@ add_task(async function test() { 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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_migrate_9-10.js +++ b/extensions/permissions/test/unit/test_permmanager_migrate_9-10.js @@ -15,21 +15,16 @@ function GetPermissionsFile(profile) { return file; } add_task(async function test() { /* Create and set up the permissions database */ let profile = do_get_profile(); Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); - // We need to execute a pm method to be sure that the DB is fully - // initialized. - var pm = Services.perms; - pm.removeAll(); - 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" + @@ -187,17 +182,17 @@ add_task(async function test() { 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 + // Force initialization of the nsPermissionManager 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] &&
--- a/extensions/permissions/test/unit/test_permmanager_oa_strip.js +++ b/extensions/permissions/test/unit/test_permmanager_oa_strip.js @@ -2,17 +2,17 @@ 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 +// as per array kStripOAPermissions in nsPermissionManager.cpp const STRIPPED_PERMS = ["cookie"]; let principal = Services.scriptSecurityManager.createContentPrincipal( TEST_URI, {} ); let principalPrivateBrowsing = Services.scriptSecurityManager.createContentPrincipal( TEST_URI,
--- a/extensions/permissions/test/unit/test_permmanager_removeall.js +++ b/extensions/permissions/test/unit/test_permmanager_removeall.js @@ -1,26 +1,21 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -add_task(async function test() { +function run_test() { // 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. + // initialize the permission manager service var pm = Services.perms; - Assert.ok(pm.all.length === 0); - - Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); // 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( @@ -35,9 +30,9 @@ add_task(async function test() { // 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(); -}); +}
--- a/extensions/permissions/test/unit/test_permmanager_removebytypesince.js +++ b/extensions/permissions/test/unit/test_permmanager_removebytypesince.js @@ -24,17 +24,17 @@ add_task(async function test() { 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 + // *sob* - on Windows at least, the now recorded by nsPermissionManager.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);
--- a/extensions/permissions/test/unit/test_permmanager_removesince.js +++ b/extensions/permissions/test/unit/test_permmanager_removesince.js @@ -35,17 +35,17 @@ function* do_run_test() { 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 + // *sob* - on Windows at least, the now recorded by nsPermissionManager.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.
--- a/layout/build/moz.build +++ b/layout/build/moz.build @@ -43,16 +43,17 @@ LOCAL_INCLUDES += [ '/dom/storage', '/dom/svg', '/dom/xslt/base', '/dom/xslt/xml', '/dom/xslt/xpath', '/dom/xslt/xslt', '/dom/xul', '/editor/composer', + '/extensions/permissions', '/js/xpconnect/loader', '/js/xpconnect/src', '/netwerk/base', '/netwerk/cookie', '/view', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
--- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -87,17 +87,17 @@ #include "nsJSEnvironment.h" #include "nsContentSink.h" #include "nsFrameMessageManager.h" #include "nsDOMMutationObserver.h" #include "nsHyphenationManager.h" #include "nsWindowMemoryReporter.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/ProcessPriorityManager.h" -#include "mozilla/PermissionManager.h" +#include "nsPermissionManager.h" #include "nsApplicationCacheService.h" #include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/EventDispatcher.h" #include "mozilla/IMEStateManager.h" #include "mozilla/dom/HTMLVideoElement.h" #include "ThirdPartyUtil.h" #include "TouchManager.h" #include "DecoderDoctorLogger.h" @@ -241,17 +241,17 @@ nsresult nsLayoutStatics::Initialize() { TouchManager::InitializeStatics(); nsWindowMemoryReporter::Init(); SVGElementFactory::Init(); ProcessPriorityManager::Init(); - PermissionManager::Startup(); + nsPermissionManager::Startup(); UIDirectionManager::Initialize(); CacheObserver::Init(); IMEStateManager::Init(); ServiceWorkerRegistrar::Initialize();
--- a/layout/tools/reftest/selftest/files/leaks.log +++ b/layout/tools/reftest/selftest/files/leaks.log @@ -53,17 +53,17 @@ 1141 |nsHttpHandler 1142 |nsHttpRequestHead | 92 92| 1190 1| 1145 |nsIDNService | 56 56| 1 1| 1146 |nsIOService | 176 176| 1 1| 1176 |nsJSPrincipals | 16 64| 12583 4| 1186 |nsLocalFile | 88 264| 13423 3| 1192 |nsMainThreadPtrHolder<T> | 20 80| 2253 4| 1222 |nsNodeWeakReference | 16 16| 919 1| 1223 |nsNotifyAddrListener | 112 112| 1 1| -1241 |PermissionManager | 136 136| 1 1| +1241 |nsPermissionManager | 136 136| 1 1| 1248 |nsPrefBranch | 76 76| 63 1| 1257 |nsProxyInfo | 72 72| 1098 1| 1265 |nsRedirectHistoryEntry | 32 32| 69 1| 1307 |nsSiteSecurityService | 56 56| 1 1| 1311 |nsSocketTransportService | 208 208| 1 1| 1313 |nsStandardURL | 196 1372| 59651 7| 1319 |nsStreamConverterService | 48 48| 1 1| 1324 |nsStringBuffer | 8 1688| 722245 211|
--- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -7702,22 +7702,22 @@ mirror: always - name: permissions.delegation.enabled type: bool value: true mirror: always - name: permissions.isolateBy.userContext - type: RelaxedAtomicBool + type: bool value: false mirror: always - name: permissions.isolateBy.privateBrowsing - type: RelaxedAtomicBool + type: bool value: @IS_EARLY_BETA_OR_EARLIER@ mirror: always #--------------------------------------------------------------------------- # Prefs starting with "plain_text." #--------------------------------------------------------------------------- # When false, text in plaintext documents does not wrap long lines.
--- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -317,16 +317,17 @@ DIRS += [ 'mozurl', 'rust-helper' ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '/docshell/base', '/dom/base', + '/extensions/permissions', '/netwerk/protocol/http', '/netwerk/socket', '/netwerk/url-classifier', '/security/manager/ssl', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': LOCAL_INCLUDES += [
--- a/netwerk/cookie/CookieJarSettings.cpp +++ b/netwerk/cookie/CookieJarSettings.cpp @@ -5,27 +5,26 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/AntiTrackingUtils.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/ContentBlockingAllowList.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/net/CookieJarSettings.h" #include "mozilla/net/NeckoChannelParams.h" -#include "mozilla/Permission.h" -#include "mozilla/PermissionManager.h" #include "mozilla/SchedulerGroup.h" #include "mozilla/StaticPrefs_network.h" #include "mozilla/Unused.h" #include "nsGlobalWindowInner.h" #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) # include "nsIProtocolHandler.h" #endif +#include "nsPermission.h" +#include "nsPermissionManager.h" #include "nsICookieService.h" -#include "nsNetUtil.h" namespace mozilla { namespace net { static StaticRefPtr<CookieJarSettings> sBlockinAll; namespace { @@ -181,17 +180,17 @@ CookieJarSettings::CookiePermission(nsIP *aCookiePermission = nsIPermissionManager::UNKNOWN_ACTION; nsresult rv; // Let's see if we know this permission. if (!mCookiePermissions.IsEmpty()) { nsCOMPtr<nsIPrincipal> principal = - Permission::ClonePrincipalForPermission(aPrincipal); + nsPermission::ClonePrincipalForPermission(aPrincipal); if (NS_WARN_IF(!principal)) { return NS_ERROR_FAILURE; } for (const RefPtr<nsIPermission>& permission : mCookiePermissions) { bool match = false; rv = permission->MatchesPrincipalForPermission(principal, false, &match); if (NS_WARN_IF(NS_FAILED(rv)) || !match) { @@ -203,44 +202,44 @@ CookieJarSettings::CookiePermission(nsIP return rv; } return NS_OK; } } // Let's ask the permission manager. - PermissionManager* pm = PermissionManager::GetInstance(); + nsPermissionManager* pm = nsPermissionManager::GetInstance(); if (NS_WARN_IF(!pm)) { return NS_ERROR_FAILURE; } #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) // Check if this protocol doesn't allow cookies. bool hasFlags; nsCOMPtr<nsIURI> uri; aPrincipal->GetURI(getter_AddRefs(uri)); rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS, &hasFlags); if (NS_FAILED(rv) || hasFlags) { - *aCookiePermission = PermissionManager::DENY_ACTION; + *aCookiePermission = nsPermissionManager::DENY_ACTION; rv = NS_OK; // Reset, so it's not caught as a bad status after the `else`. } else // Note the tricky `else` which controls the call below. #endif rv = pm->TestPermissionFromPrincipal( aPrincipal, NS_LITERAL_CSTRING("cookie"), aCookiePermission); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Let's store the permission, also if the result is UNKNOWN in order to avoid // race conditions. - nsCOMPtr<nsIPermission> permission = Permission::Create( + nsCOMPtr<nsIPermission> permission = nsPermission::Create( aPrincipal, NS_LITERAL_CSTRING("cookie"), *aCookiePermission, 0, 0, 0); if (permission) { mCookiePermissions.AppendElement(permission); } mToBeMerged = true; return NS_OK; } @@ -288,18 +287,18 @@ void CookieJarSettings::Serialize(Cookie for (const CookiePermissionData& data : aData.cookiePermissions()) { nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(data.principalInfo()); if (NS_WARN_IF(!principal)) { continue; } nsCOMPtr<nsIPermission> permission = - Permission::Create(principal, NS_LITERAL_CSTRING("cookie"), - data.cookiePermission(), 0, 0, 0); + nsPermission::Create(principal, NS_LITERAL_CSTRING("cookie"), + data.cookiePermission(), 0, 0, 0); if (NS_WARN_IF(!permission)) { continue; } list.AppendElement(permission); } RefPtr<CookieJarSettings> cookieJarSettings = new CookieJarSettings( @@ -349,18 +348,18 @@ void CookieJarSettings::Merge(const Cook for (const CookiePermissionData& data : aData.cookiePermissions()) { nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(data.principalInfo()); if (NS_WARN_IF(!principal)) { continue; } nsCOMPtr<nsIPermission> permission = - Permission::Create(principal, NS_LITERAL_CSTRING("cookie"), - data.cookiePermission(), 0, 0, 0); + nsPermission::Create(principal, NS_LITERAL_CSTRING("cookie"), + data.cookiePermission(), 0, 0, 0); if (NS_WARN_IF(!permission)) { continue; } if (!mCookiePermissions.Contains(permission, comparator)) { mCookiePermissions.AppendElement(permission); } }
--- a/netwerk/cookie/CookiePermission.cpp +++ b/netwerk/cookie/CookiePermission.cpp @@ -43,21 +43,21 @@ already_AddRefed<nsICookiePermission> Co if (!gSingleton) { gSingleton = new CookiePermission(); ClearOnShutdown(&gSingleton); } return do_AddRef(gSingleton); } bool CookiePermission::Init() { - // Initialize PermissionManager and fetch relevant prefs. This is only + // Initialize nsPermissionManager and fetch relevant prefs. This is only // required for some methods on nsICookiePermission, so it should be done // lazily. - mPermMgr = PermissionManager::GetInstance(); + mPermMgr = nsPermissionManager::GetInstance(); return mPermMgr != nullptr; } NS_IMETHODIMP CookiePermission::CanSetCookie(nsIURI* aURI, nsIChannel* /*aChannel*/, nsICookie* aCookie, bool* aIsSession, int64_t* aExpiry, bool* aResult) { NS_ASSERTION(aURI, "null uri");
--- a/netwerk/cookie/CookiePermission.h +++ b/netwerk/cookie/CookiePermission.h @@ -1,17 +1,17 @@ /* 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/. */ #ifndef mozilla_net_CookiePermission_h #define mozilla_net_CookiePermission_h #include "nsICookiePermission.h" -#include "mozilla/PermissionManager.h" +#include "nsPermissionManager.h" namespace mozilla { namespace net { class CookiePermission final : public nsICookiePermission { public: NS_DECL_ISUPPORTS NS_DECL_NSICOOKIEPERMISSION @@ -21,15 +21,15 @@ class CookiePermission final : public ns bool Init(); private: ~CookiePermission() = default; bool EnsureInitialized() { return (mPermMgr != nullptr) || Init(); }; - RefPtr<mozilla::PermissionManager> mPermMgr; + RefPtr<nsPermissionManager> mPermMgr; }; } // namespace net } // namespace mozilla #endif
--- a/netwerk/cookie/moz.build +++ b/netwerk/cookie/moz.build @@ -56,16 +56,17 @@ MOCHITEST_MANIFESTS += [ ] IPDL_SOURCES = [ 'PCookieService.ipdl', ] LOCAL_INCLUDES += [ '/dom/base', + '/extensions/permissions', '/intl/uconv', '/netwerk/base', '/netwerk/protocol/http', ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul'
--- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html +++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html @@ -17,17 +17,17 @@ const ACCESS_SESSION = SpecialPowers.Ci. const EXPIRE_TIME = SpecialPowers.Ci.nsIPermissionManager.EXPIRE_TIME; // expire Setting: // start expire time point // ----|------------------------|----------- // <------------------------> // PERIOD var start; -// PR_Now() that called in PermissionManager to get the system time +// PR_Now() that called in nsPermissionManager to get the system time // is sometimes 100ms~600s more than Date.now() on Android 4.3 API11. // Thus, the PERIOD should be larger than 600ms in this test. const PERIOD = 900; var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('specialPowers_framescript.js')); SimpleTest.requestFlakyTimeout("untriaged"); function starttest(){ SpecialPowers.addPermission("pPROMPT", PROMPT_ACTION, document); @@ -205,17 +205,17 @@ async function permissionPollingCheck() errorHandler('expired permission should be removed!'); } } function getPlatformInfo() { var version = SpecialPowers.Services.sysinfo.getProperty('version'); version = parseFloat(version); - // PR_Now() that called in PermissionManager to get the system time and + // PR_Now() that called in nsPermissionManager to get the system time and // Date.now() are out of sync on win32 platform(XP/win7). The PR_Now() is // 15~20ms less than Date.now(). Unfortunately, this time skew can't be // avoided, so it needs to add a time buffer to compensate. // Version 5.1 is win XP, 6.1 is win7 if (navigator.platform.startsWith('Win32') && (version <= 6.1)) { return { platform: "Win32", timeCompensation: -100 }; }
--- a/testing/mozbase/mozprofile/mozprofile/permissions.py +++ b/testing/mozbase/mozprofile/mozprofile/permissions.py @@ -232,17 +232,17 @@ class Permissions(object): def write_db(self, locations): """write permissions to the sqlite database""" # Open database and create table permDB = sqlite3.connect(os.path.join(self._profileDir, "permissions.sqlite")) cursor = permDB.cursor() # SQL copied from - # http://dxr.mozilla.org/mozilla-central/source/extensions/permissions/PermissionManager.cpp + # http://dxr.mozilla.org/mozilla-central/source/extensions/cookie/nsPermissionManager.cpp cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts ( id INTEGER PRIMARY KEY ,origin TEXT ,type TEXT ,permission INTEGER ,expireType INTEGER ,expireTime INTEGER ,modificationTime INTEGER
--- a/testing/web-platform/meta/fetch/metadata/redirect/__dir__.ini +++ b/testing/web-platform/meta/fetch/metadata/redirect/__dir__.ini @@ -1,3 +1,3 @@ prefs: [dom.security.secFetch.enabled:true] -lsan-allowed: [Alloc, Create, Malloc, Realloc, mozilla::BasePrincipal::CreateContentPrincipal, mozilla::ContentPrincipal::Init, mozilla::dom::DocGroup::Create, mozilla::WeakPtr, mozilla::dom::HTMLLinkElement::TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender, mozilla::net::CookieSettings::Create, mozilla::net::nsStandardURL::TemplatedMutator, nsNodeSupportsWeakRefTearoff::GetWeakReference, mozilla::Permission::Create, nsPrefetchService::Preload] +lsan-allowed: [Alloc, Create, Malloc, Realloc, mozilla::BasePrincipal::CreateContentPrincipal, mozilla::ContentPrincipal::Init, mozilla::dom::DocGroup::Create, mozilla::WeakPtr, mozilla::dom::HTMLLinkElement::TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender, mozilla::net::CookieSettings::Create, mozilla::net::nsStandardURL::TemplatedMutator, nsNodeSupportsWeakRefTearoff::GetWeakReference, nsPermission::Create, nsPrefetchService::Preload] leak-threshold: [tab:51200]
--- a/toolkit/components/antitracking/AntiTrackingUtils.cpp +++ b/toolkit/components/antitracking/AntiTrackingUtils.cpp @@ -8,21 +8,21 @@ #include "AntiTrackingLog.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/net/CookieJarSettings.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/WindowGlobalParent.h" #include "mozilla/dom/WindowContext.h" #include "mozilla/net/NeckoChannelParams.h" -#include "mozilla/PermissionManager.h" #include "nsIChannel.h" #include "nsIPermission.h" #include "nsIURI.h" #include "nsNetUtil.h" +#include "nsPermissionManager.h" #include "nsPIDOMWindow.h" #include "nsSandboxFlags.h" #include "nsScriptSecurityManager.h" #define ANTITRACKING_PERM_KEY "3rdPartyStorage" using namespace mozilla; using namespace mozilla::dom; @@ -133,17 +133,17 @@ bool AntiTrackingUtils::IsStorageAccessP } // static bool AntiTrackingUtils::CheckStoragePermission(nsIPrincipal* aPrincipal, const nsAutoCString& aType, bool aIsInPrivateBrowsing, uint32_t* aRejectedReason, uint32_t aBlockedReason) { - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); if (NS_WARN_IF(!permManager)) { LOG(("Failed to obtain the permission manager")); return false; } uint32_t result = 0; if (aIsInPrivateBrowsing) { LOG_PRIN(("Querying the permissions for private modei looking for a "
--- a/toolkit/components/antitracking/ContentBlocking.cpp +++ b/toolkit/components/antitracking/ContentBlocking.cpp @@ -11,29 +11,29 @@ #include "mozilla/ContentBlockingAllowList.h" #include "mozilla/ContentBlockingUserInteraction.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/WindowContext.h" #include "mozilla/dom/WindowGlobalParent.h" #include "mozilla/net/CookieJarSettings.h" -#include "mozilla/PermissionManager.h" #include "mozilla/StaticPrefs_privacy.h" #include "mozIThirdPartyUtil.h" #include "nsContentUtils.h" #include "nsGlobalWindowInner.h" #include "nsIClassifiedChannel.h" #include "nsICookiePermission.h" #include "nsICookieService.h" #include "nsIPermission.h" #include "nsIPrincipal.h" #include "nsIURI.h" #include "nsIOService.h" #include "nsIWebProgressListener.h" +#include "nsPermissionManager.h" #include "nsScriptSecurityManager.h" namespace mozilla { LazyLogModule gAntiTrackingLog("AntiTracking"); } @@ -495,17 +495,17 @@ ContentBlocking::SaveAccessForOriginOnPa aParentPrincipal); if (NS_WARN_IF(!aParentPrincipal)) { // The child process is sending something wrong. Let's ignore it. LOG(("aParentPrincipal is null, bailing out early")); return ParentAccessGrantPromise::CreateAndReject(false, __func__); } - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); if (NS_WARN_IF(!permManager)) { LOG(("Permission manager is null, bailing out early")); return ParentAccessGrantPromise::CreateAndReject(false, __func__); } // Remember that this pref is stored in seconds! uint32_t expirationType = nsIPermissionManager::EXPIRE_TIME; uint32_t expirationTime = aExpirationTime * 1000; @@ -1023,17 +1023,17 @@ bool ContentBlocking::ShouldAllowAccessF bool ContentBlocking::ShouldAllowAccessFor( nsIPrincipal* aPrincipal, nsICookieJarSettings* aCookieJarSettings) { MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCookieJarSettings); uint32_t access = nsICookiePermission::ACCESS_DEFAULT; if (aPrincipal->GetIsContentPrincipal()) { - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); if (permManager) { Unused << NS_WARN_IF(NS_FAILED(permManager->TestPermissionFromPrincipal( aPrincipal, NS_LITERAL_CSTRING("cookie"), &access))); } } if (access != nsICookiePermission::ACCESS_DEFAULT) { return access != nsICookiePermission::ACCESS_DENY;
--- a/toolkit/components/antitracking/ContentBlockingAllowList.cpp +++ b/toolkit/components/antitracking/ContentBlockingAllowList.cpp @@ -4,20 +4,20 @@ * 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 "AntiTrackingLog.h" #include "ContentBlockingAllowList.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/Document.h" -#include "mozilla/PermissionManager.h" #include "mozilla/ScopeExit.h" #include "nsContentUtils.h" #include "nsIHttpChannelInternal.h" +#include "nsPermissionManager.h" using namespace mozilla; /* static */ bool ContentBlockingAllowList::Check( nsIPrincipal* aTopWinPrincipal, bool aIsPrivateBrowsing) { bool isAllowed = false; nsresult rv = Check(aTopWinPrincipal, aIsPrivateBrowsing, isAllowed); if (NS_SUCCEEDED(rv) && isAllowed) { @@ -92,17 +92,17 @@ nsresult ContentBlockingAllowList::Check // Nothing to do! return NS_OK; } LOG_PRIN(("Deciding whether the user has overridden content blocking for %s", _spec), aContentBlockingAllowListPrincipal); - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); NS_ENSURE_TRUE(permManager, NS_ERROR_FAILURE); // Check both the normal mode and private browsing mode user override // permissions. std::pair<const nsLiteralCString, bool> types[] = { {NS_LITERAL_CSTRING("trackingprotection"), false}, {NS_LITERAL_CSTRING("trackingprotection-pb"), true}};
--- a/toolkit/components/antitracking/ContentBlockingUserInteraction.cpp +++ b/toolkit/components/antitracking/ContentBlockingUserInteraction.cpp @@ -4,34 +4,34 @@ * 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 "AntiTrackingLog.h" #include "ContentBlockingUserInteraction.h" #include "AntiTrackingUtils.h" #include "mozilla/dom/ContentChild.h" -#include "mozilla/PermissionManager.h" #include "nsIPrincipal.h" +#include "nsPermissionManager.h" #include "nsXULAppAPI.h" #include "prtime.h" namespace mozilla { /* static */ void ContentBlockingUserInteraction::Observe(nsIPrincipal* aPrincipal) { if (!aPrincipal) { // The content process may have sent us garbage data. return; } if (XRE_IsParentProcess()) { LOG_PRIN(("Saving the userInteraction for %s", _spec), aPrincipal); - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); if (NS_WARN_IF(!permManager)) { LOG(("Permission manager is null, bailing out early")); return; } // Remember that this pref is stored in seconds! uint32_t expirationType = nsIPermissionManager::EXPIRE_TIME; uint32_t expirationTime = @@ -60,17 +60,17 @@ void ContentBlockingUserInteraction::Obs LOG_PRIN(("Asking the parent process to save the user-interaction for us: %s", _spec), aPrincipal); cc->SendStoreUserInteractionAsPermission(IPC::Principal(aPrincipal)); } /* static */ bool ContentBlockingUserInteraction::Exists(nsIPrincipal* aPrincipal) { - PermissionManager* permManager = PermissionManager::GetInstance(); + nsPermissionManager* permManager = nsPermissionManager::GetInstance(); if (NS_WARN_IF(!permManager)) { return false; } uint32_t result = 0; nsresult rv = permManager->TestPermissionWithoutDefaultsFromPrincipal( aPrincipal, USER_INTERACTION_PERM, &result); if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/toolkit/components/antitracking/TemporaryAccessGrantObserver.cpp +++ b/toolkit/components/antitracking/TemporaryAccessGrantObserver.cpp @@ -1,38 +1,38 @@ /* -*- 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 "TemporaryAccessGrantObserver.h" -#include "mozilla/PermissionManager.h" #include "nsIObserverService.h" +#include "nsPermissionManager.h" #include "nsTHashtable.h" #include "nsXULAppAPI.h" using namespace mozilla; UniquePtr<TemporaryAccessGrantObserver::ObserversTable> TemporaryAccessGrantObserver::sObservers; TemporaryAccessGrantObserver::TemporaryAccessGrantObserver( - PermissionManager* aPM, nsIPrincipal* aPrincipal, const nsACString& aType) + nsPermissionManager* aPM, nsIPrincipal* aPrincipal, const nsACString& aType) : mPM(aPM), mPrincipal(aPrincipal), mType(aType) { MOZ_ASSERT(XRE_IsParentProcess(), "Enforcing temporary access grant lifetimes can only be done in " "the parent process"); } NS_IMPL_ISUPPORTS(TemporaryAccessGrantObserver, nsIObserver) // static -void TemporaryAccessGrantObserver::Create(PermissionManager* aPM, +void TemporaryAccessGrantObserver::Create(nsPermissionManager* aPM, nsIPrincipal* aPrincipal, const nsACString& aType) { MOZ_ASSERT(XRE_IsParentProcess()); if (!sObservers) { sObservers = MakeUnique<ObserversTable>(); } Unused << sObservers
--- a/toolkit/components/antitracking/TemporaryAccessGrantObserver.h +++ b/toolkit/components/antitracking/TemporaryAccessGrantObserver.h @@ -12,22 +12,21 @@ #include "nsHashKeys.h" #include "nsIObserver.h" #include "nsString.h" #include "PLDHashTable.h" template <class, class> class nsDataHashtable; class nsITimer; +class nsPermissionManager; class TemporaryAccessGrantCacheKey; namespace mozilla { -class PermissionManager; - class TemporaryAccessGrantCacheKey : public PLDHashEntryHdr { public: typedef std::pair<nsCOMPtr<nsIPrincipal>, nsCString> KeyType; typedef const KeyType* KeyTypePointer; explicit TemporaryAccessGrantCacheKey(KeyTypePointer aKey) : mPrincipal(aKey->first), mType(aKey->second) {} TemporaryAccessGrantCacheKey(TemporaryAccessGrantCacheKey&& aOther) = default; @@ -58,31 +57,32 @@ class TemporaryAccessGrantCacheKey : pub nsCString mType; }; class TemporaryAccessGrantObserver final : public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER - static void Create(PermissionManager* aPM, nsIPrincipal* aPrincipal, + static void Create(nsPermissionManager* aPM, nsIPrincipal* aPrincipal, const nsACString& aType); void SetTimer(nsITimer* aTimer); private: - TemporaryAccessGrantObserver(PermissionManager* aPM, nsIPrincipal* aPrincipal, + TemporaryAccessGrantObserver(nsPermissionManager* aPM, + nsIPrincipal* aPrincipal, const nsACString& aType); ~TemporaryAccessGrantObserver() = default; private: typedef nsDataHashtable<TemporaryAccessGrantCacheKey, nsCOMPtr<nsITimer>> ObserversTable; static UniquePtr<ObserversTable> sObservers; nsCOMPtr<nsITimer> mTimer; - RefPtr<PermissionManager> mPM; + RefPtr<nsPermissionManager> mPM; nsCOMPtr<nsIPrincipal> mPrincipal; nsCString mType; }; } // namespace mozilla #endif // mozilla_temporaryaccessgrantobserver_h
--- a/toolkit/components/antitracking/moz.build +++ b/toolkit/components/antitracking/moz.build @@ -57,16 +57,17 @@ UNIFIED_SOURCES += [ 'SettingsChangeObserver.cpp', 'StorageAccess.cpp', 'StoragePrincipalHelper.cpp', 'TemporaryAccessGrantObserver.cpp', 'URLDecorationStripper.cpp', ] LOCAL_INCLUDES += [ + '/extensions/permissions', '/netwerk/base', '/netwerk/protocol/http', ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul'