Closed Bug 629535 Opened 9 years ago Closed 8 years ago

add do-not-track signal to navigator global object

Categories

(Core :: DOM: Core & HTML, enhancement)

enhancement
Not set

Tracking

()

VERIFIED FIXED
mozilla9

People

(Reporter: geekboy, Assigned: justin.lebar+bug)

References

Details

(Keywords: dev-doc-complete, verified-aurora, verified-beta, Whiteboard: [qa!])

Attachments

(1 file, 2 obsolete files)

So that js-oriented tracking systems can take better advantage of the do-not-track header (bug 628197), we should expose a global variable when the "do not track" opt-out header feature is enabled.  This way, a web page can decide whether or not to even make the request for tracking code based on the user's choice, and through the global js navigator object, can examine the value sent with the HTTP header.

I'd like to propose we make do-not-track state accessible in this way:

<script>
if (!navigator.donottrack) {
  trackingStuffHere();
}
</script>

This likely involves editing nsIDOMNavigator.idl to include a new read-only string attribute "donottrack", and then the proper code in nsGlobalWindow.cpp::nsNavigator class to obtain the value that is transmitted with the header when the feature is enabled.
We use camelCaps for property names.

Also, a page can easily delete window.navigator even if navigator.doNotTrack is non-writable and non-configurable. FYI only.

/be
Sounds good.  Piwik trunk already has a check for the proposed variable to
abort the tracking request and delete existing first party cookies.

BTW navigator.doNotTrack doesn't have to be read-only.  The intent is that
setting the value to false doesn't disable the header.
I think it's good to make this variable available by JS, but there is one nasty corner case to at least note, even if we can't necessarily fix it elegantly.  People who enable DNT may also disable JavaScript, probably by using NoScript.  They may also have a tracking cookie set.

So if servers assume that they can spot DNT from JS, but keep logging whatever cookies they receive at the HTTP layer, they may keep tracking a user who has set DNT 1.

One way to mitigate this problem would be to standardise a server-side response that says, "yep, I got your DNT request and I'm honoring it" (also optionally "I got it but I'm not honoring it for reason X").  It could be a header or something in the DOM.  Then at least we can spot cases where the client sends DNT but server-side infrastructure misses it.

A different way to mitigate the problem would be to note carefully in the documentation for this JS variable that if you rely on it you should detect JS disabled users and send them to a magic URI that checks for the header using Apache or whatever, and wipes tracking cookies accordingly.
Isn't the case of NoScript a non-issue?  If the tracking server is a third-party, but uses first party cookies via JS, then the first party tracking cookies won't be relayed to the tracking server, by virtue of JS being disabled.

If the tracking server is a first-party (or appears to be one via some proxy), there's no need for a specialized server response.  A server that honors the DNT header should delete the tracking cookies (ie setting the expiry date in the past).  That's what the (server-side) DNT plugin for Piwik does.
Anthon: I see what you're saying.  If NoScript blocks the fetching of JS objects, this is trully an obscure corner case.  It could still happen if, say, it's a 3rd party iframe that *contains* JS, and the 3rd party's developer was expecting the JS to process DNT for the entire frame.
If that should happen (and I don't think it would if the developer implements both client- and server-side DNT checks), then the corrective action would be for NoScript to whitelist a 3rd party that does honor DNT.

The JS required to delete a tracking cookie is akin to a surgical procedure;  NoScript is a sledgehammer that materially changes the flow of JS execution..
A couple concerns.

First, how would the JavaScript flag handle third-party scripts included in a first-party (or other third-party) page?  For example, the common:

<script type="text/javascript" async="true" src="http://www.google-analytics.com/ga.js" />

If the user has enabled Do Not Track universally, there's no issue.  But if the user has enabled Do Not Track with some granularity (which we'd like to allow), the Google Analytics script would see the preference for its host page - not Google Analytics.

Second concern: What about the initial request for third-party JavaScript?  Assuming Do Not Track has implications for logging, a third party would still have to look for the request header.
I'm going to work on this.
Assignee: nobody → justin.lebar+bug
(From comment 0)
> through the global js navigator object, [the page] can examine the value sent with the 
> HTTP header.

I think navigator.doNotTrack should take on [true, false, null], rather than ["0", "1", ""].  This way, |if (navigator.doNotTrack)| works as one would expect.
After speaking with Jonas and Sid, I think we should use a string with ["yes", "no", "unspecified"].  (Or some other string than "unspecified".)  This fails closed -- if someone does |if (navigator.doNotTrack)|, it'll always be true.  And it forces people to explicitly handle the "unspecified" case, rather than lumping it together with |true| or |false|.
Attached patch Patch v1 (obsolete) — Splinter Review
Attachment #560503 - Flags: review?(jonas)
Comment on attachment 560503 [details] [diff] [review]
Patch v1

Suggestions welcome on an alternative to "unspecified".
Attachment #560503 - Flags: feedback?(sstamm)
Comment on attachment 560503 [details] [diff] [review]
Patch v1

Review of attachment 560503 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/tests/mochitest/general/test_bug629535.html
@@ +15,5 @@
> +
> +const dntPref = 'privacy.donottrackheader.enabled';
> +const oldDNT = SpecialPowers.getBoolPref(dntPref);
> +
> +SpecialPowers.setBoolPref(dntPref, true);

Could you check the default value before setting? If there is a default value.

@@ +16,5 @@
> +const dntPref = 'privacy.donottrackheader.enabled';
> +const oldDNT = SpecialPowers.getBoolPref(dntPref);
> +
> +SpecialPowers.setBoolPref(dntPref, true);
> +is(navigator.doNotTrack, "yes");

Could you check with setting "false" too?

@@ +21,5 @@
> +
> +SpecialPowers.clearUserPref(dntPref);
> +is(navigator.doNotTrack, "unspecified");
> +
> +dump('Old DNT is ' + oldDNT + '\n\n\n');

I think you do not want to keep this.
> Could you check the default value before setting? If there is a default value.

Do you mean that I should test that oldDNT == false?
Attached patch Patch v2 (obsolete) — Splinter Review
Attachment #560517 - Flags: review?(jonas)
Attachment #560503 - Attachment is obsolete: true
Attachment #560503 - Flags: review?(jonas)
Attachment #560503 - Flags: feedback?(sstamm)
Attachment #560518 - Flags: review?(jonas)
Attachment #560517 - Attachment is obsolete: true
Attachment #560517 - Flags: review?(jonas)
Comment on attachment 560518 [details] [diff] [review]
Patch v3 (with updated test)

Review of attachment 560518 [details] [diff] [review]:
-----------------------------------------------------------------

I would have name the test test_navigator_doNotTrack.html instead of using a cryptic bug number.

f=me. If Jonas wants to delegate his review to me, feel free to take this as a r+ ;)

::: dom/base/nsGlobalWindow.cpp
@@ +11132,5 @@
> +  if (gDoNotTrackEnabled) {
> +    aResult.AssignLiteral("yes");
> +  }
> +  else {
> +    aResult.AssignLiteral("unspecified");

I would have do:
aResult.AssignLiteral(gDoNotTrackEnabled ? "yes" : "unspecified");

but that might just be a matter of taste.
Attachment #560518 - Flags: feedback+
Comment on attachment 560518 [details] [diff] [review]
Patch v3 (with updated test)

Review of attachment 560518 [details] [diff] [review]:
-----------------------------------------------------------------

Looks good to me. I don't think you can use AssignLiteral with Mounir's suggestion due to the template magic that AssignLiteral uses.
Attachment #560518 - Flags: review?(jonas) → review+
https://hg.mozilla.org/mozilla-central/rev/40e482df5ab5
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Whiteboard: [inbound]
Target Milestone: --- → mozilla9
Documented:

https://developer.mozilla.org/en/DOM/navigator.doNotTrack

Added to the window.navigator page list of properties:

https://developer.mozilla.org/en/DOM/window.navigator

And mentioned on Firefox 9 for developers.
Verified that the automated test has passed on all OSs:
https://tbpl.mozilla.org/php/getParsedLog.php?id=7322343&full=1&branch=mozilla-beta
https://tbpl.mozilla.org/php/getParsedLog.php?id=7322331&full=1&branch=mozilla-beta
https://tbpl.mozilla.org/php/getParsedLog.php?id=7322030&full=1&branch=mozilla-beta
https://tbpl.mozilla.org/php/getParsedLog.php?id=7320492&full=1&branch=mozilla-beta

Verified as fixed with manual tests (added here http://bit.ly/sXdHaE) on Firefox 9.0 beta 1:
Mozilla/5.0 (Windows NT 5.1; rv:9.0) Gecko/20100101 Firefox/9.0
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0
Mozilla/5.0 (Windows NT 6.1; rv:9.0) Gecko/20100101 Firefox/9.0
Mozilla/5.0 (X11; Linux i686; rv:9.0) Gecko/20100101 Firefox/9.0
Keywords: verified-beta
Verified as fixed on Aurora(Fx 10): 
Manual tests - http://bit.ly/sXdHaE
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0a2) Gecko/20111109 Firefox/10.0a2
Mozilla/5.0 (X11; Linux i686; rv:10.0a2) Gecko/20111109 Firefox/10.0a2
Mozilla/5.0 (Windows NT 5.1; rv:10.0a2) Gecko/20111110 Firefox/10.0a2
Mozilla/5.0 (Windows NT 6.1; rv:10.0a2) Gecko/20111113 Firefox/10.0a2

Automated test - dom/tests/mochitest/general/test_bug629535.html
https://tbpl.mozilla.org/php/getParsedLog.php?id=7374068&full=1&branch=mozilla-aurora
https://tbpl.mozilla.org/php/getParsedLog.php?id=7368649&full=1&branch=mozilla-aurora
https://tbpl.mozilla.org/php/getParsedLog.php?id=7368492&full=1&branch=mozilla-aurora
https://tbpl.mozilla.org/php/getParsedLog.php?id=7374991&full=1&branch=mozilla-aurora

Verified as fixed on Central(Fx11):
Manual tests - http://bit.ly/sXdHaE
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:11.0a1) Gecko/20111109 Firefox/11.0a1
Mozilla/5.0 (X11; Linux i686; rv:11.0a1) Gecko/20111109 Firefox/11.0a1
Mozilla/5.0 (Windows NT 5.1; rv:11.0a1) Gecko/20111110 Firefox/11.0a1
Mozilla/5.0 (Windows NT 6.1; rv:11.0a1) Gecko/20111113 Firefox/11.0a1

Automated test - dom/tests/mochitest/general/test_bug629535.html
https://tbpl.mozilla.org/php/getParsedLog.php?id=7383147&full=1&branch=services-central
https://tbpl.mozilla.org/php/getParsedLog.php?id=7382741&full=1&branch=services-central
https://tbpl.mozilla.org/php/getParsedLog.php?id=7383091&full=1&branch=services-central
https://tbpl.mozilla.org/php/getParsedLog.php?id=7383079&full=1&branch=services-central

This issue will be set as VERIFIED FIXED as soon as I can be verified on Firefox 9.0 RC.
Keywords: verified-aurora
Blocks: 702380
No longer blocks: 702380
This feature has been released in Firefox 9.0 and signed off by QA. No issues were found.
Status: RESOLVED → VERIFIED
Whiteboard: [qa!]
You need to log in before you can comment on or make changes to this bug.