| <!DOCTYPE html> |
| <title>Fenced frame disallowed navigations</title> |
| <meta name="timeout" content="long"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/common/dispatcher/dispatcher.js"></script> |
| <script src="/common/get-host-info.sub.js"></script> |
| <script src="/common/utils.js"></script> |
| <script src="resources/utils.js"></script> |
| <script src="/fetch/private-network-access/resources/support.sub.js"></script> |
| |
| <body> |
| |
| <script> |
| // Baseline tests: |
| // - Embedder can navigate iframe to blob: URL |
| // - Embedder can navigate iframe to data: URL |
| // - Same-origin embedder can navigate iframe to javascript: URL |
| // - Embedder can navigate iframe to http: URL |
| // Fenced frame tests: |
| // - Embedder cannot navigate fenced frame to blob: URL |
| // - Embedder cannot navigate fenced frame to data: URL |
| // - Same-origin embedder cannot navigate fenced frame to |
| // javascript: URL |
| // - Embedder cannot navigate fenced frame to http: URL |
| |
| // Fenced frames are always put in the public IP address space which is the |
| // least privileged. In case a navigation to a local data: URL or blob: URL |
| // resource is allowed, they would only be able to fetch things that are *also* |
| // in the public IP address space. So for the document described by these local |
| // URLs, we'll set them up to only communicate back to the outer page via |
| // resources obtained in the public address space. |
| const kPublicUtils = resolveUrl("resources/utils.js", Server.HTTPS_PUBLIC); |
| |
| // These are just baseline tests asserting that this test's machinery to load |
| // blob:, data:, and javascript: URLs work properly in contexts where they are |
| // expected to. |
| promise_test(async () => { |
| const key = token(); |
| attachIFrame(`data:text/html, ${createLocalSource(key, kPublicUtils)}`); |
| const result = await nextValueFromServer(key); |
| assert_equals(result, "LOADED"); |
| }, "iframe data: URL"); |
| |
| promise_test(async () => { |
| const key = token(); |
| const blobURL = URL.createObjectURL( |
| new Blob([`${createLocalSource(key, kPublicUtils)}`], |
| {type: 'text/html'})); |
| attachIFrame(blobURL); |
| const result = await nextValueFromServer(key); |
| assert_equals(result, "LOADED"); |
| }, "iframe blob: URL"); |
| |
| promise_test(async () => { |
| const iframe = attachIFrameContext(); |
| iframe.src = "javascript:window.jsURLExecuted = true;" |
| await iframe.execute(async () => { |
| assert_equals(window.jsURLExecuted, true); |
| }); |
| }, "iframe javascript: URL"); |
| |
| // The following tests ensure that an embedder cannot navigate a fenced frame |
| // to: |
| // - data: URLs |
| // - blob: URLs |
| // - javascript: URLs |
| // - http: URLs |
| function getTimeoutPromise(t) { |
| return new Promise(resolve => |
| t.step_timeout(() => resolve("NOT LOADED"), 2000)); |
| } |
| |
| promise_test(async t => { |
| const key = token(); |
| attachFencedFrame(`data:text/html, ${createLocalSource(key, kPublicUtils)}`); |
| const loaded_promise = nextValueFromServer(key); |
| const result = await Promise.any([loaded_promise, getTimeoutPromise(t)]); |
| assert_equals(result, "NOT LOADED"); |
| }, `fenced frame data: URL`); |
| |
| promise_test(async t => { |
| const key = token(); |
| const blobURL = URL.createObjectURL( |
| new Blob([`${createLocalSource(key, kPublicUtils)}`], |
| {type: 'text/html'})); |
| attachFencedFrame(blobURL); |
| const loaded_promise = nextValueFromServer(key); |
| const result = await Promise.any([loaded_promise, getTimeoutPromise(t)]); |
| assert_equals(result, "NOT LOADED"); |
| }, `fenced frame blob: URL`); |
| |
| promise_test(async t => { |
| const fencedframe = attachFencedFrameContext(); |
| fencedframe.src = "javascript:window.jsURLExecuted = true;" |
| // Just in case the javascript URL executes asynchronously, let's wait for |
| // it. |
| await getTimeoutPromise(t); |
| await fencedframe.execute(async () => { |
| assert_equals(window.jsURLExecuted, undefined); |
| }); |
| }, `fenced frame javascript: URL`); |
| |
| promise_test(async t => { |
| const key = token(); |
| let http_url = new URL("resources/embeddee.html", |
| get_host_info().HTTP_ORIGIN + location.pathname); |
| http_url = generateURL(http_url, [key]); |
| assert_equals(http_url.protocol, "http:"); |
| const fencedframe = attachFencedFrame(http_url); |
| const loaded_promise = nextValueFromServer(key); |
| const result = await Promise.any([loaded_promise, getTimeoutPromise(t)]); |
| assert_equals(result, "NOT LOADED"); |
| }, `fenced frame http: URL`); |
| |
| </script> |
| |
| </body> |