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 @@ -16,6 +16,7 @@ initSuccess: 'INIT_SUCCESS', initInProgress: 'INIT_IN_PROGRESS', initError: 'INIT_ERROR', + deleting: 'DELETING', }); type DatabaseStatus = $Values; @@ -61,12 +62,35 @@ console.error(error); }; + async clearSensitiveData(): Promise { + this.status = databaseStatuses.deleting; + await this.workerProxy.scheduleOnWorker({ + type: workerRequestMessageTypes.CLEAR_SENSITIVE_DATA, + }); + const origin = window.location.origin; + try { + await this.workerProxy.scheduleOnWorker({ + type: workerRequestMessageTypes.INIT, + sqljsFilePath: `${origin}${SQLJS_FILE_PATH}`, + sqljsFilename, + }); + + this.status = databaseStatuses.initSuccess; + } catch (error) { + this.status = databaseStatuses.initError; + console.error(`Database initialization failure`, error); + } + } + async schedule( payload: WorkerRequestMessage, ): Promise { if (this.status === databaseStatuses.notSupported) { throw new Error('Database not supported'); } + if (this.status === databaseStatuses.deleting) { + throw new Error('Database being deleted'); + } if (this.status === databaseStatuses.initInProgress) { await this.initPromise; diff --git a/web/database/sqlite-data-handler-web.js b/web/database/sqlite-data-handler-web.js new file mode 100644 --- /dev/null +++ b/web/database/sqlite-data-handler-web.js @@ -0,0 +1,58 @@ +// @flow + +import * as React from 'react'; + +import { isLoggedIn } from 'lib/selectors/user-selectors.js'; + +import { databaseModule } from './database-module-provider.js'; +import { useSelector } from '../redux/redux-utils.js'; +import { workerRequestMessageTypes } from '../types/worker-types.js'; + +function SQLiteDataHandlerWeb(): React.Node { + const rehydrateConcluded = useSelector( + state => !!(state._persist && state._persist.rehydrated), + ); + const currentLoggedInUserID = useSelector(state => + state.currentUserInfo?.anonymous ? undefined : state.currentUserInfo?.id, + ); + const loggedIn = useSelector(isLoggedIn); + + const handleSensitiveData = React.useCallback(async () => { + try { + const currentUserData = await databaseModule.schedule({ + type: workerRequestMessageTypes.GET_CURRENT_USER_ID, + }); + if ( + currentUserData?.userID && + currentUserData.userID !== currentLoggedInUserID + ) { + await databaseModule.clearSensitiveData(); + } + if (currentLoggedInUserID) { + await databaseModule.schedule({ + type: workerRequestMessageTypes.SET_CURRENT_USER_ID, + userID: currentLoggedInUserID, + }); + } + } catch (error) { + console.error(error); + } + }, [currentLoggedInUserID]); + + React.useEffect(() => { + if (!rehydrateConcluded) { + return; + } + if (!loggedIn) { + return; + } + + (async () => { + await handleSensitiveData(); + })(); + }, [handleSensitiveData, loggedIn, rehydrateConcluded]); + + return null; +} + +export { SQLiteDataHandlerWeb }; diff --git a/web/database/worker/db-worker.js b/web/database/worker/db-worker.js --- a/web/database/worker/db-worker.js +++ b/web/database/worker/db-worker.js @@ -167,6 +167,13 @@ if (message.type === workerRequestMessageTypes.INIT) { await initDatabase(message.sqljsFilePath, message.sqljsFilename); return; + } else if (message.type === workerRequestMessageTypes.CLEAR_SENSITIVE_DATA) { + encryptionKey = null; + if (sqliteDb) { + sqliteDb.close(); + } + await localforage.clear(); + return; } if (!sqliteDb) { diff --git a/web/types/worker-types.js b/web/types/worker-types.js --- a/web/types/worker-types.js +++ b/web/types/worker-types.js @@ -17,6 +17,7 @@ GET_PERSIST_STORAGE_ITEM: 7, SET_PERSIST_STORAGE_ITEM: 8, REMOVE_PERSIST_STORAGE_ITEM: 9, + CLEAR_SENSITIVE_DATA: 10, }); export type PingWorkerRequestMessage = { @@ -68,6 +69,10 @@ +key: string, }; +export type ClearSensitiveDataRequestMessage = { + +type: 10, +}; + export type WorkerRequestMessage = | PingWorkerRequestMessage | InitWorkerRequestMessage @@ -78,7 +83,8 @@ | GetCurrentUserIDRequestMessage | GetPersistStorageItemRequestMessage | SetPersistStorageItemRequestMessage - | RemovePersistStorageItemRequestMessage; + | RemovePersistStorageItemRequestMessage + | ClearSensitiveDataRequestMessage; export type WorkerRequestProxyMessage = { +id: number,