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 @@ -1,5 +1,6 @@ // @flow +import localforage from 'localforage'; import * as React from 'react'; import { useDispatch } from 'react-redux'; @@ -7,9 +8,29 @@ import { convertClientDBReportToClientReportCreationRequest } from 'lib/ops/report-store-ops.js'; import { databaseModule } from './database-module-provider.js'; +import { SQLITE_ENCRYPTION_KEY } from './utils/constants.js'; +import { isDesktopSafari } from './utils/db-utils.js'; +import { + exportKeyToJWK, + generateDatabaseCryptoKey, +} from './utils/worker-crypto-utils.js'; import { useSelector } from '../redux/redux-utils.js'; import { workerRequestMessageTypes } from '../types/worker-types.js'; +const isSafari = isDesktopSafari(); + +async function getSafariEncryptionKey(): Promise { + const encryptionKey = await localforage.getItem(SQLITE_ENCRYPTION_KEY); + if (encryptionKey) { + return await exportKeyToJWK(encryptionKey); + } + const newEncryptionKey = await generateDatabaseCryptoKey({ + extractable: true, + }); + await localforage.setItem(SQLITE_ENCRYPTION_KEY, newEncryptionKey); + return await exportKeyToJWK(newEncryptionKey); +} + function SQLiteDataHandler(): React.Node { const dispatch = useDispatch(); const rehydrateConcluded = useSelector( @@ -47,7 +68,14 @@ React.useEffect(() => { (async () => { if (currentLoggedInUserID) { - await databaseModule.initDBForLoggedInUser(currentLoggedInUserID); + let databaseEncryptionKeyJWK = null; + if (isSafari) { + databaseEncryptionKeyJWK = await getSafariEncryptionKey(); + } + await databaseModule.initDBForLoggedInUser( + currentLoggedInUserID, + databaseEncryptionKeyJWK, + ); } if (!rehydrateConcluded) { 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 @@ -45,4 +45,9 @@ ); } -export { parseMultiStatementSQLiteResult, isSQLiteSupported }; +function isDesktopSafari(): boolean { + const browser = detectBrowser(); + return browser.name === 'safari' && browser.os === 'Mac OS'; +} + +export { parseMultiStatementSQLiteResult, isSQLiteSupported, isDesktopSafari };