|  | 
 | /** | 
 |  * This test checks the Secure Context state of documents for various | 
 |  * permutations of document URI types and loading methods. | 
 |  * | 
 |  * The hierarchy that is tested is: | 
 |  * | 
 |  *   creator-doc > createe-doc | 
 |  * | 
 |  * The creator-doc is one of: | 
 |  * | 
 |  *   http: | 
 |  *   https: | 
 |  * | 
 |  * The createe-doc is loaded as either a: | 
 |  * | 
 |  *   popup | 
 |  *   iframe | 
 |  *   sandboxed-iframe | 
 |  * | 
 |  * into which we load and test: | 
 |  * | 
 |  *   http: | 
 |  *   https: | 
 |  *   blob: | 
 |  *   javascript: | 
 |  *   about:blank | 
 |  *   initial about:blank | 
 |  *   srcdoc | 
 |  * | 
 |  * TODO once web-platform-tests supports it: | 
 |  *   - test http://localhost | 
 |  *   - test file: | 
 |  */ | 
 |  | 
 |  | 
 | setup({explicit_done:true}); | 
 |  | 
 |  | 
 | const host_and_dirname = location.host + | 
 |                          location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1); | 
 |  | 
 |  | 
 | // Flags to indicate where document types should be loaded for testing: | 
 | const eLoadInPopup             = (1 << 0); | 
 | const eLoadInUnsandboxedIframe = (1 << 1); | 
 | const eLoadInSandboxedIframe   = (1 << 2); | 
 | const eLoadInEverything        = eLoadInPopup | eLoadInUnsandboxedIframe | eLoadInSandboxedIframe; | 
 |  | 
 | // Flags indicating if a document type is expected to be a Secure Context: | 
 | const eSecureNo              = 1; | 
 | const eSecureIfNewWindow     = 2; | 
 | const eSecureIfCreatorSecure = 3; | 
 |  | 
 | // Flags indicating how the result of a test is obtained: | 
 | const eResultFromPostMessage       = 1; | 
 | const eResultFromExaminationOnLoad = 2; | 
 | const eResultFromExaminationSync   = 3; | 
 |  | 
 |  | 
 | const loadTypes = [ | 
 |   new LoadType("an http: URI", | 
 |                eLoadInEverything, | 
 |                http_dir + "postMessage-helper.html", | 
 |                eSecureNo, | 
 |                eResultFromPostMessage), | 
 |   new LoadType("an https: URI", | 
 |                eLoadInEverything, | 
 |                https_dir + "postMessage-helper.https.html", | 
 |                eSecureIfNewWindow, | 
 |                eResultFromPostMessage), | 
 |   new LoadType("a blob: URI", | 
 |                eLoadInEverything, | 
 |                URL.createObjectURL(new Blob(["<script>(opener||parent).postMessage(isSecureContext, '*')</script>"], {type: "text/html"})), | 
 |                eSecureIfCreatorSecure, | 
 |                eResultFromPostMessage), | 
 |   new LoadType("a srcdoc", | 
 |                // popup not relevant: | 
 |                eLoadInUnsandboxedIframe | eLoadInSandboxedIframe, | 
 |                "<script>(opener||parent).postMessage(isSecureContext, '*')</script>", | 
 |                eSecureIfNewWindow, | 
 |                eResultFromPostMessage), | 
 |   new LoadType("a javascript: URI", | 
 |                // can't load in sandbox: | 
 |                eLoadInUnsandboxedIframe | eLoadInPopup, | 
 |                "javascript:(opener||parent).postMessage(isSecureContext, '*')", | 
 |                eSecureIfCreatorSecure, | 
 |                eResultFromPostMessage), | 
 |   new LoadType("about:blank", | 
 |                // can't obtain state if sandboxed: | 
 |                eLoadInUnsandboxedIframe | eLoadInPopup, | 
 |                "about:blank", | 
 |                eSecureIfCreatorSecure, | 
 |                eResultFromExaminationOnLoad), | 
 |   new LoadType("initial about:blank", | 
 |                // can't obtain state if sandboxed: | 
 |                eLoadInUnsandboxedIframe | eLoadInPopup, | 
 |                "about:blank", // we don't wait for this to load, so whatever | 
 |                eSecureIfCreatorSecure, | 
 |                eResultFromExaminationSync), | 
 |   new LoadType("a data: URL", | 
 |                // can't load in a top-level browsing context | 
 |                eLoadInUnsandboxedIframe | eLoadInSandboxedIframe, | 
 |                "data:text/html,<script>parent.postMessage(isSecureContext, '*')</script>", | 
 |                eSecureIfCreatorSecure, | 
 |                eResultFromPostMessage), | 
 | ]; | 
 |  | 
 | const loadTargets = [ | 
 |   new LoadTarget("an iframe",          eLoadInUnsandboxedIframe), | 
 |   new LoadTarget("a sandboxed iframe", eLoadInSandboxedIframe), | 
 |   new LoadTarget("a popup",            eLoadInPopup), | 
 | ]; | 
 |  | 
 |  | 
 | function LoadType(description, loadInFlags, uri, expectedSecureFlag, resultFrom) { | 
 |   this.desc = description; | 
 |   this.loadInFlags = loadInFlags; | 
 |   this.uri = uri; | 
 |   this.expectedSecureFlag = expectedSecureFlag; | 
 |   this.resultFrom = resultFrom; | 
 | } | 
 |  | 
 |  | 
 | function LoadTarget(description, loadInFlag) { | 
 |   this.desc = description; | 
 |   this.loadInFlag = loadInFlag; | 
 | } | 
 |  | 
 | LoadTarget.prototype.open = function(loadType) { | 
 |   let loadTarget = this; | 
 |   this.currentTest.step(function() { | 
 |     assert_true((loadTarget.loadInFlag & loadType.loadInFlags) != 0, | 
 |                 loadType.desc + " cannot be tested in " + loadTarget.desc); | 
 |   }); | 
 |   if (this.loadInFlag == eLoadInUnsandboxedIframe) { | 
 |     let iframe = document.createElement("iframe"); | 
 |     document.body.appendChild(iframe); | 
 |     iframe[loadType.desc == "a srcdoc" ? "srcdoc" : "src"] = loadType.uri; | 
 |     return iframe; | 
 |   } | 
 |   if (this.loadInFlag == eLoadInSandboxedIframe) { | 
 |     let iframe = document.body.appendChild(document.createElement("iframe")); | 
 |     iframe.setAttribute("sandbox", "allow-scripts"); | 
 |     iframe[loadType.desc == "a srcdoc" ? "srcdoc" : "src"] = loadType.uri; | 
 |     return iframe; | 
 |   } | 
 |   if (this.loadInFlag == eLoadInPopup) { | 
 |     return window.open(loadType.uri); | 
 |   } | 
 |   this.currentTest.step(function() { | 
 |     assert_unreached("Unknown load type flag: " + loadInFlags); | 
 |   }); | 
 |   return null; | 
 | } | 
 |  | 
 | LoadTarget.prototype.close = function(domTarget) { | 
 |   if (this.loadInFlag == eLoadInUnsandboxedIframe || | 
 |       this.loadInFlag == eLoadInSandboxedIframe) { | 
 |     domTarget.remove(); | 
 |     return; | 
 |   } | 
 |   if (this.loadInFlag == eLoadInPopup) { | 
 |     domTarget.close(); | 
 |     return; | 
 |   } | 
 |   this.currentTest.step(function() { | 
 |     assert_unreached("Unknown load type flag: " + loadInFlags); | 
 |   }); | 
 | } | 
 |  | 
 | LoadTarget.prototype.load_and_get_result_for = function(loadType) { | 
 |   if (!(loadType.loadInFlags & this.loadInFlag)) { | 
 |     return Promise.reject("not applicable"); | 
 |   } | 
 |   if (!(this.loadInFlag & eLoadInPopup) && | 
 |       location.protocol == "https:" && | 
 |       loadType.uri.substr(0,5) == "http:") { | 
 |     // Mixed content blocker will prevent this load | 
 |     return Promise.reject("not applicable"); | 
 |   } | 
 |   this.currentTest = async_test("Test Window.isSecureContext in " + this.desc + | 
 |                                 " loading " + loadType.desc) | 
 |   if (loadType.resultFrom == eResultFromExaminationSync) { | 
 |     let domTarget = this.open(loadType); | 
 |     let isFrame = domTarget instanceof HTMLIFrameElement; | 
 |     let result = !isFrame ? | 
 |           domTarget.isSecureContext : domTarget.contentWindow.isSecureContext; | 
 |     this.close(domTarget); | 
 |     return Promise.resolve({ result: result, isFrame: isFrame}); | 
 |   } | 
 |   let target = this; | 
 |   if (loadType.resultFrom == eResultFromExaminationOnLoad) { | 
 |     return new Promise(function(resolve, reject) { | 
 |       function handleLoad(event) { | 
 |         clearTimeout(timer); | 
 |         let isFrame = domTarget instanceof HTMLIFrameElement; | 
 |         let result = !isFrame ? | 
 |               domTarget.isSecureContext : domTarget.contentWindow.isSecureContext; | 
 |         domTarget.removeEventListener("load", handleLoad); | 
 |         target.close(domTarget); | 
 |         resolve({ result: result, isFrame: isFrame}); | 
 |       } | 
 |       let domTarget = target.open(loadType); | 
 |       domTarget.addEventListener("load", handleLoad, false); | 
 |  | 
 |       // Some browsers don't fire `load` events for `about:blank`. That's weird, but it also | 
 |       // isn't what we're testing here. | 
 |       let timer = setTimeout(handleLoad, 500); | 
 |     }); | 
 |   } | 
 |   if (loadType.resultFrom == eResultFromPostMessage) { | 
 |     return new Promise(function(resolve, reject) { | 
 |       function handleMessage(event) { | 
 |         let isFrame = domTarget instanceof HTMLIFrameElement; | 
 |         window.removeEventListener("message", handleMessage); | 
 |         target.close(domTarget); | 
 |         resolve({ result: event.data, isFrame: isFrame}); | 
 |       } | 
 |       window.addEventListener("message", handleMessage, false); | 
 |       let domTarget = target.open(loadType); | 
 |    }); | 
 |   } | 
 |   return Promise.reject("unexpected 'result from' type"); | 
 | } | 
 |  | 
 |  | 
 | let current_type_index = -1; | 
 | let current_target_index = 0; | 
 |  | 
 | function run_next_test() { | 
 |   current_type_index++; | 
 |   if (current_type_index >= loadTypes.length) { | 
 |     current_type_index = 0; | 
 |     current_target_index++; | 
 |     if (current_target_index >= loadTargets.length) { | 
 |       done(); | 
 |       return; // all test permutations complete | 
 |     } | 
 |   } | 
 |   let loadTarget = loadTargets[current_target_index]; | 
 |   let loadType = loadTypes[current_type_index]; | 
 |   loadTarget.load_and_get_result_for(loadType).then( | 
 |     function(value) { | 
 |       run_next_test_soon(); | 
 |       loadTarget.currentTest.step(function() { | 
 |         // If the new context is always non-secure, the assertion is straightforward. | 
 |         if (loadType.expectedSecureFlag == eSecureNo) { | 
 |           assert_false(value.result, loadType.desc + " in " + loadTarget.desc + " should not create a Secure Context"); | 
 |         // If the new context is always secure if opened in a new window, and it's | 
 |         // been opened in a new window, the assertion is likewise straightforward. | 
 |         } else if (loadType.expectedSecureFlag == eSecureIfNewWindow && !value.isFrame) { | 
 |           assert_true(value.result, loadType.desc + " in " + loadTarget.desc + " should create a secure context regardless of its creator's state."); | 
 |         // Otherwise, we're either dealing with a context that's secure if and only | 
 |         // if its creator context (e.g. this window) is secure. | 
 |         } else if ((loadType.expectedSecureFlag == eSecureIfNewWindow && value.isFrame) || | 
 |                    (loadType.expectedSecureFlag == eSecureIfCreatorSecure)) { | 
 |           if (!window.isSecureContext) { | 
 |             assert_false(value.result, loadType.desc + " in " + loadTarget.desc + " should not create a Secure Context when its creator is not a Secure Context."); | 
 |           } else { | 
 |             assert_true(value.result, loadType.desc + " in " + loadTarget.desc + " should create a Secure Context when its creator is a Secure Context"); | 
 |           } | 
 |         } else { | 
 |           assert_unreached(loadType.desc + " - unknown expected secure flag: " + expectedSecureFlag); | 
 |         } | 
 |         loadTarget.currentTest.done(); | 
 |       }); | 
 |     }, | 
 |     function(failReason) { | 
 |       run_next_test_soon(); | 
 |       if (failReason == "not applicable") { | 
 |         return; | 
 |       } | 
 |       loadTarget.currentTest.step(function() { | 
 |         assert_unreached(loadType.desc + " - got unexpected rejected promise"); | 
 |       }); | 
 |     } | 
 |   ); | 
 | } | 
 |  | 
 | function run_next_test_soon() { | 
 |   setTimeout(run_next_test, 0); | 
 | } | 
 |  | 
 | function begin() { | 
 |   test(function() { | 
 |     if (location.protocol == "http:") { | 
 |       assert_false(isSecureContext, | 
 |                    "http: creator should not be a Secure Context"); | 
 |     } else if (location.protocol == "https:") { | 
 |       assert_true(isSecureContext, | 
 |                   "https: creator should be a Secure Context"); | 
 |     } else { | 
 |       assert_unreached("Unknown location.protocol"); | 
 |     } | 
 |   }); | 
 |   run_next_test(); | 
 | } | 
 |  |