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