tor-browser

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

reporting-to-document-reporting-endpoint.https.window.js (5329B)


      1 // META: script=/common/get-host-info.sub.js
      2 // META: script=/common/utils.js
      3 
      4 // This file consists of tests for COEP reporting using Reporting-Endpoints
      5 // header. It exclusively tests that reports can be sent to Reporting-Endpoint
      6 // configured endpoint.
      7 const { REMOTE_ORIGIN } = get_host_info();
      8 
      9 const REPORT_ENDPOINT = token();
     10 const REPORT_ONLY_ENDPOINT = token();
     11 const FRAME_URL = `resources/reporting-empty-frame.html` +
     12  `?pipe=header(cross-origin-embedder-policy,require-corp;report-to="endpoint")` +
     13  `|header(cross-origin-embedder-policy-report-only,require-corp;report-to="report-only-endpoint")` +
     14  `|header(reporting-endpoints, endpoint="/html/cross-origin-embedder-policy/resources/report.py?key=${REPORT_ENDPOINT}"\\, report-only-endpoint="/html/cross-origin-embedder-policy/resources/report.py?key=${REPORT_ONLY_ENDPOINT}")`;
     15 
     16 function wait(ms) {
     17  return new Promise(resolve => step_timeout(resolve, ms));
     18 }
     19 
     20 async function fetchReports(endpoint) {
     21  const res = await fetch(`resources/report.py?key=${endpoint}`, {
     22    cache: 'no-store'
     23  });
     24  if (res.status == 200) {
     25    return await res.json();
     26  }
     27  return [];
     28 }
     29 
     30 async function fetchCoepReport(
     31  endpoint, type, blockedUrl, contextUrl, disposition) {
     32  blockedUrl = new URL(blockedUrl, location).href;
     33  contextUrl = new URL(contextUrl, location).href;
     34  const reports = await fetchReports(endpoint);
     35  return reports.find(r => (
     36    r.type == 'coep' &&
     37    r.url == contextUrl &&
     38    r.body.type == type &&
     39    r.body.blockedURL === blockedUrl &&
     40    r.body.disposition === disposition));
     41 }
     42 
     43 async function checkCorpReportExists(
     44  endpoint, blockedUrl, contextUrl, destination, disposition) {
     45  blockedUrl = new URL(blockedUrl, location).href;
     46  contextUrl = new URL(contextUrl, location).href;
     47  contextUrl.replace(REPORT_ENDPOINT, "REPORT_ENDPOINT_UUID");
     48  contextUrl.replace(REPORT_ONLY_ENDPOINT, "REPORT_ONLY_ENDPOINT_UUID");
     49  const report = await fetchCoepReport(
     50    endpoint, 'corp', blockedUrl, contextUrl, disposition);
     51  assert_true(!!report,
     52    `A corp report with blockedURL ${blockedUrl.split("?")[0]} ` +
     53    `and url ${contextUrl} is not found.`);
     54  assert_equals(report.body.destination, destination);
     55 }
     56 
     57 async function checkNavigationReportExists(
     58  endpoint, blockedUrl, contextUrl, disposition) {
     59  blockedUrl = new URL(blockedUrl, location).href;
     60  contextUrl = new URL(contextUrl, location).href;
     61  contextUrl.replace(REPORT_ENDPOINT, "REPORT_ENDPOINT_UUID");
     62  contextUrl.replace(REPORT_ONLY_ENDPOINT, "REPORT_ONLY_ENDPOINT_UUID");
     63  const report = await fetchCoepReport(
     64    endpoint, 'navigation', blockedUrl, contextUrl, disposition);
     65  assert_true(!!report,
     66    `A navigation report with blockedURL ${blockedUrl.split("?")[0]} ` +
     67    `and url ${contextUrl} is not found.`);
     68 }
     69 
     70 promise_test(async t => {
     71  const iframe = document.createElement('iframe');
     72  t.add_cleanup(() => iframe.remove());
     73 
     74  iframe.src = FRAME_URL;
     75  await new Promise(resolve => {
     76    iframe.addEventListener('load', resolve, { once: true });
     77    document.body.appendChild(iframe);
     78  });
     79 
     80  const url = `${REMOTE_ORIGIN}/common/text-plain.txt?${token()}`;
     81  const init = { mode: 'no-cors', cache: 'no-store' };
     82  // The response comes from cross-origin, and doesn't have a CORP
     83  // header, so it is blocked.
     84  iframe.contentWindow.fetch(url, init).catch(() => { });
     85 
     86  // Wait for reports to be uploaded.
     87  await wait(1000);
     88  await checkCorpReportExists(
     89    REPORT_ENDPOINT, url, iframe.src, '', 'enforce');
     90  await checkCorpReportExists(
     91    REPORT_ONLY_ENDPOINT, url, iframe.src, '', 'reporting');
     92 }, 'subresource CORP');
     93 
     94 promise_test(async t => {
     95  const iframe = document.createElement('iframe');
     96  t.add_cleanup(() => iframe.remove());
     97 
     98  iframe.src = FRAME_URL;
     99  await new Promise(resolve => {
    100    iframe.addEventListener('load', resolve, { once: true });
    101    document.body.appendChild(iframe);
    102  });
    103 
    104  const url = `${REMOTE_ORIGIN}/common/blank.html?${token()}`;
    105  // The nested frame comes from cross-origin and doesn't have a CORP
    106  // header, so it is blocked.
    107  const nested = iframe.contentWindow.document.createElement('iframe');
    108  nested.src = url;
    109  iframe.contentWindow.document.body.appendChild(nested);
    110 
    111  // Wait for reports to be uploaded.
    112  await wait(1000);
    113  await checkCorpReportExists(
    114    REPORT_ENDPOINT, url, iframe.src, 'iframe', 'enforce');
    115  await checkCorpReportExists(
    116    REPORT_ONLY_ENDPOINT, url, iframe.src, 'iframe', 'reporting');
    117 }, 'navigation CORP on cross origin');
    118 
    119 promise_test(async (t) => {
    120  const iframe = document.createElement('iframe');
    121  t.add_cleanup(() => iframe.remove());
    122 
    123  iframe.src = FRAME_URL;
    124  const targetUrl = `/common/blank.html?${token()}`;
    125  iframe.addEventListener('load', t.step_func(() => {
    126    const nested = iframe.contentDocument.createElement('iframe');
    127    nested.src = targetUrl;
    128    // |nested| doesn't have COEP whereas |iframe| has, so it is blocked.
    129    iframe.contentDocument.body.appendChild(nested);
    130  }), { once: true });
    131 
    132  document.body.appendChild(iframe);
    133 
    134  // Wait for reports to be uploaded.
    135  await wait(1000);
    136  await checkNavigationReportExists(
    137    REPORT_ENDPOINT, targetUrl, iframe.src, 'enforce');
    138  await checkNavigationReportExists(
    139    REPORT_ONLY_ENDPOINT, targetUrl, iframe.src, 'reporting');
    140 }, 'navigation CORP on same origin');