def _check_calls( self, db, symbol_prefix, doc_url, top_url, expected_method_calls, expected_gets_and_sets, ): """Helper to check method calls and accesses in each frame""" rows = db_utils.get_javascript_entries(db, all_columns=True) observed_gets_and_sets = set() observed_calls = set() for row in rows: if not row["symbol"].startswith(symbol_prefix): continue symbol = re.sub(symbol_prefix, "", row["symbol"]) assert row["document_url"] == doc_url assert row["top_level_url"] == top_url if row["operation"] == "get" or row["operation"] == "set": observed_gets_and_sets.add( (symbol, row["operation"], row["value"])) else: observed_calls.add( (symbol, row["operation"], row["arguments"])) assert observed_calls == expected_method_calls assert observed_gets_and_sets == expected_gets_and_sets
def test_audio_fingerprinting(self): db = self.visit("/audio_fingerprinting.html") # Check that all calls and methods are recorded rows = db_utils.get_javascript_entries(db) observed_symbols = set() for item in rows: observed_symbols.add(item[1]) assert AUDIO_SYMBOLS == observed_symbols
def test_js_time_stamp(self): # Check that timestamp is recorded correctly for the javascript table MAX_TIMEDELTA = 60 # max time diff in seconds db = self.visit("/js_call_stack.html") utc_now = datetime.utcnow() # OpenWPM stores timestamp in UTC time rows = db_utils.get_javascript_entries(db, all_columns=True) assert len(rows) # make sure we have some JS events captured for row in rows: js_time = datetime.strptime(row["time_stamp"], "%Y-%m-%dT%H:%M:%S.%fZ") # compare UTC now and the timestamp recorded at the visit assert (utc_now - js_time).seconds < MAX_TIMEDELTA assert not db_utils.any_command_failed(db)
def test_canvas_fingerprinting(self): db = self.visit("/canvas_fingerprinting.html") # Check that all calls and methods are recorded rows = db_utils.get_javascript_entries(db) observed_rows = set() for row in rows: item = ( row["script_url"], row["symbol"], row["operation"], row["value"], row["arguments"], ) observed_rows.add(item) assert CANVAS_CALLS == observed_rows
def test_document_cookie_instrumentation(self): db = self.visit(utilities.BASE_TEST_URL + "/js_cookie.html") rows = db_utils.get_javascript_entries(db, all_columns=True) captured_cookie_calls = set() for row in rows: item = ( row["script_url"], row["script_line"], row["script_col"], row["func_name"], row["script_loc_eval"], row["call_stack"], row["symbol"], row["operation"], row["value"], ) captured_cookie_calls.add(item) assert captured_cookie_calls == DOCUMENT_COOKIE_READ_WRITE
def test_js_call_stack(self): db = self.visit("/js_call_stack.html") # Check that all stack info are recorded rows = db_utils.get_javascript_entries(db, all_columns=True) observed_rows = set() for row in rows: item = ( row["script_url"], row["script_line"], row["script_col"], row["func_name"], row["script_loc_eval"], row["call_stack"], row["symbol"], row["operation"], ) observed_rows.add(item) assert JS_STACK_CALLS == observed_rows
def test_webrtc_localip(self): db = self.visit("/webrtc_localip.html") # Check that all calls and methods are recorded rows = db_utils.get_javascript_entries(db) observed_rows = set() for row in rows: if row["symbol"] == "RTCPeerConnection.setLocalDescription" and ( row["operation"] == "call"): sdp_offer = row["arguments"] self.check_webrtc_sdp_offer(sdp_offer) else: item = ( row["script_url"], row["symbol"], row["operation"], row["value"], row["arguments"], ) observed_rows.add(item) assert WEBRTC_CALLS == observed_rows
def test_instrument_object(self): """Ensure instrumentObject logs all property gets, sets, and calls""" db = self.visit("/js_instrument/instrument_object.html") self._check_calls( db=db, symbol_prefix="window.test.", doc_url=self.TOP_URL, top_url=self.TOP_URL, expected_method_calls=self.METHOD_CALLS, expected_gets_and_sets=self.GETS_AND_SETS, ) self._check_calls( db=db, symbol_prefix="window.frame1Test.", doc_url=self.FRAME1_URL, top_url=self.TOP_URL, expected_method_calls=self.METHOD_CALLS, expected_gets_and_sets=self.GETS_AND_SETS, ) self._check_calls( db=db, symbol_prefix="window.frame2Test.", doc_url=self.FRAME2_URL, top_url=self.TOP_URL, expected_method_calls=self.METHOD_CALLS, expected_gets_and_sets=self.GETS_AND_SETS, ) # Check calls of recursive instrumentation observed_gets_and_sets = set() observed_calls = set() rows = db_utils.get_javascript_entries(db, all_columns=True) for row in rows: if not row["symbol"].startswith("window.test2.nestedObj"): continue assert row["document_url"] == self.TOP_URL assert row["top_level_url"] == self.TOP_URL if row["operation"] == "get" or row["operation"] == "set": observed_gets_and_sets.add( (row["symbol"], row["operation"], row["value"])) else: observed_calls.add( (row["symbol"], row["operation"], row["arguments"])) assert observed_calls == self.RECURSIVE_METHOD_CALLS assert observed_gets_and_sets == self.RECURSIVE_GETS_AND_SETS # Check that calls not present after default recursion limit (5) # We should only see the window.test2.l1.l2.l3.l4.l5.prop access # and not window.test2.l1.l2.l3.l4.l5.l6.prop access. prop_access = set() for row in rows: if not row["symbol"].startswith("window.test2.l1"): continue assert row["document_url"] == self.TOP_URL assert row["top_level_url"] == self.TOP_URL prop_access.add((row["symbol"], row["operation"], row["value"])) assert prop_access == self.RECURSIVE_PROP_SET # Check calls of object with sets prevented observed_gets_and_sets = set() observed_calls = set() for row in rows: if not row["symbol"].startswith("window.test3"): continue assert row["document_url"] == self.TOP_URL assert row["top_level_url"] == self.TOP_URL if row["operation"] == "call": observed_calls.add( (row["symbol"], row["operation"], row["arguments"])) else: observed_gets_and_sets.add( (row["symbol"], row["operation"], row["value"])) assert observed_calls == self.SET_PREVENT_CALLS assert observed_gets_and_sets == self.SET_PREVENT_GETS_AND_SETS