frame-ancestors-test.sub.js (5722B)
1 var SAME_ORIGIN = true; 2 var CROSS_ORIGIN = false; 3 4 var EXPECT_BLOCK = true; 5 var EXPECT_LOAD = false; 6 7 var SAMEORIGIN_ORIGIN = "{{location[scheme]}}://{{location[host]}}"; 8 var CROSSORIGIN_ORIGIN = "http://{{domains[www1]}}:{{ports[http][1]}}"; 9 10 var test; 11 12 function endTest(failed, message) { 13 if (typeof test === 'undefined') return; 14 15 if (failed) { 16 test.step(function() { 17 assert_unreached(message); 18 test.done(); 19 }); 20 } 21 else test.done({message: message}); 22 } 23 24 window.addEventListener("message", function (e) { 25 if (window.parent != window) 26 window.parent.postMessage(e.data, "*"); 27 else 28 if (e.data.type === 'test_result') 29 endTest(e.data.failed, "Inner IFrame msg: " + e.data.message); 30 }); 31 32 function injectNestedIframe(policy, parent, child, expectation, isSandboxed) { 33 var iframe = document.createElement("iframe"); 34 35 var url = "/content-security-policy/frame-ancestors/support/frame-in-frame.sub.html" 36 + "?policy=" + policy 37 + "&parent=" + parent 38 + "&child=" + child 39 + "&expectation=" + expectation; 40 url = (parent == "same" ? SAMEORIGIN_ORIGIN : CROSSORIGIN_ORIGIN) + url; 41 42 iframe.src = url; 43 44 if (isSandboxed) 45 iframe.sandbox = 'allow-scripts'; 46 47 document.body.appendChild(iframe); 48 } 49 50 let timer; 51 function pollForLoadCompletion({iframe, expectBlock}) { 52 let fn = iframeLoaded({expectBlock, isPoll: true}); 53 timer = test.step_timeout(() => fn({target: iframe}), 10); 54 } 55 56 function injectIFrame(policy, sameOrigin, expectBlock) { 57 var iframe = document.createElement("iframe"); 58 iframe.addEventListener("load", iframeLoaded({expectBlock, isPoll: false})); 59 iframe.addEventListener("error", iframeLoaded({expectBlock, isPoll: false})); 60 61 var url = "/content-security-policy/frame-ancestors/support/frame-ancestors.sub.html?policy=" + policy; 62 if (sameOrigin) 63 url = SAMEORIGIN_ORIGIN + url; 64 else 65 url = CROSSORIGIN_ORIGIN + url; 66 67 iframe.src = url; 68 document.body.appendChild(iframe); 69 pollForLoadCompletion({iframe, expectBlock}); 70 } 71 72 function iframeLoaded({isPoll, expectBlock}) { 73 return function(ev) { 74 clearTimeout(timer); 75 var failed = true; 76 var message = ""; 77 try { 78 let url = ev.target.contentWindow.location.href; 79 if (isPoll && (url === "about:blank" || ev.target.contentDocument.readyState !== "complete")) { 80 pollForLoadCompletion({iframe: ev.target, expectBlock}); 81 return; 82 } 83 if (expectBlock) { 84 message = "The IFrame should have been blocked (or cross-origin). It wasn't."; 85 failed = true; 86 } else { 87 message = "The IFrame should not have been blocked. It wasn't."; 88 failed = false; 89 } 90 } catch (ex) { 91 if (expectBlock) { 92 message = "The IFrame should have been blocked (or cross-origin). It was."; 93 failed = false; 94 } else { 95 message = "The IFrame should not have been blocked. It was."; 96 failed = true; 97 } 98 } 99 if (window.parent != window) 100 window.parent.postMessage({type: 'test_result', failed: failed, message: message}, '*'); 101 else 102 endTest(failed, message); 103 }; 104 } 105 106 function originFrameShouldBe(child, expectation, policy) { 107 if (child == "cross" && expectation == "blocked") crossOriginFrameShouldBeBlocked(policy); 108 if (child == "same" && expectation == "blocked") sameOriginFrameShouldBeBlocked(policy); 109 if (child == "cross" && expectation == "allowed") crossOriginFrameShouldBeAllowed(policy); 110 if (child == "same" && expectation == "allowed") sameOriginFrameShouldBeAllowed(policy); 111 } 112 113 function crossOriginFrameShouldBeBlocked(policy) { 114 window.onload = function () { 115 injectIFrame(policy, CROSS_ORIGIN, EXPECT_BLOCK); 116 }; 117 } 118 119 function crossOriginFrameShouldBeAllowed(policy) { 120 window.onload = function () { 121 injectIFrame(policy, CROSS_ORIGIN, EXPECT_LOAD); 122 }; 123 } 124 125 function sameOriginFrameShouldBeBlocked(policy) { 126 window.onload = function () { 127 injectIFrame(policy, SAME_ORIGIN, EXPECT_BLOCK); 128 }; 129 } 130 131 function sameOriginFrameShouldBeAllowed(policy) { 132 window.onload = function () { 133 injectIFrame(policy, SAME_ORIGIN, EXPECT_LOAD); 134 }; 135 } 136 137 function testNestedIFrame(policy, parent, child, expectation) { 138 window.onload = function () { 139 injectNestedIframe(policy, parent == SAME_ORIGIN ? "same" : "cross", child == SAME_ORIGIN ? "same" : "cross", expectation == EXPECT_LOAD ? "allowed" : "blocked", false /* isSandboxed */); 140 }; 141 } 142 143 function testNestedSandboxedIFrame(policy, parent, child, expectation) { 144 window.onload = function () { 145 injectNestedIframe(policy, parent == SAME_ORIGIN ? "same" : "cross", child == SAME_ORIGIN ? "same" : "cross", expectation == EXPECT_LOAD ? "allowed" : "blocked", true /* isSandboxed */); 146 }; 147 } 148 149 function testUrlWithPathIgnored() { 150 window.onload = function () { 151 // A policy with a URL with a path should block the load, because no 152 // origin matches against a source expression with a path. See 153 // https://issues.chromium.org/issues/40779556#comment12 and 154 // https://w3c.github.io/webappsec-csp/#frame-ancestors-navigation-response 155 // steps 6.2 and 6.3. 156 injectIFrame(SAMEORIGIN_ORIGIN + "/test", SAME_ORIGIN, EXPECT_BLOCK); 157 // The same policy with no path should allow the load (smoke test). 158 injectIFrame(SAMEORIGIN_ORIGIN, SAME_ORIGIN, EXPECT_LOAD); 159 }; 160 }