summaryrefslogtreecommitdiffstats
path: root/browser/components/backup/resources/MiscDataBackupResource.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/backup/resources/MiscDataBackupResource.sys.mjs')
-rw-r--r--browser/components/backup/resources/MiscDataBackupResource.sys.mjs135
1 files changed, 94 insertions, 41 deletions
diff --git a/browser/components/backup/resources/MiscDataBackupResource.sys.mjs b/browser/components/backup/resources/MiscDataBackupResource.sys.mjs
index 97224f0e31..3d66114599 100644
--- a/browser/components/backup/resources/MiscDataBackupResource.sys.mjs
+++ b/browser/components/backup/resources/MiscDataBackupResource.sys.mjs
@@ -5,11 +5,19 @@
import { BackupResource } from "resource:///modules/backup/BackupResource.sys.mjs";
const lazy = {};
-
ChromeUtils.defineESModuleGetters(lazy, {
- Sqlite: "resource://gre/modules/Sqlite.sys.mjs",
+ ActivityStreamStorage:
+ "resource://activity-stream/lib/ActivityStreamStorage.sys.mjs",
+ ProfileAge: "resource://gre/modules/ProfileAge.sys.mjs",
});
+const SNIPPETS_TABLE_NAME = "snippets";
+const FILES_FOR_BACKUP = [
+ "enumerate_devices.txt",
+ "protections.sqlite",
+ "SiteSecurityServiceState.bin",
+];
+
/**
* Class representing miscellaneous files for telemetry, site storage,
* media device origin mapping, chrome privileged IndexedDB databases,
@@ -25,57 +33,102 @@ export class MiscDataBackupResource extends BackupResource {
}
async backup(stagingPath, profilePath = PathUtils.profileDir) {
- const files = [
- "times.json",
- "enumerate_devices.txt",
- "SiteSecurityServiceState.bin",
- ];
-
- for (let fileName of files) {
- let sourcePath = PathUtils.join(profilePath, fileName);
- let destPath = PathUtils.join(stagingPath, fileName);
- if (await IOUtils.exists(sourcePath)) {
- await IOUtils.copy(sourcePath, destPath, { recursive: true });
- }
- }
+ const files = ["enumerate_devices.txt", "SiteSecurityServiceState.bin"];
+ await BackupResource.copyFiles(profilePath, stagingPath, files);
const sqliteDatabases = ["protections.sqlite"];
-
- for (let fileName of sqliteDatabases) {
- let sourcePath = PathUtils.join(profilePath, fileName);
- let destPath = PathUtils.join(stagingPath, fileName);
- let connection;
-
- try {
- connection = await lazy.Sqlite.openConnection({
- path: sourcePath,
- readOnly: true,
- });
-
- await connection.backup(destPath);
- } finally {
- await connection.close();
- }
- }
+ await BackupResource.copySqliteDatabases(
+ profilePath,
+ stagingPath,
+ sqliteDatabases
+ );
// Bug 1890585 - we don't currently have the ability to copy the
- // chrome-privileged IndexedDB databases under storage/permanent/chrome, so
- // we'll just skip that for now.
+ // chrome-privileged IndexedDB databases under storage/permanent/chrome.
+ // Instead, we'll manually export any IndexedDB data we need to backup
+ // to a separate JSON file.
+
+ // The first IndexedDB database we want to back up is the ActivityStream
+ // one - specifically, the "snippets" table, as this contains information
+ // on ASRouter impressions, blocked messages, message group impressions,
+ // etc.
+ let storage = new lazy.ActivityStreamStorage({
+ storeNames: [SNIPPETS_TABLE_NAME],
+ });
+ let snippetsTable = await storage.getDbTable(SNIPPETS_TABLE_NAME);
+ let snippetsObj = {};
+ for (let key of await snippetsTable.getAllKeys()) {
+ snippetsObj[key] = await snippetsTable.get(key);
+ }
+ let snippetsBackupFile = PathUtils.join(
+ stagingPath,
+ "activity-stream-snippets.json"
+ );
+ await IOUtils.writeJSON(snippetsBackupFile, snippetsObj);
return null;
}
- async measure(profilePath = PathUtils.profileDir) {
- const files = [
+ async recover(_manifestEntry, recoveryPath, destProfilePath) {
+ await BackupResource.copyFiles(
+ recoveryPath,
+ destProfilePath,
+ FILES_FOR_BACKUP
+ );
+
+ // The times.json file, the one that powers ProfileAge, works hand in hand
+ // with the Telemetry client ID. We don't want to accidentally _overwrite_
+ // a pre-existing times.json with data from a different profile, because
+ // then the client ID wouldn't match the times.json data anymore.
+ //
+ // The rule that we're following for backups and recoveries is that the
+ // recovered profile always inherits the client ID (and therefore the
+ // times.json) from the profile that _initiated recovery_.
+ //
+ // This means we want to copy the times.json file from the profile that's
+ // currently in use to the destProfilePath.
+ await BackupResource.copyFiles(PathUtils.profileDir, destProfilePath, [
"times.json",
- "enumerate_devices.txt",
- "protections.sqlite",
- "SiteSecurityServiceState.bin",
- ];
+ ]);
+
+ // We also want to write the recoveredFromBackup timestamp now.
+ let profileAge = await lazy.ProfileAge(destProfilePath);
+ await profileAge.recordRecoveredFromBackup();
+
+ // The activity-stream-snippets data will need to be written during the
+ // postRecovery phase, so we'll stash the path to the JSON file in the
+ // post recovery entry.
+ let snippetsBackupFile = PathUtils.join(
+ recoveryPath,
+ "activity-stream-snippets.json"
+ );
+ return { snippetsBackupFile };
+ }
+
+ async postRecovery(postRecoveryEntry) {
+ let { snippetsBackupFile } = postRecoveryEntry;
+ // If for some reason, the activity-stream-snippets data file has been
+ // removed already, there's nothing to do.
+ if (!IOUtils.exists(snippetsBackupFile)) {
+ return;
+ }
+
+ let snippetsData = await IOUtils.readJSON(snippetsBackupFile);
+ let storage = new lazy.ActivityStreamStorage({
+ storeNames: [SNIPPETS_TABLE_NAME],
+ });
+ let snippetsTable = await storage.getDbTable(SNIPPETS_TABLE_NAME);
+ for (let key in snippetsData) {
+ let value = snippetsData[key];
+ await snippetsTable.set(key, value);
+ }
+ }
+
+ async measure(profilePath = PathUtils.profileDir) {
let fullSize = 0;
- for (let filePath of files) {
+ for (let filePath of FILES_FOR_BACKUP) {
let resourcePath = PathUtils.join(profilePath, filePath);
let resourceSize = await BackupResource.getFileSize(resourcePath);
if (Number.isInteger(resourceSize)) {