tor-browser

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

about-blank-replacement-worker.js (2923B)


      1 // Helper routine to find a client that matches a particular URL.  Note, we
      2 // require that Client to be controlled to avoid false matches with other
      3 // about:blank windows the browser might have.  The initial about:blank should
      4 // inherit the controller from its parent.
      5 async function getClientByURL(url) {
      6  let list = await clients.matchAll();
      7  return list.find(client => client.url === url);
      8 }
      9 
     10 // Helper routine to perform a ping-pong with the given target client.  We
     11 // expect the Client to respond with its location URL.
     12 async function pingPong(target) {
     13  function waitForPong() {
     14    return new Promise(resolve => {
     15      self.addEventListener('message', function onMessage(evt) {
     16        if (evt.data.type === 'PONG') {
     17          resolve(evt.data.location);
     18        }
     19      });
     20    });
     21  }
     22 
     23  target.postMessage({ type: 'PING' })
     24  return await waitForPong(target);
     25 }
     26 
     27 addEventListener('fetch', async evt => {
     28  let url = new URL(evt.request.url);
     29  if (!url.searchParams.get('nested')) {
     30    return;
     31  }
     32 
     33  evt.respondWith(async function() {
     34    // Find the initial about:blank document.
     35    const client = await getClientByURL('about:blank');
     36    if (!client) {
     37      return new Response('failure: could not find about:blank client');
     38    }
     39 
     40    // If the nested frame is configured to support a ping-pong, then
     41    // ping it now to verify its message listener exists.  We also
     42    // verify the Client's idea of its own location URL while we are doing
     43    // this.
     44    if (url.searchParams.get('ping')) {
     45      const loc = await pingPong(client);
     46      if (loc !== 'about:blank') {
     47        return new Response(`failure: got location {$loc}, expected about:blank`);
     48      }
     49    }
     50 
     51    // Finally, allow the nested frame to complete loading.  We place the
     52    // Client ID we found for the initial about:blank in the body.
     53    return new Response(client.id);
     54  }());
     55 });
     56 
     57 addEventListener('message', evt => {
     58  if (evt.data.type !== 'GET_CLIENT_ID') {
     59    return;
     60  }
     61 
     62  evt.waitUntil(async function() {
     63    let url = new URL(evt.data.url);
     64 
     65    // Find the given Client by its URL.
     66    let client = await getClientByURL(evt.data.url);
     67    if (!client) {
     68      evt.source.postMessage({
     69        type: 'GET_CLIENT_ID',
     70        result: `failure: could not find ${evt.data.url} client`
     71      });
     72      return;
     73    }
     74 
     75    // If the Client supports a ping-pong, then do it now to verify
     76    // the message listener exists and its location matches the
     77    // Client object.
     78    if (url.searchParams.get('ping')) {
     79      let loc = await pingPong(client);
     80      if (loc !== evt.data.url) {
     81        evt.source.postMessage({
     82          type: 'GET_CLIENT_ID',
     83          result: `failure: got location ${loc}, expected ${evt.data.url}`
     84        });
     85        return;
     86      }
     87    }
     88 
     89    // Finally, send the client ID back.
     90    evt.source.postMessage({
     91      type: 'GET_CLIENT_ID',
     92      result: client.id
     93    });
     94  }());
     95 });