diff --git a/web/database/types/sqlite-query-executor.js b/web/database/types/sqlite-query-executor.js index 5af2cfe66..eca568c39 100644 --- a/web/database/types/sqlite-query-executor.js +++ b/web/database/types/sqlite-query-executor.js @@ -1,28 +1,32 @@ // @flow import type { ClientDBReport } from 'lib/ops/report-store-ops.js'; import type { ClientDBDraftInfo } from 'lib/types/draft-types.js'; declare export class SQLiteQueryExecutor { constructor(sqliteFilePath: string): void; updateDraft(key: string, text: string): void; moveDraft(oldKey: string, newKey: string): boolean; getAllDrafts(): ClientDBDraftInfo[]; removeAllDrafts(): void; setMetadata(entryName: string, data: string): void; clearMetadata(entryName: string): void; getMetadata(entryName: string): string; replaceReport(report: ClientDBReport): void; removeReports(ids: $ReadOnlyArray): void; removeAllReports(): void; getAllReports(): ClientDBReport[]; setPersistStorageItem(key: string, item: string): void; removePersistStorageItem(key: string): void; getPersistStorageItem(key: string): string; + + // method is provided to manually signal that a C++ object + // is no longer needed and can be deleted + delete(): void; } export type SQLiteQueryExecutorType = typeof SQLiteQueryExecutor; diff --git a/web/database/utils/db-utils.js b/web/database/utils/db-utils.js index f187396ab..3d23eccd4 100644 --- a/web/database/utils/db-utils.js +++ b/web/database/utils/db-utils.js @@ -1,52 +1,68 @@ // @flow import { detect as detectBrowser } from 'detect-browser'; import type { QueryExecResult } from 'sql.js'; 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'; const browser = detectBrowser(); +function clearSensitiveData( + dbModule: EmscriptenModule, + path: string, + sqliteQueryExecutor: SQLiteQueryExecutor, +) { + sqliteQueryExecutor.delete(); + dbModule.FS.unlink(path); +} + function parseSQLiteQueryResult(result: QueryExecResult): T[] { const { columns, values } = result; return values.map(rowResult => { const row: any = Object.fromEntries( columns.map((key, index) => [key, rowResult[index]]), ); return row; }); } // NOTE: sql.js has behavior that when there are multiple statements in query // e.g. "statement1; statement2; statement3;" // and statement2 will not return anything, the result will be: // [result1, result3], not [result1, undefined, result3] function parseMultiStatementSQLiteResult( rawResult: $ReadOnlyArray, ): T[][] { return rawResult.map((queryResult: QueryExecResult) => parseSQLiteQueryResult(queryResult), ); } function isSQLiteSupported(currentLoggedInUserID: ?string): boolean { if (!currentLoggedInUserID) { return false; } if (!isDev && (!currentLoggedInUserID || !isStaff(currentLoggedInUserID))) { return false; } return ( DB_SUPPORTED_OS.includes(browser.os) && DB_SUPPORTED_BROWSERS.includes(browser.name) ); } const isDesktopSafari: boolean = browser && browser.name === 'safari' && browser.os === 'Mac OS'; -export { parseMultiStatementSQLiteResult, isSQLiteSupported, isDesktopSafari }; +export { + parseMultiStatementSQLiteResult, + isSQLiteSupported, + isDesktopSafari, + clearSensitiveData, +};