summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js')
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js241
1 files changed, 241 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js
new file mode 100644
index 0000000000..f13e768690
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js
@@ -0,0 +1,241 @@
+// To use the functions below, be sure to include the following files in your
+// test:
+// - "/common/get-host-info.sub.js" to get the different origin values.
+// - "common.js" to have the origins easily available.
+// - "/common/dispatcher/dispatcher.js" for cross-origin messaging.
+// - "/common/utils.js" for token().
+
+function getBaseExecutorPath(origin) {
+ return origin + '/common/dispatcher/executor.html';
+}
+
+function getHeadersPipe(headers) {
+ const coop_header = headers.coop ?
+ `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(headers.coop)})` : '';
+ const coep_header = headers.coep ?
+ `|header(Cross-Origin-Embedder-Policy,${encodeURIComponent(headers.coep)})` : '';
+ return coop_header + coep_header;
+}
+
+function getExecutorPath(uuid, origin, headers) {
+ return getBaseExecutorPath(origin) +
+ `?uuid=${uuid}` +
+ `&pipe=${getHeadersPipe(headers)}`;
+}
+
+function evaluate(target_token, script) {
+ const reply_token = token();
+ send(target_token, `send('${reply_token}', ${script});`);
+ return receive(reply_token);
+}
+
+// Return true if an opened iframe can access |property| on a stored
+// window.popup object without throwing an error.
+function iframeCanAccessProperty(iframe_token, property) {
+ const reply_token = token();
+ send(iframe_token,
+ `try {
+ const unused = window.popup['${property}'];
+ send('${reply_token}', 'true')
+ } catch (errors) {
+ send('${reply_token}', 'false')
+ }`);
+ return receive(reply_token);
+}
+
+// Returns the script necessary to open a popup, given the method in
+// `popup_via`. Supported methods are 'window_open' that leverages
+// window.open(), 'anchor' that creates an <a> HTML element and clicks on it,
+// and 'form' that creates a form and submits it.
+function popupOpeningScript(popup_via, popup_url, popup_origin, headers,
+ popup_token) {
+ if (popup_via === 'window_open')
+ return `window.popup = window.open('${popup_url}', '${popup_token}');`;
+
+ if (popup_via === 'anchor') {
+ return `
+ const anchor = document.createElement('a');
+ anchor.href = '${popup_url}';
+ anchor.rel = "opener";
+ anchor.target = '${popup_token}';
+ anchor.innerText = "anchor";
+ document.body.appendChild(anchor);
+ anchor.click();
+ `;
+ }
+
+ if (popup_via === "form") {
+ return `
+ const form = document.createElement("form");
+ form.action = '${getBaseExecutorPath(popup_origin.origin)}';
+ form.target = '${popup_token}';
+ form.method = 'GET';
+ const add_param = (name, value) => {
+ const input = document.createElement("input");
+ input.name = name;
+ input.value = value;
+ form.appendChild(input);
+ };
+ add_param("uuid", "${popup_token}");
+ add_param("pipe", "${getHeadersPipe(headers)}");
+ document.body.appendChild(form);
+ form.submit();
+ `;
+ }
+
+ assert_not_reached('Unrecognized popup opening method.');
+}
+
+function promise_test_parallel(promise, description) {
+ async_test(test => {
+ promise(test)
+ .then(() => test.done())
+ .catch(test.step_func(error => { throw error; }));
+ }, description);
+};
+
+// Verifies that a popup with origin `popup_origin` and headers `headers` has
+// the expected `opener_state` after being opened from an iframe with origin
+// `iframe_origin`.
+function iframe_test(description, iframe_origin, popup_origin, headers,
+ expected_opener_state) {
+ for (const popup_via of ['window_open', 'anchor','form']) {
+ promise_test_parallel(async t => {
+ const iframe_token = token();
+ const popup_token = token();
+ const reply_token = token();
+
+ const frame = document.createElement("iframe");
+ const iframe_url = getExecutorPath(
+ iframe_token,
+ iframe_origin.origin,
+ {});
+
+ frame.src = iframe_url;
+ document.body.append(frame);
+
+ send(iframe_token, `send('${reply_token}', 'Iframe loaded');`);
+ assert_equals(await receive(reply_token), 'Iframe loaded');
+
+ const popup_url = getExecutorPath(
+ popup_token,
+ popup_origin.origin,
+ headers);
+
+ // We open popup and then ping it, it will respond after loading.
+ send(iframe_token, popupOpeningScript(popup_via, popup_url, popup_origin,
+ headers, popup_token));
+ send(popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), 'Popup loaded');
+
+ // Make sure the popup and the iframe are removed once the test has run,
+ // keeping a clean state.
+ add_completion_callback(() => {
+ frame.remove();
+ send(popup_token, `close()`);
+ });
+
+ // Give some time for things to settle across processes etc. before
+ // proceeding with verifications.
+ await new Promise(resolve => { t.step_timeout(resolve, 500); });
+
+ // Verify that the opener is in the state we expect it to be in.
+ switch (expected_opener_state) {
+ case 'preserved': {
+ assert_equals(
+ await evaluate(popup_token, 'opener != null'), "true",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === '${popup_token}'`), "true",
+ 'Popup has a name?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup != null'), "true",
+ 'Popup handle is non-null in iframe?');
+ assert_equals(
+ await evaluate(iframe_token, 'popup.closed'), "false",
+ 'Popup appears closed from iframe?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "document"),
+ popup_origin === iframe_origin ? "true" : "false",
+ 'Iframe has dom access to the popup?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "frames"), "true",
+ 'Iframe has cross origin access to the popup?');
+ }
+ break;
+ }
+ case 'restricted': {
+ assert_equals(
+ await evaluate(popup_token, 'opener != null'), "true",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === ''`), "true",
+ 'Popup name is cleared?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup != null'), "true",
+ 'Popup handle is non-null in iframe?');
+ assert_equals(
+ await evaluate(iframe_token, 'popup.closed'), "false",
+ 'Popup appears closed from iframe?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "document"), "false",
+ 'Iframe has dom access to the popup?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "frames"), "false",
+ 'Iframe has cross origin access to the popup?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "closed"), "true",
+ 'Iframe has limited cross origin access to the popup?');
+ }
+ break;
+ }
+ case 'severed': {
+ assert_equals(await evaluate(popup_token, 'opener != null'), "false",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === ''`), "true",
+ 'Popup name is cleared?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup != null'), "true",
+ 'Popup handle is non-null in iframe?');
+ assert_equals(
+ await evaluate(iframe_token, 'popup.closed'), "true",
+ 'Popup appears closed from iframe?');
+ }
+ break;
+ }
+ case 'noopener': {
+ assert_equals(await evaluate(popup_token, 'opener != null'), "false",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === ''`), "true",
+ 'Popup name is cleared?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup == null'), "true",
+ 'Popup handle is null in iframe?');
+ }
+ break;
+ }
+ default:
+ assert_not_reached('Unrecognized opener state: ' +
+ expected_opener_state);
+ }
+ }, `${description} with ${popup_via}`);
+ }
+}