forked from mirrors/gecko-dev
Bug 1858696: Created IDB and CacheAPI marionette tests to verify raw magic strings in on-disk storages.r=dom-storage-reviewers,webdriver-reviewers,whimboo,janv
Differential Revision: https://phabricator.services.mozilla.com/D192328
This commit is contained in:
parent
1eb7ddbd5d
commit
2cf947cbda
5 changed files with 134 additions and 68 deletions
|
|
@ -26,8 +26,8 @@ class CacheAPIEncryptionPBM(QuotaTestCase):
|
|||
def setUp(self):
|
||||
super(CacheAPIEncryptionPBM, self).setUp()
|
||||
|
||||
self.testHTML = "dom/cache/basicCacheAPI_PBM.html"
|
||||
self.cacheName = "CachePBMTest"
|
||||
|
||||
self.profilePath = self.marionette.instance.profile.profile
|
||||
self.cacheAPIStoragePath = None
|
||||
|
||||
|
|
@ -45,27 +45,33 @@ class CacheAPIEncryptionPBM(QuotaTestCase):
|
|||
|
||||
self.dbCheckpointThresholdBytes = 512 * 1024
|
||||
|
||||
# Navigate by opening a new private window
|
||||
pbmWindowHandle = self.marionette.open(type="window", private=True)["handle"]
|
||||
self.marionette.switch_to_window(pbmWindowHandle)
|
||||
self.marionette.navigate(
|
||||
self.marionette.absolute_url("dom/cache/basicCacheAPI_PBM.html")
|
||||
)
|
||||
|
||||
self.origin = self.marionette.absolute_url("")[:-1] + "^privateBrowsingId=1"
|
||||
|
||||
def tearDown(self):
|
||||
super(CacheAPIEncryptionPBM, self).setUp()
|
||||
|
||||
self.marionette.set_pref(CACHEAPI_PBM_PREF, self.defaultCacheAPIPBMPref)
|
||||
self.marionette.set_pref(QM_TESTING_PREF, self.defaultQMPrefValue)
|
||||
|
||||
self.marionette.execute_script("window.wrappedJSObject.releaseCache()")
|
||||
def test_request_response_ondisk(self):
|
||||
with self.using_new_window(self.testHTML, private=False) as (
|
||||
self.origin,
|
||||
self.persistenceType,
|
||||
):
|
||||
self.runAndValidate(
|
||||
lambda exists: self.assertTrue(
|
||||
exists, "Failed to find expected data on disk"
|
||||
)
|
||||
)
|
||||
|
||||
# closes the new private window we opened in the setUp and referred by 'pbmWindowHandle'
|
||||
self.marionette.close()
|
||||
def test_encrypted_request_response_ondisk(self):
|
||||
with self.using_new_window(self.testHTML, private=True) as (
|
||||
self.origin,
|
||||
self.persistenceType,
|
||||
):
|
||||
self.runAndValidate(
|
||||
lambda exists: self.assertFalse(exists, "Data on disk is not encrypted")
|
||||
)
|
||||
|
||||
def test_ensure_encrypted_request_response(self):
|
||||
def runAndValidate(self, validator):
|
||||
self.marionette.execute_async_script(
|
||||
"""
|
||||
const [name, requestStr, responseStr, resolve] = arguments;
|
||||
|
|
@ -73,24 +79,32 @@ class CacheAPIEncryptionPBM(QuotaTestCase):
|
|||
const request = new Request(requestStr);
|
||||
const response = new Response(responseStr);
|
||||
window.wrappedJSObject.addDataIntoCache(name, request, response)
|
||||
.then(()=> { resolve(); });
|
||||
.then(resolve);
|
||||
""",
|
||||
script_args=(self.cacheName, self.cacheRequestStr, self.cacheResponseStr),
|
||||
script_args=(
|
||||
self.cacheName,
|
||||
self.cacheRequestStr,
|
||||
self.cacheResponseStr,
|
||||
),
|
||||
)
|
||||
|
||||
self.ensureInvariantHolds(
|
||||
lambda _: os.path.exists(self.getCacheAPIStoragePath())
|
||||
)
|
||||
|
||||
self.ensureSqliteIsEncrypted()
|
||||
self.validateSqlite(validator)
|
||||
self.validateBodyFile(validator)
|
||||
|
||||
def validateBodyFile(self, validator):
|
||||
# Ensure response bodies have been flushed to the disk
|
||||
self.ensureInvariantHolds(
|
||||
lambda _: self.findDirObj(self.cacheAPIStoragePath, "morgue", False)
|
||||
lambda _: self.findDirObj(self.getCacheAPIStoragePath(), "morgue", False)
|
||||
is not None
|
||||
)
|
||||
|
||||
cacheResponseDir = self.findDirObj(self.cacheAPIStoragePath, "morgue", False)
|
||||
cacheResponseDir = self.findDirObj(
|
||||
self.getCacheAPIStoragePath(), "morgue", False
|
||||
)
|
||||
|
||||
self.ensureInvariantHolds(lambda _: any(os.listdir(cacheResponseDir)))
|
||||
|
||||
|
|
@ -114,26 +128,28 @@ class CacheAPIEncryptionPBM(QuotaTestCase):
|
|||
with open(cacheResponseBodyPath, "rb") as f_binary:
|
||||
foundRawValue = re.search(b"sNaPpY", f_binary.read()) is not None
|
||||
|
||||
self.assertFalse(foundRawValue, "Response body did not get encrypted")
|
||||
validator(foundRawValue)
|
||||
|
||||
def ensureSqliteIsEncrypted(self):
|
||||
def validateSqlite(self, validator):
|
||||
self.ensureInvariantHolds(
|
||||
lambda _: self.findDirObj(
|
||||
self.cacheAPIStoragePath, self.cacheDBJournalFileName, True
|
||||
self.getCacheAPIStoragePath(), self.cacheDBJournalFileName, True
|
||||
)
|
||||
is not None
|
||||
)
|
||||
dbJournalFile = self.findDirObj(
|
||||
self.cacheAPIStoragePath, self.cacheDBJournalFileName, True
|
||||
self.getCacheAPIStoragePath(), self.cacheDBJournalFileName, True
|
||||
)
|
||||
|
||||
self.ensureInvariantHolds(
|
||||
lambda _: self.findDirObj(
|
||||
self.cacheAPIStoragePath, self.cacheDBFileName, True
|
||||
self.getCacheAPIStoragePath(), self.cacheDBFileName, True
|
||||
)
|
||||
is not None
|
||||
)
|
||||
dbFile = self.findDirObj(self.cacheAPIStoragePath, self.cacheDBFileName, True)
|
||||
dbFile = self.findDirObj(
|
||||
self.getCacheAPIStoragePath(), self.cacheDBFileName, True
|
||||
)
|
||||
|
||||
# Confirm journal file size is less than 512KB which ensures that checkpoint
|
||||
# has not happend yet (dom/cache/DBSchema.cpp::InitializeConnection, kWalAutoCheckpointPages)
|
||||
|
|
@ -144,26 +160,27 @@ class CacheAPIEncryptionPBM(QuotaTestCase):
|
|||
# Before checkpointing, journal file size should be greater than main sqlite db file.
|
||||
self.assertTrue(os.path.getsize(dbJournalFile) > os.path.getsize(dbFile))
|
||||
|
||||
self.assertFalse(
|
||||
self.cacheRequestStr.encode("ascii") in open(dbJournalFile, "rb").read(),
|
||||
"Sqlite journal file did not get encrypted",
|
||||
validator(
|
||||
self.cacheRequestStr.encode("ascii") in open(dbJournalFile, "rb").read()
|
||||
)
|
||||
|
||||
self.assertTrue(self.resetStoragesForPrincipal(self.origin, "private", "cache"))
|
||||
self.assertTrue(
|
||||
self.resetStoragesForPrincipal(self.origin, self.persistenceType, "cache")
|
||||
)
|
||||
|
||||
self.assertFalse(os.path.getsize(dbJournalFile) > os.path.getsize(dbFile))
|
||||
|
||||
self.assertFalse(
|
||||
self.cacheRequestStr.encode("ascii") in open(dbFile, "rb").read(),
|
||||
"Sqlite main db file did not get encrypted",
|
||||
)
|
||||
validator(self.cacheRequestStr.encode("ascii") in open(dbFile, "rb").read())
|
||||
|
||||
def getCacheAPIStoragePath(self):
|
||||
if self.cacheAPIStoragePath is not None:
|
||||
return self.cacheAPIStoragePath
|
||||
|
||||
assert self.origin is not None
|
||||
assert self.persistenceType is not None
|
||||
|
||||
self.cacheAPIStoragePath = self.getStoragePath(
|
||||
self.profilePath, self.origin, "private", "cache"
|
||||
self.profilePath, self.origin, self.persistenceType, "cache"
|
||||
)
|
||||
|
||||
print("cacheAPI origin directory = " + self.cacheAPIStoragePath)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class IDBEncryptionPBM(QuotaTestCase):
|
|||
def setUp(self):
|
||||
super(IDBEncryptionPBM, self).setUp()
|
||||
|
||||
self.testHTML = "dom/indexedDB/basicIDB_PBM.html"
|
||||
self.IDBName = "IDBTest"
|
||||
self.IDBStoreName = "IDBTestStore"
|
||||
self.IDBVersion = 1
|
||||
|
|
@ -40,41 +41,61 @@ class IDBEncryptionPBM(QuotaTestCase):
|
|||
self.defaultQMPrefValue = self.marionette.get_pref(QM_TESTING_PREF)
|
||||
self.marionette.set_pref(QM_TESTING_PREF, True)
|
||||
|
||||
# Navigate by opening a new private window
|
||||
pbmWindowHandle = self.marionette.open(type="window", private=True)["handle"]
|
||||
self.marionette.switch_to_window(pbmWindowHandle)
|
||||
self.marionette.navigate(
|
||||
self.marionette.absolute_url("dom/indexedDB/basicIDB_PBM.html")
|
||||
)
|
||||
|
||||
self.origin = self.marionette.absolute_url("")[:-1] + "^privateBrowsingId=1"
|
||||
|
||||
def tearDown(self):
|
||||
super(IDBEncryptionPBM, self).setUp()
|
||||
super(IDBEncryptionPBM, self).tearDown()
|
||||
|
||||
self.marionette.set_pref(INDEXED_DB_PBM_PREF, self.defaultIDBPrefValue)
|
||||
self.marionette.set_pref(QM_TESTING_PREF, self.defaultQMPrefValue)
|
||||
|
||||
# closes the new private window we opened in the setUp and referred by 'pbmWindowHandle'
|
||||
self.marionette.close()
|
||||
def test_raw_IDB_data_ondisk(self):
|
||||
with self.using_new_window(self.testHTML, private=False) as (
|
||||
self.origin,
|
||||
self.persistenceType,
|
||||
):
|
||||
self.runAndValidate(
|
||||
lambda exists: self.assertTrue(
|
||||
exists, "Failed to find expected data on disk"
|
||||
)
|
||||
)
|
||||
|
||||
def test_ensure_encrypted_blob(self):
|
||||
self.marionette.execute_script(
|
||||
def test_ensure_encrypted_IDB_data_ondisk(self):
|
||||
with self.using_new_window(self.testHTML, private=True) as (
|
||||
self.origin,
|
||||
self.persistenceType,
|
||||
):
|
||||
self.runAndValidate(
|
||||
lambda exists: self.assertFalse(exists, "Data on disk is not encrypted")
|
||||
)
|
||||
|
||||
def runAndValidate(self, validator):
|
||||
self.marionette.execute_async_script(
|
||||
"""
|
||||
const [idb, store, key, value] = arguments;
|
||||
const [idb, store, key, value, resolve] = arguments;
|
||||
window.wrappedJSObject.addDataIntoIDB(idb, store, key, value).then(resolve);
|
||||
""",
|
||||
script_args=(self.IDBName, self.IDBStoreName, "textKey", self.IDBValue),
|
||||
)
|
||||
self.validateSqlite(validator)
|
||||
|
||||
self.marionette.execute_async_script(
|
||||
"""
|
||||
const [idb, store, key, value, resolve] = arguments;
|
||||
const blobValue = new Blob([value], {type:'text/plain'});
|
||||
|
||||
window.wrappedJSObject.addDataIntoIDB(idb, store, key, blobValue);
|
||||
window.wrappedJSObject.addDataIntoIDB(idb, store, key, blobValue).then(resolve);
|
||||
""",
|
||||
script_args=(self.IDBName, self.IDBStoreName, "blobKey", self.IDBValue),
|
||||
)
|
||||
self.validateBlob(validator)
|
||||
|
||||
def validateBlob(self, validator):
|
||||
self.ensureInvariantHolds(lambda _: self.sqliteWALReleased())
|
||||
self.ensureInvariantHolds(
|
||||
lambda _: self.findDirObj(self.idbStoragePath, ".files", False) is not None
|
||||
lambda _: self.findDirObj(self.getIDBStoragePath(), ".files", False)
|
||||
is not None
|
||||
)
|
||||
|
||||
idbBlobDir = self.findDirObj(self.idbStoragePath, ".files", False)
|
||||
idbBlobDir = self.findDirObj(self.getIDBStoragePath(), ".files", False)
|
||||
|
||||
# seems like there's a timing issue here. There are sometimes no blob file
|
||||
# even after WAL is released. Allowing some buffer time and ensuring blob file
|
||||
|
|
@ -88,23 +109,16 @@ class IDBEncryptionPBM(QuotaTestCase):
|
|||
re.search(self.IDBValue.encode("ascii"), f_binary.read()) is not None
|
||||
)
|
||||
|
||||
self.assertFalse(foundRawValue, "Blob file did not get encrypted")
|
||||
|
||||
def test_ensure_encrpted_sqlite_data(self):
|
||||
self.marionette.execute_script(
|
||||
"""
|
||||
const [idb, store, key, value] = arguments;
|
||||
window.wrappedJSObject.addDataIntoIDB(idb, store, key, value);
|
||||
""",
|
||||
script_args=(self.IDBName, self.IDBStoreName, "textKey", self.IDBValue),
|
||||
)
|
||||
validator(foundRawValue)
|
||||
|
||||
def validateSqlite(self, validator):
|
||||
self.ensureInvariantHolds(lambda _: self.sqliteWALReleased())
|
||||
self.ensureInvariantHolds(
|
||||
lambda _: self.findDirObj(self.idbStoragePath, ".sqlite", True) is not None
|
||||
lambda _: self.findDirObj(self.getIDBStoragePath(), ".sqlite", True)
|
||||
is not None
|
||||
)
|
||||
|
||||
sqliteDBFile = self.findDirObj(self.idbStoragePath, ".sqlite", True)
|
||||
sqliteDBFile = self.findDirObj(self.getIDBStoragePath(), ".sqlite", True)
|
||||
|
||||
foundRawValue = False
|
||||
with open(sqliteDBFile, "rb") as f_binary:
|
||||
|
|
@ -112,14 +126,17 @@ class IDBEncryptionPBM(QuotaTestCase):
|
|||
re.search(self.IDBValue.encode("ascii"), f_binary.read()) is not None
|
||||
)
|
||||
|
||||
self.assertFalse(foundRawValue, "sqlite data did not get encrypted")
|
||||
validator(foundRawValue)
|
||||
|
||||
def getIDBStoragePath(self):
|
||||
if self.idbStoragePath is not None:
|
||||
return self.idbStoragePath
|
||||
|
||||
assert self.origin is not None
|
||||
assert self.persistenceType is not None
|
||||
|
||||
self.idbStoragePath = self.getStoragePath(
|
||||
self.profilePath, self.origin, "private", "idb"
|
||||
self.profilePath, self.origin, self.persistenceType, "idb"
|
||||
)
|
||||
|
||||
print("idb origin directory = " + self.idbStoragePath)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os
|
||||
from contextlib import contextmanager
|
||||
|
||||
from marionette_driver import Wait
|
||||
from marionette_harness import MarionetteTestCase
|
||||
|
|
@ -88,3 +89,25 @@ class QuotaTestCase(MarionetteTestCase):
|
|||
|
||||
with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
|
||||
return self.marionette.execute_async_script(script)
|
||||
|
||||
@contextmanager
|
||||
def using_new_window(self, path, private=False):
|
||||
"""
|
||||
This helper method is created to ensure that a temporary
|
||||
window required inside the test scope is lifetime'd properly
|
||||
"""
|
||||
|
||||
oldWindow = self.marionette.current_window_handle
|
||||
try:
|
||||
newWindow = self.marionette.open(type="window", private=private)
|
||||
self.marionette.switch_to_window(newWindow["handle"])
|
||||
self.marionette.navigate(self.marionette.absolute_url(path))
|
||||
origin = self.marionette.absolute_url("")[:-1]
|
||||
if private:
|
||||
origin += "^privateBrowsingId=1"
|
||||
|
||||
yield (origin, "private" if private else "default")
|
||||
|
||||
finally:
|
||||
self.marionette.close()
|
||||
self.marionette.switch_to_window(oldWindow)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
async function addDataIntoCache(name, request, response) {
|
||||
let cache = await ensureCache(name);
|
||||
await cache.put(request, response);
|
||||
return cache.put(request, response);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
await (new Promise((resolve, reject) => {
|
||||
var transaction = db.transaction([store], "readwrite");
|
||||
var put = transaction.objectStore(store).put(value, key);
|
||||
put.onsuccess = resolve();
|
||||
put.onerror = reject;
|
||||
put.onsuccess = resolve;
|
||||
}));
|
||||
|
||||
closeIDB(db)
|
||||
|
|
@ -35,6 +36,14 @@
|
|||
function closeIDB(db) {
|
||||
db.close();
|
||||
}
|
||||
|
||||
function deleteIDB(db) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let deleteReq = indexedDB.deleteDatabase(db);
|
||||
deleteReq.onerror = reject;
|
||||
deleteReq.onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Reference in a new issue