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
|
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import unittest
import pbtest
from functools import partial
from pbtest import retry_until
class FingerprintingTest(pbtest.PBSeleniumTest):
"""Tests to make sure fingerprinting detection works as expected."""
def detected_fingerprinting(self, domain):
return self.js("""let tracker_origin = window.getBaseDomain("{}");
let tabData = chrome.extension.getBackgroundPage().badger.tabData;
return (
Object.keys(tabData).some(tab_id => {{
let fpData = tabData[tab_id].fpData;
return fpData &&
fpData.hasOwnProperty(tracker_origin) &&
fpData[tracker_origin].canvas &&
fpData[tracker_origin].canvas.fingerprinting === true;
}})
);""".format(domain))
def detected_tracking(self, domain, page_url):
return self.js("""let tracker_origin = window.getBaseDomain("{}"),
site_origin = window.getBaseDomain((new URI("{}")).host),
map = chrome.extension.getBackgroundPage().badger.storage.snitch_map.getItemClones();
return (
map.hasOwnProperty(tracker_origin) &&
map[tracker_origin].indexOf(site_origin) != -1
);""".format(domain, page_url))
def get_fillText_source(self):
return self.js("""
const canvas = document.getElementById("writetome");
const ctx = canvas.getContext("2d");
return ctx.fillText.toString();
""")
def setUp(self):
# enable local learning
self.load_url(self.options_url)
self.wait_for_script("return window.OPTIONS_INITIALIZED")
self.find_el_by_css('#local-learning-checkbox').click()
# TODO can fail because our content script runs too late: https://crbug.com/478183
@pbtest.repeat_if_failed(3)
def test_canvas_fingerprinting_detection(self):
FIXTURE_URL = (
"https://efforg.github.io/privacybadger-test-fixtures/html/"
"fingerprinting.html"
)
FINGERPRINTING_DOMAIN = "cdn.jsdelivr.net"
# clear pre-trained/seed tracker data
self.load_url(self.options_url)
self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
# visit the page
self.load_url(FIXTURE_URL)
# now open a new window (to avoid clearing badger.tabData)
# and verify results
self.open_window()
# check that we detected the fingerprinting domain as a tracker
self.load_url(self.options_url)
# TODO unnecessary retrying?
self.assertTrue(
retry_until(partial(self.detected_tracking, FINGERPRINTING_DOMAIN, FIXTURE_URL)),
"Canvas fingerprinting resource was detected as a tracker.")
# check that we detected canvas fingerprinting
self.assertTrue(
self.detected_fingerprinting(FINGERPRINTING_DOMAIN),
"Canvas fingerprinting resource was detected as a fingerprinter."
)
# Privacy Badger overrides a few functions on canvas contexts to check for fingerprinting.
# In previous versions, it would restore the native function after a single call. Unfortunately,
# this would wipe out polyfills that had also overridden the same functions, such as the very
# popular "hidpi-canvas-polyfill".
def test_canvas_polyfill_clobbering(self):
FIXTURE_URL = (
"https://efforg.github.io/privacybadger-test-fixtures/html/"
"fingerprinting_canvas_hidpi.html"
)
# visit the page
self.load_url(FIXTURE_URL)
# check that we did not restore the native function (should be hipdi polyfill)
self.assertNotIn("[native code]", self.get_fillText_source(),
"Canvas context fillText is not native version (polyfill has been retained)."
)
if __name__ == "__main__":
unittest.main()
|