tor-browser

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

WorkerNavigator.cpp (10033B)


      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/WorkerNavigator.h"
      8 
      9 #include "ErrorList.h"
     10 #include "MainThreadUtils.h"
     11 #include "RuntimeService.h"
     12 #include "WorkerRunnable.h"
     13 #include "WorkerScope.h"
     14 #include "mozilla/dom/LockManager.h"
     15 #include "mozilla/dom/MediaCapabilities.h"
     16 #include "mozilla/dom/Navigator.h"
     17 #include "mozilla/dom/Permissions.h"
     18 #include "mozilla/dom/ServiceWorkerContainer.h"
     19 #include "mozilla/dom/StorageManager.h"
     20 #include "mozilla/dom/WorkerCommon.h"
     21 #include "mozilla/dom/WorkerNavigatorBinding.h"
     22 #include "mozilla/dom/WorkerStatus.h"
     23 #include "mozilla/dom/network/Connection.h"
     24 #include "mozilla/webgpu/Instance.h"
     25 #include "nsCOMPtr.h"
     26 #include "nsDebug.h"
     27 #include "nsError.h"
     28 #include "nsIGlobalObject.h"
     29 #include "nsLiteralString.h"
     30 #include "nsPIDOMWindow.h"
     31 #include "nsRFPService.h"
     32 #include "nsString.h"
     33 
     34 class JSObject;
     35 struct JSContext;
     36 
     37 namespace mozilla::dom {
     38 
     39 using namespace workerinternals;
     40 
     41 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WorkerNavigator)
     42 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkerNavigator)
     43  tmp->Invalidate();
     44  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     45 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     46 
     47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkerNavigator)
     48  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
     49  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
     50  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaCapabilities)
     51  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebGpu)
     52  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocks)
     53  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
     54  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
     55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     56 
     57 WorkerNavigator::WorkerNavigator(const NavigatorProperties& aProperties,
     58                                 bool aOnline)
     59    : mProperties(aProperties), mOnline(aOnline) {}
     60 
     61 WorkerNavigator::~WorkerNavigator() { Invalidate(); }
     62 
     63 /* static */
     64 already_AddRefed<WorkerNavigator> WorkerNavigator::Create(bool aOnLine) {
     65  RuntimeService* rts = RuntimeService::GetService();
     66  MOZ_ASSERT(rts);
     67 
     68  const RuntimeService::NavigatorProperties& properties =
     69      rts->GetNavigatorProperties();
     70 
     71  RefPtr<WorkerNavigator> navigator = new WorkerNavigator(properties, aOnLine);
     72 
     73  return navigator.forget();
     74 }
     75 
     76 void WorkerNavigator::Invalidate() {
     77  if (mStorageManager) {
     78    mStorageManager->Shutdown();
     79    mStorageManager = nullptr;
     80  }
     81 
     82  mConnection = nullptr;
     83 
     84  mMediaCapabilities = nullptr;
     85 
     86  mWebGpu = nullptr;
     87 
     88  if (mLocks) {
     89    mLocks->Shutdown();
     90    mLocks = nullptr;
     91  }
     92 
     93  mPermissions = nullptr;
     94 
     95  mServiceWorkerContainer = nullptr;
     96 }
     97 
     98 JSObject* WorkerNavigator::WrapObject(JSContext* aCx,
     99                                      JS::Handle<JSObject*> aGivenProto) {
    100  return WorkerNavigator_Binding::Wrap(aCx, this, aGivenProto);
    101 }
    102 
    103 bool WorkerNavigator::GlobalPrivacyControl() const {
    104  bool gpcStatus = StaticPrefs::privacy_globalprivacycontrol_enabled();
    105  if (!gpcStatus) {
    106    JSObject* jso = GetWrapper();
    107    if (const nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(jso)) {
    108      if (const nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull()) {
    109        gpcStatus = principal->GetIsInPrivateBrowsing() &&
    110                    StaticPrefs::privacy_globalprivacycontrol_pbmode_enabled();
    111      }
    112    }
    113  }
    114  return StaticPrefs::privacy_globalprivacycontrol_functionality_enabled() &&
    115         gpcStatus;
    116 }
    117 
    118 void WorkerNavigator::SetLanguages(const nsTArray<nsString>& aLanguages) {
    119  WorkerNavigator_Binding::ClearCachedLanguagesValue(this);
    120  mProperties.mLanguages = aLanguages.Clone();
    121 }
    122 
    123 void WorkerNavigator::GetAppVersion(nsString& aAppVersion,
    124                                    CallerType aCallerType,
    125                                    ErrorResult& aRv) const {
    126  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    127  MOZ_ASSERT(workerPrivate);
    128 
    129  if (aCallerType != CallerType::System) {
    130    if (workerPrivate->ShouldResistFingerprinting(
    131            RFPTarget::NavigatorAppVersion)) {
    132      // See nsRFPService.h for spoofed value.
    133      aAppVersion.AssignLiteral(SPOOFED_APPVERSION);
    134      return;
    135    }
    136 
    137    if (!mProperties.mAppVersionOverridden.IsEmpty()) {
    138      aAppVersion = mProperties.mAppVersionOverridden;
    139      return;
    140    }
    141  }
    142 
    143  aAppVersion = mProperties.mAppVersion;
    144 }
    145 
    146 void WorkerNavigator::GetPlatform(nsString& aPlatform, CallerType aCallerType,
    147                                  ErrorResult& aRv) const {
    148  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    149  MOZ_ASSERT(workerPrivate);
    150 
    151  // navigator.platform is the same for default and spoofed values. The
    152  // "general.platform.override" pref should override the default platform,
    153  // but the spoofed platform should override the pref.
    154  if (aCallerType == CallerType::System ||
    155      workerPrivate->ShouldResistFingerprinting(RFPTarget::NavigatorPlatform) ||
    156      mProperties.mPlatformOverridden.IsEmpty()) {
    157    aPlatform = mProperties.mPlatform;
    158  } else {
    159    // from "general.platform.override" pref.
    160    aPlatform = mProperties.mPlatformOverridden;
    161  }
    162 }
    163 
    164 namespace {
    165 
    166 /*
    167 * This Worker Runnable needs to check RFP; but our standard way of doing so
    168 * relies on accessing GlobalScope() - which can only be accessed on the worker
    169 * thread. So we need to pass it in.
    170 */
    171 class GetUserAgentRunnable final : public WorkerMainThreadRunnable {
    172  nsString& mUA;
    173  bool mShouldResistFingerprinting;
    174 
    175 public:
    176  GetUserAgentRunnable(WorkerPrivate* aWorkerPrivate, nsString& aUA,
    177                       bool aShouldResistFingerprinting)
    178      : WorkerMainThreadRunnable(aWorkerPrivate, "UserAgent getter"_ns),
    179        mUA(aUA),
    180        mShouldResistFingerprinting(aShouldResistFingerprinting) {
    181    MOZ_ASSERT(aWorkerPrivate);
    182    aWorkerPrivate->AssertIsOnWorkerThread();
    183  }
    184 
    185  virtual bool MainThreadRun() override {
    186    AssertIsOnMainThread();
    187    MOZ_ASSERT(mWorkerRef);
    188 
    189    WorkerPrivate* workerPrivate = mWorkerRef->Private();
    190 
    191    nsCOMPtr<nsPIDOMWindowInner> window = workerPrivate->GetWindow();
    192 
    193    nsresult rv =
    194        dom::Navigator::GetUserAgent(window, workerPrivate->GetDocument(),
    195                                     Some(mShouldResistFingerprinting), mUA);
    196    if (NS_FAILED(rv)) {
    197      NS_WARNING("Failed to retrieve user-agent from the worker thread.");
    198    }
    199 
    200    return true;
    201  }
    202 };
    203 
    204 }  // namespace
    205 
    206 void WorkerNavigator::GetUserAgent(nsString& aUserAgent, CallerType aCallerType,
    207                                   ErrorResult& aRv) const {
    208  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    209  MOZ_ASSERT(workerPrivate);
    210 
    211  RefPtr<GetUserAgentRunnable> runnable = new GetUserAgentRunnable(
    212      workerPrivate, aUserAgent,
    213      workerPrivate->ShouldResistFingerprinting(RFPTarget::NavigatorUserAgent));
    214 
    215  runnable->Dispatch(workerPrivate, Canceling, aRv);
    216 }
    217 
    218 uint64_t WorkerNavigator::HardwareConcurrency() const {
    219  RuntimeService* rts = RuntimeService::GetService();
    220  MOZ_ASSERT(rts);
    221 
    222  WorkerPrivate* aWorkerPrivate = GetCurrentThreadWorkerPrivate();
    223 
    224  return rts->ClampedHardwareConcurrency(
    225      aWorkerPrivate->ShouldResistFingerprinting(
    226          RFPTarget::NavigatorHWConcurrency),
    227      aWorkerPrivate->ShouldResistFingerprinting(
    228          RFPTarget::NavigatorHWConcurrencyTiered));
    229 }
    230 
    231 StorageManager* WorkerNavigator::Storage() {
    232  if (!mStorageManager) {
    233    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    234    MOZ_ASSERT(workerPrivate);
    235 
    236    RefPtr<nsIGlobalObject> global = workerPrivate->GlobalScope();
    237    MOZ_ASSERT(global);
    238 
    239    mStorageManager = new StorageManager(global);
    240 
    241    workerPrivate->NotifyStorageKeyUsed();
    242  }
    243 
    244  return mStorageManager;
    245 }
    246 
    247 network::Connection* WorkerNavigator::GetConnection(ErrorResult& aRv) {
    248  if (!mConnection) {
    249    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    250    MOZ_ASSERT(workerPrivate);
    251 
    252    mConnection = network::Connection::CreateForWorker(workerPrivate, aRv);
    253  }
    254 
    255  return mConnection;
    256 }
    257 
    258 dom::MediaCapabilities* WorkerNavigator::MediaCapabilities() {
    259  if (!mMediaCapabilities) {
    260    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    261    MOZ_ASSERT(workerPrivate);
    262 
    263    nsIGlobalObject* global = workerPrivate->GlobalScope();
    264    MOZ_ASSERT(global);
    265 
    266    mMediaCapabilities = new dom::MediaCapabilities(global);
    267  }
    268  return mMediaCapabilities;
    269 }
    270 
    271 webgpu::Instance* WorkerNavigator::Gpu() {
    272  if (!mWebGpu) {
    273    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    274    MOZ_ASSERT(workerPrivate);
    275 
    276    nsIGlobalObject* global = workerPrivate->GlobalScope();
    277    MOZ_ASSERT(global);
    278 
    279    mWebGpu = webgpu::Instance::Create(global);
    280  }
    281  return mWebGpu;
    282 }
    283 
    284 dom::LockManager* WorkerNavigator::Locks() {
    285  if (!mLocks) {
    286    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    287    MOZ_ASSERT(workerPrivate);
    288 
    289    nsIGlobalObject* global = workerPrivate->GlobalScope();
    290    MOZ_ASSERT(global);
    291 
    292    mLocks = dom::LockManager::Create(*global);
    293  }
    294  return mLocks;
    295 }
    296 
    297 dom::Permissions* WorkerNavigator::Permissions() {
    298  if (!mPermissions) {
    299    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    300    MOZ_ASSERT(workerPrivate);
    301 
    302    nsIGlobalObject* global = workerPrivate->GlobalScope();
    303    MOZ_ASSERT(global);
    304    mPermissions = new dom::Permissions(global);
    305  }
    306 
    307  return mPermissions;
    308 }
    309 
    310 already_AddRefed<ServiceWorkerContainer> WorkerNavigator::ServiceWorker() {
    311  if (!mServiceWorkerContainer) {
    312    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    313    MOZ_ASSERT(workerPrivate);
    314 
    315    nsIGlobalObject* global = workerPrivate->GlobalScope();
    316    MOZ_ASSERT(global);
    317 
    318    mServiceWorkerContainer = ServiceWorkerContainer::Create(global);
    319  }
    320 
    321  RefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
    322  return ref.forget();
    323 }
    324 
    325 }  // namespace mozilla::dom