style.https.html (11221B)
1 <!doctype html> 2 <meta name="timeout" content="long"> 3 <meta name="variant" content="?reporting=false"> 4 <meta name="variant" content="?reporting=true"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/common/dispatcher/dispatcher.js"></script> 8 <script src="/common/utils.js"></script> 9 <script src="/common/get-host-info.sub.js"></script> 10 <script src="/reporting/resources/report-helper.js"></script> 11 12 <body> 13 <script> 14 const params = new URLSearchParams(location.search); 15 const with_reporting = params.get('reporting') === "true"; 16 const {ORIGIN} = get_host_info(); 17 const getAbsoluteUrl = url => { 18 return new URL(url, window.location.href).href; 19 } 20 21 const check_report = async (reporting_endpoint, reporting_uuid, iframe_url, url, report_only) => { 22 const reports = await pollReports(reporting_endpoint, reporting_uuid); 23 const abs_iframe_url = getAbsoluteUrl(iframe_url); 24 checkReportExists(reports, 'integrity-violation', abs_iframe_url); 25 const abs_blocked_url = getAbsoluteUrl(url); 26 const report = getReport(reports, 'integrity-violation', abs_iframe_url, abs_blocked_url); 27 assert_not_equals(report, null); 28 assert_equals(report.body.documentURL, abs_iframe_url); 29 assert_equals(report.body.blockedURL, abs_blocked_url); 30 assert_equals(report.body.destination, "style"); 31 assert_equals(report.body.reportOnly, report_only); 32 }; 33 const css = "#colorme{color:red}"; 34 const data_url = "data:text/css," + encodeURIComponent(css); 35 const blob_url = URL.createObjectURL( 36 new Blob([css], { type: "text/css" }) 37 ); 38 39 const test_cases = [ 40 { 41 description: "Ensure that a style without integrity did not run", 42 url: "/subresource-integrity/integrity-policy/resources/style.css", 43 cross_origin: true, 44 integrity: "", 45 policy_violation: true, 46 add_blocking_header: true, 47 endpoints: true, 48 expected: {blocked: ORIGIN + "/subresource-integrity/integrity-policy/resources/style.css", ran: false}, 49 }, 50 { 51 description: "Ensure that a style with unknown integrity algorithm did not run", 52 url: "/subresource-integrity/integrity-policy/resources/style.css", 53 cross_origin: true, 54 integrity: "foobar-AAAAAAAAAAAAAAAAAAAa", 55 policy_violation: true, 56 add_blocking_header: true, 57 endpoints: true, 58 expected: {blocked: ORIGIN + "/subresource-integrity/integrity-policy/resources/style.css", ran: false}, 59 }, 60 { 61 description: "Ensure that a style without integrity algorithm runs and gets reported in report-only mode", 62 url: "/subresource-integrity/integrity-policy/resources/style.css", 63 cross_origin: true, 64 integrity: "", 65 policy_violation: true, 66 add_blocking_header: false, 67 endpoints: true, 68 expected: {blocked: ORIGIN + "/subresource-integrity/integrity-policy/resources/style.css", ran: true}, 69 }, 70 { 71 description: "Ensure that a no-cors style gets blocked", 72 url: "/subresource-integrity/integrity-policy/resources/style.css", 73 cross_origin: false, 74 integrity: "sha384-ZjBq1bS4AaQJymICRIs2uvZpdcyP4YGXo8zIK63yJEsflw9K+r5oefJVZ3JAJ0xn", 75 policy_violation: true, 76 add_blocking_header: true, 77 endpoints: true, 78 expected: {blocked: ORIGIN + "/subresource-integrity/integrity-policy/resources/style.css", ran: false}, 79 }, 80 { 81 description: "Ensure that ReportingObserver gets called without endpoints", 82 url: "/subresource-integrity/integrity-policy/resources/style.css", 83 cross_origin: false, 84 integrity: "sha384-ZjBq1bS4AaQJymICRIs2uvZpdcyP4YGXo8zIK63yJEsflw9K+r5oefJVZ3JAJ0xn", 85 policy_violation: true, 86 add_blocking_header: true, 87 endpoints: false, 88 expected: {blocked: ORIGIN + "/subresource-integrity/integrity-policy/resources/style.css", ran: false}, 89 }, 90 { 91 description: "Ensure that a style with integrity runs", 92 url: "/subresource-integrity/integrity-policy/resources/style.css", 93 cross_origin: true, 94 integrity: "sha384-ZjBq1bS4AaQJymICRIs2uvZpdcyP4YGXo8zIK63yJEsflw9K+r5oefJVZ3JAJ0xn", 95 policy_violation: false, 96 add_blocking_header: true, 97 endpoints: true, 98 expected: {blocked: "", ran: true}, 99 }, 100 { 101 description: "Ensure that a data URI style with no integrity runs", 102 url: "data:text/css," + encodeURIComponent("#colorme{color:red}"), 103 cross_origin: true, 104 integrity: "", 105 policy_violation: false, 106 add_blocking_header: true, 107 endpoints: true, 108 expected: {blocked: "", ran: true}, 109 }, 110 { 111 description: "Ensure that a no-CORS data URI style with no integrity runs", 112 url: "data:text/css," + encodeURIComponent("#colorme{color:red}"), 113 cross_origin: false, 114 integrity: "", 115 policy_violation: false, 116 add_blocking_header: true, 117 endpoints: true, 118 expected: {blocked: "", ran: true}, 119 }, 120 { 121 description: "Ensure that a blob URL style with no integrity runs", 122 url: blob_url, 123 cross_origin: true, 124 integrity: "", 125 policy_violation: false, 126 add_blocking_header: true, 127 endpoints: true, 128 expected: {blocked: "", ran: true}, 129 }, 130 { 131 description: "Ensure that a no-CORS blob URL style with no integrity runs", 132 url: blob_url, 133 cross_origin: false, 134 integrity: "", 135 policy_violation: false, 136 add_blocking_header: true, 137 endpoints: true, 138 expected: {blocked: "", ran: true}, 139 }, 140 { 141 description: "Ensure that an about:blank URL style with no integrity does not trigger a report", 142 url: "about:blank", 143 cross_origin: true, 144 integrity: "", 145 policy_violation: false, 146 add_blocking_header: true, 147 endpoints: false, 148 expected: {blocked: "", ran: false}, 149 }, 150 { 151 description: "Ensure that a no-CORS about:blank URL style with no integrity does not trigger a report", 152 url: "about:blank", 153 cross_origin: false, 154 integrity: "", 155 policy_violation: false, 156 add_blocking_header: true, 157 endpoints: false, 158 expected: {blocked: "", ran: false}, 159 } 160 ]; 161 test_cases.map(test_case => { 162 promise_test(async () => { 163 const REMOTE_EXECUTOR = 164 `/common/dispatcher/remote-executor.html?pipe=`; 165 const iframe_uuid = token(); 166 167 const params = new URLSearchParams(location.search); 168 if (params.get('type') === "report") { 169 if (test_case.expected.blocked) { 170 return; 171 } 172 header_name += "-Report-Only"; 173 } 174 const reporting_uuid_1 = token(); 175 const reporting_uuid_2 = token(); 176 const reporting_uuid_3 = token(); 177 const reporting_endpoint = `${ORIGIN}/reporting/resources/report.py`; 178 let header = ""; 179 if (test_case.add_blocking_header) { 180 header += 181 `header(Integrity-Policy,blocked-destinations=\\(style\\)\\, endpoints=\\(integrity-endpoint-1 integrity-endpoint-2\\))`; 182 } 183 header += 184 `|header(Integrity-Policy-Report-Only,blocked-destinations=\\(style\\)\\, endpoints=\\(integrity-endpoint-3\\))`; 185 if (test_case.endpoints) { 186 header += 187 `|header(Reporting-Endpoints, integrity-endpoint-1=\"${reporting_endpoint}?reportID=${reporting_uuid_1}\"\\, ` + 188 `integrity-endpoint-2=\"${reporting_endpoint}?reportID=${reporting_uuid_2}\"\\, ` + 189 `integrity-endpoint-3=\"${reporting_endpoint}?reportID=${reporting_uuid_3}\")`; 190 } 191 const iframe_url = `${REMOTE_EXECUTOR}${encodeURIComponent(header)}&uuid=${iframe_uuid}`; 192 193 const iframe = document.createElement('iframe'); 194 iframe.src = iframe_url; 195 document.body.appendChild(iframe); 196 197 // Execute code directly from the iframe. 198 const ctx = new RemoteContext(iframe_uuid); 199 const result = await ctx.execute_script(async (test_case, with_reporting) => { 200 document.body.appendChild(document.createElement("span")).id = "colorme"; 201 202 // Always set up report observer to catch any unexpected reports 203 const report_observed_promise = new Promise(r => { 204 (new ReportingObserver((reports, observer) => { 205 reports.forEach(report => { 206 // Match the tested URL against the stripped one: 207 // https://www.w3.org/TR/reporting-1/#strip-url-for-use-in-reports 208 // 1. If url’s scheme is not an HTTP(S) scheme, then return url’s scheme. 209 const test_url = test_case.url.startsWith("http") ? 210 test_case.url : 211 test_case.url.split(":")[0]; 212 if (report.body.blockedURL.endsWith(test_url)) { 213 r(report.body); 214 observer.disconnect(); 215 } 216 }); 217 })).observe('integrity-violation'); 218 }); 219 220 // Load the style 221 await new Promise(resolve => { 222 const link = document.createElement('link'); 223 link.rel = "stylesheet"; 224 if (test_case.cross_origin) { 225 link.crossOrigin="anonymous"; 226 } 227 if (test_case.integrity) { 228 link.integrity = test_case.integrity; 229 } 230 link.onload = resolve; 231 link.onerror = resolve; 232 link.href = test_case.url; 233 document.body.appendChild(link); 234 }); 235 let report_body = null; 236 if (with_reporting) { 237 if (test_case.policy_violation) { 238 report_body = await report_observed_promise; 239 } else { 240 const timeout_promise = new Promise(r => setTimeout(() => r('timeout'), 100)); 241 const race_result = await Promise.race([report_observed_promise, timeout_promise]); 242 if (race_result !== 'timeout') { 243 report_body = race_result; 244 } 245 } 246 } 247 const ran = getComputedStyle(document.getElementById("colorme")).color === "rgb(255, 0, 0)"; 248 return { body: report_body, ran }; 249 }, [test_case, with_reporting]); 250 251 assert_equals(result.ran, test_case.expected.ran, "Ran"); 252 if (with_reporting) { 253 if (test_case.policy_violation) { 254 assert_not_equals(result.body, null, "Expected a policy violation report"); 255 assert_equals(result.body.blockedURL, test_case.expected.blocked); 256 assert_true(result.body.documentURL.endsWith(iframe_url)); 257 assert_equals(result.body.destination, "style"); 258 assert_equals(result.body.reportOnly, !test_case.add_blocking_header); 259 } else { 260 assert_equals(result.body, null, "No policy violation report should be observed"); 261 } 262 263 if (test_case.endpoints && test_case.policy_violation) { 264 if (test_case.add_blocking_header) { 265 await check_report(reporting_endpoint, reporting_uuid_1, iframe_url, test_case.url, !test_case.add_blocking_header); 266 await check_report(reporting_endpoint, reporting_uuid_2, iframe_url, test_case.url, !test_case.add_blocking_header); 267 } 268 await check_report(reporting_endpoint, reporting_uuid_3, iframe_url, test_case.url, true); 269 } 270 } 271 }, test_case.description); 272 }); 273 </script>