1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
|
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import unittest
import pbtest
from functools import partial
from selenium.common.exceptions import NoSuchElementException
from pbtest import retry_until
class DntTest(pbtest.PBSeleniumTest):
"""Tests to make sure DNT policy checking works as expected."""
CHECK_FOR_DNT_POLICY_JS = (
"chrome.extension.getBackgroundPage()."
"badger.checkForDNTPolicy("
" arguments[0],"
" r => window.DNT_CHECK_RESULT = r"
");"
)
# TODO switch to non-delayed version
# https://gist.github.com/ghostwords/9fc6900566a2f93edd8e4a1e48bbaa28
# once race condition (https://crbug.com/478183) is fixed
NAVIGATOR_DNT_TEST_URL = (
"https://efforg.github.io/privacybadger-test-fixtures/html/"
"navigator_donottrack_delayed.html"
)
def get_first_party_headers(self, url):
self.load_url(url)
text = self.driver.find_element_by_tag_name('body').text
try:
headers = json.loads(text)['headers']
except ValueError:
print("\nFailed to parse JSON from {}".format(repr(text)))
return None
return headers
def domain_was_recorded(self, domain):
return self.js(
"return (Object.keys("
" chrome.extension.getBackgroundPage()."
" badger.storage.action_map.getItemClones()"
").indexOf(arguments[0]) != -1);",
domain
)
def domain_was_detected(self, domain):
return self.js(
"return (Object.keys(chrome.extension.getBackgroundPage().badger.tabData).some(tab_id => {"
" let origins = chrome.extension.getBackgroundPage().badger.tabData[tab_id].origins;"
" return origins.hasOwnProperty(arguments[0]);"
"}));",
domain
)
def domain_was_blocked(self, domain):
return self.js(
"return (Object.keys(chrome.extension.getBackgroundPage().badger.tabData).some(tab_id => {"
" let origins = chrome.extension.getBackgroundPage().badger.tabData[tab_id].origins;"
" return ("
" origins.hasOwnProperty(arguments[0]) &&"
" chrome.extension.getBackgroundPage().constants.BLOCKED_ACTIONS.has(origins[arguments[0]])"
" );"
"}));",
domain
)
@pbtest.repeat_if_failed(3)
def test_dnt_policy_check_should_happen_for_blocked_domains(self):
PAGE_URL = (
"https://efforg.github.io/privacybadger-test-fixtures/html/"
"dnt.html"
)
DNT_DOMAIN = "www.eff.org"
# mark a DNT-compliant domain for blocking
self.block_domain(DNT_DOMAIN)
# visit a page that loads a resource from that DNT-compliant domain
self.open_window()
self.load_url(PAGE_URL)
# switch back to Badger's options page
self.switch_to_window_with_url(self.options_url)
# verify that the domain is blocked
self.assertTrue(self.domain_was_detected(DNT_DOMAIN),
msg="Domain should have been detected.")
self.assertTrue(self.domain_was_blocked(DNT_DOMAIN),
msg="DNT-compliant resource should have been blocked at first.")
def reload_and_see_if_unblocked():
# switch back to the page with the DNT-compliant resource
self.switch_to_window_with_url(PAGE_URL)
# reload it
self.load_url(PAGE_URL)
# switch back to Badger's options page
self.switch_to_window_with_url(self.options_url)
return (
self.domain_was_detected(DNT_DOMAIN) and
self.domain_was_blocked(DNT_DOMAIN)
)
# verify that the domain is allowed
was_blocked = retry_until(
reload_and_see_if_unblocked,
tester=lambda x: not x,
msg="Waiting a bit for DNT check to complete and retrying ...")
self.assertFalse(was_blocked,
msg="DNT-compliant resource should have gotten unblocked.")
def test_dnt_policy_check_should_not_set_cookies(self):
TEST_DOMAIN = "dnt-test.trackersimulator.org"
TEST_URL = "https://{}/".format(TEST_DOMAIN)
# verify that the domain itself doesn't set cookies
self.load_url(TEST_URL)
self.assertEqual(len(self.driver.get_cookies()), 0,
"No cookies initially")
# directly visit a DNT policy URL known to set cookies
self.load_url(TEST_URL + ".well-known/dnt-policy.txt")
self.assertEqual(len(self.driver.get_cookies()), 1,
"DNT policy URL set a cookie")
# verify we got a cookie
self.load_url(TEST_URL)
self.assertEqual(len(self.driver.get_cookies()), 1,
"We still have just one cookie")
# clear cookies and verify
self.driver.delete_all_cookies()
self.load_url(TEST_URL)
self.assertEqual(len(self.driver.get_cookies()), 0,
"No cookies again")
self.load_url(self.options_url)
# perform a DNT policy check
self.js(DntTest.CHECK_FOR_DNT_POLICY_JS, TEST_DOMAIN)
# wait until checkForDNTPolicy completed
self.wait_for_script("return window.DNT_CHECK_RESULT === false")
# check that we didn't get cookied by the DNT URL
self.load_url(TEST_URL)
self.assertEqual(len(self.driver.get_cookies()), 0,
"Shouldn't have any cookies after the DNT check")
def test_dnt_policy_check_should_not_send_cookies(self):
TEST_DOMAIN = "dnt-request-cookies-test.trackersimulator.org"
TEST_URL = "https://{}/".format(TEST_DOMAIN)
# directly visit a DNT policy URL known to set cookies
self.load_url(TEST_URL + ".well-known/dnt-policy.txt")
self.assertEqual(len(self.driver.get_cookies()), 1,
"DNT policy URL set a cookie")
# how to check we didn't send a cookie along with request?
# the DNT policy URL used by this test returns "cookies=X"
# where X is the number of cookies it got
# MEGAHACK: make sha1 of "cookies=0" a valid DNT hash
self.load_url(self.options_url)
self.js(
"chrome.extension.getBackgroundPage()."
"badger.storage.updateDntHashes({"
" 'cookies=0 test policy': 'f63ee614ebd77f8634b92633c6bb809a64b9a3d7'"
"});"
)
# perform a DNT policy check
self.js(DntTest.CHECK_FOR_DNT_POLICY_JS, TEST_DOMAIN)
# wait until checkForDNTPolicy completed
self.wait_for_script("return typeof window.DNT_CHECK_RESULT != 'undefined';")
# get the result
result = self.js("return window.DNT_CHECK_RESULT;")
self.assertTrue(result, "No cookies were sent")
def test_should_not_record_nontracking_domains(self):
FIXTURE_URL = (
"https://efforg.github.io/privacybadger-test-fixtures/html/"
"recording_nontracking_domains.html"
)
TRACKING_DOMAIN = "dnt-request-cookies-test.trackersimulator.org"
NON_TRACKING_DOMAIN = "www.eff.org"
# clear pre-trained/seed tracker data
self.load_url(self.options_url)
self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
# enable local learning
self.wait_for_script("return window.OPTIONS_INITIALIZED")
self.find_el_by_css('#local-learning-checkbox').click()
# visit a page containing two third-party resources,
# one from a cookie-tracking domain
# and one from a non-tracking domain
self.load_url(FIXTURE_URL)
# verify both domains are present on the page
try:
selector = "iframe[src*='%s']" % TRACKING_DOMAIN
self.driver.find_element_by_css_selector(selector)
except NoSuchElementException:
self.fail("Unable to find the tracking domain on the page")
try:
selector = "img[src*='%s']" % NON_TRACKING_DOMAIN
self.driver.find_element_by_css_selector(selector)
except NoSuchElementException:
self.fail("Unable to find the non-tracking domain on the page")
self.load_url(self.options_url)
# verify that the cookie-tracking domain was recorded
self.assertTrue(
self.domain_was_recorded(TRACKING_DOMAIN),
"Tracking domain should have gotten recorded"
)
# verify that the non-tracking domain was not recorded
self.assertFalse(
self.domain_was_recorded(NON_TRACKING_DOMAIN),
"Non-tracking domain should not have gotten recorded"
)
def test_first_party_dnt_header(self):
TEST_URL = "https://httpbin.org/get"
headers = retry_until(partial(self.get_first_party_headers, TEST_URL),
times=8)
self.assertTrue(headers is not None, "It seems we failed to get headers")
self.assertIn('Dnt', headers, "DNT header should have been present")
self.assertIn('Sec-Gpc', headers, "GPC header should have been present")
self.assertEqual(headers['Dnt'], "1",
'DNT header should have been set to "1"')
self.assertEqual(headers['Sec-Gpc'], "1",
'Sec-Gpc header should have been set to "1"')
def test_no_dnt_header_when_disabled_on_site(self):
TEST_URL = "https://httpbin.org/get"
self.disable_badger_on_site(TEST_URL)
headers = retry_until(partial(self.get_first_party_headers, TEST_URL),
times=8)
self.assertTrue(headers is not None, "It seems we failed to get headers")
self.assertNotIn('Dnt', headers, "DNT header should have been missing")
self.assertNotIn('Sec-Gpc', headers, "GPC header should have been missing")
def test_no_dnt_header_when_dnt_disabled(self):
TEST_URL = "https://httpbin.org/get"
self.load_url(self.options_url)
self.wait_for_script("return window.OPTIONS_INITIALIZED")
self.find_el_by_css('#enable_dnt_checkbox').click()
headers = retry_until(partial(self.get_first_party_headers, TEST_URL),
times=8)
self.assertTrue(headers is not None, "It seems we failed to get headers")
self.assertNotIn('Dnt', headers, "DNT header should have been missing")
self.assertNotIn('Sec-Gpc', headers, "GPC header should have been missing")
def test_navigator_object(self):
self.load_url(DntTest.NAVIGATOR_DNT_TEST_URL, wait_for_body_text=True)
self.assertEqual(
self.driver.find_element_by_tag_name('body').text,
'no tracking (navigator.doNotTrack="1")',
"navigator.DoNotTrack should have been set to \"1\""
)
self.assertEqual(
self.js("return navigator.globalPrivacyControl"),
"1",
"navigator.globalPrivacyControl should have been set to \"1\""
)
def test_navigator_unmodified_when_disabled_on_site(self):
self.disable_badger_on_site(DntTest.NAVIGATOR_DNT_TEST_URL)
self.load_url(DntTest.NAVIGATOR_DNT_TEST_URL, wait_for_body_text=True)
# navigator.doNotTrack defaults to null in Chrome, "unspecified" in Firefox
self.assertEqual(
self.driver.find_element_by_tag_name('body').text[0:5],
'unset',
"navigator.DoNotTrack should have been left unset"
)
self.assertEqual(
self.js("return navigator.globalPrivacyControl"),
None,
"navigator.globalPrivacyControl should have been left unset"
)
def test_navigator_unmodified_when_dnt_disabled(self):
self.load_url(self.options_url)
self.wait_for_script("return window.OPTIONS_INITIALIZED")
self.find_el_by_css('#enable_dnt_checkbox').click()
self.load_url(DntTest.NAVIGATOR_DNT_TEST_URL, wait_for_body_text=True)
# navigator.doNotTrack defaults to null in Chrome, "unspecified" in Firefox
self.assertEqual(
self.driver.find_element_by_tag_name('body').text[0:5],
'unset',
"navigator.DoNotTrack should have been left unset"
)
self.assertEqual(
self.js("return navigator.globalPrivacyControl"),
None,
"navigator.globalPrivacyControl should have been left unset"
)
if __name__ == "__main__":
unittest.main()
|