tor-browser

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

util.sub.js (6156B)


      1 function loadSharedStorageImage(data) {
      2  let {key, value, hasSharedStorageWritableAttribute, isSameOrigin} = data;
      3  const encodedKey = encodeURIComponent(key);
      4  const encodedValue = encodeURIComponent(value);
      5  const sameOriginSrc = `/shared-storage/resources/` +
      6      `shared-storage-writable-pixel.png?key=${encodedKey}&value=${encodedValue}`;
      7  const crossOriginSrc =
      8      'https://{{domains[www]}}:{{ports[https][0]}}' + sameOriginSrc;
      9 
     10  let image = document.createElement('img');
     11  image.src = isSameOrigin ? sameOriginSrc : crossOriginSrc;
     12  if (hasSharedStorageWritableAttribute) {
     13    image.sharedStorageWritable = true;
     14  }
     15 
     16  const promise = new Promise((resolve, reject) => {
     17    image.addEventListener('load', () => {
     18      resolve(image);
     19    });
     20    image.addEventListener('error', () => {
     21      reject(new Error('Image load failed'));
     22    });
     23  });
     24 
     25  document.body.appendChild(image);
     26  return promise;
     27 }
     28 
     29 function navigateSharedStorageIframe(data) {
     30  let {
     31    hasSharedStorageWritableAttribute,
     32    rawWriteHeader,
     33    isSameOrigin,
     34    expectSharedStorageWritableHeader
     35  } = data;
     36  const writeHeader = encodeURIComponent(rawWriteHeader);
     37  const sameOriginSrc =
     38      `/shared-storage/resources/shared-storage-write-notify-parent.py` +
     39      `?write=${writeHeader}`;
     40  const crossOriginSrc =
     41      'https://{{domains[www]}}:{{ports[https][0]}}' + sameOriginSrc;
     42 
     43  let frame = document.createElement('iframe');
     44  frame.src = isSameOrigin ? sameOriginSrc : crossOriginSrc;
     45  if (hasSharedStorageWritableAttribute) {
     46    frame.sharedStorageWritable = true;
     47  }
     48 
     49  const expectedResult = expectSharedStorageWritableHeader ?
     50      '?1' :
     51      'NO_SHARED_STORAGE_WRITABLE_HEADER';
     52 
     53  function checkExpectedResult(data) {
     54    assert_equals(data.sharedStorageWritableHeader, expectedResult);
     55  }
     56 
     57  const promise = new Promise((resolve, reject) => {
     58    window.addEventListener('message', async function handler(evt) {
     59      if (evt.source === frame.contentWindow) {
     60        checkExpectedResult(evt.data);
     61        document.body.removeChild(frame);
     62        window.removeEventListener('message', handler);
     63        resolve();
     64      }
     65    });
     66    window.addEventListener('error', () => {
     67      reject(new Error('Navigation error'));
     68    });
     69  });
     70 
     71  document.body.appendChild(frame);
     72  return promise;
     73 }
     74 
     75 async function loadNestedSharedStorageFrameInNewFrame(data) {
     76  const SCOPE = '/shared-storage/resources/shared-storage-writ';
     77  const INTERMEDIATE_FRAME_SUFFIX =
     78      'able-fetch-request-fallback-to-network-iframe.https.html'
     79  const CROSS_ORIGIN = 'https://{{domains[www]}}:{{ports[https][0]}}';
     80 
     81  let {key, value, hasSharedStorageWritableAttribute, isSameOrigin} = data;
     82 
     83  const windowPromise = new Promise((resolve, reject) => {
     84    window.addEventListener('message', async function handler(evt) {
     85      if (evt.data.msg && evt.data.msg === 'iframe loaded') {
     86        window.removeEventListener('message', handler);
     87        resolve();
     88      }
     89    });
     90    window.addEventListener('error', () => {
     91      reject(new Error('Navigation error'));
     92    });
     93  });
     94 
     95  const framePromise = new Promise((resolve, reject) => {
     96    let frame = document.createElement('iframe');
     97    frame.src = SCOPE + INTERMEDIATE_FRAME_SUFFIX;
     98    frame.onload = function() {
     99      resolve(frame);
    100    };
    101    frame.onerror = function() {
    102      reject(new Error('Iframe load failed'));
    103    };
    104    document.body.appendChild(frame);
    105  });
    106  let frame = await framePromise;
    107 
    108  let rawWriteHeader = `set;key=${key};value=${value}`;
    109  let writeHeader = encodeURIComponent(rawWriteHeader);
    110  const sameOriginNestedSrc = `/shared-storage/resources/` +
    111      `shared-storage-write.py?write=${writeHeader}`;
    112  const nestedSrc =
    113      isSameOrigin ? sameOriginNestedSrc : CROSS_ORIGIN + sameOriginNestedSrc;
    114 
    115  let nestedFrame = frame.contentWindow.loadFrame(
    116      nestedSrc, hasSharedStorageWritableAttribute);
    117  await windowPromise;
    118  return {frame: frame, nestedFrame: nestedFrame, nestedFrameUrl: nestedSrc};
    119 }
    120 
    121 async function createWorkletAndVerifyDataOrigin(
    122    t, data_origin, script_origin, expect_success, error_type) {
    123  if (error_type) {
    124    assert_false(expect_success);
    125  }
    126  const key = 'key0';
    127  const value = 'value0';
    128  const sameOrigin = location.origin;
    129  const sameOriginScriptUrl = `/shared-storage/resources/simple-module.js`;
    130  const scriptUrl = (script_origin === location.origin) ?
    131      sameOriginScriptUrl :
    132      script_origin + sameOriginScriptUrl;
    133  let dataOrigin = sameOrigin;
    134  if (data_origin === 'script-origin') {
    135    dataOrigin = script_origin;
    136  } else if (data_origin !== '' && data_origin !== 'context-origin') {
    137    try {
    138      dataOrigin = new URL(data_origin).origin;
    139    } catch (e) {
    140      if (e.message !== 'Failed to construct \'URL\': Invalid URL') {
    141        throw e;
    142      }
    143      assert_false(expect_success);
    144    }
    145  }
    146  const options = (data_origin === '') ?
    147      {credentials: 'omit'} :
    148      {credentials: 'omit', dataOrigin: data_origin};
    149  let success = false;
    150  let error = null;
    151 
    152  try {
    153    const worklet = await sharedStorage.createWorklet(scriptUrl, options);
    154 
    155    const ancestor_key = token();
    156    let url0 =
    157        generateURL('/shared-storage/resources/frame0.html', [ancestor_key]);
    158 
    159    let select_url_result =
    160        await worklet.selectURL('test-url-selection-operation', [{url: url0}], {
    161          data: {'mockResult': 0, 'setKey': key, 'setValue': value},
    162          resolveToConfig: true,
    163          keepAlive: true
    164        });
    165 
    166    assert_true(validateSelectURLResult(select_url_result, true));
    167    attachFencedFrame(select_url_result, 'opaque-ads');
    168    const result0 = await nextValueFromServer(ancestor_key);
    169    assert_equals(result0, 'frame0_loaded');
    170 
    171    await verifyKeyValueForOrigin(key, value, dataOrigin);
    172    await deleteKeyForOrigin(key, dataOrigin);
    173    success = true;
    174  } catch (e) {
    175    error = e;
    176    assert_equals(e.name, error_type, e.message);
    177  } finally {
    178    assert_equals(
    179        expect_success, success,
    180        error ? 'expected success but error thrown: ' + error.toString() :
    181                'no error caught even though one was expected');
    182    t.done();
    183  }
    184 }