1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
const executor_path = '/common/dispatcher/executor.html?pipe=';
const coop_header = policy => {
return `|header(Cross-Origin-Opener-Policy,${policy})`;
};
function getExecutorPath(uuid, origin, coop_header) {
return origin.origin + executor_path + coop_header + `&uuid=${uuid}`;
}
// Open a same-origin popup with `opener_coop` header, then open a popup with
// `openee_coop` header. Check whether the opener can script the openee.
const test_noopener_opening_popup = (
opener_coop,
openee_coop,
origin,
opener_expectation
) => {
promise_test(async t => {
// Set up dispatcher communications.
const popup_token = token();
const reply_token = token();
const popup_reply_token = token();
const popup_openee_token = token();
const popup_url = getExecutorPath(
popup_token, SAME_ORIGIN, coop_header(opener_coop));
// We open a popup and then ping it, it will respond after loading.
const popup = window.open(popup_url);
t.add_cleanup(() => send(popup_token, 'window.close()'));
send(popup_token, `send('${reply_token}', 'Popup loaded');`);
assert_equals(await receive(reply_token), 'Popup loaded');
if (opener_coop == 'noopener-allow-popups') {
// Assert that we can't script the popup.
await t.step_wait(() => popup.closed, 'Opener popup.closed')
}
// Ensure that the popup has no access to its opener.
send(popup_token, `
let openerDOMAccessAllowed = false;
try {
openerDOMAccessAllowed = !!self.opener.document.URL;
} catch(ex) {}
const payload = {
opener: !!self.opener,
openerDOMAccess: openerDOMAccessAllowed
};
send('${reply_token}', JSON.stringify(payload));
`);
let payload = JSON.parse(await receive(reply_token));
if (opener_coop == 'noopener-allow-popups') {
assert_false(payload.opener, 'popup opener');
assert_false(payload.openerDOMAccess, 'popup DOM access');
}
// Open another popup from inside the popup, and wait for it to load.
const popup_openee_url = getExecutorPath(popup_openee_token, origin,
coop_header(openee_coop));
send(popup_token, `
window.openee = open("${popup_openee_url}");
await receive('${popup_reply_token}');
const payload = {
openee: !!window.openee,
closed: window.openee.closed
};
send('${reply_token}', JSON.stringify(payload));
`);
t.add_cleanup(() => send(popup_token, 'window.openee.close()'));
// Notify the popup that its openee was loaded.
send(popup_openee_token, `
send('${popup_reply_token}', 'popup openee opened');
`);
// Assert that the popup has access to its openee.
payload = JSON.parse(await receive(reply_token));
assert_true(payload.openee, 'popup openee');
// Assert that the openee has access to its popup opener.
send(popup_openee_token, `
let openerDOMAccessAllowed = false;
try {
openerDOMAccessAllowed = !!self.opener.document.URL;
} catch(ex) {}
const payload = {
opener: !!self.opener,
openerDOMAccess: openerDOMAccessAllowed
};
send('${reply_token}', JSON.stringify(payload));
`);
payload = JSON.parse(await receive(reply_token));
if (opener_expectation) {
assert_true(payload.opener, 'Opener is not null');
assert_true(payload.openerDOMAccess, 'No DOM access');
} else {
assert_false(payload.opener, 'Opener is null');
assert_false(payload.openerDOMAccess, 'No DOM access');
}
},
'noopener-allow-popups ensures that the opener cannot script the openee,' +
' but further popups with no COOP can access their opener: ' +
opener_coop + '/' + openee_coop + ':' + origin == SAME_ORIGIN);
};
// Open a same-origin popup with `popup_coop` header, then navigate away toward
// one with `noopener-allow-popups`. Check the opener can't script the openee.
const test_noopener_navigating_away = (popup_coop) => {
promise_test(async t => {
// Set up dispatcher communications.
const popup_token = token();
const reply_token = token();
const popup_reply_token = token();
const popup_second_token = token();
const popup_url =
getExecutorPath(popup_token, SAME_ORIGIN, coop_header(popup_coop));
// We open a popup and then ping it, it will respond after loading.
const popup = window.open(popup_url);
send(popup_token, `send('${reply_token}', 'Popup loaded');`);
assert_equals(await receive(reply_token), 'Popup loaded');
t.add_cleanup(() => send(popup_token, 'window.close()'));
// There's an open question if we should check that popup.window is null here.
// See https://github.com/whatwg/html/issues/10457
// Assert that we cannot script the popup.
assert_false(popup.closed, 'popup closed');
// Ensure that the popup has no access to its opener.
send(popup_token, `
let openerDOMAccessAllowed = false;
try {
openerDOMAccessAllowed = !!self.opener.document.URL;
} catch(ex) {}
const payload = {
opener: !!self.opener,
openerDOMAccess: openerDOMAccessAllowed
};
send('${reply_token}', JSON.stringify(payload));
`);
let payload = JSON.parse(await receive(reply_token));
assert_true(payload.opener, 'popup opener');
assert_true(payload.openerDOMAccess, 'popup DOM access');
// Navigate the popup.
const popup_second_url = getExecutorPath(
popup_second_token, SAME_ORIGIN,
coop_header('noopener-allow-popups'));
send(popup_token, `
window.location = '${popup_second_url}';
`);
// Notify the popup that its openee was loaded.
send(popup_second_token, `
send('${reply_token}', 'popup navigated away');
`);
assert_equals(await receive(reply_token), 'popup navigated away');
// There's an open question if we should check that popup.window is null here.
// See https://github.com/whatwg/html/issues/10457
assert_true(popup.closed, 'popup.closed');
},
'noopener-allow-popups ensures that the opener cannot script the openee,' +
' even after a navigation: ' + popup_coop);
};
|