| <!DOCTYPE html> |
| <title>Cross-Origin-Opener-Policy and a "javascript:" URL popup</title> |
| <meta charset="utf-8"> |
| <meta name="timeout" content="long"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/common/get-host-info.sub.js"></script> |
| <script src="/common/utils.js"></script> |
| |
| <p>According to HTML's navigate algorithm, requests to <code>javascript:</code> |
| URLs should inherit the cross-origin opener policy of the active document. To |
| observe this, each subtest uses the following procedure.</p> |
| |
| <ol> |
| <li>create popup with a given COOP (the <code>parentCOOP</code>)</li> |
| <li>navigate the popup to a <code>javascript:</code> URL (the new document is |
| expected to inherit the <code>parentCOOP</code>)</li> |
| <li>from the popup, create a second popup window with a given COOP (the |
| <code>childCOOP</code>)</li> |
| </ol> |
| |
| <p>Both popup windows inspect state and report back to the test context using |
| BroadcastChannels.</p> |
| |
| <pre> |
| .---- test ----. |
| | open(https:) | |
| | parentCOOP | .----- subject -------. |
| | '---------> | --------. | |
| | | | v | |
| | | | assign(javascript:) | |
| | | | (COOP under test) | |
| | | | | | |
| | | | open(https:) | |
| | | | childCOOP | .- child -. |
| | | | '--------------> | | |
| | | '---------------------' '---------' |
| | | | | |
| | validate | <--status---+---------------------' |
| '--------------' |
| </pre> |
| |
| <script> |
| 'use strict'; |
| |
| function run(t, parentCOOP, childCOOP, origin, name) { |
| const bc = new BroadcastChannel(name); |
| const childURL = encodeURIComponent(`${origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=${childCOOP}&coep=&channel=${name}`); |
| |
| open( |
| `/html/cross-origin-opener-policy/resources/javascript-url-same-origin.https.html` + |
| `?pipe=header(cross-origin-opener-policy,${parentCOOP})` + |
| `&childURL=${childURL}` + |
| `&childName=${name}` |
| ); |
| |
| t.add_cleanup(() => { |
| bc.postMessage('close'); |
| }); |
| |
| return new Promise((resolve) => { |
| bc.addEventListener('message', ({data}) => { |
| resolve(data); |
| }, {once: true}); |
| }).then(({name: childName, opener: childOpener}) => { |
| return new Promise((resolve) => { |
| bc.postMessage('inspectChild'); |
| |
| bc.addEventListener('message', function handle({data}) { |
| if (typeof data !== 'object' || !('childClosed' in data)) { return; } |
| |
| bc.removeEventListener('message', handle); |
| |
| resolve({ |
| childName, |
| childOpener, |
| childClosed: data.childClosed |
| }); |
| }); |
| }); |
| }); |
| } |
| const { HTTPS_ORIGIN, HTTPS_REMOTE_ORIGIN } = get_host_info(); |
| |
| function assert_isolated(results) { |
| assert_equals(results.childName, '', 'child name'); |
| assert_false(results.childOpener, 'child opener'); |
| // The test subject's reference to the "child" window must report "closed" |
| // when COOP enforces isolation because the document initially created during |
| // the window open steps must be discarded when a new document object is |
| // created at the end of the navigation. |
| assert_true(results.childClosed, 'child closed'); |
| } |
| |
| function assert_not_isolated(results, expectedName) { |
| assert_equals(results.childName, expectedName, 'child name'); |
| assert_true(results.childOpener, 'child opener'); |
| assert_false(results.childClosed, 'child closed'); |
| } |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'unsafe-none', 'unsafe-none', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_not_isolated(results, name); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: unsafe-none; childCOOP: unsafe-none'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'unsafe-none', 'unsafe-none', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_not_isolated(results, name); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: unsafe-none; childCOOP: unsafe-none'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'unsafe-none', 'same-origin-allow-popups', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: unsafe-none; childCOOP: same-origin-allow-popups'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'unsafe-none', 'same-origin-allow-popups', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: unsafe-none; childCOOP: same-origin-allow-popups'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'unsafe-none', 'same-origin', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: unsafe-none; childCOOP: same-origin'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'unsafe-none', 'same-origin', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: unsafe-none; childCOOP: same-origin'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin-allow-popups', 'unsafe-none', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_not_isolated(results, name); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: same-origin-allow-popups; childCOOP: unsafe-none'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin-allow-popups', 'unsafe-none', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_not_isolated(results, name); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: same-origin-allow-popups; childCOOP: unsafe-none'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin-allow-popups', 'same-origin-allow-popups', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_not_isolated(results, name); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: same-origin-allow-popups; childCOOP: same-origin-allow-popups'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin-allow-popups', 'same-origin-allow-popups', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: same-origin-allow-popups; childCOOP: same-origin-allow-popups'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin-allow-popups', 'same-origin', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: same-origin-allow-popups; childCOOP: same-origin'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin-allow-popups', 'same-origin', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: same-origin-allow-popups; childCOOP: same-origin'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin', 'unsafe-none', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: same-origin; childCOOP: unsafe-none'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin', 'unsafe-none', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: same-origin; childCOOP: unsafe-none'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin', 'same-origin-allow-popups', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: same-origin; childCOOP: same-origin-allow-popups'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin', 'same-origin-allow-popups', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: same-origin; childCOOP: same-origin-allow-popups'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin', 'same-origin', HTTPS_ORIGIN, name) |
| .then((results) => { |
| assert_not_isolated(results, name); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: same origin; parentCOOP: same-origin; childCOOP: same-origin'); |
| |
| async_test((t) => { |
| const name = token(); |
| run(t, 'same-origin', 'same-origin', HTTPS_REMOTE_ORIGIN, name) |
| .then((results) => { |
| assert_isolated(results); |
| }) |
| .then(t.step_func_done(), t.step_func((e) => { throw e; })); |
| }, 'navigation: cross origin; parentCOOP: same-origin; childCOOP: same-origin'); |
| </script> |