diff --git a/web/grpc/identity-service-client-proxy.js b/web/grpc/identity-service-client-proxy.js index 12b549075..6740f58cf 100644 --- a/web/grpc/identity-service-client-proxy.js +++ b/web/grpc/identity-service-client-proxy.js @@ -1,127 +1,125 @@ // @flow import type { OneTimeKeysResultValues, SignedPrekeys, } from 'lib/types/crypto-types.js'; import type { SignedDeviceList, SignedMessage, IdentityServiceClient, IdentityServiceAuthLayer, DeviceOlmOutboundKeys, IdentityAuthResult, UserDevicesOlmInboundKeys, UserDevicesOlmOutboundKeys, } from 'lib/types/identity-service-types.js'; -import { getConfig } from 'lib/utils/config.js'; import { type CommSharedWorker, getCommSharedWorker, } from '../shared-worker/shared-worker-provider.js'; import { getOpaqueWasmPath } from '../shared-worker/utils/constants.js'; import { workerRequestMessageTypes, workerResponseMessageTypes, } from '../types/worker-types.js'; class IdentityServiceClientSharedProxy implements IdentityServiceClient { sharedWorkerPromise: Promise; constructor(authLayer: ?IdentityServiceAuthLayer) { this.sharedWorkerPromise = (async () => { const sharedWorker = await getCommSharedWorker(); await sharedWorker.schedule({ type: workerRequestMessageTypes.CREATE_IDENTITY_SERVICE_CLIENT, opaqueWasmPath: getOpaqueWasmPath(), - platformDetails: getConfig().platformDetails, authLayer, }); return sharedWorker; })(); } proxyToWorker( method: $Keys, ): (...args: $ReadOnlyArray) => Promise { return async (...args: $ReadOnlyArray) => { const sharedWorker = await this.sharedWorkerPromise; const result = await sharedWorker.schedule({ type: workerRequestMessageTypes.CALL_IDENTITY_CLIENT_METHOD, method, args, }); if (!result) { throw new Error(`Worker identity call didn't return expected message`); } else if ( result.type !== workerResponseMessageTypes.CALL_IDENTITY_CLIENT_METHOD ) { throw new Error( `Worker identity call didn't return expected message. Instead got: ${JSON.stringify( result, )}`, ); } // Worker should return a message with the corresponding return type return (result.result: any); }; } deleteUser: () => Promise = this.proxyToWorker('deleteUser'); logOut: () => Promise = this.proxyToWorker('logOut'); getKeyserverKeys: (keyserverID: string) => Promise = this.proxyToWorker('getKeyserverKeys'); getOutboundKeysForUser: ( userID: string, ) => Promise = this.proxyToWorker( 'getOutboundKeysForUser', ); getInboundKeysForUser: ( userID: string, ) => Promise = this.proxyToWorker( 'getInboundKeysForUser', ); uploadOneTimeKeys: (oneTimeKeys: OneTimeKeysResultValues) => Promise = this.proxyToWorker('uploadOneTimeKeys'); logInPasswordUser: ( username: string, password: string, ) => Promise = this.proxyToWorker('logInPasswordUser'); logInWalletUser: ( walletAddress: string, siweMessage: string, siweSignature: string, ) => Promise = this.proxyToWorker('logInWalletUser'); uploadKeysForRegisteredDeviceAndLogIn: ( userID: string, nonceChallengeResponse: SignedMessage, ) => Promise = this.proxyToWorker( 'uploadKeysForRegisteredDeviceAndLogIn', ); generateNonce: () => Promise = this.proxyToWorker('generateNonce'); publishWebPrekeys: (prekeys: SignedPrekeys) => Promise = this.proxyToWorker('publishWebPrekeys'); getDeviceListHistoryForUser: ( userID: string, sinceTimestamp?: number, ) => Promise<$ReadOnlyArray> = this.proxyToWorker( 'getDeviceListHistoryForUser', ); } export { IdentityServiceClientSharedProxy }; diff --git a/web/shared-worker/shared-worker-provider.js b/web/shared-worker/shared-worker-provider.js index 78a110c40..58cdf495e 100644 --- a/web/shared-worker/shared-worker-provider.js +++ b/web/shared-worker/shared-worker-provider.js @@ -1,169 +1,171 @@ // @flow import invariant from 'invariant'; import localforage from 'localforage'; import { getConfig } from 'lib/utils/config.js'; import { DATABASE_WORKER_PATH, WORKERS_MODULES_DIR_PATH, SQLITE_ENCRYPTION_KEY, } from './utils/constants.js'; import { isDesktopSafari, isSQLiteSupported } from './utils/db-utils.js'; import WorkerConnectionProxy from './utils/worker-connection-proxy.js'; import { exportKeyToJWK, generateCryptoKey, } from '../crypto/aes-gcm-crypto-utils.js'; import { workerRequestMessageTypes, type WorkerRequestMessage, type WorkerResponseMessage, } from '../types/worker-types.js'; declare var baseURL: string; declare var commQueryExecutorFilename: string; declare var backupClientFilename: string; const sharedWorkerStatuses = Object.freeze({ notRunning: 'NOT_RUNNING', initSuccess: 'INIT_SUCCESS', initInProgress: 'INIT_IN_PROGRESS', initError: 'INIT_ERROR', }); type SharedWorkerStatus = | { +type: 'NOT_RUNNING' | 'INIT_SUCCESS' | 'INIT_ERROR' } | { +type: 'INIT_IN_PROGRESS', +initPromise: Promise }; type InitOptions = { +clearDatabase: boolean }; class CommSharedWorker { worker: ?SharedWorker; workerProxy: ?WorkerConnectionProxy; status: SharedWorkerStatus = { type: sharedWorkerStatuses.notRunning }; async init({ clearDatabase }: InitOptions): Promise { if (!isSQLiteSupported()) { console.warn('SQLite is not supported'); this.status = { type: sharedWorkerStatuses.initError }; return; } if (this.status.type === sharedWorkerStatuses.initInProgress) { await this.status.initPromise; return; } if ( (this.status.type === sharedWorkerStatuses.initSuccess && !clearDatabase) || this.status.type === sharedWorkerStatuses.initError ) { return; } const initPromise = (async () => { if ( clearDatabase && this.status.type === sharedWorkerStatuses.initSuccess ) { console.info('Clearing sensitive data'); invariant(this.workerProxy, 'Worker proxy should exist'); await this.workerProxy.scheduleOnWorker({ type: workerRequestMessageTypes.CLEAR_SENSITIVE_DATA, }); } - const codeVersion = getConfig().platformDetails.codeVersion ?? ''; + const platformDetails = getConfig().platformDetails; + const codeVersion = platformDetails.codeVersion ?? ''; const workerName = `comm-app-shared-worker-${codeVersion}`; this.worker = new SharedWorker(DATABASE_WORKER_PATH, workerName); this.worker.onerror = console.error; this.workerProxy = new WorkerConnectionProxy( this.worker.port, console.error, ); const origin = window.location.origin; try { let encryptionKey = null; if (isDesktopSafari) { encryptionKey = await getSafariEncryptionKey(); } invariant(this.workerProxy, 'Worker proxy should exist'); await this.workerProxy.scheduleOnWorker({ type: workerRequestMessageTypes.INIT, + platformDetails, webworkerModulesFilePath: `${origin}${baseURL}${WORKERS_MODULES_DIR_PATH}`, encryptionKey, commQueryExecutorFilename, backupClientFilename, }); this.status = { type: sharedWorkerStatuses.initSuccess }; console.info('Database initialization success'); } catch (error) { this.status = { type: sharedWorkerStatuses.initError }; console.error(`Database initialization failure`, error); } })(); this.status = { type: sharedWorkerStatuses.initInProgress, initPromise }; await initPromise; } async isSupported(): Promise { if (this.status.type === sharedWorkerStatuses.initInProgress) { await this.status.initPromise; } return this.status.type === sharedWorkerStatuses.initSuccess; } async schedule( payload: WorkerRequestMessage, ): Promise { if (this.status.type === sharedWorkerStatuses.notRunning) { throw new Error('Database not running'); } if (this.status.type === sharedWorkerStatuses.initInProgress) { await this.status.initPromise; } if (this.status.type === sharedWorkerStatuses.initError) { throw new Error('Database could not be initialized'); } invariant(this.workerProxy, 'Worker proxy should exist'); return this.workerProxy.scheduleOnWorker(payload); } } async function getSafariEncryptionKey(): Promise { const encryptionKey = await localforage.getItem( SQLITE_ENCRYPTION_KEY, ); if (encryptionKey) { return await exportKeyToJWK(encryptionKey); } const newEncryptionKey = await generateCryptoKey({ extractable: true, }); await localforage.setItem(SQLITE_ENCRYPTION_KEY, newEncryptionKey); return await exportKeyToJWK(newEncryptionKey); } let sharedWorker: ?CommSharedWorker = null; async function getCommSharedWorker(): Promise { if (sharedWorker) { return sharedWorker; } const newModule = new CommSharedWorker(); sharedWorker = newModule; await newModule.init({ clearDatabase: false }); return newModule; } export { CommSharedWorker, getCommSharedWorker }; diff --git a/web/shared-worker/worker/identity-client.js b/web/shared-worker/worker/identity-client.js index 2e4a7f036..d12cdb42d 100644 --- a/web/shared-worker/worker/identity-client.js +++ b/web/shared-worker/worker/identity-client.js @@ -1,66 +1,69 @@ // @flow +import type { PlatformDetails } from 'lib/types/device-types.js'; + import { getNewDeviceKeyUpload, getExistingDeviceKeyUpload, } from './worker-crypto.js'; import { IdentityServiceClientWrapper } from '../../grpc/identity-service-client-wrapper.js'; import { type WorkerResponseMessage, type WorkerRequestMessage, workerRequestMessageTypes, workerResponseMessageTypes, } from '../../types/worker-types.js'; import type { EmscriptenModule } from '../types/module.js'; import type { SQLiteQueryExecutor } from '../types/sqlite-query-executor.js'; let identityClient: ?IdentityServiceClientWrapper = null; async function processAppIdentityClientRequest( sqliteQueryExecutor: SQLiteQueryExecutor, dbModule: EmscriptenModule, + platformDetails: PlatformDetails, message: WorkerRequestMessage, ): Promise { if ( message.type === workerRequestMessageTypes.CREATE_IDENTITY_SERVICE_CLIENT ) { identityClient = new IdentityServiceClientWrapper( - message.platformDetails, + platformDetails, message.opaqueWasmPath, message.authLayer, async () => getNewDeviceKeyUpload(), async () => getExistingDeviceKeyUpload(), ); return undefined; } if (!identityClient) { throw new Error('Identity client not created'); } if (message.type === workerRequestMessageTypes.CALL_IDENTITY_CLIENT_METHOD) { // Flow doesn't allow us to access methods like this (it needs an index // signature declaration in the object type) const method: (...$ReadOnlyArray) => mixed = (identityClient: any)[ message.method ]; if (typeof method !== 'function') { throw new Error( `Couldn't find identity client method with name '${message.method}'`, ); } const result = await method(...message.args); return { type: workerResponseMessageTypes.CALL_IDENTITY_CLIENT_METHOD, result, }; } return undefined; } function getIdentityClient(): ?IdentityServiceClientWrapper { return identityClient; } export { processAppIdentityClientRequest, getIdentityClient }; diff --git a/web/shared-worker/worker/shared-worker.js b/web/shared-worker/worker/shared-worker.js index db332cba6..40e78057e 100644 --- a/web/shared-worker/worker/shared-worker.js +++ b/web/shared-worker/worker/shared-worker.js @@ -1,337 +1,347 @@ // @flow import localforage from 'localforage'; import { restoreBackup } from './backup.js'; import { processAppIdentityClientRequest } from './identity-client.js'; import { getClientStoreFromQueryExecutor, processDBStoreOperations, } from './process-operations.js'; import { clearCryptoStore, processAppOlmApiRequest } from './worker-crypto.js'; import { getDBModule, getSQLiteQueryExecutor, setDBModule, setSQLiteQueryExecutor, + getPlatformDetails, + setPlatformDetails, } from './worker-database.js'; import initBackupClientModule from '../../backup-client-wasm/wasm/backup-client-wasm.js'; import { decryptData, encryptData, generateCryptoKey, importJWKKey, type EncryptedData, } from '../../crypto/aes-gcm-crypto-utils.js'; import { type SharedWorkerMessageEvent, type WorkerRequestMessage, type WorkerResponseMessage, workerRequestMessageTypes, workerResponseMessageTypes, type WorkerRequestProxyMessage, workerWriteRequests, workerOlmAPIRequests, } from '../../types/worker-types.js'; import { workerIdentityClientRequests } from '../../types/worker-types.js'; import { getDatabaseModule } from '../db-module.js'; import { COMM_SQLITE_DATABASE_PATH, CURRENT_USER_ID_KEY, localforageConfig, SQLITE_CONTENT, SQLITE_ENCRYPTION_KEY, DEFAULT_BACKUP_CLIENT_FILENAME, } from '../utils/constants.js'; import { clearSensitiveData, exportDatabaseContent, importDatabaseContent, } from '../utils/db-utils.js'; localforage.config(localforageConfig); let encryptionKey: ?CryptoKey = null; let persistNeeded: boolean = false; let persistInProgress: boolean = false; async function initDatabase( webworkerModulesFilePath: string, commQueryExecutorFilename: ?string, encryptionKeyJWK?: ?SubtleCrypto$JsonWebKey, ) { const dbModule = getDBModule(); const sqliteQueryExecutor = getSQLiteQueryExecutor(); if (!!dbModule && !!sqliteQueryExecutor) { console.log('Database already initialized'); return; } const newModule = dbModule ? dbModule : getDatabaseModule(commQueryExecutorFilename, webworkerModulesFilePath); if (!dbModule) { setDBModule(newModule); } if (encryptionKeyJWK) { encryptionKey = await importJWKKey(encryptionKeyJWK); } else { encryptionKey = await localforage.getItem(SQLITE_ENCRYPTION_KEY); if (!encryptionKey) { const cryptoKey = await generateCryptoKey({ extractable: false }); await localforage.setItem(SQLITE_ENCRYPTION_KEY, cryptoKey); } } const encryptedContent = await localforage.getItem(SQLITE_CONTENT); let dbContent = null; try { if (encryptionKey && encryptedContent) { dbContent = await decryptData(encryptedContent, encryptionKey); } } catch (e) { console.error('Error while decrypting content, clearing database content'); await localforage.removeItem(SQLITE_CONTENT); } if (dbContent) { importDatabaseContent(dbContent, newModule, COMM_SQLITE_DATABASE_PATH); console.info( 'Database exists and is properly encrypted, using persisted data', ); } else { console.info('Creating fresh database'); } setSQLiteQueryExecutor( new newModule.SQLiteQueryExecutor(COMM_SQLITE_DATABASE_PATH), ); } async function initBackupClient( webworkerModulesFilePath: string, backupClientFilename: ?string, ) { let modulePath; if (backupClientFilename) { modulePath = `${webworkerModulesFilePath}/${backupClientFilename}`; } else { modulePath = `${webworkerModulesFilePath}/${DEFAULT_BACKUP_CLIENT_FILENAME}`; } await initBackupClientModule(modulePath); } async function persist() { persistInProgress = true; const sqliteQueryExecutor = getSQLiteQueryExecutor(); const dbModule = getDBModule(); if (!sqliteQueryExecutor || !dbModule) { persistInProgress = false; throw new Error( 'Database not initialized while persisting database content', ); } if (!encryptionKey) { encryptionKey = await localforage.getItem(SQLITE_ENCRYPTION_KEY); } while (persistNeeded) { persistNeeded = false; const dbData = exportDatabaseContent(dbModule, COMM_SQLITE_DATABASE_PATH); if (!encryptionKey) { persistInProgress = false; throw new Error('Encryption key is missing'); } const encryptedData = await encryptData(dbData, encryptionKey); await localforage.setItem(SQLITE_CONTENT, encryptedData); } persistInProgress = false; } async function processAppRequest( message: WorkerRequestMessage, ): Promise { // non-database operations if (message.type === workerRequestMessageTypes.PING) { return { type: workerResponseMessageTypes.PONG, text: 'PONG', }; } else if ( message.type === workerRequestMessageTypes.GENERATE_DATABASE_ENCRYPTION_KEY ) { const cryptoKey = await generateCryptoKey({ extractable: false }); await localforage.setItem(SQLITE_ENCRYPTION_KEY, cryptoKey); return undefined; } const sqliteQueryExecutor = getSQLiteQueryExecutor(); const dbModule = getDBModule(); // database operations if (message.type === workerRequestMessageTypes.INIT) { + setPlatformDetails(message.platformDetails); const promises = [ initDatabase( message.webworkerModulesFilePath, message.commQueryExecutorFilename, message.encryptionKey, ), ]; if (message.backupClientFilename !== undefined) { promises.push( initBackupClient( message.webworkerModulesFilePath, message.backupClientFilename, ), ); } await Promise.all(promises); return undefined; } else if (message.type === workerRequestMessageTypes.CLEAR_SENSITIVE_DATA) { clearCryptoStore(); encryptionKey = null; await localforage.clear(); if (dbModule && sqliteQueryExecutor) { clearSensitiveData( dbModule, COMM_SQLITE_DATABASE_PATH, sqliteQueryExecutor, ); } setSQLiteQueryExecutor(null); return undefined; } if (!sqliteQueryExecutor) { throw new Error( `Database not initialized, unable to process request type: ${message.type}`, ); } // read-only operations if (message.type === workerRequestMessageTypes.GET_CLIENT_STORE) { return { type: workerResponseMessageTypes.CLIENT_STORE, store: getClientStoreFromQueryExecutor(sqliteQueryExecutor), }; } else if (message.type === workerRequestMessageTypes.GET_CURRENT_USER_ID) { return { type: workerResponseMessageTypes.GET_CURRENT_USER_ID, userID: sqliteQueryExecutor.getMetadata(CURRENT_USER_ID_KEY), }; } else if ( message.type === workerRequestMessageTypes.GET_PERSIST_STORAGE_ITEM ) { return { type: workerResponseMessageTypes.GET_PERSIST_STORAGE_ITEM, item: sqliteQueryExecutor.getPersistStorageItem(message.key), }; } // write operations const isOlmAPIRequest = workerOlmAPIRequests.includes(message.type); const isIdentityClientRequest = workerIdentityClientRequests.includes( message.type, ); if ( !workerWriteRequests.includes(message.type) && !isOlmAPIRequest && !isIdentityClientRequest ) { throw new Error(`Request type ${message.type} not supported`); } if (!sqliteQueryExecutor || !dbModule) { throw new Error( `Database not initialized, unable to process request type: ${message.type}`, ); } let result; if (isOlmAPIRequest) { result = await processAppOlmApiRequest(message); } else if (isIdentityClientRequest) { + const platformDetails = getPlatformDetails(); + if (!platformDetails) { + throw new Error( + 'Platform details not set, unable to process identity client request', + ); + } result = await processAppIdentityClientRequest( sqliteQueryExecutor, dbModule, + platformDetails, message, ); } else if ( message.type === workerRequestMessageTypes.PROCESS_STORE_OPERATIONS ) { processDBStoreOperations( sqliteQueryExecutor, message.storeOperations, dbModule, ); } else if (message.type === workerRequestMessageTypes.SET_CURRENT_USER_ID) { sqliteQueryExecutor.setMetadata(CURRENT_USER_ID_KEY, message.userID); } else if ( message.type === workerRequestMessageTypes.SET_PERSIST_STORAGE_ITEM ) { sqliteQueryExecutor.setPersistStorageItem(message.key, message.item); } else if ( message.type === workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM ) { sqliteQueryExecutor.removePersistStorageItem(message.key); } else if (message.type === workerRequestMessageTypes.BACKUP_RESTORE) { await restoreBackup( sqliteQueryExecutor, dbModule, message.authMetadata, message.backupID, message.backupDataKey, message.backupLogDataKey, ); } persistNeeded = true; if (!persistInProgress) { void persist(); } return result; } let currentlyProcessedMessage: ?Promise = null; function connectHandler(event: SharedWorkerMessageEvent) { if (!event.ports.length) { return; } const port: MessagePort = event.ports[0]; console.log('Web database worker alive!'); port.onmessage = async function (messageEvent: MessageEvent) { const data: WorkerRequestProxyMessage = (messageEvent.data: any); const { id, message } = data; if (!id) { port.postMessage({ error: 'Request without identifier', }); } currentlyProcessedMessage = (async () => { await currentlyProcessedMessage; try { const result = await processAppRequest(message); port.postMessage({ id, message: result, }); } catch (e) { port.postMessage({ id, error: e.message, }); } })(); }; } self.addEventListener('connect', connectHandler); diff --git a/web/shared-worker/worker/worker-database.js b/web/shared-worker/worker/worker-database.js index 6d6fbb38d..16b366095 100644 --- a/web/shared-worker/worker/worker-database.js +++ b/web/shared-worker/worker/worker-database.js @@ -1,31 +1,45 @@ // @flow +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; function getSQLiteQueryExecutor(): ?SQLiteQueryExecutor { return sqliteQueryExecutor; } function setSQLiteQueryExecutor(newSQLiteQueryExecutor: ?SQLiteQueryExecutor) { sqliteQueryExecutor = newSQLiteQueryExecutor; } let dbModule: ?EmscriptenModule = null; function getDBModule(): ?EmscriptenModule { return dbModule; } function setDBModule(newDBModule: EmscriptenModule) { dbModule = newDBModule; } +let platformDetails: ?PlatformDetails = null; + +function getPlatformDetails(): ?PlatformDetails { + return platformDetails; +} + +function setPlatformDetails(newPlatformDetails: PlatformDetails) { + platformDetails = newPlatformDetails; +} + export { getSQLiteQueryExecutor, setSQLiteQueryExecutor, getDBModule, setDBModule, + getPlatformDetails, + setPlatformDetails, }; diff --git a/web/types/worker-types.js b/web/types/worker-types.js index abbb88879..47030c37f 100644 --- a/web/types/worker-types.js +++ b/web/types/worker-types.js @@ -1,223 +1,223 @@ // @flow import type { AuthMetadata } from 'lib/shared/identity-client-context.js'; import type { OlmAPI, CryptoStore } from 'lib/types/crypto-types.js'; import type { PlatformDetails } from 'lib/types/device-types.js'; import type { IdentityServiceClient, IdentityServiceAuthLayer, } from 'lib/types/identity-service-types.js'; import type { ClientDBStore, ClientDBStoreOperations, } from 'lib/types/store-ops-types.js'; // The types of messages sent from app to worker export const workerRequestMessageTypes = Object.freeze({ PING: 0, INIT: 1, GENERATE_DATABASE_ENCRYPTION_KEY: 2, PROCESS_STORE_OPERATIONS: 3, GET_CLIENT_STORE: 4, SET_CURRENT_USER_ID: 5, GET_CURRENT_USER_ID: 6, GET_PERSIST_STORAGE_ITEM: 7, SET_PERSIST_STORAGE_ITEM: 8, REMOVE_PERSIST_STORAGE_ITEM: 9, CLEAR_SENSITIVE_DATA: 10, BACKUP_RESTORE: 11, INITIALIZE_CRYPTO_ACCOUNT: 12, CREATE_IDENTITY_SERVICE_CLIENT: 13, CALL_IDENTITY_CLIENT_METHOD: 14, CALL_OLM_API_METHOD: 15, }); export const workerWriteRequests: $ReadOnlyArray = [ workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, workerRequestMessageTypes.SET_CURRENT_USER_ID, workerRequestMessageTypes.SET_PERSIST_STORAGE_ITEM, workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM, workerRequestMessageTypes.BACKUP_RESTORE, workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT, ]; export const workerOlmAPIRequests: $ReadOnlyArray = [ workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT, workerRequestMessageTypes.CALL_OLM_API_METHOD, ]; export const workerIdentityClientRequests: $ReadOnlyArray = [ workerRequestMessageTypes.CREATE_IDENTITY_SERVICE_CLIENT, workerRequestMessageTypes.CALL_IDENTITY_CLIENT_METHOD, ]; export type PingWorkerRequestMessage = { +type: 0, +text: string, }; export type InitWorkerRequestMessage = { +type: 1, + +platformDetails: PlatformDetails, +webworkerModulesFilePath: string, +commQueryExecutorFilename: ?string, +encryptionKey?: ?SubtleCrypto$JsonWebKey, +backupClientFilename?: ?string, }; export type GenerateDatabaseEncryptionKeyRequestMessage = { +type: 2, }; export type ProcessStoreOperationsRequestMessage = { +type: 3, +storeOperations: ClientDBStoreOperations, }; export type GetClientStoreRequestMessage = { +type: 4, }; export type SetCurrentUserIDRequestMessage = { +type: 5, +userID: string, }; export type GetCurrentUserIDRequestMessage = { +type: 6, }; export type GetPersistStorageItemRequestMessage = { +type: 7, +key: string, }; export type SetPersistStorageItemRequestMessage = { +type: 8, +key: string, +item: string, }; export type RemovePersistStorageItemRequestMessage = { +type: 9, +key: string, }; export type ClearSensitiveDataRequestMessage = { +type: 10, }; export type BackupRestoreRequestMessage = { +type: 11, +authMetadata: AuthMetadata, +backupID: string, +backupDataKey: string, +backupLogDataKey: string, }; export type InitializeCryptoAccountRequestMessage = { +type: 12, +olmWasmPath: string, +initialCryptoStore?: CryptoStore, }; export type CreateIdentityServiceClientRequestMessage = { +type: 13, +opaqueWasmPath: string, - +platformDetails: PlatformDetails, +authLayer: ?IdentityServiceAuthLayer, }; export type CallIdentityClientMethodRequestMessage = { +type: 14, +method: $Keys, +args: $ReadOnlyArray, }; export type CallOLMApiMethodRequestMessage = { +type: 15, +method: $Keys, +args: $ReadOnlyArray, }; export type WorkerRequestMessage = | PingWorkerRequestMessage | InitWorkerRequestMessage | GenerateDatabaseEncryptionKeyRequestMessage | ProcessStoreOperationsRequestMessage | GetClientStoreRequestMessage | SetCurrentUserIDRequestMessage | GetCurrentUserIDRequestMessage | GetPersistStorageItemRequestMessage | SetPersistStorageItemRequestMessage | RemovePersistStorageItemRequestMessage | ClearSensitiveDataRequestMessage | BackupRestoreRequestMessage | InitializeCryptoAccountRequestMessage | CreateIdentityServiceClientRequestMessage | CallIdentityClientMethodRequestMessage | CallOLMApiMethodRequestMessage; export type WorkerRequestProxyMessage = { +id: number, +message: WorkerRequestMessage, }; // The types of messages sent from worker to app export const workerResponseMessageTypes = Object.freeze({ PONG: 0, CLIENT_STORE: 1, GET_CURRENT_USER_ID: 2, GET_PERSIST_STORAGE_ITEM: 3, CALL_IDENTITY_CLIENT_METHOD: 4, CALL_OLM_API_METHOD: 5, }); export type PongWorkerResponseMessage = { +type: 0, +text: string, }; export type ClientStoreResponseMessage = { +type: 1, +store: ClientDBStore, }; export type GetCurrentUserIDResponseMessage = { +type: 2, +userID: ?string, }; export type GetPersistStorageItemResponseMessage = { +type: 3, +item: string, }; export type CallIdentityClientMethodResponseMessage = { +type: 4, +result: mixed, }; export type CallOLMApiMethodResponseMessage = { +type: 5, +result: mixed, }; export type WorkerResponseMessage = | PongWorkerResponseMessage | ClientStoreResponseMessage | GetCurrentUserIDResponseMessage | GetPersistStorageItemResponseMessage | CallIdentityClientMethodResponseMessage | CallOLMApiMethodResponseMessage; export type WorkerResponseProxyMessage = { +id?: number, +message?: WorkerResponseMessage, +error?: string, }; // SharedWorker types export type SharedWorkerMessageEvent = MessageEvent & { +ports: $ReadOnlyArray, ... };