tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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        )