diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.h --- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.h +++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.h @@ -1,8 +1,10 @@ #pragma once +#include "DatabaseIdentifier.h" #include "DatabaseQueryExecutor.h" #include "NativeSQLiteConnectionManager.h" #include "SQLiteQueryExecutor.h" +#include "WebSQLiteConnectionManager.h" #include @@ -17,6 +19,10 @@ // database. // DatabaseIdentifier::MAIN connectionManager. static std::shared_ptr mainConnectionManager; + // Backup database after decrypting (at backup level) is not encrypted, so we + // use an unencrypted connection manager. + // DatabaseIdentifier::RESTORED connectionManager. + static std::shared_ptr restoredConnectionManager; // Indicate that at least one instance of SQLiteQueryExecutor was created, // which is identical to finishing the migration process and having a fully @@ -40,6 +46,8 @@ public: static const DatabaseQueryExecutor &getQueryExecutor(); + static const DatabaseQueryExecutor &getQueryExecutor(DatabaseIdentifier id); + static void clearSensitiveData(); static void initializeQueryExecutor(std::string &databasePath); static bool checkIfDatabaseNeedsDeletion(); diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.cpp b/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.cpp --- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.cpp +++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseManager.cpp @@ -24,6 +24,11 @@ std::shared_ptr DatabaseManager::mainConnectionManager; +// Backup database after decrypting (at backup level) is not encrypted, so we +// use an unencrypted connection manager. +std::shared_ptr + DatabaseManager::restoredConnectionManager; + std::once_flag DatabaseManager::queryExecutorCreationIndicated; std::once_flag DatabaseManager::sqliteQueryExecutorPropertiesInitialized; @@ -36,6 +41,21 @@ const std::string DATABASE_MANAGER_STATUS_KEY = "DATABASE_MANAGER_STATUS"; const DatabaseQueryExecutor &DatabaseManager::getQueryExecutor() { + return DatabaseManager::getQueryExecutor(DatabaseIdentifier::MAIN); +} + +const DatabaseQueryExecutor & +DatabaseManager::getQueryExecutor(DatabaseIdentifier id) { + if (id == DatabaseIdentifier::RESTORED) { + if (!DatabaseManager::restoredConnectionManager) { + throw std::runtime_error("restoredConnectionManager is not set"); + } + + thread_local SQLiteQueryExecutor restoredQueryExecutor( + DatabaseManager::restoredConnectionManager, true); + return restoredQueryExecutor; + } + thread_local SQLiteQueryExecutor mainQueryExecutor( DatabaseManager::mainConnectionManager); @@ -367,6 +387,8 @@ std::string maxVersion) { std::string backupPath = SQLiteBackup::restoreFromMainCompaction( mainCompactionPath, mainCompactionEncryptionKey, maxVersion); + DatabaseManager::restoredConnectionManager = + std::make_shared(backupPath); DatabaseManager::getQueryExecutor().copyContentFromDatabase(backupPath); } diff --git a/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.cpp b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.cpp --- a/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.cpp +++ b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.cpp @@ -51,7 +51,8 @@ size_t futureID) { taskType job = [backupLog, futureID]() { try { - DatabaseManager::getQueryExecutor().restoreFromBackupLog(backupLog); + DatabaseManager::getQueryExecutor(DatabaseIdentifier::RESTORED) + .restoreFromBackupLog(backupLog); ::resolveUnitFuture(futureID); } catch (const std::exception &e) { std::string errorDetails = std::string(e.what()); diff --git a/web/shared-worker/worker/backup.js b/web/shared-worker/worker/backup.js --- a/web/shared-worker/worker/backup.js +++ b/web/shared-worker/worker/backup.js @@ -3,8 +3,13 @@ import backupService from 'lib/facts/backup-service.js'; import { decryptCommon } from 'lib/media/aes-crypto-utils-common.js'; import type { AuthMetadata } from 'lib/shared/identity-client-context.js'; +import { databaseIdentifier } from 'lib/types/database-identifier-types.js'; import { getProcessingStoreOpsExceptionMessage } from './process-operations.js'; +import { + getSQLiteQueryExecutor, + setSQLiteQueryExecutor, +} from './worker-database.js'; import { BackupClient, RequestedData, @@ -59,7 +64,10 @@ `${storeVersion ?? -1}`, ); - sqliteQueryExecutor.copyContentFromDatabase(backupPath); + setSQLiteQueryExecutor( + new dbModule.SQLiteQueryExecutor(backupPath, true), + databaseIdentifier.RESTORED, + ); sqliteQueryExecutor.setPersistStorageItem( completeRootKey, @@ -69,10 +77,17 @@ throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule)); } + const restoredQueryExecutor = getSQLiteQueryExecutor( + databaseIdentifier.RESTORED, + ); + if (!restoredQueryExecutor) { + throw new Error('restoredQueryExecutor is not set'); + } + await client.downloadLogs(userIdentity, backupID, async log => { const content = await decryptCommon(crypto, decryptionKey, log); try { - sqliteQueryExecutor.restoreFromBackupLog(content); + restoredQueryExecutor.restoreFromBackupLog(content); } catch (err) { throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule)); } diff --git a/web/shared-worker/worker/worker-database.js b/web/shared-worker/worker/worker-database.js --- a/web/shared-worker/worker/worker-database.js +++ b/web/shared-worker/worker/worker-database.js @@ -1,18 +1,35 @@ // @flow +import { + databaseIdentifier, + type DatabaseIdentifier, +} from 'lib/types/database-identifier-types.js'; import type { PlatformDetails } from 'lib/types/device-types.js'; import type { EmscriptenModule } from '../types/module.js'; import type { SQLiteQueryExecutor } from '../types/sqlite-query-executor.js'; -let sqliteQueryExecutor: ?SQLiteQueryExecutor = null; +let mainQueryExecutor: ?SQLiteQueryExecutor = null; +let restoredQueryExecutor: ?SQLiteQueryExecutor = null; -function getSQLiteQueryExecutor(): ?SQLiteQueryExecutor { - return sqliteQueryExecutor; +function getSQLiteQueryExecutor( + id: DatabaseIdentifier = databaseIdentifier.MAIN, +): ?SQLiteQueryExecutor { + if (id === databaseIdentifier.RESTORED) { + return restoredQueryExecutor; + } + return mainQueryExecutor; } -function setSQLiteQueryExecutor(newSQLiteQueryExecutor: ?SQLiteQueryExecutor) { - sqliteQueryExecutor = newSQLiteQueryExecutor; +function setSQLiteQueryExecutor( + newSQLiteQueryExecutor: ?SQLiteQueryExecutor, + id: DatabaseIdentifier = databaseIdentifier.MAIN, +) { + if (id === databaseIdentifier.RESTORED) { + restoredQueryExecutor = newSQLiteQueryExecutor; + return; + } + mainQueryExecutor = newSQLiteQueryExecutor; } let dbModule: ?EmscriptenModule = null;