tor-browser

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

database-names-by-origin.html (4872B)


      1 <!doctype html>
      2 <meta charset="utf8">
      3 <meta name="timeout" content="long">
      4 <title>IndexedDB: origins have isolated namespaces</title>
      5 <link rel="author" href="pwnall@chromium.org" title="Victor Costan">
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="../common/get-host-info.sub.js"></script>
      9 <script src="resources/support-promises.js"></script>
     10 
     11 <body>
     12 <script>
     13 'use strict';
     14 
     15 // Returns a Promise that resolves with the helper's response.
     16 function waitForCrossOriginHelperResponse(origin, request) {
     17  return new Promise((resolve, reject) => {
     18    self.addEventListener('message', event => {
     19      if (event.origin !== origin) {
     20        reject(new Error(`Unexpected message from ${event.origin}`));
     21        return;
     22      }
     23 
     24      if (event.data.action === request.action) {
     25        resolve(event.data.response);
     26      } else {
     27        reject(new Error(`Unexpected message ${JSON.stringify(event.data)}`));
     28      }
     29    }, { once: true });
     30  });
     31 }
     32 
     33 // Returns a Promise that resolves with the helper's response.
     34 async function crossOriginIframeHelper(testCase, origin, request) {
     35  const iframe = document.createElement('iframe');
     36  iframe.src = origin + '/IndexedDB/resources/cross-origin-helper-frame.html';
     37  document.body.appendChild(iframe);
     38  testCase.add_cleanup(() => {
     39    try {
     40      document.body.removeChild(iframe);
     41    } catch (e) {
     42      // removeChild() throws if the iframe was already removed, which happens
     43      // if this method runs to completion.
     44    }
     45  });
     46 
     47  await new Promise((resolve, reject) => {
     48    iframe.onload = resolve;
     49    iframe.onerror = reject;
     50  });
     51 
     52  iframe.contentWindow.postMessage(request, origin);
     53  const response = await waitForCrossOriginHelperResponse(origin, request);
     54  document.body.removeChild(iframe);
     55  return response;
     56 };
     57 
     58 // Returns a Promise that resolves with the helper's response.
     59 async function crossOriginWindowHelper(testCase, origin, request) {
     60  const helperWindow = window.open(
     61      origin + '/IndexedDB/resources/cross-origin-helper-frame.html',
     62      '_blank');
     63  testCase.add_cleanup(() => { helperWindow.close(); });
     64 
     65  await new Promise((resolve, reject) => {
     66    self.addEventListener('message', event => {
     67      if (event.origin !== origin) {
     68        reject(new Error(`Unexpected message from ${event.origin}`));
     69        return;
     70      }
     71 
     72      if (event.data.action === null && event.data.response === 'ready') {
     73        resolve(event.data.response);
     74      } else {
     75        reject(new Error(`Unexpected message ${JSON.stringify(event.data)}`));
     76      }
     77    }, { once: true });
     78  });
     79 
     80  helperWindow.postMessage(request, origin);
     81  const response = await waitForCrossOriginHelperResponse(origin, request);
     82  helperWindow.close();
     83  return response;
     84 };
     85 
     86 // Returns a Promise that resolves with the helper's response.
     87 function crossOriginHelper(testCase, mode, origin, request) {
     88  switch (mode) {
     89    case 'iframe':
     90      return crossOriginIframeHelper(testCase, origin, request);
     91    case 'window':
     92      return crossOriginWindowHelper(testCase, origin, request);
     93    default:
     94      throw new Error(`Unsupported cross-origin helper mode ${mode}`);
     95  }
     96 }
     97 
     98 const sameOrigin = get_host_info().ORIGIN;
     99 const otherOrigin = get_host_info().REMOTE_ORIGIN;
    100 
    101 // The disclosure that inspired this test demonstrated leaked open database
    102 // connections across windows.
    103 for (const databaseKind of ['open', 'closed']) {
    104  for (const mode of ['iframe', 'window']) {
    105    promise_test(async testCase => {
    106      const dbName = databaseName(testCase);
    107 
    108      assert_true(
    109          await crossOriginHelper(
    110              testCase, mode, sameOrigin,
    111              {action: 'delete-database', name: dbName}),
    112          'Same-origin setup error');
    113      assert_true(
    114          await crossOriginHelper(
    115              testCase, mode, otherOrigin,
    116              { action: 'delete-database', name: dbName }),
    117          'Cross-origin setup error');
    118 
    119      const db = await createNamedDatabase(testCase, dbName, database => {
    120        database.createObjectStore('store');
    121      });
    122 
    123      if (databaseKind === 'closed')
    124        await db.close();
    125 
    126      const sameOriginDbNames = await crossOriginHelper(
    127          testCase, mode, sameOrigin, { action: 'get-database-names' });
    128      assert_in_array(
    129          dbName, sameOriginDbNames,
    130          `Database creation should reflect in same-origin ${mode}`);
    131 
    132      const otherOriginDbNames = await crossOriginHelper(
    133          testCase, mode, otherOrigin, { action: 'get-database-names' });
    134      assert_true(
    135          otherOriginDbNames.indexOf(dbName) === -1,
    136          `Database creation should not impact cross-origin ${mode} list`);
    137 
    138      if (databaseKind !== 'closed')
    139        await db.close();
    140    }, `${databaseKind} database names don't leak to cross-origin ${mode}`);
    141  }
    142 }
    143 </script>
    144 </body>