diff options
Diffstat (limited to 'netwerk/url-classifier/ChannelClassifierService.cpp')
-rw-r--r-- | netwerk/url-classifier/ChannelClassifierService.cpp | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/netwerk/url-classifier/ChannelClassifierService.cpp b/netwerk/url-classifier/ChannelClassifierService.cpp new file mode 100644 index 0000000000..5d8605e909 --- /dev/null +++ b/netwerk/url-classifier/ChannelClassifierService.cpp @@ -0,0 +1,268 @@ +/* -*- 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 |