tor-browser

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

cross-partition.https.html (19612B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <meta name="timeout" content="long">
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script src="/common/get-host-info.sub.js"></script>
      7 <script src="/common/utils.js"></script>
      8 <script src="/common/dispatcher/dispatcher.js"></script>
      9 <!-- Pull in executor_path needed by newPopup / newIframe -->
     10 <script src="/html/cross-origin-embedder-policy/credentialless/resources/common.js"></script>
     11 <!-- Pull in importScript / newPopup / newIframe -->
     12 <script src="/html/anonymous-iframe/resources/common.js"></script>
     13 <script src="resources/common.js"></script>
     14 <body>
     15 <script>
     16 
     17 const fetch_unsuccessful_response = "Fetch failed";
     18 const fetch_successful_response = "Fetch succeeded";
     19 const js_finished = "revoking blob_url js finished";
     20 
     21 // Fetches a previously revoked blob_url to see if the revoking was successful.
     22 async function fetch_contents_check(blob_url) {
     23  try {
     24    const blob = await fetch(blob_url).then(response => response.blob());
     25    await blob.text();
     26  } catch(e) {
     27    return fetch_unsuccessful_response;
     28  }
     29  return fetch_successful_response;
     30 }
     31 
     32 const can_blob_url_be_revoked_js = (blob_url, response_queue_name) => `
     33  async function test() {
     34    if (!('revokeObjectURL' in URL)) {
     35      return send("${response_queue_name}", "URL.revokeObjectURL is not exposed");
     36    }
     37    try {
     38      URL.revokeObjectURL("${blob_url}");
     39    } catch(e) {
     40      return send("${response_queue_name}", e.toString());
     41    }
     42 
     43    // Create, fetch, and revoke a separate blob URL to better ensure that the
     44    // revoke call above has had time to take effect before we return.
     45    const blob_1 = new Blob(["blob data"], {type : "text/plain"});
     46    const blob_url_1 = URL.createObjectURL(blob_1);
     47    await fetch(blob_url_1).then(response => response.blob());
     48    URL.revokeObjectURL(blob_url_1);
     49 
     50    return send("${response_queue_name}", "${js_finished}");
     51  }
     52  await test();
     53 `;
     54 
     55 const can_blob_url_be_fetched_js = (blob_url, response_queue_name) => `
     56  async function test() {
     57    try {
     58      const blob = await fetch("${blob_url}").then(response => response.blob());
     59      await blob.text();
     60    } catch(e) {
     61      return send("${response_queue_name}", "${fetch_unsuccessful_response}");
     62    }
     63 
     64    return send("${response_queue_name}", "${fetch_successful_response}");
     65  }
     66  await test();
     67 `;
     68 
     69 const same_site_origin = get_host_info().HTTPS_ORIGIN;
     70 
     71 // Tests revoking blob URL for same and cross partition iframes.
     72 promise_test(t => {
     73  return new Promise(async (resolve, reject) => {
     74    try {
     75      // Creates blob URL.
     76      const blob = new Blob(["blob data"], {type : "text/plain"});
     77      const blob_url = window.URL.createObjectURL(blob);
     78 
     79      // Fetches blob URL to ensure that it's valid.
     80      const blob_fetch = await fetch_contents_check(blob_url);
     81      if (blob_fetch !== fetch_successful_response) {
     82        reject("Blob URL invalid");
     83      }
     84 
     85      // Creates same and cross partition iframes.
     86      const response_queue_uuid = token();
     87 
     88      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
     89        await create_test_iframes(t, response_queue_uuid);
     90 
     91      // Attempt to revoke blob URL in cross partition iframe.
     92      await send(cross_site_iframe_uuid, can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
     93      var response_1 = await receive(response_queue_uuid);
     94      if (response_1 !== js_finished) {
     95        reject(response_1);
     96      }
     97      response_1 = await fetch_contents_check(blob_url);
     98      if (response_1 !== fetch_successful_response) {
     99        reject(`Blob URL was revoked in not-same-top-level-site iframe: ${response_1}`);
    100      }
    101 
    102      // Attempt to revoke blob URL in same partition iframe.
    103      await send(same_site_iframe_uuid, can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
    104      var response_2 = await receive(response_queue_uuid);
    105      if (response_2 !== js_finished) {
    106        reject(response_2);
    107      }
    108      response_2 = await fetch_contents_check(blob_url);
    109      if (response_2 !== fetch_unsuccessful_response) {
    110        t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    111        reject(`Blob URL wasn't revoked in same-top-level-site iframe: ${response_2}`);
    112      }
    113 
    114      resolve();
    115    } catch (e) {
    116      reject(e);
    117    }
    118  });
    119 }, "Blob URL shouldn't be revocable from a cross-partition iframe");
    120 
    121 const newWorker = (origin) => {
    122  const worker_token = token();
    123  const worker_url = origin + executor_worker_path + `&uuid=${worker_token}`;
    124  const worker = new Worker(worker_url);
    125  return worker_token;
    126 }
    127 
    128 const create_dedicated_worker_js = (origin, response_queue_uuid) => `
    129  const importScript = ${importScript};
    130  await importScript("/html/cross-origin-embedder-policy/credentialless" +
    131                    "/resources/common.js");
    132  await importScript("/html/anonymous-iframe/resources/common.js");
    133  await importScript("/common/utils.js");
    134 
    135  // dispatcher.js has already been loaded by the popup this is running in.
    136  const newWorker = ${newWorker};
    137  await send("${response_queue_uuid}", newWorker("${origin}"));
    138 `;
    139 
    140 // Tests revoking blob URL from same and cross partition dedicated worker.
    141 promise_test(t => {
    142  return new Promise(async (resolve, reject) => {
    143    try {
    144      const response_queue_uuid = token();
    145 
    146      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    147        await create_test_iframes(t, response_queue_uuid);
    148 
    149      await send(cross_site_iframe_uuid, create_dedicated_worker_js(same_site_origin, response_queue_uuid));
    150      const worker_1_uuid = await receive(response_queue_uuid);
    151 
    152      await send(same_site_iframe_uuid, create_dedicated_worker_js(same_site_origin, response_queue_uuid));
    153      const worker_2_uuid = await receive(response_queue_uuid);
    154 
    155      const blob = new Blob(["blob data"], {type : "text/plain"});
    156      const blob_url = window.URL.createObjectURL(blob);
    157 
    158      await send(worker_1_uuid, can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
    159      var response_1 = await receive(response_queue_uuid);
    160      if (response_1 !== js_finished) {
    161        reject(response_1);
    162      }
    163      response_1 = await fetch_contents_check(blob_url);
    164      if (response_1 !== fetch_successful_response) {
    165        reject(`Blob URL was revoked in not-same-top-level-site dedicated worker: ${response_1}`);
    166      }
    167 
    168      await send(worker_2_uuid, can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
    169      var response_2 = await receive(response_queue_uuid);
    170      if (response_2 !== js_finished) {
    171        reject(response_2);
    172      }
    173      response_2 = await fetch_contents_check(blob_url);
    174      if (response_2 !== fetch_unsuccessful_response) {
    175        t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    176        reject(`Blob URL wasn't revoked in same-top-level-site dedicated worker: ${response_2}`);
    177      }
    178 
    179      resolve();
    180    } catch (e) {
    181      reject(e);
    182    }
    183  });
    184 }, "Blob URL shouldn't be revocable from a cross-partition dedicated worker");
    185 
    186 const newSharedWorker = (origin) => {
    187  const worker_token = token();
    188  const worker_url = origin + executor_worker_path + `&uuid=${worker_token}`;
    189  const worker = new SharedWorker(worker_url, worker_token);
    190  return worker_token;
    191 }
    192 
    193 const create_shared_worker_js = (origin, response_queue_uuid) => `
    194  const importScript = ${importScript};
    195  await importScript("/html/cross-origin-embedder-policy/credentialless" +
    196                    "/resources/common.js");
    197  await importScript("/html/anonymous-iframe/resources/common.js");
    198  await importScript("/common/utils.js");
    199 
    200  // dispatcher.js has already been loaded by the popup this is running in.
    201  const newSharedWorker = ${newSharedWorker};
    202  await send("${response_queue_uuid}", newSharedWorker("${origin}"));
    203 `;
    204 
    205 // Tests revoking blob URL from same and cross partition shared worker.
    206 promise_test(t => {
    207  return new Promise(async (resolve, reject) => {
    208    try {
    209      const response_queue_uuid = token();
    210 
    211      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    212        await create_test_iframes(t, response_queue_uuid);
    213 
    214      // Create a shared worker in the cross-top-level-site iframe.
    215      await send(cross_site_iframe_uuid, create_shared_worker_js(same_site_origin, response_queue_uuid));
    216      const worker_1_uuid = await receive(response_queue_uuid);
    217 
    218      // Create a shared worker in the same-top-level-site iframe.
    219      await send(same_site_iframe_uuid, create_shared_worker_js(same_site_origin, response_queue_uuid));
    220      const worker_2_uuid = await receive(response_queue_uuid);
    221 
    222      const blob = new Blob(["blob data"], {type : "text/plain"});
    223      const blob_url = window.URL.createObjectURL(blob);
    224 
    225      await send(worker_1_uuid, can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
    226      var response_1 = await receive(response_queue_uuid);
    227      if (response_1 !== js_finished) {
    228        reject(response_1);
    229      }
    230      response_1 = await fetch_contents_check(blob_url);
    231      if (response_1 !== fetch_successful_response) {
    232        reject(`Blob URL was revoked in not-same-top-level-site shared worker: ${response_1}`);
    233      }
    234 
    235      await send(worker_2_uuid, can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
    236      var response_2 = await receive(response_queue_uuid);
    237      if (response_2 !== js_finished) {
    238        reject(response_2);
    239      }
    240      response_2 = await fetch_contents_check(blob_url);
    241      if (response_2 !== fetch_unsuccessful_response) {
    242        t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    243        reject(`Blob URL wasn't revoked in same-top-level-site shared worker: ${response_2}`);
    244      }
    245 
    246      resolve();
    247    } catch (e) {
    248      reject(e);
    249    }
    250  });
    251 }, "Blob URL shouldn't be revocable from a cross-partition shared worker");
    252 
    253 const newServiceWorker = async (origin) => {
    254  const worker_token = token();
    255  const worker_url = origin + executor_service_worker_path +
    256                     `&uuid=${worker_token}`;
    257  const worker_url_path = executor_service_worker_path.substring(0,
    258                              executor_service_worker_path.lastIndexOf('/'));
    259  const scope = worker_url_path + "/not-used/";
    260  const reg = await navigator.serviceWorker.register(worker_url,
    261                                                     {'scope': scope});
    262  return worker_token;
    263 }
    264 
    265 const create_service_worker_js = (origin, response_queue_uuid) => `
    266  const importScript = ${importScript};
    267  await importScript("/html/cross-origin-embedder-policy/credentialless" +
    268                    "/resources/common.js");
    269  await importScript("/html/anonymous-iframe/resources/common.js");
    270  await importScript("/common/utils.js");
    271 
    272  // dispatcher.js has already been loaded by the popup this is running in.
    273  const newServiceWorker = ${newServiceWorker};
    274  await send("${response_queue_uuid}", await newServiceWorker("${origin}"));
    275 `;
    276 
    277 // Tests revoking blob URL from a service worker.
    278 promise_test(t => {
    279  return new Promise(async (resolve, reject) => {
    280    try {
    281      const response_queue_uuid = token();
    282 
    283      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    284        await create_test_iframes(t, response_queue_uuid);
    285 
    286      // Create a service worker in either iframe.
    287      await send(cross_site_iframe_uuid, create_service_worker_js(same_site_origin, response_queue_uuid));
    288      var worker_1_uuid = await receive(response_queue_uuid);
    289      t.add_cleanup(() =>
    290        send(worker_1_uuid, "self.registration.unregister();"));
    291 
    292      const blob = new Blob(["blob data"], {type : "text/plain"});
    293      const blob_url = window.URL.createObjectURL(blob);
    294      t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    295 
    296      await send(worker_1_uuid,
    297           can_blob_url_be_revoked_js(blob_url, response_queue_uuid));
    298      const response = await receive(response_queue_uuid);
    299      if (response !== "URL.revokeObjectURL is not exposed") {
    300        reject(`URL.revokeObjectURL is exposed in a Service Worker context: ${response}`);
    301      }
    302      resolve();
    303    } catch (e) {
    304      reject(e);
    305    }
    306  });
    307 }, "Blob URL shouldn't be revocable from a service worker");
    308 
    309 // Tests fetching blob URL for same and cross partition iframes.
    310 promise_test(t => {
    311  return new Promise(async (resolve, reject) => {
    312    try {
    313      // Creates blob URL.
    314      const blob = new Blob(["blob data"], {type : "text/plain"});
    315      const blob_url = window.URL.createObjectURL(blob);
    316      t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    317 
    318      // Fetches blob URL to ensure that it's valid.
    319      const blob_fetch = await fetch_contents_check(blob_url);
    320      if (blob_fetch !== fetch_successful_response) {
    321        reject("Blob URL invalid");
    322      }
    323 
    324      // Creates same and cross partition iframes.
    325      const response_queue_uuid = token();
    326 
    327      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    328        await create_test_iframes(t, response_queue_uuid);
    329 
    330      // Attempt to fetch blob URL in cross partition iframe.
    331      await send(cross_site_iframe_uuid, can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    332      var response_1 = await receive(response_queue_uuid);
    333      if (response_1 !== fetch_unsuccessful_response) {
    334        reject(`Blob URL was fetched in not-same-top-level-site iframe: ${response_1}`);
    335      }
    336 
    337      // Attempt to fetch blob URL in same partition iframe.
    338      await send(same_site_iframe_uuid, can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    339      var response_2 = await receive(response_queue_uuid);
    340      if (response_2 !== fetch_successful_response) {
    341        reject(`Blob URL wasn't fetched in same-top-level-site iframe: ${response_2}`);
    342      }
    343 
    344      resolve();
    345    } catch (e) {
    346      reject(e);
    347    }
    348  });
    349 }, "Blob URL shouldn't be fetched from a cross-partition iframe");
    350 
    351 // Tests fetching blob URL from same and cross partition dedicated worker.
    352 promise_test(t => {
    353  return new Promise(async (resolve, reject) => {
    354    try {
    355      const response_queue_uuid = token();
    356 
    357      // Creates same and cross partition iframes.
    358      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    359        await create_test_iframes(t, response_queue_uuid);
    360 
    361      // Creates a dedicated worker in the cross-top-level-site iframe.
    362      await send(cross_site_iframe_uuid, create_dedicated_worker_js(same_site_origin, response_queue_uuid));
    363      const worker_1_uuid = await receive(response_queue_uuid);
    364 
    365      // Creates a dedicated worker in the same-top-level-site iframe.
    366      await send(same_site_iframe_uuid, create_dedicated_worker_js(same_site_origin, response_queue_uuid));
    367      const worker_2_uuid = await receive(response_queue_uuid);
    368 
    369      const blob = new Blob(["blob data"], {type : "text/plain"});
    370      const blob_url = window.URL.createObjectURL(blob);
    371      t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    372 
    373      // Attempts to fetch in the cross-top-level-site dedicated worker.
    374      await send(worker_1_uuid, can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    375      var response_1 = await receive(response_queue_uuid);
    376      if (response_1 !== fetch_unsuccessful_response) {
    377        reject(`Blob URL was fetched in not-same-top-level-site dedicated worker: ${response_1}`);
    378      }
    379 
    380      // Attempts to fetch in the same-top-level-site dedicated worker.
    381      await send(worker_2_uuid, can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    382      var response_2 = await receive(response_queue_uuid);
    383      if (response_2 !== fetch_successful_response) {
    384        reject(`Blob URL wasn't fetched in same-top-level-site dedicated worker: ${response_2}`);
    385      }
    386 
    387      resolve();
    388    } catch (e) {
    389      reject(e);
    390    }
    391  });
    392 }, "Blob URL shouldn't be fetched from a cross-partition dedicated worker");
    393 
    394 // Tests fetching blob URL from same and cross partition shared worker.
    395 promise_test(t => {
    396  return new Promise(async (resolve, reject) => {
    397    try {
    398      const response_queue_uuid = token();
    399 
    400      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    401        await create_test_iframes(t, response_queue_uuid);
    402 
    403      // Create a shared worker in the cross-top-level-site iframe.
    404      await send(cross_site_iframe_uuid, create_shared_worker_js(same_site_origin, response_queue_uuid));
    405      const worker_1_uuid = await receive(response_queue_uuid);
    406 
    407      // Create a shared worker in the same-top-level-site iframe.
    408      await send(same_site_iframe_uuid, create_shared_worker_js(same_site_origin, response_queue_uuid));
    409      const worker_2_uuid = await receive(response_queue_uuid);
    410 
    411      const blob = new Blob(["blob data"], {type : "text/plain"});
    412      const blob_url = window.URL.createObjectURL(blob);
    413      t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    414 
    415      // Attempts to fetch in the cross-top-level-site shared worker.
    416      await send(worker_1_uuid, can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    417      var response_1 = await receive(response_queue_uuid);
    418      if (response_1 !== fetch_unsuccessful_response) {
    419        reject(`Blob URL was fetched in not-same-top-level-site shared worker: ${response_1}`);
    420      }
    421 
    422      // Attempts to fetch in the same-top-level-site shared worker.
    423      await send(worker_2_uuid, can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    424      var response_2 = await receive(response_queue_uuid);
    425      if (response_2 !== fetch_successful_response) {
    426        reject(`Blob URL wasn't fetched in same-top-level-site shared worker: ${response_2}`);
    427      }
    428 
    429      resolve();
    430    } catch (e) {
    431      reject(e);
    432    }
    433  });
    434 }, "Blob URL shouldn't be fetched from a cross-partition shared worker");
    435 
    436 // Tests fetching blob URL from a cross partition service worker.
    437 promise_test(t => {
    438  return new Promise(async (resolve, reject) => {
    439    try {
    440      const response_queue_uuid = token();
    441 
    442      const [cross_site_iframe_uuid, same_site_iframe_uuid] =
    443        await create_test_iframes(t, response_queue_uuid);
    444 
    445      const blob = new Blob(["blob data"], {type : "text/plain"});
    446      const blob_url = window.URL.createObjectURL(blob);
    447      t.add_cleanup(() => window.URL.revokeObjectURL(blob_url));
    448 
    449      // Create a service worker in cross-top-level-site iframe.
    450      await send(cross_site_iframe_uuid, create_service_worker_js(same_site_origin, response_queue_uuid));
    451      var worker_1_uuid = await receive(response_queue_uuid);
    452      t.add_cleanup(() =>
    453        send(worker_1_uuid, "self.registration.unregister();"));
    454 
    455      await send(worker_1_uuid,
    456           can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    457      const response_1 = await receive(response_queue_uuid);
    458      if (response_1 !== fetch_unsuccessful_response) {
    459        reject(`Blob URL was fetched in not-same-top-level-site service worker: ${response_1}`);
    460      }
    461 
    462      // Create a service worker in same-top-level-site iframe.
    463      await send(same_site_iframe_uuid, create_service_worker_js(same_site_origin, response_queue_uuid));
    464      var worker_2_uuid = await receive(response_queue_uuid);
    465      t.add_cleanup(() =>
    466        send(worker_2_uuid, "self.registration.unregister();"));
    467 
    468      await send(worker_2_uuid,
    469           can_blob_url_be_fetched_js(blob_url, response_queue_uuid));
    470      const response_2 = await receive(response_queue_uuid);
    471      if (response_2 !== fetch_successful_response) {
    472        reject(`Blob URL wasn't fetched in same-top-level-site service worker: ${response_2}`);
    473      }
    474      resolve();
    475    } catch (e) {
    476      reject(e);
    477    }
    478  });
    479 }, "Blob URL shouldn't be fetched from a cross-partition service worker");
    480 
    481 </script>
    482 </body>