From 9a26b7fd29ab4f6f4a1bcb96effa3fabcb825ff3 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 22 Sep 2018 17:04:38 -0400 Subject: [PATCH] Bug 1493563 - Part 2: Record a log of content blocking actions on each top-level document; r=baku Differential Revision: https://phabricator.services.mozilla.com/D6592 --- dom/base/ContentBlockingLog.h | 53 +++++++++++++++++++ dom/base/moz.build | 1 + dom/base/nsGlobalWindowOuter.cpp | 20 ++++--- dom/base/nsGlobalWindowOuter.h | 3 +- dom/base/nsIDocument.h | 50 ++++++++++++++--- dom/base/nsPIDOMWindow.h | 3 +- .../antitracking/AntiTrackingCommon.cpp | 4 +- 7 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 dom/base/ContentBlockingLog.h diff --git a/dom/base/ContentBlockingLog.h b/dom/base/ContentBlockingLog.h new file mode 100644 index 000000000000..5db9aadbdf3a --- /dev/null +++ b/dom/base/ContentBlockingLog.h @@ -0,0 +1,53 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_ContentBlockingLog_h +#define mozilla_dom_ContentBlockingLog_h + +#include "mozilla/Pair.h" +#include "mozilla/UniquePtr.h" +#include "nsClassHashtable.h" +#include "nsHashKeys.h" +#include "nsTArray.h" + +namespace mozilla { +namespace dom { + +class ContentBlockingLog final +{ + // Each element is a pair of (type, blocked). The type values come from the + // blocking types defined in nsIWebProgressListener. + typedef nsTArray> OriginLog; + +public: + ContentBlockingLog() = default; + ~ContentBlockingLog() = default; + + void RecordLog(const nsAString& aOrigin, uint32_t aType, bool aBlocked) + { + if (aOrigin.IsVoid()) { + return; + } + auto entry = mLog.LookupForAdd(aOrigin); + if (entry) { + entry.Data()->AppendElement(mozilla::MakePair(aType, aBlocked)); + } else { + entry.OrInsert([=] { + auto log(MakeUnique()); + log->AppendElement(mozilla::MakePair(aType, aBlocked)); + return log.release(); + }); + } + } + +private: + nsClassHashtable mLog; +}; + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/base/moz.build b/dom/base/moz.build index 447aef561d54..0100a4d17e77 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -153,6 +153,7 @@ EXPORTS.mozilla.dom += [ 'ChromeNodeList.h', 'ChromeUtils.h', 'Comment.h', + 'ContentBlockingLog.h', 'ContentFrameMessageManager.h', 'ContentProcessMessageManager.h', 'CustomElementRegistry.h', diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 4d602add9eb7..18e5b87e5242 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -5281,7 +5281,8 @@ nsGlobalWindowOuter::FirePopupBlockedEvent(nsIDocument* aDoc, void nsGlobalWindowOuter::NotifyContentBlockingState(unsigned aState, - nsIChannel* aChannel) + nsIChannel* aChannel, + nsIURI* aURIHint) { nsCOMPtr docShell = GetDocShell(); if (!docShell) { @@ -5310,18 +5311,23 @@ nsGlobalWindowOuter::NotifyContentBlockingState(unsigned aState, return; } securityUI->GetState(&state); + nsAutoString origin; + origin.SetIsVoid(true); + if (aURIHint) { + nsContentUtils::GetUTFOrigin(aURIHint, origin); + } if (aState == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) { - doc->SetHasTrackingContentBlocked(true); + doc->SetHasTrackingContentBlocked(true, origin); } else if (aState == nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT) { - doc->SetHasSlowTrackingContentBlocked(true); + doc->SetHasSlowTrackingContentBlocked(true, origin); } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION) { - doc->SetHasCookiesBlockedByPermission(true); + doc->SetHasCookiesBlockedByPermission(true, origin); } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) { - doc->SetHasTrackingCookiesBlocked(true); + doc->SetHasTrackingCookiesBlocked(true, origin); } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) { - doc->SetHasAllCookiesBlocked(true); + doc->SetHasAllCookiesBlocked(true, origin); } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) { - doc->SetHasForeignCookiesBlocked(true); + doc->SetHasForeignCookiesBlocked(true, origin); } else { // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT; } diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h index 74152324e18c..c62db2c071e1 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h @@ -484,7 +484,8 @@ public: virtual void NotifyContentBlockingState(unsigned aState, - nsIChannel* aChannel) override; + nsIChannel* aChannel, + nsIURI* aURIHint) override; virtual uint32_t GetSerial() override { return mSerial; diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 7f7089a2aee2..f6a7c451185a 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -7,6 +7,7 @@ #define nsIDocument_h___ #include "mozilla/FlushType.h" // for enum +#include "mozilla/Pair.h" // for Pair #include "nsAutoPtr.h" // for member #include "nsCOMArray.h" // for member #include "nsCompatibility.h" // for member @@ -29,6 +30,7 @@ #include "nsIServiceManager.h" #include "nsIURI.h" // for use in inline functions #include "nsIUUIDGenerator.h" +#include "nsIWebProgressListener.h" // for nsIWebProgressListener #include "nsPIDOMWindow.h" // for use in inline functions #include "nsPropertyTable.h" // for member #include "nsStringFwd.h" @@ -43,6 +45,7 @@ #include "nsExpirationTracker.h" #include "nsClassHashtable.h" #include "mozilla/CORSMode.h" +#include "mozilla/dom/ContentBlockingLog.h" #include "mozilla/dom/DispatcherTrait.h" #include "mozilla/dom/DocumentOrShadowRoot.h" #include "mozilla/EnumSet.h" @@ -1027,49 +1030,73 @@ public: /** * Set the tracking content blocked flag for this document. */ - void SetHasTrackingContentBlocked(bool aHasTrackingContentBlocked) + void SetHasTrackingContentBlocked(bool aHasTrackingContentBlocked, + const nsAString& aOriginBlocked) { mHasTrackingContentBlocked = aHasTrackingContentBlocked; + RecordContentBlockingLog(aOriginBlocked, + nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT, + aHasTrackingContentBlocked); } /** * Set the slow tracking content blocked flag for this document. */ - void SetHasSlowTrackingContentBlocked(bool aHasSlowTrackingContentBlocked) + void SetHasSlowTrackingContentBlocked(bool aHasSlowTrackingContentBlocked, + const nsAString& aOriginBlocked) { mHasSlowTrackingContentBlocked = aHasSlowTrackingContentBlocked; + RecordContentBlockingLog(aOriginBlocked, + nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT, + aHasSlowTrackingContentBlocked); } /** * Set the all cookies blocked flag for this document. */ - void SetHasAllCookiesBlocked(bool aHasAllCookiesBlocked) + void SetHasAllCookiesBlocked(bool aHasAllCookiesBlocked, + const nsAString& aOriginBlocked) { mHasAllCookiesBlocked = aHasAllCookiesBlocked; + RecordContentBlockingLog(aOriginBlocked, + nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL, + aHasAllCookiesBlocked); } /** * Set the tracking cookies blocked flag for this document. */ - void SetHasTrackingCookiesBlocked(bool aHasTrackingCookiesBlocked) + void SetHasTrackingCookiesBlocked(bool aHasTrackingCookiesBlocked, + const nsAString& aOriginBlocked) { mHasTrackingCookiesBlocked = aHasTrackingCookiesBlocked; + RecordContentBlockingLog(aOriginBlocked, + nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER, + aHasTrackingCookiesBlocked); } /** * Set the third-party cookies blocked flag for this document. */ - void SetHasForeignCookiesBlocked(bool aHasForeignCookiesBlocked) + void SetHasForeignCookiesBlocked(bool aHasForeignCookiesBlocked, + const nsAString& aOriginBlocked) { mHasForeignCookiesBlocked = aHasForeignCookiesBlocked; + RecordContentBlockingLog(aOriginBlocked, + nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN, + aHasForeignCookiesBlocked); } /** * Set the cookies blocked by site permission flag for this document. */ - void SetHasCookiesBlockedByPermission(bool aHasCookiesBlockedByPermission) + void SetHasCookiesBlockedByPermission(bool aHasCookiesBlockedByPermission, + const nsAString& aOriginBlocked) { mHasCookiesBlockedByPermission = aHasCookiesBlockedByPermission; + RecordContentBlockingLog(aOriginBlocked, + nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION, + aHasCookiesBlockedByPermission); } /** @@ -3850,6 +3877,12 @@ protected: bool aUpdateCSSLoader); private: + void RecordContentBlockingLog(const nsAString& aOrigin, + uint32_t aType, bool aBlocked) + { + mContentBlockingLog.RecordLog(aOrigin, aType, aBlocked); + } + mutable std::bitset mDeprecationWarnedAbout; mutable std::bitset mDocWarningWarnedAbout; @@ -4519,6 +4552,11 @@ protected: // existing in the set means the corresponding script isn't a tracking script. nsTHashtable mTrackingScripts; + // The log of all content blocking actions taken on this document. This is only + // stored on top-level documents and includes the activity log for all of the + // nested subdocuments as well. + mozilla::dom::ContentBlockingLog mContentBlockingLog; + // List of ancestor principals. This is set at the point a document // is connected to a docshell and not mutated thereafter. nsTArray> mAncestorPrincipals; diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 98bca9eca1b5..dbbe0a50e7f3 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -1094,7 +1094,8 @@ public: virtual void NotifyContentBlockingState(unsigned aState, - nsIChannel* aChannel) = 0; + nsIChannel* aChannel, + nsIURI* aURIHint = nullptr) = 0; // WebIDL-ish APIs void MarkUncollectableForCCGeneration(uint32_t aGeneration) diff --git a/toolkit/components/antitracking/AntiTrackingCommon.cpp b/toolkit/components/antitracking/AntiTrackingCommon.cpp index 572b22815407..f2d0bdfd54cb 100644 --- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -1089,7 +1089,7 @@ AntiTrackingCommon::NotifyRejection(nsIChannel* aChannel, nsCOMPtr uri; aChannel->GetURI(getter_AddRefs(uri)); - pwin->NotifyContentBlockingState(aRejectedReason, aChannel); + pwin->NotifyContentBlockingState(aRejectedReason, aChannel, uri); ReportBlockingToConsole(pwin, uri, aRejectedReason); } @@ -1128,7 +1128,7 @@ AntiTrackingCommon::NotifyRejection(nsPIDOMWindowInner* aWindow, nsCOMPtr uri; channel->GetURI(getter_AddRefs(uri)); - pwin->NotifyContentBlockingState(aRejectedReason, channel); + pwin->NotifyContentBlockingState(aRejectedReason, channel, uri); ReportBlockingToConsole(pwin, uri, aRejectedReason); }