StorageAccessPermissionStatus.cpp (5864B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/StorageAccessPermissionStatus.h" 8 9 #include "PermissionStatusSink.h" 10 #include "mozilla/AntiTrackingUtils.h" 11 #include "mozilla/dom/BrowsingContext.h" 12 #include "mozilla/dom/FeaturePolicyUtils.h" 13 #include "mozilla/dom/PermissionStatus.h" 14 #include "mozilla/dom/PermissionStatusBinding.h" 15 #include "mozilla/dom/WindowGlobalChild.h" 16 #include "mozilla/dom/WorkerPrivate.h" 17 #include "mozilla/dom/WorkerRef.h" 18 #include "nsGlobalWindowInner.h" 19 #include "nsIPermissionManager.h" 20 21 namespace mozilla::dom { 22 23 class StorageAccessPermissionStatusSink final : public PermissionStatusSink { 24 Mutex mWorkerRefMutex; 25 26 // Protected by mutex. 27 // Created and released on worker-thread. Used also on main-thread. 28 RefPtr<WeakWorkerRef> mWeakWorkerRef MOZ_GUARDED_BY(mWorkerRefMutex); 29 30 public: 31 StorageAccessPermissionStatusSink(PermissionStatus* aPermissionStatus, 32 PermissionName aPermissionName, 33 const nsACString& aPermissionType) 34 : PermissionStatusSink(aPermissionStatus, aPermissionName, 35 aPermissionType), 36 mWorkerRefMutex("StorageAccessPermissionStatusSink::mWorkerRefMutex") {} 37 38 void Init() { 39 if (!NS_IsMainThread()) { 40 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 41 MOZ_ASSERT(workerPrivate); 42 43 MutexAutoLock lock(mWorkerRefMutex); 44 45 mWeakWorkerRef = 46 WeakWorkerRef::Create(workerPrivate, [self = RefPtr(this)]() { 47 MutexAutoLock lock(self->mWorkerRefMutex); 48 self->mWeakWorkerRef = nullptr; 49 }); 50 } 51 } 52 53 protected: 54 bool MaybeUpdatedByOnMainThread(nsIPermission* aPermission) override { 55 return false; 56 } 57 58 bool MaybeUpdatedByNotifyOnlyOnMainThread( 59 nsPIDOMWindowInner* aInnerWindow) override { 60 NS_ENSURE_TRUE(aInnerWindow, false); 61 62 if (!mPermissionStatus) { 63 return false; 64 } 65 66 nsCOMPtr<nsPIDOMWindowInner> ownerWindow; 67 68 if (mSerialEventTarget->IsOnCurrentThread()) { 69 ownerWindow = mPermissionStatus->GetOwnerWindow(); 70 } else { 71 MutexAutoLock lock(mWorkerRefMutex); 72 73 if (!mWeakWorkerRef) { 74 return false; 75 } 76 77 // If we have mWeakWorkerRef, we haven't received the WorkerRef 78 // notification yet. 79 WorkerPrivate* workerPrivate = mWeakWorkerRef->GetUnsafePrivate(); 80 MOZ_ASSERT(workerPrivate); 81 82 ownerWindow = workerPrivate->GetAncestorWindow(); 83 } 84 85 NS_ENSURE_TRUE(ownerWindow, false); 86 87 return ownerWindow->WindowID() == aInnerWindow->WindowID(); 88 } 89 90 RefPtr<PermissionStatePromise> ComputeStateOnMainThread() override { 91 if (mSerialEventTarget->IsOnCurrentThread()) { 92 if (!mPermissionStatus) { 93 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE, 94 __func__); 95 } 96 97 nsGlobalWindowInner* window = mPermissionStatus->GetOwnerWindow(); 98 if (NS_WARN_IF(!window)) { 99 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE, 100 __func__); 101 } 102 103 WindowGlobalChild* wgc = window->GetWindowGlobalChild(); 104 if (NS_WARN_IF(!wgc)) { 105 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE, 106 __func__); 107 } 108 109 // Perform a Permission Policy Request 110 if (!FeaturePolicyUtils::IsFeatureAllowed(window->GetExtantDoc(), 111 u"storage-access"_ns)) { 112 return PermissionStatePromise::CreateAndResolve( 113 nsIPermissionManager::PROMPT_ACTION, __func__); 114 } 115 116 return wgc->SendGetStorageAccessPermission(false)->Then( 117 GetMainThreadSerialEventTarget(), __func__, 118 [self = RefPtr(this)](uint32_t aAction) { 119 // We never reveal PermissionState::Denied here 120 return PermissionStatePromise::CreateAndResolve( 121 aAction == nsIPermissionManager::ALLOW_ACTION 122 ? aAction 123 : nsIPermissionManager::PROMPT_ACTION, 124 __func__); 125 }, 126 [](mozilla::ipc::ResponseRejectReason aError) { 127 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE, 128 __func__); 129 }); 130 } 131 132 // For workers we already have the correct value in workerPrivate. 133 return InvokeAsync(mSerialEventTarget, __func__, [self = RefPtr(this)] { 134 if (!self->mPermissionStatus) { 135 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE, 136 __func__); 137 } 138 139 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 140 MOZ_ASSERT(workerPrivate); 141 142 return PermissionStatePromise::CreateAndResolve( 143 workerPrivate->StorageAccess() == StorageAccess::eAllow 144 ? nsIPermissionManager::ALLOW_ACTION 145 : nsIPermissionManager::PROMPT_ACTION, 146 __func__); 147 }); 148 } 149 }; 150 151 StorageAccessPermissionStatus::StorageAccessPermissionStatus( 152 nsIGlobalObject* aGlobal) 153 : PermissionStatus(aGlobal, PermissionName::Storage_access) {} 154 155 already_AddRefed<PermissionStatusSink> 156 StorageAccessPermissionStatus::CreateSink() { 157 RefPtr<StorageAccessPermissionStatusSink> sink = 158 new StorageAccessPermissionStatusSink(this, Name(), GetPermissionType()); 159 sink->Init(); 160 return sink.forget(); 161 } 162 163 } // namespace mozilla::dom