tor-browser

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

common.js (4688B)


      1 const executor_path = '/common/dispatcher/executor.html?pipe=';
      2 const executor_worker_path = '/common/dispatcher/executor-worker.js?pipe=';
      3 const executor_service_worker_path = '/common/dispatcher/executor-service-worker.js?pipe=';
      4 
      5 // COEP
      6 const coep_none =
      7    '|header(Cross-Origin-Embedder-Policy,none)';
      8 const coep_credentialless =
      9    '|header(Cross-Origin-Embedder-Policy,credentialless)';
     10 const coep_require_corp =
     11    '|header(Cross-Origin-Embedder-Policy,require-corp)';
     12 
     13 // COEP-Report-Only
     14 const coep_report_only_credentialless =
     15    '|header(Cross-Origin-Embedder-Policy-Report-Only,credentialless)';
     16 
     17 // COOP
     18 const coop_same_origin =
     19    '|header(Cross-Origin-Opener-Policy,same-origin)';
     20 
     21 // CORP
     22 const corp_cross_origin =
     23    '|header(Cross-Origin-Resource-Policy,cross-origin)';
     24 
     25 const cookie_same_site_none = ';SameSite=None;Secure';
     26 
     27 // Test using the modern async/await primitives are easier to read/write.
     28 // However they run sequentially, contrary to async_test. This is the parallel
     29 // version, to avoid timing out.
     30 let promise_test_parallel = (promise, description) => {
     31  async_test(test => {
     32    promise(test)
     33      .then(() => test.done())
     34      .catch(test.step_func(error => { throw error; }));
     35  }, description);
     36 };
     37 
     38 // Add a cookie |cookie_key|=|cookie_value| on an |origin|.
     39 // Note: cookies visibility depends on the path of the document. Those are set
     40 // from a document from: /html/cross-origin-embedder-policy/credentialless/. So
     41 // the cookie is visible to every path underneath.
     42 const setCookie = async (origin, cookie_key, cookie_value) => {
     43  const popup_token = token();
     44  const popup_url = origin + executor_path + `&uuid=${popup_token}`;
     45  const popup = window.open(popup_url);
     46 
     47  const reply_token = token();
     48  send(popup_token, `
     49    document.cookie = "${cookie_key}=${cookie_value}";
     50    send("${reply_token}", "done");
     51  `);
     52  assert_equals(await receive(reply_token), "done");
     53  popup.close();
     54 }
     55 
     56 let parseCookies = function(headers_json) {
     57  if (!headers_json["cookie"])
     58    return {};
     59 
     60  return headers_json["cookie"]
     61    .split(';')
     62    .map(v => v.split('='))
     63    .reduce((acc, v) => {
     64      acc[v[0].trim()] = v[1].trim();
     65      return acc;
     66    }, {});
     67 }
     68 
     69 // Open a new window with a given |origin|, loaded with COEP:credentialless. The
     70 // new document will execute any scripts sent toward the token it returns.
     71 const newCredentiallessWindow = (origin) => {
     72  const main_document_token = token();
     73  const url = origin + executor_path + coep_credentialless +
     74    `&uuid=${main_document_token}`;
     75  const context = window.open(url);
     76  add_completion_callback(() => w.close());
     77  return main_document_token;
     78 };
     79 
     80 // Create a new iframe, loaded with COEP:credentialless.
     81 // The new document will execute any scripts sent toward the token it returns.
     82 const newCredentiallessIframe = (parent_token, child_origin) => {
     83  const sub_document_token = token();
     84  const iframe_url = child_origin + executor_path + coep_credentialless +
     85    `&uuid=${sub_document_token}`;
     86  send(parent_token, `
     87    let iframe = document.createElement("iframe");
     88    iframe.src = "${iframe_url}";
     89    document.body.appendChild(iframe);
     90  `)
     91  return sub_document_token;
     92 };
     93 
     94 // A common interface for building the 4 type of execution contexts:
     95 // It outputs: [
     96 //   - The token to communicate with the environment.
     97 //   - A promise resolved when the environment encounters an error.
     98 // ]
     99 const environments = {
    100  document: headers => {
    101    const tok = token();
    102    const url = window.origin + executor_path + headers + `&uuid=${tok}`;
    103    const context = window.open(url);
    104    add_completion_callback(() => context.close());
    105    return [tok, new Promise(resolve => {})];
    106  },
    107 
    108  dedicated_worker: headers => {
    109    const tok = token();
    110    const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
    111    const context = new Worker(url);
    112    return [tok, new Promise(resolve => context.onerror = resolve)];
    113  },
    114 
    115  shared_worker: headers => {
    116    const tok = token();
    117    const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
    118    const context = new SharedWorker(url);
    119    return [tok, new Promise(resolve => context.onerror = resolve)];
    120  },
    121 
    122  service_worker: headers => {
    123    const tok = token();
    124    const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
    125    const scope = url; // Generate a one-time scope for service worker.
    126    const error = new Promise(resolve => {
    127      navigator.serviceWorker.register(url, {scope: scope})
    128        .then(registration => {
    129          add_completion_callback(() => registration.unregister());
    130        }, /* catch */ resolve);
    131    });
    132    return [tok, error];
    133  },
    134 };