tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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