<!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>