Bug 1576641 - Add two new content blocking event flags to indicate a tracking/social-tracking cookie has been loaded in a tab; r=baku,droeh

Differential Revision: https://phabricator.services.mozilla.com/D44216

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ehsan Akhgari 2019-09-03 17:37:43 +00:00
Родитель 1aa9ec41ed
Коммит 86c74f0485
9 изменённых файлов: 267 добавлений и 53 удалений

Просмотреть файл

@ -38,6 +38,8 @@ class ContentBlockingLog final {
bool mHasTrackingContentLoaded;
Maybe<bool> mHasCookiesLoaded;
Maybe<bool> mHasTrackerCookiesLoaded;
Maybe<bool> mHasSocialTrackerCookiesLoaded;
nsTArray<LogEntry> mLogs;
};
@ -97,16 +99,7 @@ class ContentBlockingLog final {
return;
}
if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
entry.mData->mHasTrackingContentLoaded = aBlocked;
return;
}
if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
if (entry.mData->mHasCookiesLoaded.isSome()) {
entry.mData->mHasCookiesLoaded.ref() = aBlocked;
} else {
entry.mData->mHasCookiesLoaded.emplace(aBlocked);
}
if (RecordLogEntryInCustomField(aType, entry, aBlocked)) {
return;
}
if (!entry.mData->mLogs.IsEmpty()) {
@ -152,6 +145,13 @@ class ContentBlockingLog final {
} else if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
MOZ_ASSERT(entry->mData->mHasCookiesLoaded.isNothing());
entry->mData->mHasCookiesLoaded.emplace(aBlocked);
} else if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER) {
MOZ_ASSERT(entry->mData->mHasTrackerCookiesLoaded.isNothing());
entry->mData->mHasTrackerCookiesLoaded.emplace(aBlocked);
} else if (aType ==
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER) {
MOZ_ASSERT(entry->mData->mHasSocialTrackerCookiesLoaded.isNothing());
entry->mData->mHasSocialTrackerCookiesLoaded.emplace(aBlocked);
} else {
entry->mData->mLogs.AppendElement(
LogEntry{aType, 1u, aBlocked, aReason,
@ -175,24 +175,7 @@ class ContentBlockingLog final {
w.StartArrayProperty(entry.mOrigin.get(), w.SingleLineStyle);
if (entry.mData->mHasTrackingContentLoaded) {
w.StartArrayElement(w.SingleLineStyle);
{
w.IntElement(nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
w.BoolElement(true); // blocked
w.IntElement(1); // repeat count
}
w.EndArray();
}
if (entry.mData->mHasCookiesLoaded.isSome()) {
w.StartArrayElement(w.SingleLineStyle);
{
w.IntElement(nsIWebProgressListener::STATE_COOKIES_LOADED);
w.BoolElement(entry.mData->mHasCookiesLoaded.value()); // blocked
w.IntElement(1); // repeat count
}
w.EndArray();
}
StringifyCustomFields(entry, w);
for (const LogEntry& item : entry.mData->mLogs) {
w.StartArrayElement(w.SingleLineStyle);
{
@ -232,6 +215,18 @@ class ContentBlockingLog final {
entry.mData->mHasCookiesLoaded.value()) {
return true;
}
} else if (aType ==
nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER) {
if (entry.mData->mHasTrackerCookiesLoaded.isSome() &&
entry.mData->mHasTrackerCookiesLoaded.value()) {
return true;
}
} else if (aType ==
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER) {
if (entry.mData->mHasSocialTrackerCookiesLoaded.isSome() &&
entry.mData->mHasSocialTrackerCookiesLoaded.value()) {
return true;
}
} else {
for (const auto& item : entry.mData->mLogs) {
if (((item.mType & aType) != 0) && item.mBlocked) {
@ -257,6 +252,85 @@ class ContentBlockingLog final {
}
}
private:
bool RecordLogEntryInCustomField(uint32_t aType, OriginEntry& aEntry,
bool aBlocked) {
if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
aEntry.mData->mHasTrackingContentLoaded = aBlocked;
return true;
}
if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
if (aEntry.mData->mHasCookiesLoaded.isSome()) {
aEntry.mData->mHasCookiesLoaded.ref() = aBlocked;
} else {
aEntry.mData->mHasCookiesLoaded.emplace(aBlocked);
}
return true;
}
if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER) {
if (aEntry.mData->mHasTrackerCookiesLoaded.isSome()) {
aEntry.mData->mHasTrackerCookiesLoaded.ref() = aBlocked;
} else {
aEntry.mData->mHasTrackerCookiesLoaded.emplace(aBlocked);
}
return true;
}
if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER) {
if (aEntry.mData->mHasSocialTrackerCookiesLoaded.isSome()) {
aEntry.mData->mHasSocialTrackerCookiesLoaded.ref() = aBlocked;
} else {
aEntry.mData->mHasSocialTrackerCookiesLoaded.emplace(aBlocked);
}
return true;
}
return false;
}
void StringifyCustomFields(const OriginEntry& aEntry, JSONWriter& aWriter) {
if (aEntry.mData->mHasTrackingContentLoaded) {
aWriter.StartArrayElement(aWriter.SingleLineStyle);
{
aWriter.IntElement(
nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
aWriter.BoolElement(true); // blocked
aWriter.IntElement(1); // repeat count
}
aWriter.EndArray();
}
if (aEntry.mData->mHasCookiesLoaded.isSome()) {
aWriter.StartArrayElement(aWriter.SingleLineStyle);
{
aWriter.IntElement(nsIWebProgressListener::STATE_COOKIES_LOADED);
aWriter.BoolElement(
aEntry.mData->mHasCookiesLoaded.value()); // blocked
aWriter.IntElement(1); // repeat count
}
aWriter.EndArray();
}
if (aEntry.mData->mHasTrackerCookiesLoaded.isSome()) {
aWriter.StartArrayElement(aWriter.SingleLineStyle);
{
aWriter.IntElement(
nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER);
aWriter.BoolElement(
aEntry.mData->mHasTrackerCookiesLoaded.value()); // blocked
aWriter.IntElement(1); // repeat count
}
aWriter.EndArray();
}
if (aEntry.mData->mHasSocialTrackerCookiesLoaded.isSome()) {
aWriter.StartArrayElement(aWriter.SingleLineStyle);
{
aWriter.IntElement(
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER);
aWriter.BoolElement(
aEntry.mData->mHasSocialTrackerCookiesLoaded.value()); // blocked
aWriter.IntElement(1); // repeat count
}
aWriter.EndArray();
}
}
private:
OriginDataTable mLog;
};

Просмотреть файл

@ -1279,13 +1279,50 @@ class Document : public nsINode,
}
/**
* Get cookies loaded flag for this document.
* Get the cookies loaded flag for this document.
*/
bool GetHasCookiesLoaded() {
return mContentBlockingLog.HasBlockedAnyOfType(
nsIWebProgressListener::STATE_COOKIES_LOADED);
}
/**
* Set the tracker cookies loaded flag for this document.
*/
void SetHasTrackerCookiesLoaded(bool aHasTrackerCookiesLoaded,
const nsACString& aOriginLoaded) {
RecordContentBlockingLog(
aOriginLoaded, nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER,
aHasTrackerCookiesLoaded);
}
/**
* Get the tracker cookies loaded flag for this document.
*/
bool GetHasTrackerCookiesLoaded() {
return mContentBlockingLog.HasBlockedAnyOfType(
nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER);
}
/**
* Set the social tracker cookies loaded flag for this document.
*/
void SetHasSocialTrackerCookiesLoaded(bool aHasSocialTrackerCookiesLoaded,
const nsACString& aOriginLoaded) {
RecordContentBlockingLog(
aOriginLoaded,
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER,
aHasSocialTrackerCookiesLoaded);
}
/**
* Get the social tracker cookies loaded flag for this document.
*/
bool GetHasSocialTrackerCookiesLoaded() {
return mContentBlockingLog.HasBlockedAnyOfType(
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER);
}
/**
* Get tracking content loaded flag for this document.
*/

Просмотреть файл

@ -5512,6 +5512,32 @@ void nsGlobalWindowOuter::NotifyContentBlockingEvent(
if (!aBlocked) {
unblocked = !doc->GetHasCookiesLoaded();
}
} else if (aEvent ==
nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER) {
MOZ_ASSERT(
!aBlocked,
"We don't expected to see blocked STATE_COOKIES_LOADED_TRACKER");
// Note that the logic in this branch is the logical negation of the
// logic in other branches, since the Document API we have is phrased
// in "loaded" terms as opposed to "blocked" terms.
blockedValue = !aBlocked;
doc->SetHasTrackerCookiesLoaded(blockedValue, origin);
if (!aBlocked) {
unblocked = !doc->GetHasTrackerCookiesLoaded();
}
} else if (aEvent ==
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER) {
MOZ_ASSERT(!aBlocked,
"We don't expected to see blocked "
"STATE_COOKIES_LOADED_SOCIALTRACKER");
// Note that the logic in this branch is the logical negation of
// the logic in other branches, since the Document API we have is
// phrased in "loaded" terms as opposed to "blocked" terms.
blockedValue = !aBlocked;
doc->SetHasSocialTrackerCookiesLoaded(blockedValue, origin);
if (!aBlocked) {
unblocked = !doc->GetHasSocialTrackerCookiesLoaded();
}
} else {
// Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
}

Просмотреть файл

@ -752,6 +752,8 @@ public class ContentBlocking {
// Match flags with nsIWebProgressListener.idl.
private static final long STATE_COOKIES_LOADED = 0x8000L;
private static final long STATE_COOKIES_LOADED_TRACKER = 0x40000L;
private static final long STATE_COOKIES_LOADED_SOCIALTRACKER = 0x80000L;
private static final long STATE_COOKIES_BLOCKED_TRACKER = 0x20000000L;
private static final long STATE_COOKIES_BLOCKED_ALL = 0x40000000L;
private static final long STATE_COOKIES_BLOCKED_FOREIGN = 0x80L;
@ -775,7 +777,11 @@ public class ContentBlocking {
if ((geckoCat & STATE_COOKIES_BLOCKED_FOREIGN) != 0) {
return CookieBehavior.ACCEPT_FIRST_PARTY;
}
if ((geckoCat & STATE_COOKIES_BLOCKED_TRACKER) != 0) {
// If we receive STATE_COOKIES_LOADED_{SOCIAL,}TRACKER we know that this
// setting would block this cookie.
if ((geckoCat & (STATE_COOKIES_BLOCKED_TRACKER |
STATE_COOKIES_LOADED_TRACKER |
STATE_COOKIES_LOADED_SOCIALTRACKER)) != 0) {
return CookieBehavior.ACCEPT_NON_TRACKERS;
}
if ((geckoCat & STATE_COOKIES_BLOCKED_ALL) != 0) {

Просмотреть файл

@ -236,6 +236,14 @@ void nsSecureBrowserUIImpl::CheckForContentBlockingEvents() {
if (doc->GetHasCookiesLoaded()) {
mEvent |= STATE_COOKIES_LOADED;
}
if (doc->GetHasTrackerCookiesLoaded()) {
mEvent |= STATE_COOKIES_LOADED_TRACKER;
}
if (doc->GetHasSocialTrackerCookiesLoaded()) {
mEvent |= STATE_COOKIES_LOADED_SOCIALTRACKER;
}
}
// Helper function to determine if the given URI can be considered secure.

Просмотреть файл

@ -900,6 +900,45 @@ bool CheckAntiTrackingPermission(nsIPrincipal* aPrincipal,
return true;
}
void NotifyBlockingDecisionInternal(
nsIChannel* aReportingChannel, nsIChannel* aTrackingChannel,
AntiTrackingCommon::BlockingDecision aDecision, uint32_t aRejectedReason,
nsIURI* aURI, nsPIDOMWindowOuter* aWindow) {
if (aDecision == AntiTrackingCommon::BlockingDecision::eBlock) {
aWindow->NotifyContentBlockingEvent(aRejectedReason, aReportingChannel,
true, aURI, aTrackingChannel);
ReportBlockingToConsole(aWindow, aURI, aRejectedReason);
}
// Now send the generic "cookies loaded" notifications, from the most generic
// to the most specific.
aWindow->NotifyContentBlockingEvent(
nsIWebProgressListener::STATE_COOKIES_LOADED, aReportingChannel, false,
aURI, aTrackingChannel);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aTrackingChannel);
if (!httpChannel) {
return;
}
uint32_t classificationFlags =
httpChannel->GetThirdPartyClassificationFlags();
if (classificationFlags &
nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING) {
aWindow->NotifyContentBlockingEvent(
nsIWebProgressListener::STATE_COOKIES_LOADED_TRACKER, aReportingChannel,
false, aURI, aTrackingChannel);
}
if (classificationFlags &
nsIHttpChannel::ClassificationFlags::CLASSIFIED_SOCIALTRACKING) {
aWindow->NotifyContentBlockingEvent(
nsIWebProgressListener::STATE_COOKIES_LOADED_SOCIALTRACKER,
aReportingChannel, false, aURI, aTrackingChannel);
}
}
} // namespace
/* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise>
@ -2065,15 +2104,8 @@ void AntiTrackingCommon::NotifyBlockingDecision(nsIChannel* aChannel,
nsCOMPtr<nsIURI> uri;
aChannel->GetURI(getter_AddRefs(uri));
if (aDecision == BlockingDecision::eBlock) {
pwin->NotifyContentBlockingEvent(aRejectedReason, aChannel, true, uri,
aChannel);
ReportBlockingToConsole(pwin, uri, aRejectedReason);
}
pwin->NotifyContentBlockingEvent(nsIWebProgressListener::STATE_COOKIES_LOADED,
aChannel, false, uri, aChannel);
NotifyBlockingDecisionInternal(aChannel, aChannel, aDecision, aRejectedReason,
uri, pwin);
}
/* static */
@ -2119,15 +2151,8 @@ void AntiTrackingCommon::NotifyBlockingDecision(nsPIDOMWindowInner* aWindow,
nsIURI* uri = document->GetDocumentURI();
nsIChannel* trackingChannel = document->GetChannel();
if (aDecision == BlockingDecision::eBlock) {
pwin->NotifyContentBlockingEvent(aRejectedReason, channel, true, uri,
trackingChannel);
ReportBlockingToConsole(pwin, uri, aRejectedReason);
}
pwin->NotifyContentBlockingEvent(nsIWebProgressListener::STATE_COOKIES_LOADED,
channel, false, uri, trackingChannel);
NotifyBlockingDecisionInternal(channel, trackingChannel, aDecision,
aRejectedReason, uri, pwin);
}
/* static */

Просмотреть файл

@ -225,6 +225,16 @@ add_task(async function() {
ok(item[2] >= 1, "Correct repeat count reported");
};
let expectTrackerCookiesLoaded = item => {
is(
item[0],
Ci.nsIWebProgressListener.STATE_COOKIES_LOADED_TRACKER,
"Correct blocking type reported"
);
is(item[1], true, "Correct blocking status reported");
ok(item[2] >= 1, "Correct repeat count reported");
};
let log = JSON.parse(await browser.getContentBlockingLog());
for (let trackerOrigin in log) {
is(
@ -233,11 +243,12 @@ add_task(async function() {
"Correct tracker origin must be reported"
);
let originLog = log[trackerOrigin];
is(originLog.length, 4, "We should have 4 entries in the compressed log");
is(originLog.length, 5, "We should have 4 entries in the compressed log");
expectTrackerFound(originLog[0]);
expectCookiesLoaded(originLog[1]);
expectTrackerBlocked(originLog[2], true);
expectTrackerBlocked(originLog[3], false);
expectTrackerCookiesLoaded(originLog[2]);
expectTrackerBlocked(originLog[3], true);
expectTrackerBlocked(originLog[4], false);
}
info("Removing the tab");

Просмотреть файл

@ -66,12 +66,20 @@ const LOG = {
"https://7.example.com": [
[Ci.nsIWebProgressListener.STATE_COOKIES_LOADED, true, 1],
],
// Cookie blocked for other reason (not a tracker)
// Tracker cookie loaded but not blocked.
"https://8.example.com": [
[Ci.nsIWebProgressListener.STATE_COOKIES_LOADED_TRACKER, true, 1],
],
// Social tracker cookie loaded but not blocked.
"https://9.example.com": [
[Ci.nsIWebProgressListener.STATE_COOKIES_LOADED_SOCIALTRACKER, true, 1],
],
// Cookie blocked for other reason (not a tracker)
"https://10.example.com": [
[Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_BY_PERMISSION, true, 2],
],
// Fingerprinters set to block, but this one has an exception
"https://9.example.com": [
"https://11.example.com": [
[Ci.nsIWebProgressListener.STATE_BLOCKED_FINGERPRINTING_CONTENT, false, 1],
],
};

Просмотреть файл

@ -285,6 +285,23 @@ interface nsIWebProgressListener : nsISupports
* STATE_BLOCKED_UNSAFE_CONTENT
* Content which againts SafeBrowsing list has been blocked from loading.
*
* STATE_COOKIES_LOADED
* Performed a storage access check, which usually means something like a
* cookie or a storage item was loaded/stored on the current tab.
* Alternatively this could indicate that something in the current tab
* attempted to communicate with its same-origin counterparts in other
* tabs.
*
* STATE_COOKIES_LOADED_TRACKER
* Similar to STATE_COOKIES_LOADED, but only sent if the subject of the
* action was a third-party tracker when the active cookie policy imposes
* restrictions on such content.
*
* STATE_COOKIES_LOADED_SOCIALTRACKER
* Similar to STATE_COOKIES_LOADED, but only sent if the subject of the
* action was a third-party social tracker when the active cookie policy
* imposes restrictions on such content.
*
* STATE_COOKIES_BLOCKED_BY_PERMISSION
* Rejected for custom site permission.
*
@ -316,6 +333,8 @@ interface nsIWebProgressListener : nsISupports
const unsigned long STATE_LOADED_CRYPTOMINING_CONTENT = 0x00200000;
const unsigned long STATE_BLOCKED_UNSAFE_CONTENT = 0x00004000;
const unsigned long STATE_COOKIES_LOADED = 0x00008000;
const unsigned long STATE_COOKIES_LOADED_TRACKER = 0x00040000;
const unsigned long STATE_COOKIES_LOADED_SOCIALTRACKER = 0x00080000;
const unsigned long STATE_COOKIES_BLOCKED_BY_PERMISSION = 0x10000000;
const unsigned long STATE_COOKIES_BLOCKED_TRACKER = 0x20000000;
const unsigned long STATE_COOKIES_BLOCKED_ALL = 0x40000000;