Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import sys
from pathlib import Path
sys.path.append(os.fspath(Path(__file__).parents[3] / "quota/test/marionette"))
from quota_test_case import QuotaTestCase
QM_ENCRYPTION_PREF = "dom.quotaManager.encryption.enabled"
QM_TESTING_PREF = "dom.quotaManager.testing"
class IDBEncryptionPersistence(QuotaTestCase):
"""
Verify that encrypted IndexedDB data persists across a browser restart.
The lockstore keystore lives in the profile, so the same DEKs should be
available after restart and data should be readable.
"""
def setUp(self):
super().setUp()
self.marionette.instance.profile.set_preferences({
QM_ENCRYPTION_PREF: True,
QM_TESTING_PREF: True,
})
self.marionette.restart(in_app=False)
self.testHTML = "dom/indexedDB/basicIDB_PBM.html"
self.IDBName = "PersistDB"
self.IDBStoreName = "PersistStore"
self.testValue = "persist_test_value_lockstore"
def test_data_survives_restart(self):
with self.using_new_window(self.testHTML, private=False):
self.marionette.execute_async_script(
"""
const [idb, store, key, value, resolve] = arguments;
window.wrappedJSObject.addDataIntoIDB(idb, store, key, value).then(resolve);
""",
script_args=(
self.IDBName,
self.IDBStoreName,
"persistKey",
self.testValue,
),
)
self.marionette.restart(in_app=True)
readback = self.readBack()
self.assertEqual(
readback,
self.testValue,
f"Encrypted IDB data did not survive browser restart: {readback}",
)
# Origins encrypted earlier must stay readable after the pref is
# turned off.
self.marionette.instance.profile.set_preferences({QM_ENCRYPTION_PREF: False})
self.marionette.restart(in_app=False)
readback = self.readBack()
self.assertEqual(
readback,
self.testValue,
f"Encrypted IDB data unreadable after disabling encryption: {readback}",
)
def readBack(self):
with self.using_new_window(self.testHTML, private=False):
return self.marionette.execute_async_script(
"""
const resolve = arguments[arguments.length - 1];
const dbName = arguments[0];
const storeName = arguments[1];
const key = arguments[2];
try {
const req = indexedDB.open(dbName);
req.onsuccess = (e) => {
const db = e.target.result;
const tx = db.transaction(storeName, "readonly");
const getReq = tx.objectStore(storeName).get(key);
getReq.onsuccess = () => {
db.close();
resolve(getReq.result != null ? getReq.result : "no_result");
};
getReq.onerror = (ev) => {
db.close();
resolve("get_error:" + ev.target.error);
};
};
req.onerror = (e) => resolve("open_error:" + e.target.error);
} catch(ex) { resolve("exception:" + ex); }
""",
script_args=(self.IDBName, self.IDBStoreName, "persistKey"),
)