test_circuit_isolation.py (3943B)
1 from ipaddress import ip_address 2 3 from marionette_driver import By 4 from marionette_driver.errors import NoSuchElementException 5 from marionette_harness import MarionetteTestCase 6 7 TOR_BOOTSTRAP_TIMEOUT = 30000 # 30s 8 9 10 class TestCircuitIsolation(MarionetteTestCase): 11 def tearDown(self): 12 self.marionette.restart(in_app=False, clean=True) 13 super().tearDown() 14 15 def bootstrap(self): 16 with self.marionette.using_context("chrome"): 17 self.marionette.execute_async_script( 18 """ 19 const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule( 20 "resource://gre/modules/TorConnect.sys.mjs" 21 ); 22 const [resolve] = arguments; 23 24 function waitForBootstrap() { 25 const topic = TorConnectTopics.BootstrapComplete; 26 Services.obs.addObserver(function observer() { 27 Services.obs.removeObserver(observer, topic); 28 resolve(); 29 }, topic); 30 TorConnect.beginBootstrapping(); 31 } 32 33 const stageTopic = TorConnectTopics.StageChange; 34 function stageObserver() { 35 if (TorConnect.canBeginNormalBootstrap) { 36 Services.obs.removeObserver(stageObserver, stageTopic); 37 waitForBootstrap(); 38 } 39 } 40 Services.obs.addObserver(stageObserver, stageTopic); 41 stageObserver(); 42 """, 43 script_timeout=TOR_BOOTSTRAP_TIMEOUT, 44 ) 45 46 def extract_from_check_tpo(self): 47 # Fetch the IP from check.torproject.org. 48 # In addition to that, since we are loading this page, we 49 # perform some additional sanity checks. 50 self.marionette.navigate("https://check.torproject.org/") 51 # When check.tpo's check succeed (i.e., it thinks we're 52 # connecting through tor), we should be able to find a h1.on, 53 # with some message... 54 on = self.marionette.find_element(By.CLASS_NAME, "on") 55 self.assertIsNotNone( 56 on, 57 "h1.on not found, you might not be connected through tor", 58 ) 59 # ... but if it fails, the message is inside a h1.off. We want 60 # to make sure we do not find that either (even though there is 61 # no reason for both of the h1 to be outputted at the moment). 62 self.assertRaises( 63 NoSuchElementException, 64 self.marionette.find_element, 65 By.CLASS_NAME, 66 "off", 67 ) 68 ip = self.marionette.find_element(By.TAG_NAME, "strong") 69 return ip_address(ip.text.strip()) 70 71 def extract_generic(self, url): 72 # Fetch the IP address from any generic page that only contains 73 # the address. 74 self.marionette.navigate(url) 75 return ip_address( 76 self.marionette.execute_script( 77 "return document.documentElement.textContent" 78 ).strip() 79 ) 80 81 def test_circuit_isolation(self): 82 self.bootstrap() 83 ips = [ 84 self.extract_from_check_tpo(), 85 self.extract_generic("https://am.i.mullvad.net/ip"), 86 self.extract_generic("https://test1.ifconfig.me/ip"), 87 ] 88 self.logger.info(f"Found the following IP addresses: {ips}") 89 unique_ips = set(ips) 90 self.logger.info(f"Found the following unique IP addresses: {unique_ips}") 91 self.assertEqual( 92 len(ips), 93 len(unique_ips), 94 "Some of the IP addresses we got are not unique.", 95 ) 96 duplicate = self.extract_generic("https://test2.ifconfig.me/ip") 97 self.assertEqual( 98 ips[-1], 99 duplicate, 100 "Two IPs that were expected to be equal are different, we might be over isolating!", 101 )