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/. */
7 #include "mozilla/dom/StorageAccessPermissionStatus.h"
9 #include "mozilla/AntiTrackingUtils.h"
10 #include "mozilla/dom/WindowGlobalChild.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/WorkerPrivate.h"
16 #include "mozilla/dom/WorkerRef.h"
17 #include "nsGlobalWindowInner.h"
18 #include "nsIPermissionManager.h"
19 #include "PermissionStatusSink.h"
21 namespace mozilla::dom
{
23 class StorageAccessPermissionStatusSink final
: public PermissionStatusSink
{
24 Mutex mWorkerRefMutex
;
26 // Protected by mutex.
27 // Created and released on worker-thread. Used also on main-thread.
28 RefPtr
<WeakWorkerRef
> mWeakWorkerRef
MOZ_GUARDED_BY(mWorkerRefMutex
);
31 StorageAccessPermissionStatusSink(PermissionStatus
* aPermissionStatus
,
32 PermissionName aPermissionName
,
33 const nsACString
& aPermissionType
)
34 : PermissionStatusSink(aPermissionStatus
, aPermissionName
,
36 mWorkerRefMutex("StorageAccessPermissionStatusSink::mWorkerRefMutex") {}
39 if (!NS_IsMainThread()) {
40 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
41 MOZ_ASSERT(workerPrivate
);
43 MutexAutoLock
lock(mWorkerRefMutex
);
46 WeakWorkerRef::Create(workerPrivate
, [self
= RefPtr(this)]() {
47 MutexAutoLock
lock(self
->mWorkerRefMutex
);
48 self
->mWeakWorkerRef
= nullptr;
54 bool MaybeUpdatedByOnMainThread(nsIPermission
* aPermission
) override
{
58 bool MaybeUpdatedByNotifyOnlyOnMainThread(
59 nsPIDOMWindowInner
* aInnerWindow
) override
{
60 NS_ENSURE_TRUE(aInnerWindow
, false);
62 if (!mPermissionStatus
) {
66 nsCOMPtr
<nsPIDOMWindowInner
> ownerWindow
;
68 if (mSerialEventTarget
->IsOnCurrentThread()) {
69 ownerWindow
= mPermissionStatus
->GetOwnerWindow();
71 MutexAutoLock
lock(mWorkerRefMutex
);
73 if (!mWeakWorkerRef
) {
77 // If we have mWeakWorkerRef, we haven't received the WorkerRef
79 WorkerPrivate
* workerPrivate
= mWeakWorkerRef
->GetUnsafePrivate();
80 MOZ_ASSERT(workerPrivate
);
82 ownerWindow
= workerPrivate
->GetAncestorWindow();
85 NS_ENSURE_TRUE(ownerWindow
, false);
87 return ownerWindow
->WindowID() == aInnerWindow
->WindowID();
90 RefPtr
<PermissionStatePromise
> ComputeStateOnMainThread() override
{
91 if (mSerialEventTarget
->IsOnCurrentThread()) {
92 if (!mPermissionStatus
) {
93 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE
,
97 nsGlobalWindowInner
* window
= mPermissionStatus
->GetOwnerWindow();
98 if (NS_WARN_IF(!window
)) {
99 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE
,
103 WindowGlobalChild
* wgc
= window
->GetWindowGlobalChild();
104 if (NS_WARN_IF(!wgc
)) {
105 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE
,
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__
);
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
123 : nsIPermissionManager::PROMPT_ACTION
,
126 [](mozilla::ipc::ResponseRejectReason aError
) {
127 return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE
,
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
,
139 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
140 MOZ_ASSERT(workerPrivate
);
142 return PermissionStatePromise::CreateAndResolve(
143 workerPrivate
->StorageAccess() == StorageAccess::eAllow
144 ? nsIPermissionManager::ALLOW_ACTION
145 : nsIPermissionManager::PROMPT_ACTION
,
151 StorageAccessPermissionStatus::StorageAccessPermissionStatus(
152 nsIGlobalObject
* aGlobal
)
153 : PermissionStatus(aGlobal
, PermissionName::Storage_access
) {}
155 already_AddRefed
<PermissionStatusSink
>
156 StorageAccessPermissionStatus::CreateSink() {
157 RefPtr
<StorageAccessPermissionStatusSink
> sink
=
158 new StorageAccessPermissionStatusSink(this, Name(), GetPermissionType());
160 return sink
.forget();
163 } // namespace mozilla::dom