basic-popup-and-iframe-tests.https.js (10730B)
1 /** 2 * This test checks the Secure Context state of documents for various 3 * permutations of document URI types and loading methods. 4 * 5 * The hierarchy that is tested is: 6 * 7 * creator-doc > createe-doc 8 * 9 * The creator-doc is one of: 10 * 11 * http: 12 * https: 13 * 14 * The createe-doc is loaded as either a: 15 * 16 * popup 17 * iframe 18 * sandboxed-iframe 19 * 20 * into which we load and test: 21 * 22 * http: 23 * https: 24 * blob: 25 * javascript: 26 * about:blank 27 * initial about:blank 28 * srcdoc 29 * 30 * TODO once web-platform-tests supports it: 31 * - test http://localhost 32 * - test file: 33 */ 34 35 36 setup({explicit_done:true}); 37 38 39 const host_and_dirname = location.host + 40 location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1); 41 42 43 // Flags to indicate where document types should be loaded for testing: 44 const eLoadInPopup = (1 << 0); 45 const eLoadInUnsandboxedIframe = (1 << 1); 46 const eLoadInSandboxedIframe = (1 << 2); 47 const eLoadInEverything = eLoadInPopup | eLoadInUnsandboxedIframe | eLoadInSandboxedIframe; 48 49 // Flags indicating if a document type is expected to be a Secure Context: 50 const eSecureNo = 1; 51 const eSecureIfNewWindow = 2; 52 const eSecureIfCreatorSecure = 3; 53 54 // Flags indicating how the result of a test is obtained: 55 const eResultFromPostMessage = 1; 56 const eResultFromExaminationOnLoad = 2; 57 const eResultFromExaminationSync = 3; 58 59 60 const loadTypes = [ 61 new LoadType("an http: URI", 62 eLoadInEverything, 63 http_dir + "postMessage-helper.html", 64 eSecureNo, 65 eResultFromPostMessage), 66 new LoadType("an https: URI", 67 eLoadInEverything, 68 https_dir + "postMessage-helper.https.html", 69 eSecureIfNewWindow, 70 eResultFromPostMessage), 71 new LoadType("a blob: URI", 72 eLoadInEverything, 73 URL.createObjectURL(new Blob(["<script>(opener||parent).postMessage(isSecureContext, '*')</script>"], {type: "text/html"})), 74 eSecureIfCreatorSecure, 75 eResultFromPostMessage), 76 new LoadType("a srcdoc", 77 // popup not relevant: 78 eLoadInUnsandboxedIframe | eLoadInSandboxedIframe, 79 "<script>(opener||parent).postMessage(isSecureContext, '*')</script>", 80 eSecureIfNewWindow, 81 eResultFromPostMessage), 82 new LoadType("a javascript: URI", 83 // can't load in sandbox: 84 eLoadInUnsandboxedIframe | eLoadInPopup, 85 "javascript:(opener||parent).postMessage(isSecureContext, '*')", 86 eSecureIfCreatorSecure, 87 eResultFromPostMessage), 88 new LoadType("about:blank", 89 // can't obtain state if sandboxed: 90 eLoadInUnsandboxedIframe | eLoadInPopup, 91 "about:blank", 92 eSecureIfCreatorSecure, 93 eResultFromExaminationOnLoad), 94 new LoadType("initial about:blank", 95 // can't obtain state if sandboxed: 96 eLoadInUnsandboxedIframe | eLoadInPopup, 97 "about:blank", // we don't wait for this to load, so whatever 98 eSecureIfCreatorSecure, 99 eResultFromExaminationSync), 100 new LoadType("a data: URL", 101 // can't load in a top-level browsing context 102 eLoadInUnsandboxedIframe | eLoadInSandboxedIframe, 103 "data:text/html,<script>parent.postMessage(isSecureContext, '*')</script>", 104 eSecureIfCreatorSecure, 105 eResultFromPostMessage), 106 ]; 107 108 const loadTargets = [ 109 new LoadTarget("an iframe", eLoadInUnsandboxedIframe), 110 new LoadTarget("a sandboxed iframe", eLoadInSandboxedIframe), 111 new LoadTarget("a popup", eLoadInPopup), 112 ]; 113 114 115 function LoadType(description, loadInFlags, uri, expectedSecureFlag, resultFrom) { 116 this.desc = description; 117 this.loadInFlags = loadInFlags; 118 this.uri = uri; 119 this.expectedSecureFlag = expectedSecureFlag; 120 this.resultFrom = resultFrom; 121 } 122 123 124 function LoadTarget(description, loadInFlag) { 125 this.desc = description; 126 this.loadInFlag = loadInFlag; 127 } 128 129 LoadTarget.prototype.open = function(loadType) { 130 let loadTarget = this; 131 this.currentTest.step(function() { 132 assert_true((loadTarget.loadInFlag & loadType.loadInFlags) != 0, 133 loadType.desc + " cannot be tested in " + loadTarget.desc); 134 }); 135 if (this.loadInFlag == eLoadInUnsandboxedIframe) { 136 let iframe = document.createElement("iframe"); 137 document.body.appendChild(iframe); 138 iframe[loadType.desc == "a srcdoc" ? "srcdoc" : "src"] = loadType.uri; 139 return iframe; 140 } 141 if (this.loadInFlag == eLoadInSandboxedIframe) { 142 let iframe = document.body.appendChild(document.createElement("iframe")); 143 iframe.setAttribute("sandbox", "allow-scripts"); 144 iframe[loadType.desc == "a srcdoc" ? "srcdoc" : "src"] = loadType.uri; 145 return iframe; 146 } 147 if (this.loadInFlag == eLoadInPopup) { 148 return window.open(loadType.uri); 149 } 150 this.currentTest.step(function() { 151 assert_unreached("Unknown load type flag: " + loadInFlags); 152 }); 153 return null; 154 } 155 156 LoadTarget.prototype.close = function(domTarget) { 157 if (this.loadInFlag == eLoadInUnsandboxedIframe || 158 this.loadInFlag == eLoadInSandboxedIframe) { 159 domTarget.remove(); 160 return; 161 } 162 if (this.loadInFlag == eLoadInPopup) { 163 domTarget.close(); 164 return; 165 } 166 this.currentTest.step(function() { 167 assert_unreached("Unknown load type flag: " + loadInFlags); 168 }); 169 } 170 171 LoadTarget.prototype.load_and_get_result_for = function(loadType) { 172 if (!(loadType.loadInFlags & this.loadInFlag)) { 173 return Promise.reject("not applicable"); 174 } 175 if (!(this.loadInFlag & eLoadInPopup) && 176 location.protocol == "https:" && 177 loadType.uri.substr(0,5) == "http:") { 178 // Mixed content blocker will prevent this load 179 return Promise.reject("not applicable"); 180 } 181 this.currentTest = async_test("Test Window.isSecureContext in " + this.desc + 182 " loading " + loadType.desc) 183 if (loadType.resultFrom == eResultFromExaminationSync) { 184 let domTarget = this.open(loadType); 185 let isFrame = domTarget instanceof HTMLIFrameElement; 186 let result = !isFrame ? 187 domTarget.isSecureContext : domTarget.contentWindow.isSecureContext; 188 this.close(domTarget); 189 return Promise.resolve({ result: result, isFrame: isFrame}); 190 } 191 let target = this; 192 if (loadType.resultFrom == eResultFromExaminationOnLoad) { 193 return new Promise(function(resolve, reject) { 194 function handleLoad(event) { 195 clearTimeout(timer); 196 let isFrame = domTarget instanceof HTMLIFrameElement; 197 let result = !isFrame ? 198 domTarget.isSecureContext : domTarget.contentWindow.isSecureContext; 199 domTarget.removeEventListener("load", handleLoad); 200 target.close(domTarget); 201 resolve({ result: result, isFrame: isFrame}); 202 } 203 let domTarget = target.open(loadType); 204 domTarget.addEventListener("load", handleLoad, false); 205 206 // Some browsers don't fire `load` events for `about:blank`. That's weird, but it also 207 // isn't what we're testing here. 208 let timer = setTimeout(handleLoad, 500); 209 }); 210 } 211 if (loadType.resultFrom == eResultFromPostMessage) { 212 return new Promise(function(resolve, reject) { 213 function handleMessage(event) { 214 let isFrame = domTarget instanceof HTMLIFrameElement; 215 window.removeEventListener("message", handleMessage); 216 target.close(domTarget); 217 resolve({ result: event.data, isFrame: isFrame}); 218 } 219 window.addEventListener("message", handleMessage, false); 220 let domTarget = target.open(loadType); 221 }); 222 } 223 return Promise.reject("unexpected 'result from' type"); 224 } 225 226 227 let current_type_index = -1; 228 let current_target_index = 0; 229 230 function run_next_test() { 231 current_type_index++; 232 if (current_type_index >= loadTypes.length) { 233 current_type_index = 0; 234 current_target_index++; 235 if (current_target_index >= loadTargets.length) { 236 done(); 237 return; // all test permutations complete 238 } 239 } 240 let loadTarget = loadTargets[current_target_index]; 241 let loadType = loadTypes[current_type_index]; 242 loadTarget.load_and_get_result_for(loadType).then( 243 function(value) { 244 run_next_test_soon(); 245 loadTarget.currentTest.step(function() { 246 // If the new context is always non-secure, the assertion is straightforward. 247 if (loadType.expectedSecureFlag == eSecureNo) { 248 assert_false(value.result, loadType.desc + " in " + loadTarget.desc + " should not create a Secure Context"); 249 // If the new context is always secure if opened in a new window, and it's 250 // been opened in a new window, the assertion is likewise straightforward. 251 } else if (loadType.expectedSecureFlag == eSecureIfNewWindow && !value.isFrame) { 252 assert_true(value.result, loadType.desc + " in " + loadTarget.desc + " should create a secure context regardless of its creator's state."); 253 // Otherwise, we're either dealing with a context that's secure if and only 254 // if its creator context (e.g. this window) is secure. 255 } else if ((loadType.expectedSecureFlag == eSecureIfNewWindow && value.isFrame) || 256 (loadType.expectedSecureFlag == eSecureIfCreatorSecure)) { 257 if (!window.isSecureContext) { 258 assert_false(value.result, loadType.desc + " in " + loadTarget.desc + " should not create a Secure Context when its creator is not a Secure Context."); 259 } else { 260 assert_true(value.result, loadType.desc + " in " + loadTarget.desc + " should create a Secure Context when its creator is a Secure Context"); 261 } 262 } else { 263 assert_unreached(loadType.desc + " - unknown expected secure flag: " + expectedSecureFlag); 264 } 265 loadTarget.currentTest.done(); 266 }); 267 }, 268 function(failReason) { 269 run_next_test_soon(); 270 if (failReason == "not applicable") { 271 return; 272 } 273 loadTarget.currentTest.step(function() { 274 assert_unreached(loadType.desc + " - got unexpected rejected promise"); 275 }); 276 } 277 ); 278 } 279 280 function run_next_test_soon() { 281 setTimeout(run_next_test, 0); 282 } 283 284 function begin() { 285 test(function() { 286 if (location.protocol == "http:") { 287 assert_false(isSecureContext, 288 "http: creator should not be a Secure Context"); 289 } else if (location.protocol == "https:") { 290 assert_true(isSecureContext, 291 "https: creator should be a Secure Context"); 292 } else { 293 assert_unreached("Unknown location.protocol"); 294 } 295 }); 296 run_next_test(); 297 }