144 lines
4.8 KiB
HTML
144 lines
4.8 KiB
HTML
<!doctype html>
|
|
<meta charset="utf8">
|
|
<meta name="timeout" content="long">
|
|
<title>IndexedDB: origins have isolated namespaces</title>
|
|
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="../common/get-host-info.sub.js"></script>
|
|
<script src="resources/support-promises.js"></script>
|
|
|
|
<body>
|
|
<script>
|
|
'use strict';
|
|
|
|
// Returns a Promise that resolves with the helper's response.
|
|
function waitForCrossOriginHelperResponse(origin, request) {
|
|
return new Promise((resolve, reject) => {
|
|
self.addEventListener('message', event => {
|
|
if (event.origin !== origin) {
|
|
reject(new Error(`Unexpected message from ${event.origin}`));
|
|
return;
|
|
}
|
|
|
|
if (event.data.action === request.action) {
|
|
resolve(event.data.response);
|
|
} else {
|
|
reject(new Error(`Unexpected message ${JSON.stringify(event.data)}`));
|
|
}
|
|
}, { once: true });
|
|
});
|
|
}
|
|
|
|
// Returns a Promise that resolves with the helper's response.
|
|
async function crossOriginIframeHelper(testCase, origin, request) {
|
|
const iframe = document.createElement('iframe');
|
|
iframe.src = origin + '/IndexedDB/resources/cross-origin-helper-frame.html';
|
|
document.body.appendChild(iframe);
|
|
testCase.add_cleanup(() => {
|
|
try {
|
|
document.body.removeChild(iframe);
|
|
} catch (e) {
|
|
// removeChild() throws if the iframe was already removed, which happens
|
|
// if this method runs to completion.
|
|
}
|
|
});
|
|
|
|
await new Promise((resolve, reject) => {
|
|
iframe.onload = resolve;
|
|
iframe.onerror = reject;
|
|
});
|
|
|
|
iframe.contentWindow.postMessage(request, origin);
|
|
const response = await waitForCrossOriginHelperResponse(origin, request);
|
|
document.body.removeChild(iframe);
|
|
return response;
|
|
};
|
|
|
|
// Returns a Promise that resolves with the helper's response.
|
|
async function crossOriginWindowHelper(testCase, origin, request) {
|
|
const helperWindow = window.open(
|
|
origin + '/IndexedDB/resources/cross-origin-helper-frame.html',
|
|
'_blank');
|
|
testCase.add_cleanup(() => { helperWindow.close(); });
|
|
|
|
await new Promise((resolve, reject) => {
|
|
self.addEventListener('message', event => {
|
|
if (event.origin !== origin) {
|
|
reject(new Error(`Unexpected message from ${event.origin}`));
|
|
return;
|
|
}
|
|
|
|
if (event.data.action === null && event.data.response === 'ready') {
|
|
resolve(event.data.response);
|
|
} else {
|
|
reject(new Error(`Unexpected message ${JSON.stringify(event.data)}`));
|
|
}
|
|
}, { once: true });
|
|
});
|
|
|
|
helperWindow.postMessage(request, origin);
|
|
const response = await waitForCrossOriginHelperResponse(origin, request);
|
|
helperWindow.close();
|
|
return response;
|
|
};
|
|
|
|
// Returns a Promise that resolves with the helper's response.
|
|
function crossOriginHelper(testCase, mode, origin, request) {
|
|
switch (mode) {
|
|
case 'iframe':
|
|
return crossOriginIframeHelper(testCase, origin, request);
|
|
case 'window':
|
|
return crossOriginWindowHelper(testCase, origin, request);
|
|
default:
|
|
throw new Error(`Unsupported cross-origin helper mode ${mode}`);
|
|
}
|
|
}
|
|
|
|
const sameOrigin = get_host_info().ORIGIN;
|
|
const otherOrigin = get_host_info().REMOTE_ORIGIN;
|
|
|
|
// The disclosure that inspired this test demonstrated leaked open database
|
|
// connections across windows.
|
|
for (const databaseKind of ['open', 'closed']) {
|
|
for (const mode of ['iframe', 'window']) {
|
|
promise_test(async testCase => {
|
|
const dbName = databaseName(testCase);
|
|
|
|
assert_true(
|
|
await crossOriginHelper(
|
|
testCase, mode, sameOrigin,
|
|
{action: 'delete-database', name: dbName}),
|
|
'Same-origin setup error');
|
|
assert_true(
|
|
await crossOriginHelper(
|
|
testCase, mode, otherOrigin,
|
|
{ action: 'delete-database', name: dbName }),
|
|
'Cross-origin setup error');
|
|
|
|
const db = await createNamedDatabase(testCase, dbName, database => {
|
|
database.createObjectStore('store');
|
|
});
|
|
|
|
if (databaseKind === 'closed')
|
|
await db.close();
|
|
|
|
const sameOriginDbNames = await crossOriginHelper(
|
|
testCase, mode, sameOrigin, { action: 'get-database-names' });
|
|
assert_in_array(
|
|
dbName, sameOriginDbNames,
|
|
`Database creation should reflect in same-origin ${mode}`);
|
|
|
|
const otherOriginDbNames = await crossOriginHelper(
|
|
testCase, mode, otherOrigin, { action: 'get-database-names' });
|
|
assert_true(
|
|
otherOriginDbNames.indexOf(dbName) === -1,
|
|
`Database creation should not impact cross-origin ${mode} list`);
|
|
|
|
if (databaseKind !== 'closed')
|
|
await db.close();
|
|
}, `${databaseKind} database names don't leak to cross-origin ${mode}`);
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|