tor-browser

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

browser_ProxyPerUserContextManager.js (12330B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const { ContextualIdentityListener } = ChromeUtils.importESModule(
      8  "chrome://remote/content/shared/listeners/ContextualIdentityListener.sys.mjs"
      9 );
     10 
     11 const { HttpServer } = ChromeUtils.importESModule(
     12  "resource://testing-common/httpd.sys.mjs"
     13 );
     14 
     15 // eslint-disable-next-line mozilla/no-redeclare-with-import-autofix
     16 const { ProxyConfiguration } = ChromeUtils.importESModule(
     17  "chrome://remote/content/shared/webdriver/Capabilities.sys.mjs"
     18 );
     19 
     20 const { ProxyPerUserContextManager } = ChromeUtils.importESModule(
     21  "chrome://remote/content/webdriver-bidi/ProxyPerUserContextManager.sys.mjs"
     22 );
     23 
     24 const gOverride = Cc["@mozilla.org/network/native-dns-override;1"].getService(
     25  Ci.nsINativeDNSResolverOverride
     26 );
     27 
     28 add_setup(async function () {
     29  await SpecialPowers.pushPrefEnv({
     30    set: [["network.proxy.allow_hijacking_localhost", true]],
     31  });
     32  gOverride.addIPOverride("test1.example.com", "127.0.0.1");
     33 
     34  registerCleanupFunction(async () => {
     35    gOverride.clearOverrides();
     36  });
     37 });
     38 
     39 add_task(async function test_manual_http_proxy_per_user_context() {
     40  const [serverURL, proxyURL] = createHTTPProxy();
     41 
     42  const proxyManager = new ProxyPerUserContextManager();
     43 
     44  const userContext = ContextualIdentityService.create("test_name");
     45  const { userContextId } = userContext;
     46 
     47  const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
     48    userContextId,
     49  });
     50  const browserInUserContext = tabInUserContext.linkedBrowser;
     51 
     52  info("Set up a manual proxy for user context");
     53  const proxyConfiguration = ProxyConfiguration.fromJSON({
     54    proxyType: "manual",
     55    httpProxy: proxyURL,
     56  });
     57  proxyManager.addConfiguration(userContextId, proxyConfiguration);
     58 
     59  info("Verify that navigation request in user context is proxied");
     60  await isPageProxied(browserInUserContext, serverURL);
     61 
     62  const tabInDefaultUserContext = BrowserTestUtils.addTab(gBrowser, serverURL);
     63  const browserInDefaultUserContext = tabInDefaultUserContext.linkedBrowser;
     64 
     65  info("Verify that navigation request in default user context is not proxied");
     66  await isPageNotProxied(browserInDefaultUserContext, serverURL);
     67 
     68  info("Destroy proxy manager");
     69  proxyManager.destroy();
     70 
     71  info("Verify that navigation request in user context is not proxied");
     72  await isPageNotProxied(browserInUserContext, serverURL);
     73 
     74  BrowserTestUtils.removeTab(tabInUserContext);
     75  ContextualIdentityService.remove(userContextId);
     76  BrowserTestUtils.removeTab(tabInDefaultUserContext);
     77 });
     78 
     79 add_task(async function test_manual_http_proxy_per_user_context_with_noProxy() {
     80  const [serverURL, proxyURL] = createHTTPProxy();
     81 
     82  const proxyManager = new ProxyPerUserContextManager();
     83 
     84  const userContext = ContextualIdentityService.create("test_name");
     85  const { userContextId } = userContext;
     86 
     87  const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
     88    userContextId,
     89  });
     90  const browserInUserContext = tabInUserContext.linkedBrowser;
     91 
     92  info("Set up a manual proxy for user context with `noProxy` field");
     93  const proxyConfiguration = ProxyConfiguration.fromJSON({
     94    proxyType: "manual",
     95    httpProxy: proxyURL,
     96    noProxy: ["test1.example.com"],
     97  });
     98  proxyManager.addConfiguration(userContextId, proxyConfiguration);
     99 
    100  info("Verify that navigation request is not proxied");
    101  await isPageNotProxied(browserInUserContext, serverURL);
    102 
    103  proxyManager.destroy();
    104 
    105  BrowserTestUtils.removeTab(tabInUserContext);
    106  ContextualIdentityService.remove(userContextId);
    107 });
    108 
    109 add_task(
    110  async function test_manual_http_proxy_per_user_context_with_noProxy_with_url_pattern() {
    111    const [serverURL, proxyURL, secondServerURL] = createHTTPProxy();
    112 
    113    const proxyManager = new ProxyPerUserContextManager();
    114 
    115    const userContext = ContextualIdentityService.create("test_name");
    116    const { userContextId } = userContext;
    117 
    118    const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
    119      userContextId,
    120    });
    121    const browserInUserContext = tabInUserContext.linkedBrowser;
    122 
    123    info(
    124      "Set up a manual proxy for user context with `noProxy` field for an URL pattern"
    125    );
    126    const proxyConfiguration = ProxyConfiguration.fromJSON({
    127      proxyType: "manual",
    128      httpProxy: proxyURL,
    129      noProxy: [".example.com"],
    130    });
    131    proxyManager.addConfiguration(userContextId, proxyConfiguration);
    132 
    133    info("Verify that navigation request is not proxied");
    134    await isPageNotProxied(browserInUserContext, serverURL);
    135 
    136    info("Verify that navigation to url not matching the pattern is proxied");
    137    await isPageProxied(browserInUserContext, secondServerURL);
    138 
    139    proxyManager.destroy();
    140 
    141    BrowserTestUtils.removeTab(tabInUserContext);
    142    ContextualIdentityService.remove(userContextId);
    143  }
    144 );
    145 
    146 add_task(async function test_override_manual_http_proxy_per_user_context() {
    147  const [serverURL, proxyURL] = createHTTPProxy();
    148 
    149  const proxyManager = new ProxyPerUserContextManager();
    150 
    151  const userContext = ContextualIdentityService.create("test_name");
    152  const { userContextId } = userContext;
    153 
    154  const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
    155    userContextId,
    156  });
    157  const browserInUserContext = tabInUserContext.linkedBrowser;
    158 
    159  info("Set up a manual proxy for user context");
    160  const proxyConfiguration = ProxyConfiguration.fromJSON({
    161    proxyType: "manual",
    162    httpProxy: proxyURL,
    163  });
    164  proxyManager.addConfiguration(userContextId, proxyConfiguration);
    165 
    166  info("Verify that navigation request is proxied");
    167  await isPageProxied(browserInUserContext, serverURL);
    168 
    169  info("Set a new proxy configuration for user context with direct proxy");
    170  const newProxyConfiguration = ProxyConfiguration.fromJSON({
    171    proxyType: "direct",
    172  });
    173  proxyManager.addConfiguration(userContextId, newProxyConfiguration);
    174 
    175  info("Verify that navigation request is not proxied");
    176  await isPageNotProxied(browserInUserContext, serverURL);
    177 
    178  proxyManager.destroy();
    179 
    180  BrowserTestUtils.removeTab(tabInUserContext);
    181  ContextualIdentityService.remove(userContextId);
    182 });
    183 
    184 add_task(
    185  async function test_override_global_manual_proxy_with_direct_proxy_per_user_context() {
    186    const [serverURL, proxyURL] = createHTTPProxy();
    187 
    188    info("Set up a global manual proxy");
    189    const globalProxy = ProxyConfiguration.fromJSON({
    190      proxyType: "manual",
    191      httpProxy: proxyURL,
    192    });
    193 
    194    globalProxy.init();
    195 
    196    const tabInDefaultUserContext = BrowserTestUtils.addTab(
    197      gBrowser,
    198      serverURL
    199    );
    200    const browserInDefaultUserContext = tabInDefaultUserContext.linkedBrowser;
    201 
    202    info("Verify that navigation request is proxied");
    203    await isPageProxied(browserInDefaultUserContext, serverURL);
    204 
    205    const proxyManager = new ProxyPerUserContextManager();
    206 
    207    const userContext = ContextualIdentityService.create("test_name");
    208    const { userContextId } = userContext;
    209 
    210    const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
    211      userContextId,
    212    });
    213    const browserInUserContext = tabInUserContext.linkedBrowser;
    214 
    215    info("Set up a direct proxy for user context");
    216    const proxyConfiguration = ProxyConfiguration.fromJSON({
    217      proxyType: "direct",
    218    });
    219    proxyManager.addConfiguration(userContextId, proxyConfiguration);
    220 
    221    info("Verify that navigation request is not proxied");
    222    await isPageNotProxied(browserInUserContext, serverURL);
    223 
    224    proxyManager.destroy();
    225 
    226    globalProxy.destroy();
    227 
    228    BrowserTestUtils.removeTab(tabInUserContext);
    229    ContextualIdentityService.remove(userContextId);
    230    BrowserTestUtils.removeTab(tabInDefaultUserContext);
    231  }
    232 );
    233 
    234 add_task(
    235  async function test_override_global_system_proxy_with_direct_proxy_per_user_context() {
    236    const [serverURL] = createHTTPProxy();
    237 
    238    info("Set up a global system proxy");
    239    const globalProxy = ProxyConfiguration.fromJSON({
    240      proxyType: "system",
    241    });
    242 
    243    globalProxy.init();
    244 
    245    const proxyManager = new ProxyPerUserContextManager();
    246 
    247    const userContext = ContextualIdentityService.create("test_name");
    248    const { userContextId } = userContext;
    249 
    250    const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
    251      userContextId,
    252    });
    253    const browserInUserContext = tabInUserContext.linkedBrowser;
    254 
    255    info("Set up a direct proxy for user context");
    256    const proxyConfiguration = ProxyConfiguration.fromJSON({
    257      proxyType: "direct",
    258    });
    259 
    260    proxyManager.addConfiguration(userContextId, proxyConfiguration);
    261 
    262    info("Verify that navigation request is not proxied");
    263    await isPageNotProxied(browserInUserContext, serverURL);
    264 
    265    proxyManager.destroy();
    266 
    267    globalProxy.destroy();
    268 
    269    BrowserTestUtils.removeTab(tabInUserContext);
    270    ContextualIdentityService.remove(userContextId);
    271  }
    272 );
    273 
    274 add_task(
    275  async function test_delete_configuration_for_manual_http_proxy_per_user_context() {
    276    const [serverURL, proxyURL] = createHTTPProxy();
    277 
    278    const proxyManager = new ProxyPerUserContextManager();
    279 
    280    const userContext = ContextualIdentityService.create("test_name");
    281    const { userContextId } = userContext;
    282 
    283    const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, {
    284      userContextId,
    285    });
    286    const browserInUserContext = tabInUserContext.linkedBrowser;
    287 
    288    info("Set up a manual proxy for user context");
    289    const proxyConfiguration = ProxyConfiguration.fromJSON({
    290      proxyType: "manual",
    291      httpProxy: proxyURL,
    292    });
    293    proxyManager.addConfiguration(userContextId, proxyConfiguration);
    294 
    295    info("Verify that navigation request is proxied");
    296    await isPageProxied(browserInUserContext, serverURL);
    297 
    298    info("Delete the proxy configuration");
    299    proxyManager.deleteConfiguration(userContextId);
    300 
    301    info("Verify that navigation request is not proxied");
    302    await isPageNotProxied(browserInUserContext, serverURL);
    303 
    304    info("Try to delete the configuration again");
    305    proxyManager.deleteConfiguration(userContextId);
    306 
    307    proxyManager.destroy();
    308 
    309    BrowserTestUtils.removeTab(tabInUserContext);
    310    ContextualIdentityService.remove(userContextId);
    311  }
    312 );
    313 
    314 function createHTTPProxy() {
    315  const server = new HttpServer();
    316  server.start(-1);
    317  server.identity.add("http", "test1.example.com", server.identity.primaryPort);
    318  server.identity.add("http", "example.com", server.identity.primaryPort);
    319  server.registerPathHandler("/", (request, response) => {
    320    response.setStatusLine(request.httpVersion, 200, "OK");
    321    response.setHeader("Content-Type", "text/plain", true);
    322    response.write("Not proxied");
    323  });
    324 
    325  const proxyServer = new HttpServer();
    326  proxyServer.start(-1);
    327  proxyServer.identity.add(
    328    "http",
    329    "test1.example.com",
    330    server.identity.primaryPort
    331  );
    332  proxyServer.identity.add("http", "example.com", server.identity.primaryPort);
    333  proxyServer.registerPathHandler("/", (request, response) => {
    334    response.setStatusLine(request.httpVersion, 200, "OK");
    335    response.setHeader("Content-Type", "text/plain", true);
    336    response.write("Proxied");
    337  });
    338 
    339  registerCleanupFunction(async () => {
    340    await server.stop();
    341    await proxyServer.stop();
    342  });
    343 
    344  return [
    345    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    346    `http://test1.example.com:${server.identity.primaryPort}`,
    347    `localhost:${proxyServer.identity.primaryPort}`,
    348    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    349    `http://example.com:${server.identity.primaryPort}`,
    350  ];
    351 }
    352 
    353 async function isPageProxied(browser, url) {
    354  await loadPage(browser, url);
    355  return SpecialPowers.spawn(browser, [], async () => {
    356    Assert.strictEqual(
    357      content.document.body.textContent,
    358      "Proxied",
    359      "The page was proxied"
    360    );
    361  });
    362 }
    363 
    364 async function isPageNotProxied(browser, url) {
    365  await loadPage(browser, url);
    366  return SpecialPowers.spawn(browser, [], async () => {
    367    Assert.strictEqual(
    368      content.document.body.textContent,
    369      "Not proxied",
    370      "The page was not proxied"
    371    );
    372  });
    373 }
    374 
    375 async function loadPage(browser, url) {
    376  const loadedPromise = BrowserTestUtils.browserLoaded(browser);
    377  BrowserTestUtils.startLoadingURIString(browser, url);
    378  return loadedPromise;
    379 }