| <!DOCTYPE html> |
| <html> |
| <head> |
| <script src="/cookies/resources/cookie-utilities.js"></script> |
| <script src="../resources/util.js"></script> |
| </head> |
| <body onload="setTimeout('runTest()', 0)"> |
| <div id="description">Check that website data does not get removed after a period of no user interaction if the website is app-bound.</div> |
| <br> |
| <div id="output"></div> |
| <br> |
| <script> |
| testRunner.waitUntilDone(); |
| testRunner.dumpAsText(); |
| |
| const httpOnlyCookieName = "http-only-cookie"; |
| const serverSideCookieName = "server-side-cookie"; |
| const clientSideCookieName = "client-side-cookie"; |
| |
| function sortStringArray(a, b) { |
| a = a.toLowerCase(); |
| b = b.toLowerCase(); |
| |
| return a > b ? 1 : b > a ? -1 : 0; |
| } |
| |
| function addLinebreakToOutput() { |
| let element = document.createElement("br"); |
| output.appendChild(element); |
| } |
| |
| function addOutput(message) { |
| let element = document.createElement("div"); |
| element.innerText = message; |
| output.appendChild(element); |
| } |
| |
| function checkCookies(isAfterDeletion) { |
| let unsortedTestPassedMessages = []; |
| let cookies = internals.getCookies(); |
| if (!cookies.length) |
| addOutput((isAfterDeletion ? "After" : "Before") + " script-accessible deletion: No cookies found."); |
| for (let cookie of cookies) { |
| switch (cookie.name) { |
| case httpOnlyCookieName: |
| unsortedTestPassedMessages.push((isAfterDeletion ? "After" : "Before") + " deletion: " + (isAfterDeletion ? " " : "") + "HttpOnly cookie exists."); |
| break; |
| case serverSideCookieName: |
| unsortedTestPassedMessages.push((isAfterDeletion ? "After" : "Before") + " deletion: Regular server-side cookie exists."); |
| break; |
| case clientSideCookieName: |
| unsortedTestPassedMessages.push((isAfterDeletion ? "After" : "Before") + " deletion: Client-side cookie exists."); |
| break; |
| } |
| } |
| let sortedTestPassedMessages = unsortedTestPassedMessages.sort(sortStringArray); |
| for (let testPassedMessage of sortedTestPassedMessages) { |
| addOutput(testPassedMessage); |
| } |
| } |
| |
| const dbName = "TestDatabase"; |
| |
| function createIDBDataStore(callback) { |
| let request = indexedDB.open(dbName); |
| request.onerror = function() { |
| addOutput("Couldn't create indexedDB."); |
| finishTest(); |
| }; |
| request.onupgradeneeded = function(event) { |
| let db = event.target.result; |
| let objStore = db.createObjectStore("test", {autoIncrement: true}); |
| objStore.add("value"); |
| callback(); |
| } |
| } |
| |
| const maxIntervals = 20; |
| |
| let intervalCounterIDB; |
| let checkIDBCallback; |
| let checkIDBIntervalID; |
| let semaphoreIDBCheck = false; |
| function checkIDBDataStoreExists(isAfterDeletion, callback) { |
| let request; |
| intervalCounterIDB = 0; |
| checkIDBCallback = callback; |
| if (!isAfterDeletion) { |
| // Check until there is a IDB. |
| checkIDBIntervalID = setInterval(function() { |
| if (semaphoreIDBCheck) |
| return; |
| semaphoreIDBCheck = true; |
| |
| if (++intervalCounterIDB >= maxIntervals) { |
| clearInterval(checkIDBIntervalID); |
| addOutput("Before deletion: IDB entry does not exist."); |
| semaphoreIDBCheck = false; |
| checkIDBCallback(); |
| } else { |
| request = indexedDB.open(dbName); |
| request.onerror = function () { |
| clearInterval(checkIDBIntervalID); |
| addOutput("Couldn't open indexedDB."); |
| semaphoreIDBCheck = false; |
| finishTest(); |
| }; |
| request.onupgradeneeded = function () { |
| // Let the next interval check again. |
| semaphoreIDBCheck = false; |
| }; |
| request.onsuccess = function () { |
| clearInterval(checkIDBIntervalID); |
| addOutput("Before deletion: IDB entry does exist."); |
| semaphoreIDBCheck = false; |
| checkIDBCallback(); |
| }; |
| } |
| }, 200); |
| } else { |
| // Check until there is a IDB. |
| checkIDBIntervalID = setInterval(function () { |
| if (semaphoreIDBCheck) |
| return; |
| semaphoreIDBCheck = true; |
| |
| if (++intervalCounterIDB >= maxIntervals) { |
| clearInterval(checkIDBIntervalID); |
| addOutput("After deletion: IDB entry checks exhausted."); |
| semaphoreIDBCheck = false; |
| checkIDBCallback(); |
| } else { |
| request = indexedDB.open(dbName); |
| request.onerror = function () { |
| clearInterval(checkIDBIntervalID); |
| addOutput("Couldn't open indexedDB."); |
| semaphoreIDBCheck = false; |
| finishTest(); |
| }; |
| request.onupgradeneeded = function () { |
| // Let the next interval check again. |
| semaphoreIDBCheck = false; |
| }; |
| request.onsuccess = function () { |
| clearInterval(checkIDBIntervalID); |
| addOutput("After deletion: IDB entry does exist."); |
| semaphoreIDBCheck = false; |
| checkIDBCallback(); |
| }; |
| } |
| }, 200); |
| } |
| } |
| |
| let intervalCounterLocalStorage; |
| let checkLocalStorageCallback; |
| let checkLocalStorageIntervalID; |
| const localStorageName = "test"; |
| const localStorageValue = "value"; |
| function checkLocalStorageExists(isAfterDeletion, callback) { |
| intervalCounterLocalStorage = 0; |
| checkLocalStorageCallback = callback; |
| if (!isAfterDeletion) { |
| // Check until there is LocalStorage. |
| checkLocalStorageIntervalID = setInterval(function() { |
| if (++intervalCounterLocalStorage >= maxIntervals) { |
| clearInterval(checkLocalStorageIntervalID); |
| let value = localStorage.getItem(localStorageName); |
| addOutput("Before deletion: LocalStorage entry " + (value === localStorageValue ? "does" : "does not") + " exist."); |
| checkLocalStorageCallback(); |
| } else if (testRunner.isStatisticsHasLocalStorage(originUnderTest)) { |
| clearInterval(checkLocalStorageIntervalID); |
| let value = localStorage.getItem(localStorageName); |
| addOutput("Before deletion: LocalStorage entry " + (value === localStorageValue ? "does" : "does not") + " exist."); |
| checkLocalStorageCallback(); |
| } |
| }, 100); |
| } else { |
| // Check until there is no LocalStorage. |
| checkLocalStorageIntervalID = setInterval(function() { |
| if (++intervalCounterLocalStorage >= maxIntervals) { |
| clearInterval(checkLocalStorageIntervalID); |
| let value = localStorage.getItem(localStorageName); |
| addOutput("After deletion: LocalStorage entry " + (value === localStorageValue ? "does" : "does not") + " exist."); |
| checkLocalStorageCallback(); |
| } else if (!testRunner.isStatisticsHasLocalStorage(originUnderTest)) { |
| clearInterval(checkLocalStorageIntervalID); |
| let value = localStorage.getItem(localStorageName); |
| addOutput("After deletion: LocalStorage entry " + (value === localStorageValue ? "does" : "does not") + " exist."); |
| checkLocalStorageCallback(); |
| } |
| }, 100); |
| } |
| } |
| |
| async function writeWebsiteDataAndContinue() { |
| // Write cookies. |
| await fetch("/cookies/resources/set-http-only-cookie.py?cookieName=" + httpOnlyCookieName, { credentials: "same-origin" }); |
| await fetch("/cookies/resources/setCookies.cgi", { headers: { "Set-Cookie": serverSideCookieName + "=1; path=/;" }, credentials: "same-origin" }); |
| document.cookie = clientSideCookieName + "=1"; |
| |
| checkCookies(false); |
| |
| // Write LocalStorage |
| localStorage.setItem(localStorageName, localStorageValue); |
| checkLocalStorageExists(false, function() { |
| |
| // Write IndexedDB. |
| createIDBDataStore(function () { |
| checkIDBDataStoreExists(false, function() { |
| addLinebreakToOutput(); |
| processWebsiteDataAndContinue(); |
| }); |
| }); |
| }); |
| } |
| |
| function processWebsiteDataAndContinue() { |
| testRunner.installStatisticsDidScanDataRecordsCallback(checkWebsiteDataAndContinue); |
| testRunner.statisticsProcessStatisticsAndDataRecords(); |
| } |
| |
| function checkWebsiteDataAndContinue() { |
| checkCookies(true); |
| checkLocalStorageExists(true, function () { |
| checkIDBDataStoreExists(true, finishTest); |
| }); |
| } |
| |
| function finishTest() { |
| resetCookies(); |
| testRunner.setStatisticsFirstPartyWebsiteDataRemovalMode(false, function() { |
| setEnableFeature(false, function() { |
| testRunner.notifyDone(); |
| }); |
| }); |
| } |
| |
| const originUnderTest = "http://127.0.0.1:8000"; |
| function runTest() { |
| setEnableFeature(true, function () { |
| testRunner.setAppBoundDomains([ originUnderTest ], function() { |
| testRunner.setStatisticsFirstPartyWebsiteDataRemovalMode(true, function() { |
| testRunner.setStatisticsPrevalentResource(originUnderTest, true, function() { |
| if (!testRunner.isStatisticsPrevalentResource(originUnderTest)) |
| addOutput("FAIL: " + originUnderTest + " didn't get classified as prevalent."); |
| writeWebsiteDataAndContinue(); |
| }); |
| }); |
| }); |
| }); |
| } |
| </script> |
| </body> |
| </html> |