<!doctype html>
<meta charset="utf-8">
<meta name="timeout" content="long">
<title>
  Check the ReportingObserver(s) are notified about the coop-access-violation
  events.
</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/common/get-host-info.sub.js></script>
<script src="/common/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
<script>

const directory = "/html/cross-origin-opener-policy";
const same_origin = get_host_info().HTTPS_ORIGIN;
const cross_site = get_host_info().HTTPS_NOTSAMESITE_ORIGIN;
const corp_header = '|header(Cross-Origin-Resource-Policy,cross-origin)';

promise_test(async t => {
  // This test window.
  const this_window_token = token();

  // The "opener" window, using COOP-Report-Only and a reporter.
  const opener_token = token();
  const opener_reportTo = reportToHeaders(token());
  const opener_url = same_origin + executor_path + opener_reportTo.header +
    opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
    `&uuid=${opener_token}`;

  // The "openee" window, NOT using COOP.
  const openee_token = token();
  const openee_url = same_origin + executor_path + `&uuid=${openee_token}`;

  // 1. Create the opener window.
  window.open(opener_url);
  t.add_cleanup(() => send(opener_token, "window.close();"));

  // 2. The opener opens its openee.
  send(opener_token, `openee = window.open('${openee_url}');`);
  t.add_cleanup(() => send(openee_token, `window.close();`));

  // 3. Wait for the openee to load its document.
  send(openee_token, `send("${this_window_token}", "Ready");`);
  assert_equals(await receive(this_window_token), "Ready");

  // 4. The opener tries to access its openee. All reports for blocked access
  //    from the COOP page should notify the ReportingObservers.
  send(opener_token, addScriptAndTriggerOnload(
    directory + "/reporting/resources/try-access.js", `
      let observer = new ReportingObserver(()=>{});
      observer.observe();
      tryAccess(openee);
      let reports = observer.takeRecords();
      send("${this_window_token}", JSON.stringify(reports));
      observer.disconnect();
    `));

  let report_access_from = JSON.parse(await receive(this_window_token));
  assert_equals(report_access_from.length, 1, "No report received.");
  assert_equals(report_access_from[0].type, "coop-access-violation");
  assert_equals(report_access_from[0].url, opener_url.replace(/"/g, '%22'));
  assert_source_location_found(report_access_from[0])
  assert_equals(report_access_from[0].body.type,
                "access-from-coop-page-to-openee");
  assert_equals(report_access_from[0].body.openeeURL, openee_url);
  assert_equals(report_access_from[0].body.openerURL, undefined);
  assert_equals(report_access_from[0].body.otherDocumentURL, undefined);

  // 5. The openee tries to access its opener. No reports for blocked access
  //    to the COOP page should be dispatched.
  send(openee_token, addScriptAndTriggerOnload(
    directory + "/reporting/resources/try-access.js", `
      let observer = new ReportingObserver(()=>{});
      observer.observe();
      tryAccess(opener);
      let reports = observer.takeRecords();
      send("${this_window_token}", JSON.stringify(reports));
      observer.disconnect();
    `));
  let report_access_to = JSON.parse(await receive(this_window_token));
  assert_equals(report_access_to.length, 0, "Unexpected report received.");
}, "Opener COOP");

promise_test(async t => {
  // This test window.
  const this_window_token = token();

  // The "opener" window, NOT using COOP.
  const opener_token = token();
  const opener_url = same_origin + executor_path + `&uuid=${opener_token}`;

  // The "openee" window, using COOP-Report-Only and a reporter.
  const openee_token = token();
  const openee_reportTo = reportToHeaders(token());
  const openee_url = same_origin + executor_path + openee_reportTo.header +
    openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
    `&uuid=${openee_token}`;

  // 1. Create the opener window.
  window.open(opener_url);
  t.add_cleanup(() => send(opener_token, "window.close();"));

  // 2. The opener opens its openee.
  send(opener_token,
    `openee = window.open('${openee_url.replace(/,/g, '\\,')}');`);
  t.add_cleanup(() => send(openee_token, `window.close();`));

  // 3. The openee tries to access its opener. All reports for blocked access
  //    from the COOP page should notify the ReportingObservers.
  send(openee_token, addScriptAndTriggerOnload(
    directory + "/reporting/resources/try-access.js", `
      let observer = new ReportingObserver(()=>{});
      observer.observe();
      tryAccess(opener);
      let reports = observer.takeRecords();
      send("${this_window_token}", JSON.stringify(reports));
      observer.disconnect();
    `));
  let report_access_from = JSON.parse(await receive(this_window_token));
  assert_equals(report_access_from.length, 1, "No report received.");
  assert_equals(report_access_from[0].type, "coop-access-violation");
  assert_equals(report_access_from[0].url, openee_url.replace(/"/g, '%22'));
  assert_true(report_access_from[0].body.sourceFile.includes("try-access.js"));
  assert_source_location_found(report_access_from[0])
  assert_equals(report_access_from[0].body.type,
                "access-from-coop-page-to-opener");
  assert_equals(report_access_from[0].body.openeeURL, undefined);
  assert_equals(report_access_from[0].body.openerURL, opener_url);
  assert_equals(report_access_from[0].body.otherDocumentURL, undefined);

  // 4. The opener tries to access its openee. No reports for blocked access
  //    to the COOP page should be dispatched.
  send(opener_token, addScriptAndTriggerOnload(
    directory + "/reporting/resources/try-access.js", `
      let observer = new ReportingObserver(()=>{});
      observer.observe();
      tryAccess(openee);
      let reports = observer.takeRecords();
      send("${this_window_token}", JSON.stringify(reports));
      observer.disconnect();
    `));
  let report_access_to = JSON.parse(await receive(this_window_token));
  assert_equals(report_access_to.length, 0, "Unexpected report received.");
}, "Openee COOP");

promise_test(async t => {
  // This test window.
  const this_window_token = token();

  // The "opener" window, using COOP-Report-Only and a reporter.
  const opener_token = token();
  const opener_reportTo = reportToHeaders(token());
  const opener_url = same_origin + executor_path + opener_reportTo.header +
    opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
    `&uuid=${opener_token}`;

  // The "opener's iframe", same-origin with its parent.
  const opener_iframe_token = token();
  const opener_iframe_url = same_origin + executor_path + coep_header +
    `&uuid=${opener_iframe_token}`;

  // The "openee" window, NOT using COOP.
  const openee_token = token();
  const openee_url = same_origin + executor_path + coep_header +
    `&uuid=${openee_token}`;

  // 1. Create the opener window.
  window.open(opener_url);
  t.add_cleanup(() => send(opener_token, "window.close();"));

  // 2. The opener opens an iframe, and install a ReportingObserver to catch
  //    future accesses.
  send(opener_token, `
    iframe = document.createElement("iframe");
    iframe.src = "${opener_iframe_url}";
    document.body.appendChild(iframe);

    let observer = new ReportingObserver(reports => {
      send("${this_window_token}", JSON.stringify(reports));
      observer.disconnect();
    });
    observer.observe();
  `);

  // 3. The iframe opens the openee.
  send(opener_iframe_token, `openee = window.open('${openee_url}');`);
  t.add_cleanup(() => send(openee_token, `window.close();`));

  // 4. Wait for the openee to load its document.
  send(openee_token, `send("${this_window_token}", "Ready");`);
  assert_equals(await receive(this_window_token), "Ready");

  // 4. The opener's iframe tries to access the openee. This is an
  //    "access-from-coop-page" from a same-origin iframe, so the
  //    ReportingObserver(s) are notified.
  send(opener_iframe_token, addScriptAndTriggerOnload(
    directory + "/reporting/resources/try-access.js", `tryAccess(openee);`));

  let reports = await receive(this_window_token);
  reports = JSON.parse(reports);
  assert_equals(reports.length, 1, "No report received.");
  assert_equals(reports[0].type, "coop-access-violation");
  assert_equals(reports[0].url, opener_url.replace(/"/g, '%22'));
  assert_true(reports[0].body.sourceFile.includes("try-access.js"));
  assert_source_location_found(reports[0]);
  assert_equals(reports[0].body.type,
                "access-from-coop-page-to-openee");
  assert_equals(reports[0].body.openeeURL, openee_url);
  assert_equals(reports[0].body.openerURL, undefined);
  assert_equals(reports[0].body.otherDocumentURL, undefined);
}, "Access from same-origin iframe")

promise_test(async t => {
  // This test window.
  const this_window_token = token();

  // The "opener" window, using COOP-Report-Only and a reporter.
  const opener_token = token();
  const opener_reportTo = reportToHeaders(token());
  const opener_url = same_origin + executor_path + opener_reportTo.header +
    opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
    `&uuid=${opener_token}`;

  // The "opener's iframe", same-origin with its parent.
  const opener_iframe_token = token();
  const opener_iframe_url = cross_site + executor_path + coep_header +
    corp_header +
    `&uuid=${opener_iframe_token}`;

  // The "openee" window, NOT using COOP.
  const openee_token = token();
  const openee_url = same_origin + executor_path + coep_header +
    `&uuid=${openee_token}`;

  // 1. Create the opener window.
  window.open(opener_url);
  t.add_cleanup(() => send(opener_token, "window.close();"));

  // 2. The opener opens an iframe, and install a ReportingObserver to catch
  //    future accesses.
  send(opener_token, `
    iframe = document.createElement("iframe");
    iframe.src = "${opener_iframe_url}";
    document.body.appendChild(iframe);

    let observer = new ReportingObserver(reports => {
      send("${this_window_token}", JSON.stringify(reports));
      observer.disconnect();
    });
    observer.observe();
  `);

  // 3. The iframe opens the openee.
  send(opener_iframe_token, `openee = window.open('${openee_url}');`);
  t.add_cleanup(() => send(openee_token, `window.close();`));

  // 4. Wait for the openee to load its document.
  send(openee_token, `send("${this_window_token}", "Ready");`);
  assert_equals(await receive(this_window_token), "Ready");

  // 5. The opener's iframe tries to access the openee. This is an
  //    "access-from-coop-page" from a cross-site iframe. The ReportingObservers
  //    from the main document aren't notified.
  send(opener_iframe_token, addScriptAndTriggerOnload(
    directory + "/reporting/resources/try-access.js", `tryAccess(openee);`));

  let reports = await receive(this_window_token, 2000);
  assert_equals(reports, "timeout", "Unexpected report received.");
}, "Access from cross-site iframe")

</script>
