diff options
Diffstat (limited to 'testing/web-platform/tests/IndexedDB/database-names-by-origin.html')
-rw-r--r-- | testing/web-platform/tests/IndexedDB/database-names-by-origin.html | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/testing/web-platform/tests/IndexedDB/database-names-by-origin.html b/testing/web-platform/tests/IndexedDB/database-names-by-origin.html new file mode 100644 index 0000000000..5833b7e9ba --- /dev/null +++ b/testing/web-platform/tests/IndexedDB/database-names-by-origin.html @@ -0,0 +1,144 @@ +<!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> |