summaryrefslogtreecommitdiffstats
path: root/tests/selenium/dnt_test.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/selenium/dnt_test.py324
1 files changed, 324 insertions, 0 deletions
diff --git a/tests/selenium/dnt_test.py b/tests/selenium/dnt_test.py
new file mode 100644
index 0000000..fb3fdf8
--- /dev/null
+++ b/tests/selenium/dnt_test.py
@@ -0,0 +1,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()