forked from mirrors/gecko-dev
		
	UI needs to distinguish the cases when a channel is shimmed and is unshimmed. When a channel is unshimmed, we unblock the channel and simply treat the channel as a non-tracking channel. When a channel is shimmed, although the channel is unblocked by URLCLassifier, we still want to show it in the UI. For this case, URLClassifier will notify a content blocking event when a channel is unblocked. This patch adds a new allow API, so the caller can use unblock() or allow() depending upon the case it requires. Differential Revision: https://phabricator.services.mozilla.com/D93271
		
			
				
	
	
		
			268 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			268 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "ChannelClassifierService.h"
 | 
						|
 | 
						|
#include "mozilla/ClearOnShutdown.h"
 | 
						|
#include "mozilla/dom/BrowserParent.h"
 | 
						|
#include "mozilla/dom/BrowsingContext.h"
 | 
						|
#include "mozilla/dom/CanonicalBrowsingContext.h"
 | 
						|
#include "mozilla/dom/WindowGlobalParent.h"
 | 
						|
#include "mozilla/net/UrlClassifierCommon.h"
 | 
						|
 | 
						|
#include "UrlClassifierFeatureCryptominingProtection.h"
 | 
						|
#include "UrlClassifierFeatureFingerprintingProtection.h"
 | 
						|
#include "UrlClassifierFeatureSocialTrackingProtection.h"
 | 
						|
#include "UrlClassifierFeatureTrackingProtection.h"
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
namespace net {
 | 
						|
 | 
						|
static StaticRefPtr<ChannelClassifierService> gChannelClassifierService;
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(UrlClassifierBlockedChannel, nsIUrlClassifierBlockedChannel)
 | 
						|
 | 
						|
UrlClassifierBlockedChannel::UrlClassifierBlockedChannel(nsIChannel* aChannel)
 | 
						|
    : mChannel(aChannel),
 | 
						|
      mDecision(ChannelBlockDecision::Blocked),
 | 
						|
      mReason(TRACKING_PROTECTION) {
 | 
						|
  MOZ_ASSERT(aChannel);
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetReason(uint8_t* aReason) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aReason);
 | 
						|
 | 
						|
  *aReason = mReason;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetUrl(nsAString& aUrl) {
 | 
						|
  nsCOMPtr<nsIURI> uri;
 | 
						|
  mChannel->GetURI(getter_AddRefs(uri));
 | 
						|
  if (uri) {
 | 
						|
    CopyUTF8toUTF16(uri->GetSpecOrDefault(), aUrl);
 | 
						|
  }
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetTabId(uint64_t* aTabId) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aTabId);
 | 
						|
 | 
						|
  *aTabId = 0;
 | 
						|
 | 
						|
  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
 | 
						|
  MOZ_ASSERT(loadInfo);
 | 
						|
 | 
						|
  RefPtr<dom::BrowsingContext> browsingContext;
 | 
						|
  nsresult rv =
 | 
						|
      loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get top-level browsing context to ensure window global parent is ready
 | 
						|
  // to use, tabId is the same anyway.
 | 
						|
  dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
 | 
						|
  dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
 | 
						|
  if (!wgp) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<dom::BrowserParent> browserParent = wgp->GetBrowserParent();
 | 
						|
  if (!browserParent) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  *aTabId = browserParent->GetTabId();
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetChannelId(uint64_t* aChannelId) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aChannelId);
 | 
						|
 | 
						|
  nsCOMPtr<nsIIdentChannel> channel(do_QueryInterface(mChannel));
 | 
						|
  *aChannelId = channel ? channel->ChannelId() : 0;
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetTopLevelUrl(nsAString& aTopLevelUrl) {
 | 
						|
  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
 | 
						|
  MOZ_ASSERT(loadInfo);
 | 
						|
 | 
						|
  RefPtr<dom::BrowsingContext> browsingContext;
 | 
						|
  nsresult rv =
 | 
						|
      loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv)) || !browsingContext) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get top-level browsing context to ensure window global parent is ready
 | 
						|
  // to use, tabId is the same anyway.
 | 
						|
  dom::CanonicalBrowsingContext* top = browsingContext->Canonical()->Top();
 | 
						|
  dom::WindowGlobalParent* wgp = top->GetCurrentWindowGlobal();
 | 
						|
  if (!wgp) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  RefPtr<nsIURI> uri = wgp->GetDocumentURI();
 | 
						|
  if (!uri) {
 | 
						|
    return NS_ERROR_FAILURE;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyUTF8toUTF16(uri->GetSpecOrDefault(), aTopLevelUrl);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetTables(nsACString& aTables) {
 | 
						|
  aTables.Assign(mTables);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::GetIsPrivateBrowsing(bool* aIsPrivateBrowsing) {
 | 
						|
  NS_ENSURE_ARG_POINTER(aIsPrivateBrowsing);
 | 
						|
 | 
						|
  *aIsPrivateBrowsing = NS_UsePrivateBrowsing(mChannel);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::Allow() {
 | 
						|
  UC_LOG(("ChannelClassifierService: allow loading the channel %p",
 | 
						|
          mChannel.get()));
 | 
						|
 | 
						|
  mDecision = ChannelBlockDecision::Allowed;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
UrlClassifierBlockedChannel::Unblock() {
 | 
						|
  UC_LOG(("ChannelClassifierService: unblock channel %p", mChannel.get()));
 | 
						|
 | 
						|
  mDecision = ChannelBlockDecision::Unblocked;
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void UrlClassifierBlockedChannel::SetReason(const nsACString& aFeatureName,
 | 
						|
                                            const nsACString& aTableName) {
 | 
						|
  mTables = aTableName;
 | 
						|
 | 
						|
  nsCOMPtr<nsIUrlClassifierFeature> feature;
 | 
						|
  feature =
 | 
						|
      UrlClassifierFeatureTrackingProtection::GetIfNameMatches(aFeatureName);
 | 
						|
  if (feature) {
 | 
						|
    mReason = TRACKING_PROTECTION;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  feature = UrlClassifierFeatureSocialTrackingProtection::GetIfNameMatches(
 | 
						|
      aFeatureName);
 | 
						|
  if (feature) {
 | 
						|
    mReason = SOCIAL_TRACKING_PROTECTION;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  feature = UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches(
 | 
						|
      aFeatureName);
 | 
						|
  if (feature) {
 | 
						|
    mReason = FINGERPRINTING_PROTECTION;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  feature = UrlClassifierFeatureCryptominingProtection::GetIfNameMatches(
 | 
						|
      aFeatureName);
 | 
						|
  if (feature) {
 | 
						|
    mReason = CRYPTOMINING_PROTECTION;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
NS_IMPL_ISUPPORTS(ChannelClassifierService, nsIChannelClassifierService)
 | 
						|
 | 
						|
// static
 | 
						|
already_AddRefed<nsIChannelClassifierService>
 | 
						|
ChannelClassifierService::GetSingleton() {
 | 
						|
  if (gChannelClassifierService) {
 | 
						|
    return do_AddRef(gChannelClassifierService);
 | 
						|
  }
 | 
						|
 | 
						|
  gChannelClassifierService = new ChannelClassifierService();
 | 
						|
  ClearOnShutdown(&gChannelClassifierService);
 | 
						|
  return do_AddRef(gChannelClassifierService);
 | 
						|
}
 | 
						|
 | 
						|
ChannelClassifierService::ChannelClassifierService() { mListeners.Clear(); }
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ChannelClassifierService::AddListener(nsIObserver* aObserver) {
 | 
						|
  MOZ_ASSERT(aObserver);
 | 
						|
  MOZ_ASSERT(!mListeners.Contains(aObserver));
 | 
						|
 | 
						|
  mListeners.AppendElement(aObserver);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
NS_IMETHODIMP
 | 
						|
ChannelClassifierService::RemoveListener(nsIObserver* aObserver) {
 | 
						|
  MOZ_ASSERT(aObserver);
 | 
						|
  MOZ_ASSERT(mListeners.Contains(aObserver));
 | 
						|
 | 
						|
  mListeners.RemoveElement(aObserver);
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
ChannelBlockDecision ChannelClassifierService::OnBeforeBlockChannel(
 | 
						|
    nsIChannel* aChannel, const nsACString& aFeatureName,
 | 
						|
    const nsACString& aTableName) {
 | 
						|
  MOZ_ASSERT(aChannel);
 | 
						|
 | 
						|
  // Don't bother continuing if no one has ever registered listener
 | 
						|
  if (!gChannelClassifierService || !gChannelClassifierService->HasListener()) {
 | 
						|
    return ChannelBlockDecision::Blocked;
 | 
						|
  }
 | 
						|
 | 
						|
  ChannelBlockDecision decision;
 | 
						|
  nsresult rv = gChannelClassifierService->OnBeforeBlockChannel(
 | 
						|
      aChannel, aFeatureName, aTableName, decision);
 | 
						|
  if (NS_WARN_IF(NS_FAILED(rv))) {
 | 
						|
    return ChannelBlockDecision::Blocked;
 | 
						|
  }
 | 
						|
 | 
						|
  return decision;
 | 
						|
}
 | 
						|
 | 
						|
nsresult ChannelClassifierService::OnBeforeBlockChannel(
 | 
						|
    nsIChannel* aChannel, const nsACString& aFeatureName,
 | 
						|
    const nsACString& aTableName, ChannelBlockDecision& aDecision) {
 | 
						|
  MOZ_ASSERT(aChannel);
 | 
						|
 | 
						|
  aDecision = ChannelBlockDecision::Blocked;
 | 
						|
 | 
						|
  RefPtr<UrlClassifierBlockedChannel> channel =
 | 
						|
      new UrlClassifierBlockedChannel(aChannel);
 | 
						|
  channel->SetReason(aFeatureName, aTableName);
 | 
						|
 | 
						|
  for (const auto& listener : mListeners) {
 | 
						|
    listener->Observe(
 | 
						|
        NS_ISUPPORTS_CAST(nsIUrlClassifierBlockedChannel*, channel),
 | 
						|
        "urlclassifier-before-block-channel", nullptr);
 | 
						|
 | 
						|
    aDecision = channel->GetDecision();
 | 
						|
  }
 | 
						|
 | 
						|
  return NS_OK;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace net
 | 
						|
}  // namespace mozilla
 |