diff --git a/web/database/database-module-provider.js b/web/database/database-module-provider.js --- a/web/database/database-module-provider.js +++ b/web/database/database-module-provider.js @@ -13,7 +13,6 @@ generateDatabaseCryptoKey, } from './utils/worker-crypto-utils.js'; import WorkerConnectionProxy from './utils/WorkerConnectionProxy.js'; -import type { AppState } from '../redux/redux-setup.js'; import { workerRequestMessageTypes, type WorkerRequestMessage, @@ -21,10 +20,8 @@ } from '../types/worker-types.js'; declare var commQueryExecutorFilename: string; -declare var preloadedState: AppState; - const databaseStatuses = Object.freeze({ - notSupported: 'NOT_SUPPORTED', + notRunning: 'NOT_RUNNING', initSuccess: 'INIT_SUCCESS', initInProgress: 'INIT_IN_PROGRESS', initError: 'INIT_ERROR', @@ -36,17 +33,21 @@ worker: SharedWorker; workerProxy: WorkerConnectionProxy; initPromise: Promise; - status: DatabaseStatus = databaseStatuses.notSupported; + status: DatabaseStatus = databaseStatuses.notRunning; - async init(currentLoggedInUserID: ?string): Promise { - if (!currentLoggedInUserID) { + async init({ clearDatabase }: { clearDatabase: boolean }): Promise { + if (!isSQLiteSupported()) { + console.warn('Sqlite is not supported'); + this.status = databaseStatuses.initError; return; } - if (!isSQLiteSupported(currentLoggedInUserID)) { - console.warn('Sqlite is not supported'); - this.status = databaseStatuses.notSupported; - return; + if (clearDatabase && this.status === databaseStatuses.initSuccess) { + console.info('Clearing sensitive data'); + await this.workerProxy.scheduleOnWorker({ + type: workerRequestMessageTypes.CLEAR_SENSITIVE_DATA, + }); + this.status = databaseStatuses.notRunning; } if (this.status === databaseStatuses.initInProgress) { @@ -96,13 +97,6 @@ await this.initPromise; } - async clearSensitiveData(): Promise { - this.status = databaseStatuses.notSupported; - await this.workerProxy.scheduleOnWorker({ - type: workerRequestMessageTypes.CLEAR_SENSITIVE_DATA, - }); - } - async isDatabaseSupported(): Promise { if (this.status === databaseStatuses.initInProgress) { await this.initPromise; @@ -113,8 +107,8 @@ async schedule( payload: WorkerRequestMessage, ): Promise { - if (this.status === databaseStatuses.notSupported) { - throw new Error('Database not supported'); + if (this.status === databaseStatuses.notRunning) { + throw new Error('Database not running'); } if (this.status === databaseStatuses.initInProgress) { @@ -145,12 +139,11 @@ async function getDatabaseModule(): Promise { if (!databaseModule) { databaseModule = new DatabaseModule(); - const currentLoggedInUserID = preloadedState.currentUserInfo?.anonymous - ? undefined - : preloadedState.currentUserInfo?.id; - await databaseModule.init(currentLoggedInUserID); + await databaseModule.init({ clearDatabase: false }); } return databaseModule; } +// Start initializing the database immediately +getDatabaseModule(); export { getDatabaseModule }; diff --git a/web/database/sqlite-data-handler.js b/web/database/sqlite-data-handler.js --- a/web/database/sqlite-data-handler.js +++ b/web/database/sqlite-data-handler.js @@ -27,17 +27,16 @@ }); const currentDBUserID = currentUserData?.userID; - if (currentDBUserID && currentDBUserID !== currentLoggedInUserID) { - await databaseModule.clearSensitiveData(); - } - if ( - currentLoggedInUserID && - (currentDBUserID || currentDBUserID !== currentLoggedInUserID) - ) { - await databaseModule.schedule({ - type: workerRequestMessageTypes.SET_CURRENT_USER_ID, - userID: currentLoggedInUserID, - }); + if (currentDBUserID !== currentLoggedInUserID) { + if (currentDBUserID) { + await databaseModule.init({ clearDatabase: true }); + } + if (currentLoggedInUserID) { + await databaseModule.schedule({ + type: workerRequestMessageTypes.SET_CURRENT_USER_ID, + userID: currentLoggedInUserID, + }); + } } } catch (error) { console.error(error); @@ -49,10 +48,6 @@ (async () => { const databaseModule = await getDatabaseModule(); - if (currentLoggedInUserID) { - await databaseModule.init(currentLoggedInUserID); - } - if (!rehydrateConcluded) { return; } diff --git a/web/database/utils/db-utils.js b/web/database/utils/db-utils.js --- a/web/database/utils/db-utils.js +++ b/web/database/utils/db-utils.js @@ -2,9 +2,6 @@ import { detect as detectBrowser } from 'detect-browser'; -import { isStaff } from 'lib/shared/staff-utils.js'; -import { isDev } from 'lib/utils/dev-utils.js'; - import { DB_SUPPORTED_BROWSERS, DB_SUPPORTED_OS } from './constants.js'; import type { EmscriptenModule } from '../types/module.js'; import { type SQLiteQueryExecutor } from '../types/sqlite-query-executor.js'; @@ -39,14 +36,7 @@ }); } -function isSQLiteSupported(currentLoggedInUserID: ?string): boolean { - if (!currentLoggedInUserID) { - return false; - } - if (!isDev && (!currentLoggedInUserID || !isStaff(currentLoggedInUserID))) { - return false; - } - +function isSQLiteSupported(): boolean { return ( DB_SUPPORTED_OS.includes(browser.os) && DB_SUPPORTED_BROWSERS.includes(browser.name) diff --git a/web/redux/persist.js b/web/redux/persist.js --- a/web/redux/persist.js +++ b/web/redux/persist.js @@ -37,11 +37,6 @@ declare var preloadedState: AppState; -const initiallyLoggedInUserID = preloadedState.currentUserInfo?.anonymous - ? undefined - : preloadedState.currentUserInfo?.id; -const isDatabaseSupported = isSQLiteSupported(initiallyLoggedInUserID); - const migrations = { [1]: async state => { const { @@ -60,6 +55,7 @@ }, [2]: async state => { const databaseModule = await getDatabaseModule(); + const isDatabaseSupported = await databaseModule.isDatabaseSupported(); if (!isDatabaseSupported) { return state; } @@ -91,6 +87,7 @@ } const databaseModule = await getDatabaseModule(); + const isDatabaseSupported = await databaseModule.isDatabaseSupported(); if (!isDatabaseSupported) { return newState; @@ -148,7 +145,7 @@ return undefined; } - const oldStorage = await getStoredState({ storage, key: rootKey }); + let oldStorage = await getStoredState({ storage, key: rootKey }); if (!oldStorage) { return undefined; } @@ -158,6 +155,33 @@ console.log('redux-persist: migrating state to SQLite storage'); } + // We need to simulate the keyserverStoreTransform for data stored in the + // old local storage (because redux persist will only run it for the + // sqlite storage which is empty in this case). + // We don't just use keyserverStoreTransform.out(oldStorage) because + // the transform might change in the future, but we need to treat + // this code like migration code (it shouldn't change). + if (oldStorage?._persist?.version === 4) { + const { connection, updatesCurrentAsOf, sessionID } = + preloadedState.keyserverStore.keyserverInfos[ashoatKeyserverID]; + + oldStorage = { + ...oldStorage, + keyserverStore: { + ...oldStorage.keyserverStore, + keyserverInfos: { + ...oldStorage.keyserverStore.keyserverInfos, + [ashoatKeyserverID]: { + ...oldStorage.keyserverStore.keyserverInfos[ashoatKeyserverID], + connection, + updatesCurrentAsOf, + sessionID, + }, + }, + }, + }; + } + return oldStorage; }; @@ -208,7 +232,7 @@ const persistConfig: PersistConfig = { key: rootKey, storage: commReduxStorageEngine, - whitelist: isDatabaseSupported + whitelist: isSQLiteSupported() ? persistWhitelist : [...persistWhitelist, 'draftStore'], migrate: (createAsyncMigrate(