tor-browser

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

ChannelClassifierService.cpp (8137B)


      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 "ChannelClassifierService.h"
      8 
      9 #include "mozilla/ClearOnShutdown.h"
     10 #include "mozilla/dom/BrowserParent.h"
     11 #include "mozilla/dom/BrowsingContext.h"
     12 #include "mozilla/dom/CanonicalBrowsingContext.h"
     13 #include "mozilla/dom/WindowGlobalParent.h"
     14 #include "mozilla/net/UrlClassifierCommon.h"
     15 
     16 #include "UrlClassifierFeatureCryptominingProtection.h"
     17 #include "UrlClassifierFeatureFingerprintingProtection.h"
     18 #include "UrlClassifierFeatureSocialTrackingProtection.h"
     19 #include "UrlClassifierFeatureTrackingProtection.h"
     20 
     21 #include "mozilla/StaticPtr.h"
     22 #include "nsIChannel.h"
     23 
     24 namespace mozilla {
     25 namespace net {
     26 
     27 static StaticRefPtr<ChannelClassifierService> gChannelClassifierService;
     28 
     29 NS_IMPL_ISUPPORTS(UrlClassifierBlockedChannel, nsIUrlClassifierBlockedChannel)
     30 
     31 UrlClassifierBlockedChannel::UrlClassifierBlockedChannel(nsIChannel* aChannel)
     32    : mChannel(aChannel),
     33      mDecision(ChannelBlockDecision::Blocked),
     34      mReason(TRACKING_PROTECTION) {
     35  MOZ_ASSERT(aChannel);
     36 }
     37 
     38 NS_IMETHODIMP
     39 UrlClassifierBlockedChannel::GetReason(uint8_t* aReason) {
     40  NS_ENSURE_ARG_POINTER(aReason);
     41 
     42  *aReason = mReason;
     43  return NS_OK;
     44 }
     45 
     46 NS_IMETHODIMP
     47 UrlClassifierBlockedChannel::GetUrl(nsAString& aUrl) {
     48  nsCOMPtr<nsIURI> uri;
     49  mChannel->GetURI(getter_AddRefs(uri));
     50  if (uri) {
     51    CopyUTF8toUTF16(uri->GetSpecOrDefault(), aUrl);
     52  }
     53  return NS_OK;
     54 }
     55 
     56 NS_IMETHODIMP
     57 UrlClassifierBlockedChannel::GetTabId(uint64_t* aTabId) {
     58  NS_ENSURE_ARG_POINTER(aTabId);
     59 
     60  *aTabId = 0;
     61 
     62  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
     63  MOZ_ASSERT(loadInfo);
     64 
     65  RefPtr<dom::BrowsingContext> browsingContext;
     66  nsresult rv =
     67      loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
     68  if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
     69    return NS_ERROR_FAILURE;
     70  }
     71 
     72  // Get top-level browsing context to ensure window global parent is ready
     73  // to use, tabId is the same anyway.
     74  dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
     75  dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
     76  if (!wgp) {
     77    return NS_ERROR_FAILURE;
     78  }
     79 
     80  RefPtr<dom::BrowserParent> browserParent = wgp->GetBrowserParent();
     81  if (!browserParent) {
     82    return NS_ERROR_FAILURE;
     83  }
     84 
     85  *aTabId = browserParent->GetTabId();
     86  return NS_OK;
     87 }
     88 
     89 NS_IMETHODIMP
     90 UrlClassifierBlockedChannel::GetChannelId(uint64_t* aChannelId) {
     91  NS_ENSURE_ARG_POINTER(aChannelId);
     92 
     93  nsCOMPtr<nsIIdentChannel> channel(do_QueryInterface(mChannel));
     94  *aChannelId = channel ? channel->ChannelId() : 0;
     95 
     96  return NS_OK;
     97 }
     98 
     99 NS_IMETHODIMP
    100 UrlClassifierBlockedChannel::GetTopLevelUrl(nsAString& aTopLevelUrl) {
    101  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
    102  MOZ_ASSERT(loadInfo);
    103 
    104  RefPtr<dom::BrowsingContext> browsingContext;
    105  nsresult rv =
    106      loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
    107  if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
    108    return NS_ERROR_FAILURE;
    109  }
    110 
    111  // Get top-level browsing context to ensure window global parent is ready
    112  // to use, tabId is the same anyway.
    113  dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
    114  dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
    115  if (!wgp) {
    116    return NS_ERROR_FAILURE;
    117  }
    118 
    119  RefPtr<nsIURI> uri = wgp->GetDocumentURI();
    120  if (!uri) {
    121    return NS_ERROR_FAILURE;
    122  }
    123 
    124  CopyUTF8toUTF16(uri->GetSpecOrDefault(), aTopLevelUrl);
    125  return NS_OK;
    126 }
    127 
    128 NS_IMETHODIMP
    129 UrlClassifierBlockedChannel::GetTables(nsACString& aTables) {
    130  aTables.Assign(mTables);
    131  return NS_OK;
    132 }
    133 
    134 NS_IMETHODIMP
    135 UrlClassifierBlockedChannel::GetBrowserId(uint64_t* aBrowserId) {
    136  NS_ENSURE_ARG_POINTER(aBrowserId);
    137  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
    138  MOZ_ASSERT(loadInfo);
    139 
    140  RefPtr<dom::BrowsingContext> browsingContext;
    141  nsresult rv =
    142      loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
    143  if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
    144    return NS_ERROR_FAILURE;
    145  }
    146  *aBrowserId = browsingContext->BrowserId();
    147 
    148  return NS_OK;
    149 }
    150 
    151 NS_IMETHODIMP
    152 UrlClassifierBlockedChannel::GetIsPrivateBrowsing(bool* aIsPrivateBrowsing) {
    153  NS_ENSURE_ARG_POINTER(aIsPrivateBrowsing);
    154 
    155  *aIsPrivateBrowsing = NS_UsePrivateBrowsing(mChannel);
    156  return NS_OK;
    157 }
    158 
    159 NS_IMETHODIMP
    160 UrlClassifierBlockedChannel::Allow() {
    161  UC_LOG(("ChannelClassifierService: allow loading the channel %p",
    162          mChannel.get()));
    163 
    164  mDecision = ChannelBlockDecision::Allowed;
    165  return NS_OK;
    166 }
    167 
    168 NS_IMETHODIMP
    169 UrlClassifierBlockedChannel::Replace() {
    170  UC_LOG(("ChannelClassifierService: replace channel %p", mChannel.get()));
    171 
    172  mDecision = ChannelBlockDecision::Replaced;
    173  return NS_OK;
    174 }
    175 
    176 void UrlClassifierBlockedChannel::SetReason(const nsACString& aFeatureName,
    177                                            const nsACString& aTableName) {
    178  mTables = aTableName;
    179 
    180  nsCOMPtr<nsIUrlClassifierFeature> feature;
    181  feature =
    182      UrlClassifierFeatureTrackingProtection::GetIfNameMatches(aFeatureName);
    183  if (feature) {
    184    mReason = TRACKING_PROTECTION;
    185    return;
    186  }
    187 
    188  feature = UrlClassifierFeatureSocialTrackingProtection::GetIfNameMatches(
    189      aFeatureName);
    190  if (feature) {
    191    mReason = SOCIAL_TRACKING_PROTECTION;
    192    return;
    193  }
    194 
    195  feature = UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches(
    196      aFeatureName);
    197  if (feature) {
    198    mReason = FINGERPRINTING_PROTECTION;
    199    return;
    200  }
    201 
    202  feature = UrlClassifierFeatureCryptominingProtection::GetIfNameMatches(
    203      aFeatureName);
    204  if (feature) {
    205    mReason = CRYPTOMINING_PROTECTION;
    206    return;
    207  }
    208 }
    209 
    210 NS_IMPL_ISUPPORTS(ChannelClassifierService, nsIChannelClassifierService)
    211 
    212 // static
    213 already_AddRefed<nsIChannelClassifierService>
    214 ChannelClassifierService::GetSingleton() {
    215  if (gChannelClassifierService) {
    216    return do_AddRef(gChannelClassifierService);
    217  }
    218 
    219  gChannelClassifierService = new ChannelClassifierService();
    220  ClearOnShutdown(&gChannelClassifierService);
    221  return do_AddRef(gChannelClassifierService);
    222 }
    223 
    224 ChannelClassifierService::ChannelClassifierService() { mListeners.Clear(); }
    225 
    226 NS_IMETHODIMP
    227 ChannelClassifierService::AddListener(nsIObserver* aObserver) {
    228  MOZ_ASSERT(aObserver);
    229  MOZ_ASSERT(!mListeners.Contains(aObserver));
    230 
    231  mListeners.AppendElement(aObserver);
    232  return NS_OK;
    233 }
    234 
    235 NS_IMETHODIMP
    236 ChannelClassifierService::RemoveListener(nsIObserver* aObserver) {
    237  MOZ_ASSERT(aObserver);
    238  MOZ_ASSERT(mListeners.Contains(aObserver));
    239 
    240  mListeners.RemoveElement(aObserver);
    241  return NS_OK;
    242 }
    243 
    244 /* static */
    245 ChannelBlockDecision ChannelClassifierService::OnBeforeBlockChannel(
    246    nsIChannel* aChannel, const nsACString& aFeatureName,
    247    const nsACString& aTableName) {
    248  MOZ_ASSERT(aChannel);
    249 
    250  // Don't bother continuing if no one has ever registered listener
    251  if (!gChannelClassifierService || !gChannelClassifierService->HasListener()) {
    252    return ChannelBlockDecision::Blocked;
    253  }
    254 
    255  ChannelBlockDecision decision;
    256  nsresult rv = gChannelClassifierService->OnBeforeBlockChannel(
    257      aChannel, aFeatureName, aTableName, decision);
    258  if (NS_WARN_IF(NS_FAILED(rv))) {
    259    return ChannelBlockDecision::Blocked;
    260  }
    261 
    262  return decision;
    263 }
    264 
    265 nsresult ChannelClassifierService::OnBeforeBlockChannel(
    266    nsIChannel* aChannel, const nsACString& aFeatureName,
    267    const nsACString& aTableName, ChannelBlockDecision& aDecision) {
    268  MOZ_ASSERT(aChannel);
    269 
    270  aDecision = ChannelBlockDecision::Blocked;
    271 
    272  RefPtr<UrlClassifierBlockedChannel> channel =
    273      new UrlClassifierBlockedChannel(aChannel);
    274  channel->SetReason(aFeatureName, aTableName);
    275 
    276  for (const auto& listener : mListeners) {
    277    listener->Observe(
    278        NS_ISUPPORTS_CAST(nsIUrlClassifierBlockedChannel*, channel),
    279        "urlclassifier-before-block-channel", nullptr);
    280 
    281    aDecision = channel->GetDecision();
    282  }
    283 
    284  return NS_OK;
    285 }
    286 
    287 }  // namespace net
    288 }  // namespace mozilla