From fad3b7b7a1acdd2abcf69371179f4df48e4ff749 Mon Sep 17 00:00:00 2001 From: Blink WPT Bot Date: Wed, 3 Nov 2021 11:47:44 -0700 Subject: [PATCH] WPT tests for COOP with Reporting-Endpoints header (#31099) * Test the integration between new Reporting-Endpoints header with coop reporters * Added new cases covering reports sent from redirects. Bug: 1209057, 1062359 Change-Id: I2e061f2f9e235264d569032204c75df30cdb5220 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3202651 Commit-Queue: Rodney Ding Reviewed-by: Ian Clelland Cr-Commit-Position: refs/heads/main@{#937859} Co-authored-by: Rodney Ding --- .../report-only-four-reports.https.html | 86 ++++++++++ ...t-only-four-reports.https.html.sub.headers | 6 + .../report-to-both_coop-ro.https.html | 129 ++++++++++++++ ...t-with-same-origin-allow-popups.https.html | 116 +++++++++++++ ...rting-redirect-with-unsafe-none.https.html | 135 +++++++++++++++ .../reporting-coop-navigated-popup.https.html | 4 +- ...t-with-same-origin-allow-popups.https.html | 2 +- .../reporting/resources/reporting-common.js | 158 ++++++++++++++---- 8 files changed, 597 insertions(+), 39 deletions(-) create mode 100644 html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html create mode 100644 html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers create mode 100644 html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html create mode 100644 html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html create mode 100644 html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html diff --git a/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html b/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html new file mode 100644 index 000000000000000..7bfdab133070e95 --- /dev/null +++ b/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html @@ -0,0 +1,86 @@ + + +A test with both COOP and COOP report only setup using Reporting-Endpoints header + + + + + + + + + diff --git a/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers b/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers new file mode 100644 index 000000000000000..de48445f38fafc0 --- /dev/null +++ b/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers @@ -0,0 +1,6 @@ +Cross-Origin-Opener-Policy: same-origin-allow-popups; report-to="coop-report-endpoint" +Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="coop-report-only-endpoint" +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Embedder-Policy-Report-Only: require-corp +Referrer-Policy: origin +Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=2aee31d2-cd11-43bd-b34d-5f081ca3b2b4", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=d18f1779-e2ab-4a7a-8b1c-44e3a6f440f5" diff --git a/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html b/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html new file mode 100644 index 000000000000000..43da4b79b30243b --- /dev/null +++ b/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html @@ -0,0 +1,129 @@ + + Both the openee and the opener have a COOP reporter. The report are sent to + both side. + + + + + + + + + + + diff --git a/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html b/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html new file mode 100644 index 000000000000000..764b4128ff773ce --- /dev/null +++ b/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html @@ -0,0 +1,116 @@ + + Tests the redirect interaction with COOP same-origin-allow-popups. + + + + + + + + + + diff --git a/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html b/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html new file mode 100644 index 000000000000000..ae94d6871a77c63 --- /dev/null +++ b/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html @@ -0,0 +1,135 @@ + + Tests the redirect interaction with COOP unsafe-none. + + + + + + + + + + diff --git a/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html b/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html index 68ecd913756fa25..ae91e7dc04b1cb6 100644 --- a/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html +++ b/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html @@ -21,11 +21,11 @@ const coopToken= token(); await reportingTest(async resolve => { const noCOOPUrl = executor_path + - `|header(report-to,${encodeURIComponent(getReportEndpoints(location.origin))})` + + convertToWPTHeaderPipe(getReportToHeader(location.origin)) + `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(`unsafe-none; report-to="${popupReportEndpoint.name}"`)})` + `&uuid=${noCoopToken}`; const coopUrl = executor_path + - `|header(report-to,${encodeURIComponent(getReportEndpoints(location.origin))})` + + convertToWPTHeaderPipe(getReportToHeader(location.origin)) + `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(`same-origin; report-to="${redirectReportEndpoint.name}"`)})` + `&uuid=${coopToken}`; diff --git a/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html b/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html index d337541dfff01e8..b19cdd5a9c1e131 100644 --- a/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html +++ b/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html @@ -22,7 +22,7 @@ // Tests the redirect interaction with COOP same-origin-allow-popups and // reporting: -// 1 - open the opener document on origin same_origin wit COOP +// 1 - open the opener document on origin same_origin with COOP // same-origin-allow-popups. // 2 - opener opens popup with document on origin popup_origin, no COOP and a // redirect header (HTTP 302, location). diff --git a/html/cross-origin-opener-policy/reporting/resources/reporting-common.js b/html/cross-origin-opener-policy/reporting/resources/reporting-common.js index 246c9224a3aed46..48d48aa3884710e 100644 --- a/html/cross-origin-opener-policy/reporting/resources/reporting-common.js +++ b/html/cross-origin-opener-policy/reporting/resources/reporting-common.js @@ -190,50 +190,68 @@ async function reportingTest(testFunction, executorToken, expectedReports) { await Promise.all(Array.from(expectedReports, checkForExpectedReport)); } -function getReportEndpoints(host) { - result = ""; - reportEndpoints.forEach( - reportEndpoint => { - let reportToJSON = { - 'group': `${reportEndpoint.name}`, - 'max_age': 3600, - 'endpoints': [ - { - 'url': `${host}/reporting/resources/report.py?reportID=${reportEndpoint.reportID}` - }, - ] - }; - result += JSON.stringify(reportToJSON) - .replace(/,/g, '\\,') - .replace(/\(/g, '\\\(') - .replace(/\)/g, '\\\)=') - + "\\,"; - } - ); - return result.slice(0, -2); +function convertToWPTHeaderPipe([name, value]) { + return `header(${name}, ${encodeURIComponent(value)})`; +} + +function getReportToHeader(host) { + return [ + "Report-To", + reportEndpoints.map( + reportEndpoint => { + const reportToJSON = { + 'group': `${reportEndpoint.name}`, + 'max_age': 3600, + 'endpoints': [{ + 'url': `${host}${getReportEndpointURL(reportEndpoint.reportID)}` + }] + }; + // Escape comma as required by wpt pipes. + return JSON.stringify(reportToJSON) + .replace(/,/g, '\\,') + .replace(/\(/g, '\\\(') + .replace(/\)/g, '\\\)='); + } + ).join("\\, ")]; +} + +function getReportingEndpointsHeader(host) { + return [ + "Reporting-Endpoints", + reportEndpoints.map(reportEndpoint => { + return `${reportEndpoint.name}="${host}${getReportEndpointURL(reportEndpoint.reportID)}"`; + }).join("\\, ")]; +} + +// Return Report and Report-Only policy headers. +function getPolicyHeaders(coop, coep, coopRo, coepRo) { + return [ + [`Cross-Origin-Opener-Policy`, coop], + [`Cross-Origin-Embedder-Policy`, coep], + [`Cross-Origin-Opener-Policy-Report-Only`, coopRo], + [`Cross-Origin-Embedder-Policy-Report-Only`, coepRo]]; } function navigationReportingTest(testName, host, coop, coep, coopRo, coepRo, - expectedReports ){ + expectedReports) { const executorToken = token(); const callbackToken = token(); promise_test(async t => { - await reportingTest( async resolve => { + await reportingTest(async resolve => { + const openee_headers = [ + getReportToHeader(host.origin), + ...getPolicyHeaders(coop, coep, coopRo, coepRo) + ].map(convertToWPTHeaderPipe); const openee_url = host.origin + executor_path + - `|header(report-to,${encodeURIComponent(getReportEndpoints(host.origin))})` + - `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(coop)})` + - `|header(Cross-Origin-Embedder-Policy,${encodeURIComponent(coep)})` + - `|header(Cross-Origin-Opener-Policy-Report-Only,${encodeURIComponent(coopRo)})` + - `|header(Cross-Origin-Embedder-Policy-Report-Only,${encodeURIComponent(coepRo)})`+ - `&uuid=${executorToken}`; + openee_headers.join('|') + `&uuid=${executorToken}`; const openee = window.open(openee_url); const uuid = token(); t.add_cleanup(() => send(uuid, "window.close()")); // 1. Make sure the new document is loaded. send(executorToken, ` - send("${callbackToken}", "Ready"); - `); + send("${callbackToken}", "Ready"); + `); let reply = await receive(callbackToken); assert_equals(reply, "Ready"); resolve(); @@ -241,6 +259,43 @@ function navigationReportingTest(testName, host, coop, coep, coopRo, coepRo, }, `coop reporting test ${testName} to ${host.name} with ${coop}, ${coep}, ${coopRo}, ${coepRo}`); } +function navigationDocumentReportingTest(testName, host, coop, coep, coopRo, + coepRo, expectedReports) { + const executorToken = token(); + const callbackToken = token(); + promise_test(async t => { + const openee_headers = [ + getReportingEndpointsHeader(host.origin), + ...getPolicyHeaders(coop, coep, coopRo, coepRo) + ].map(convertToWPTHeaderPipe); + const openee_url = host.origin + executor_path + + openee_headers.join('|') + `&uuid=${executorToken}`; + window.open(openee_url); + t.add_cleanup(() => send(executorToken, "window.close()")); + // Have openee window send a message through dispatcher, once we receive + // the Ready message from dispatcher it means the openee is fully loaded. + send(executorToken, ` + send("${callbackToken}", "Ready"); + `); + let reply = await receive(callbackToken); + assert_equals(reply, "Ready"); + + await wait(1000); + + expectedReports = expectedReports.map( + (report) => replaceValuesInExpectedReport(report, executorToken)); + return Promise.all(expectedReports.map( + async ({ endpoint, report: expectedReport }) => { + await pollReports(endpoint); + for (let report of endpoint.reports) { + assert_true(isObjectAsExpected(report, expectedReport), + `report received for endpoint: ${endpoint.name} ${JSON.stringify(report)} should match ${JSON.stringify(expectedReport)}`); + } + assert_equals(endpoint.reports.length, 1, `has exactly one report for ${endpoint.name}`) + })); + }, `coop document reporting test ${testName} to ${host.name} with ${coop}, ${coep}, ${coopRo}, ${coepRo}`); +} + // Run an array of reporting tests then verify there's no reports that were not // expected. // Tests' elements contain: host, coop, coep, coop-report-only, @@ -254,6 +309,17 @@ async function runNavigationReportingTests(testName, tests) { verifyRemainingReports(); } +// Run an array of reporting tests using Reporting-Endpoints header then +// verify there's no reports that were not expected. +// Tests' elements contain: host, coop, coep, coop-report-only, +// coep-report-only, expectedReports. +// See isObjectAsExpected for explanations regarding the matching behavior. +function runNavigationDocumentReportingTests(testName, tests) { + clearReportsOnServer(); + tests.forEach(test => { + navigationDocumentReportingTest(testName, ...test); + }); +} function verifyRemainingReports() { promise_test(t => { @@ -275,7 +341,6 @@ const receiveReport = async function(uuid, type) { if (reports == "timeout") return "timeout"; reports = JSON.parse(reports); - for(report of reports) { if (report?.body?.type == type) return report; @@ -283,6 +348,17 @@ const receiveReport = async function(uuid, type) { } } +// Build a set of 'Cross-Origin-Opener-Policy' and +// 'Cross-Origin-Opener-Policy-Report-Only' headers. +const coopHeaders = function (uuid) { + return { + coopSameOriginHeader: `|header(Cross-Origin-Opener-Policy,same-origin%3Breport-to="${uuid}")`, + coopSameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy,same-origin-allow-popups%3Breport-to="${uuid}")`, + coopReportOnlySameOriginHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin%3Breport-to="${uuid}")`, + coopReportOnlySameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin-allow-popups%3Breport-to="${uuid}")` + }; +} + // Build a set of headers to tests the reporting API. This defines a set of // matching 'Report-To', 'Cross-Origin-Opener-Policy' and // 'Cross-Origin-Opener-Policy-Report-Only' headers. @@ -302,9 +378,19 @@ const reportToHeaders = function(uuid) { return { header: `|header(report-to,${reportToJSON})`, - coopSameOriginHeader: `|header(Cross-Origin-Opener-Policy,same-origin%3Breport-to="${uuid}")`, - coopSameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy,same-origin-allow-popups%3Breport-to="${uuid}")`, - coopReportOnlySameOriginHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin%3Breport-to="${uuid}")`, - coopReportOnlySameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin-allow-popups%3Breport-to="${uuid}")`, + ...coopHeaders(uuid) + }; +}; + +// Build a set of headers to tests the reporting API. This defines a set of +// matching 'Reporting-Endpoints', 'Cross-Origin-Opener-Policy' and +// 'Cross-Origin-Opener-Policy-Report-Only' headers. +const reportingEndpointsHeaders = function (uuid) { + const report_endpoint_url = dispatcher_path + `?uuid=${uuid}`; + const reporting_endpoints_header = `${uuid}="${report_endpoint_url}"`; + + return { + header: `|header(Reporting-Endpoints,${reporting_endpoints_header})`, + ...coopHeaders(uuid) }; };