|
| 1 | +<!DOCTYPE html> |
| 2 | +<script src="/resources/testharness.js"></script> |
| 3 | +<script src="/resources/testharnessreport.js"></script> |
| 4 | +<script src="support/namespaces.js"></script> |
| 5 | +<script src="support/passthroughpolicy.js"></script> |
| 6 | +<script src="support/script-messages.js"></script> |
| 7 | +<link rel="help" href="https://w3c.github.io/trusted-types/dist/spec/#enforcement-in-scripts"> |
| 8 | +<link rel="help" href="https://html.spec.whatwg.org/#prepare-the-script-element"> |
| 9 | +<link rel="help" href="https://w3c.github.io/webappsec-csp/#should-block-inline"> |
| 10 | +<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'"> |
| 11 | +<meta id="metaTagForScriptSrc" http-equiv="Content-Security-Policy" content="script-src 'nonce-script-messages' 'nonce-self' 'sha256-IpCtvKVFQbqDBhwCvQEsZoqgVXvAd6T2uRWd/Pz7FuI=' 'sha256-xanaWuoRdfLzI0+K8zpwr8eHi4RK2P6GglgCFXv0r00=' 'sha256-BPWjrQT1GMyyQ+6Fmycn7pSqh8L945ToMJ/nfGClLBc='"> |
| 12 | +<!-- This test covers the following step from the "prepare the script element" |
| 13 | + algorithm, verifying that "source text" is the one after application of |
| 14 | + the default policy: "If el does not have a src content attribute, and the |
| 15 | + Should element's inline behavior be blocked by Content Security Policy? |
| 16 | + algorithm returns "Blocked" when given el, "script", and source text, then |
| 17 | + return." --> |
| 18 | +<div id="container"></div> |
| 19 | +<script nonce="self"> |
| 20 | + const logMessageModulePath = "./support/logMessage-module.sub.js"; |
| 21 | + |
| 22 | + // Define a default policy that transforms the script's type to some valid |
| 23 | + // source content. |
| 24 | + function scriptTypeToValue(value) { |
| 25 | + switch (value) { |
| 26 | + case "classic": |
| 27 | + return `window.log_message('CLASSIC');`; |
| 28 | + case "module": |
| 29 | + return `window.log_message('MODULE');`; |
| 30 | + case "importmap": |
| 31 | + return `{ "imports": { "${logMessageModulePath}?message=UNMAPPED": "${logMessageModulePath}?message=IMPORTMAP" }}`; |
| 32 | + } |
| 33 | + } |
| 34 | + trustedTypes.createPolicy("default", { |
| 35 | + createScript: (value, _, sink) => { |
| 36 | + window.log_message("CREATE_SCRIPT"); |
| 37 | + window.log_message(sink); |
| 38 | + return scriptTypeToValue(value); |
| 39 | + } |
| 40 | + }); |
| 41 | + |
| 42 | + promise_test(async t => { |
| 43 | + let classicHash = await base64_hash_for_inline_script(scriptTypeToValue("classic"), "SHA-256"); |
| 44 | + let moduleHash = await base64_hash_for_inline_script(scriptTypeToValue("module"), "SHA-256"); |
| 45 | + let importmapHash = await base64_hash_for_inline_script(scriptTypeToValue("importmap"), "SHA-256"); |
| 46 | + let metaTagContent = document.getElementById("metaTagForScriptSrc").getAttribute("content"); |
| 47 | + assert_equals(metaTagContent, `script-src 'nonce-script-messages' 'nonce-self' 'sha256-${classicHash}' 'sha256-${moduleHash}' 'sha256-${importmapHash}'`); |
| 48 | + }, "script-src CSP directive is properly set."); |
| 49 | + |
| 50 | + promise_test(async t => { |
| 51 | + let messages = await script_messages_for(_ => { |
| 52 | + let script = create_html_script_with_untrusted_source_text("classic"); |
| 53 | + script.setAttribute("type", "application/ecmascript"); |
| 54 | + // Appending the script will log "CLASSIC". |
| 55 | + container.appendChild(script); |
| 56 | + }); |
| 57 | + assert_array_equals(messages, ["CREATE_SCRIPT", "HTMLScriptElement text", "CLASSIC"]); |
| 58 | + }, "Untrusted HTMLScriptElement with classic type uses the source text returned by the default policy for inline CSP check."); |
| 59 | + |
| 60 | + // Firefox disallows import map after a module load, so place this promise |
| 61 | + // test before the module test. |
| 62 | + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1916277#c4 |
| 63 | + promise_test(async t => { |
| 64 | + let messages = await script_messages_for(async _ => { |
| 65 | + let script = create_html_script_with_untrusted_source_text("importmap"); |
| 66 | + script.setAttribute("type", "importmap"); |
| 67 | + |
| 68 | + // Appending the script sets up an import map for logMessageModulePath. |
| 69 | + container.appendChild(script); |
| 70 | + |
| 71 | + // Importing logMessageModulePath will log message "IMPORTMAP" |
| 72 | + await import(`${logMessageModulePath}?message=UNMAPPED`); |
| 73 | + }); |
| 74 | + assert_array_equals(messages, ["CREATE_SCRIPT", "HTMLScriptElement text", "IMPORTMAP"]); |
| 75 | + }, "Untrusted HTMLScriptElement of importmap type uses the source text returned by the default policy for inline CSP check."); |
| 76 | + |
| 77 | + promise_test(async t => { |
| 78 | + let messages = await script_messages_for(async _ => { |
| 79 | + let script = create_html_script_with_untrusted_source_text("module"); |
| 80 | + script.setAttribute("type", "module"); |
| 81 | + |
| 82 | + // Appending the script will log message "MODULE" |
| 83 | + container.appendChild(script); |
| 84 | + }); |
| 85 | + assert_array_equals(messages, ["CREATE_SCRIPT", "HTMLScriptElement text", "MODULE"]); |
| 86 | + }, "Untrusted HTMLScriptElement of module type uses the source text returned by the default policy for inline CSP check."); |
| 87 | +</script> |
0 commit comments