Skip to content

Commit

Permalink
[Private Network Access] Test insecure fetches within workers loaded …
Browse files Browse the repository at this point in the history
…from blob urls

Workers can be loaded from a blob URL. This CL adds a test that tests
Private Network fetches within such workers.

This test will also be useful when we start allowing same origin PNA
requests. We don't currently have a working same-origin tests about
fetches in dedicated workers. The current treat-as-public-address tests
don't work well because dedicated workers don't get their policies from
network headers when PlzDedicatedWorker is disabled.

Bug: 1382068
Change-Id: I483575eece53e7232ce0baae308f147b1ab65b46
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4250757
Commit-Queue: Jonathan Hao <phao@chromium.org>
Reviewed-by: Yifan Luo <lyf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1105696}
  • Loading branch information
johnathan79717 authored and marcoscaceres committed Mar 28, 2023
1 parent b610ced commit 28b4820
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 0 deletions.
17 changes: 17 additions & 0 deletions fetch/private-network-access/resources/support.sub.js
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,23 @@ async function workerFetchTest(t, { source, target, expected }) {
assert_equals(message, expected.message, "response body");
}

async function workerBlobFetchTest(t, { source, target, expected }) {
const targetUrl = preflightUrl(target);

const fetcherUrl = resolveUrl(
'resources/worker-blob-fetcher.html', sourceResolveOptions(source));

const reply = futureMessage();
const iframe = await appendIframe(t, document, fetcherUrl);

iframe.contentWindow.postMessage({ url: targetUrl.href }, "*");

const { error, status, message } = await reply;
assert_equals(error, expected.error, "fetch error");
assert_equals(status, expected.status, "response status");
assert_equals(message, expected.message, "response body");
}

async function sharedWorkerFetchTest(t, { source, target, expected }) {
const targetUrl = preflightUrl(target);

Expand Down
45 changes: 45 additions & 0 deletions fetch/private-network-access/resources/worker-blob-fetcher.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Worker Fetcher</title>
<script>
window.addEventListener("message", function (evt) {
const { url } = evt.data;

const workerScriptContent = `
async function doFetch(url) {
const response = await fetch(url);
const body = await response.text();
return {
status: response.status,
body,
};
}
async function fetchAndPost(url) {
try {
const message = await doFetch(url);
self.postMessage(message);
} catch(e) {
self.postMessage({ error: e.name });
}
}
fetchAndPost("${url}");
`;
const blob =
new Blob([workerScriptContent], {type: 'application/javascript'});
const workerScriptUrl = URL.createObjectURL(blob);

const worker = new Worker(workerScriptUrl);

URL.revokeObjectURL(workerScriptUrl);

worker.addEventListener("message", (evt) => {
parent.postMessage(evt.data, "*");
});

worker.addEventListener("error", (evt) => {
parent.postMessage({ error: evt.message || "unknown error" }, "*");
});
});
</script>
143 changes: 143 additions & 0 deletions fetch/private-network-access/worker-blob-fetch.window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// META: script=/common/utils.js
// META: script=resources/support.sub.js
//
// Spec: https://wicg.github.io/private-network-access/#integration-fetch
//
// These tests check that fetches from within `Worker` scripts loaded from blob
// URLs are subject to Private Network Access checks, just like fetches from
// within documents.
//
// This file covers only those tests that must execute in a non-secure context.
// Other tests are defined in: worker-fetch.https.window.js

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTP_LOCAL },
target: { server: Server.HTTP_LOCAL },
expected: WorkerFetchTestResult.SUCCESS,
}), "local to local: success.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTP_PRIVATE },
target: {
server: Server.HTTP_LOCAL,
behavior: {
preflight: PreflightBehavior.optionalSuccess(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "private to local: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTP_PRIVATE },
target: { server: Server.HTTP_PRIVATE },
expected: WorkerFetchTestResult.SUCCESS,
}), "private to private: success.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTP_PUBLIC },
target: {
server: Server.HTTP_LOCAL,
behavior: {
preflight: PreflightBehavior.optionalSuccess(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "public to local: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTP_PUBLIC },
target: {
server: Server.HTTP_PRIVATE,
behavior: {
preflight: PreflightBehavior.optionalSuccess(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "public to private: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTP_PUBLIC },
target: { server: Server.HTTP_PUBLIC },
expected: WorkerFetchTestResult.SUCCESS,
}), "public to public: success.");

promise_test(t => workerBlobFetchTest(t, {
source: {
server: Server.HTTP_LOCAL,
treatAsPublic: true,
},
target: {
server: Server.HTTP_LOCAL,
behavior: { preflight: PreflightBehavior.optionalSuccess(token()) },
},
expected: WorkerFetchTestResult.FAILURE,
}), "treat-as-public to local: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: {
server: Server.HTTP_LOCAL,
treatAsPublic: true,
},
target: {
server: Server.HTTP_PRIVATE,
behavior: {
preflight: PreflightBehavior.optionalSuccess(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "treat-as-public to private: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: {
server: Server.HTTP_LOCAL,
treatAsPublic: true,
},
target: {
server: Server.HTTP_PUBLIC,
behavior: { response: ResponseBehavior.allowCrossOrigin() },
},
expected: WorkerFetchTestResult.SUCCESS,
}), "treat-as-public to public: success.");

// The following tests verify that workers served over HTTPS are not allowed to
// make private network requests because they are not secure contexts.

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTPS_PRIVATE },
target: {
server: Server.HTTP_LOCAL,
behavior: {
preflight: PreflightBehavior.success(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "private https to local: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTPS_PUBLIC },
target: {
server: Server.HTTP_PRIVATE,
behavior: {
preflight: PreflightBehavior.success(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "public https to private: failure.");

promise_test(t => workerBlobFetchTest(t, {
source: { server: Server.HTTPS_PUBLIC },
target: {
server: Server.HTTP_LOCAL,
behavior: {
preflight: PreflightBehavior.success(token()),
response: ResponseBehavior.allowCrossOrigin(),
},
},
expected: WorkerFetchTestResult.FAILURE,
}), "public https to local: failure.");

0 comments on commit 28b4820

Please sign in to comment.