tor-browser

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

LNAPermissionRequest.cpp (5836B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "LNAPermissionRequest.h"
      8 #include "nsGlobalWindowInner.h"
      9 #include "mozilla/dom/Document.h"
     10 #include "nsPIDOMWindow.h"
     11 #include "mozilla/Preferences.h"
     12 #include "nsContentUtils.h"
     13 #include "mozilla/glean/NetwerkMetrics.h"
     14 
     15 #include "mozilla/dom/WindowGlobalParent.h"
     16 #include "nsIIOService.h"
     17 #include "nsIOService.h"
     18 
     19 namespace mozilla::net {
     20 
     21 //-------------------------------------------------
     22 // LNA Permission Requests
     23 //-------------------------------------------------
     24 
     25 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(LNAPermissionRequest,
     26                                               ContentPermissionRequestBase)
     27 
     28 NS_IMPL_CYCLE_COLLECTION_INHERITED(LNAPermissionRequest,
     29                                   ContentPermissionRequestBase)
     30 
     31 LNAPermissionRequest::LNAPermissionRequest(PermissionPromptCallback&& aCallback,
     32                                           nsILoadInfo* aLoadInfo,
     33                                           const nsACString& aType)
     34    : dom::ContentPermissionRequestBase(
     35          aLoadInfo->GetLoadingPrincipal(), nullptr,
     36          (aType.Equals(LOCAL_HOST_PERMISSION_KEY) ? "network.localhost"_ns
     37                                                   : "network.localnetwork"_ns),
     38          aType),
     39      mPermissionPromptCallback(std::move(aCallback)) {
     40  MOZ_ASSERT(aLoadInfo);
     41 
     42  aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(mPrincipal));
     43 
     44  RefPtr<mozilla::dom::BrowsingContext> bc;
     45  aLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
     46  if (bc && bc->Top()) {
     47    if (bc->Top()->Canonical()) {
     48      RefPtr<mozilla::dom::WindowGlobalParent> topWindowGlobal =
     49          bc->Top()->Canonical()->GetCurrentWindowGlobal();
     50      if (topWindowGlobal) {
     51        mTopLevelPrincipal = topWindowGlobal->DocumentPrincipal();
     52      }
     53    }
     54  }
     55 
     56  if (!mTopLevelPrincipal) {
     57    // this could happen in tests
     58    mTopLevelPrincipal = mPrincipal;
     59  }
     60 
     61  if (!mPrincipal->Equals(mTopLevelPrincipal)) {
     62    // This is a cross origin request from Iframe
     63    // Since permission delegation is not implemented yet in the parent process
     64    // we need to set this flag to true explicitly and display the origin of the
     65    // iframe in the prompt. See Bug 1978550
     66    mIsRequestDelegatedToUnsafeThirdParty = true;
     67    // permissions for this iframe is limited to the iframe's principal
     68    mTopLevelPrincipal = mPrincipal;
     69  }
     70 
     71  mLoadInfo = aLoadInfo;
     72 
     73  MOZ_ASSERT(mPrincipal);
     74 }
     75 
     76 NS_IMETHODIMP
     77 LNAPermissionRequest::GetElement(mozilla::dom::Element** aElement) {
     78  NS_ENSURE_ARG_POINTER(aElement);
     79  RefPtr<mozilla::dom::BrowsingContext> bc;
     80  mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
     81  if (!bc) {
     82    return NS_ERROR_FAILURE;
     83  }
     84 
     85  return bc->GetTopFrameElement(aElement);
     86 }
     87 
     88 // callback when the permission request is denied
     89 NS_IMETHODIMP
     90 LNAPermissionRequest::Cancel() {
     91  // callback to the http channel on the prompt failure result
     92  mPermissionPromptCallback(false, mType, mPromptWasShown);
     93  return NS_OK;
     94 }
     95 
     96 // callback when the permission request is allowed
     97 NS_IMETHODIMP
     98 LNAPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
     99  // callback to the http channel on the prompt success result
    100  mPermissionPromptCallback(true, mType, mPromptWasShown);
    101  return NS_OK;
    102 }
    103 
    104 // callback when the permission prompt is shown
    105 NS_IMETHODIMP
    106 LNAPermissionRequest::NotifyShown() {
    107  // Mark that the prompt was shown to the user
    108  mPromptWasShown = true;
    109 
    110  // Record telemetry for permission prompts shown to users
    111  if (mType.Equals(LOCAL_HOST_PERMISSION_KEY)) {
    112    if (mIsRequestDelegatedToUnsafeThirdParty) {
    113      mozilla::glean::networking::local_network_access_prompts_shown
    114          .Get("localhost_cross_site"_ns)
    115          .Add(1);
    116    } else {
    117      mozilla::glean::networking::local_network_access_prompts_shown
    118          .Get("localhost"_ns)
    119          .Add(1);
    120    }
    121  } else if (mType.Equals(LOCAL_NETWORK_PERMISSION_KEY)) {
    122    if (mIsRequestDelegatedToUnsafeThirdParty) {
    123      mozilla::glean::networking::local_network_access_prompts_shown
    124          .Get("local_network_cross_site"_ns)
    125          .Add(1);
    126    } else {
    127      mozilla::glean::networking::local_network_access_prompts_shown
    128          .Get("local_network"_ns)
    129          .Add(1);
    130    }
    131  }
    132 
    133  return NS_OK;
    134 }
    135 
    136 nsresult LNAPermissionRequest::RequestPermission() {
    137  MOZ_ASSERT(NS_IsMainThread());
    138  // This check always returns true
    139  // See Bug 1978550
    140  if (!CheckPermissionDelegate()) {
    141    return Cancel();
    142  }
    143 
    144  // Check if the domain should skip LNA checks
    145  if (mPrincipal && gIOService) {
    146    nsAutoCString origin;
    147    nsresult rv = mPrincipal->GetAsciiHost(origin);
    148    if (NS_SUCCEEDED(rv) && !origin.IsEmpty()) {
    149      if (gIOService->ShouldSkipDomainForLNA(origin)) {
    150        // Domain is in the skip list, grant permission automatically
    151        return Allow(JS::UndefinedHandleValue);
    152      }
    153    }
    154  }
    155 
    156  PromptResult pr = CheckPromptPrefs();
    157  if (pr == PromptResult::Granted) {
    158    return Allow(JS::UndefinedHandleValue);
    159  }
    160 
    161  if (pr == PromptResult::Denied) {
    162    return Cancel();
    163  }
    164 
    165  if (NS_SUCCEEDED(
    166          dom::nsContentPermissionUtils::AskPermission(this, mWindow))) {
    167    // Here we could be getting synchronous callback from the prompts depending
    168    // on whether there is already a permission for this or not. If we have a
    169    // permission, we will get a synchronous callback Allow/Deny and async if
    170    // we don't have a permission yet and waiting for user permission.
    171    return NS_OK;
    172  }
    173 
    174  return Cancel();
    175 }
    176 
    177 }  // namespace mozilla::net