blob: 6c94923955799752a4b3a2742a0ac03607ffa80f [file] [log] [blame]
<!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>