tor-browser

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

browser_target_server_compartment.js (4255B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Bug 1515290 - Ensure that DevToolsServer runs in its own compartment when debugging
      5 // chrome context. If not, Debugger API's addGlobal will throw when trying to attach
      6 // to chrome scripts as debugger actor's module and the chrome script will be in the same
      7 // compartment. Debugger and debuggee can't be running in the same compartment.
      8 
      9 const CHROME_PAGE =
     10  "chrome://mochitests/content/browser/devtools/client/framework/" +
     11  "test/test_chrome_page.html";
     12 
     13 add_task(async function () {
     14  await testChromeTab();
     15  await testMainProcess();
     16 });
     17 
     18 // Test that Tab Target can debug chrome pages
     19 async function testChromeTab() {
     20  const tab = await addTab(CHROME_PAGE);
     21  const browser = tab.linkedBrowser;
     22  ok(!browser.isRemoteBrowser, "chrome page is not remote");
     23  ok(
     24    browser.contentWindow.document.nodePrincipal.isSystemPrincipal,
     25    "chrome page is a privileged document"
     26  );
     27 
     28  const onThreadActorInstantiated = new Promise(resolve => {
     29    const observe = function (subject, topic) {
     30      if (topic === "devtools-thread-ready") {
     31        Services.obs.removeObserver(observe, "devtools-thread-ready");
     32        const threadActor = subject.wrappedJSObject;
     33        resolve(threadActor);
     34      }
     35    };
     36    Services.obs.addObserver(observe, "devtools-thread-ready");
     37  });
     38 
     39  const commands = await CommandsFactory.forTab(tab);
     40  await commands.targetCommand.startListening();
     41 
     42  const sources = [];
     43  await commands.resourceCommand.watchResources(
     44    [commands.resourceCommand.TYPES.SOURCE],
     45    {
     46      onAvailable(resources) {
     47        sources.push(...resources);
     48      },
     49    }
     50  );
     51  ok(
     52    sources.find(s => s.url == CHROME_PAGE),
     53    "The thread actor is able to attach to the chrome page and its sources"
     54  );
     55 
     56  const threadActor = await onThreadActorInstantiated;
     57  const serverGlobal = Cu.getGlobalForObject(threadActor);
     58  isnot(
     59    loader.id,
     60    serverGlobal.loader.id,
     61    "The actors are loaded in a distinct loader in order for the actors to use its very own compartment"
     62  );
     63 
     64  const onDedicatedLoaderDestroy = new Promise(resolve => {
     65    const observe = function (subject, topic) {
     66      if (topic === "devtools:loader:destroy") {
     67        Services.obs.removeObserver(observe, "devtools:loader:destroy");
     68        resolve();
     69      }
     70    };
     71    Services.obs.addObserver(observe, "devtools:loader:destroy");
     72  });
     73 
     74  await commands.destroy();
     75 
     76  // Wait for the dedicated loader used for DevToolsServer to be destroyed
     77  // in order to prevent leak reports on try
     78  await onDedicatedLoaderDestroy;
     79 }
     80 
     81 // Test that Main process Target can debug chrome scripts
     82 async function testMainProcess() {
     83  const onThreadActorInstantiated = new Promise(resolve => {
     84    const observe = function (subject, topic) {
     85      if (topic === "devtools-thread-ready") {
     86        Services.obs.removeObserver(observe, "devtools-thread-ready");
     87        const threadActor = subject.wrappedJSObject;
     88        resolve(threadActor);
     89      }
     90    };
     91    Services.obs.addObserver(observe, "devtools-thread-ready");
     92  });
     93 
     94  const client = await CommandsFactory.spawnClientToDebugSystemPrincipal();
     95  const commands = await CommandsFactory.forMainProcess({ client });
     96  await commands.targetCommand.startListening();
     97 
     98  const sources = [];
     99  await commands.resourceCommand.watchResources(
    100    [commands.resourceCommand.TYPES.SOURCE],
    101    {
    102      onAvailable(resources) {
    103        sources.push(...resources);
    104      },
    105    }
    106  );
    107  ok(
    108    sources.find(
    109      s => s.url == "resource://devtools/client/framework/devtools.js"
    110    ),
    111    "The thread actor is able to attach to the chrome script, like client modules"
    112  );
    113 
    114  const threadActor = await onThreadActorInstantiated;
    115  const serverGlobal = Cu.getGlobalForObject(threadActor);
    116  isnot(
    117    loader.id,
    118    serverGlobal.loader.id,
    119    "The actors are loaded in a distinct loader in order for the actors to use its very own compartment"
    120  );
    121 
    122  // As this target is remote (i.e. isn't a local tab) calling Target.destroy won't close
    123  // the client. So do it manually here in order to ensure cleaning up the DevToolsServer
    124  // spawn for this main process actor.
    125  await commands.destroy();
    126 }