diff --git a/doc/tests.md b/doc/tests.md index 1c99a0b191..b04af050fb 100644 --- a/doc/tests.md +++ b/doc/tests.md @@ -50,9 +50,11 @@ the code below. This should take several minutes. $ BROWSER=chrome pytest -v ``` -macOS users may need to provide the full path to the browser application folder. For example, to run tests on macOS in Firefox: +macOS users may need to provide the full path to the browser application folder. For example, to run tests on macOS: ```bash $ BROWSER=/Applications/Firefox.app/Contents/MacOS/firefox-bin pytest -v +# or +$ BROWSER=/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome pytest -v ``` For more information, see our Travis CI [setup](/scripts/setup_travis.sh) and diff --git a/src/js/contentscripts/fingerprinting.js b/src/js/contentscripts/fingerprinting.js index 28cdb4641b..b6dbb2ea0e 100644 --- a/src/js/contentscripts/fingerprinting.js +++ b/src/js/contentscripts/fingerprinting.js @@ -204,14 +204,19 @@ function getFpPageScript() { ); item.obj[item.propName] = (function (orig) { + // set to true after the first write, if the method is not + // restorable. Happens if another library also overwrites + // this method. + var skip_monitoring = false; function wrapped() { var args = arguments; if (is_canvas_write) { // to avoid false positives, - // bail if the text being written is too short - if (!args[0] || args[0].length < 5) { + // bail if the text being written is too short, + // of if we've already sent a monitoring payload + if (skip_monitoring || !args[0] || args[0].length < 5) { return orig.apply(this, args); } } @@ -237,7 +242,13 @@ function getFpPageScript() { // optimization: one canvas write is enough, // restore original write method // to this CanvasRenderingContext2D object instance - this[item.propName] = orig; + // Careful! Only restorable if we haven't already been replaced + // by another lib, such as the hidpi polyfill + if (this[item.propName] === wrapped) { + this[item.propName] = orig; + } else { + skip_monitoring = true; + } } return orig.apply(this, args); diff --git a/tests/selenium/fingerprinting_test.py b/tests/selenium/fingerprinting_test.py index 657999937a..6e1d22d09c 100644 --- a/tests/selenium/fingerprinting_test.py +++ b/tests/selenium/fingerprinting_test.py @@ -36,6 +36,13 @@ def detected_tracking(self, domain, page_url): 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(); + """) + # 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): @@ -69,6 +76,24 @@ def test_canvas_fingerprinting_detection(self): "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() diff --git a/tests/selenium/pbtest.py b/tests/selenium/pbtest.py index 88b72b421c..cc18a0f243 100644 --- a/tests/selenium/pbtest.py +++ b/tests/selenium/pbtest.py @@ -44,7 +44,7 @@ def unix_which(command, silent=False): def get_browser_type(string): for t in BROWSER_TYPES: - if t in string: + if t in string.lower(): return t raise ValueError("couldn't get browser type from %s" % string)