diff --git a/lib/types/sqlite-types.js b/lib/types/sqlite-types.js --- a/lib/types/sqlite-types.js +++ b/lib/types/sqlite-types.js @@ -1,6 +1,7 @@ // @flow import type { DatabaseIdentifier } from './database-identifier-types.js'; +import type { StoredHolders } from './holder-types.js'; import type { IdentityAuthResult } from './identity-service-types.js'; import type { ClientDBMessageInfo } from './message-types.js'; import type { ClientStore, StoreOperations } from './store-ops-types.js'; @@ -79,6 +80,7 @@ entryName: string, dbID: DatabaseIdentifier, ) => Promise, + +getHolders: (dbID: DatabaseIdentifier) => Promise, // write operations +removeInboundP2PMessages: (ids: $ReadOnlyArray) => Promise, diff --git a/lib/utils/__mocks__/config.js b/lib/utils/__mocks__/config.js --- a/lib/utils/__mocks__/config.js +++ b/lib/utils/__mocks__/config.js @@ -53,6 +53,7 @@ migrateBackupSchema: jest.fn(), getDatabaseVersion: jest.fn(), getSyncedMetadata: jest.fn(), + getHolders: jest.fn(), }, encryptedNotifUtilsAPI: { generateAESKey: jest.fn(), diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h @@ -263,6 +263,7 @@ jsi::Runtime &rt, jsi::String entryName, jsi::String dbID) override; + virtual jsi::Value getHolders(jsi::Runtime &rt, jsi::String dbID) override; virtual jsi::Value markPrekeysAsPublished(jsi::Runtime &rt) override; virtual jsi::Value getRelatedMessages(jsi::Runtime &rt, jsi::String messageID) override; diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp @@ -3118,6 +3118,42 @@ }); } +jsi::Value CommCoreModule::getHolders(jsi::Runtime &rt, jsi::String dbID) { + DatabaseIdentifier identifier = stringToDatabaseIdentifier(dbID.utf8(rt)); + return createPromiseAsJSIValue( + rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { + taskType job = [=, &innerRt]() { + std::string error; + std::vector holdersVector; + try { + holdersVector = + DatabaseManager::getQueryExecutor(identifier).getHolders(); + } catch (std::system_error &e) { + error = e.what(); + } + + auto holdersVectorPtr = + std::make_shared>(std::move(holdersVector)); + + this->jsInvoker_->invokeAsync([&innerRt, + error, + promise, + holdersVectorPtr, + holderStore = this->holderStore]() { + if (error.size()) { + promise->reject(error); + return; + } + jsi::Array jsiHolders = + holderStore.parseDBDataStore(innerRt, holdersVectorPtr); + promise->resolve(std::move(jsiHolders)); + }); + }; + GlobalDBSingleton::instance.scheduleOrRunCancellable( + job, promise, this->jsInvoker_); + }); +} + jsi::Value CommCoreModule::markPrekeysAsPublished(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { diff --git a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp --- a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp @@ -238,6 +238,9 @@ static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_copyContentFromBackupDatabase(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->copyContentFromBackupDatabase(rt); } +static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getHolders(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getHolders(rt, args[0].asString(rt)); +} CommCoreModuleSchemaCxxSpecJSI::CommCoreModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommTurboModule", jsInvoker) { @@ -314,6 +317,7 @@ methodMap_["getDMOperationsByType"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getDMOperationsByType}; methodMap_["migrateBackupSchema"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_migrateBackupSchema}; methodMap_["copyContentFromBackupDatabase"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_copyContentFromBackupDatabase}; + methodMap_["getHolders"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getHolders}; } diff --git a/native/cpp/CommonCpp/_generated/commJSI.h b/native/cpp/CommonCpp/_generated/commJSI.h --- a/native/cpp/CommonCpp/_generated/commJSI.h +++ b/native/cpp/CommonCpp/_generated/commJSI.h @@ -93,6 +93,7 @@ virtual jsi::Value getDMOperationsByType(jsi::Runtime &rt, jsi::String type) = 0; virtual jsi::Value migrateBackupSchema(jsi::Runtime &rt) = 0; virtual jsi::Value copyContentFromBackupDatabase(jsi::Runtime &rt) = 0; + virtual jsi::Value getHolders(jsi::Runtime &rt, jsi::String dbID) = 0; }; @@ -698,6 +699,14 @@ return bridging::callFromJs( rt, &T::copyContentFromBackupDatabase, jsInvoker_, instance_); } + jsi::Value getHolders(jsi::Runtime &rt, jsi::String dbID) override { + static_assert( + bridging::getParameterCount(&T::getHolders) == 2, + "Expected getHolders(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::getHolders, jsInvoker_, instance_, std::move(dbID)); + } private: T *instance_; diff --git a/native/database/sqlite-api.js b/native/database/sqlite-api.js --- a/native/database/sqlite-api.js +++ b/native/database/sqlite-api.js @@ -1,8 +1,10 @@ // @flow +import { holderStoreOpsHandlers } from 'lib/ops/holder-store-ops.js'; import { getKeyserversToRemoveFromNotifsStore } from 'lib/ops/keyserver-store-ops.js'; import { convertStoreOperationsToClientDBStoreOperations } from 'lib/shared/redux/client-db-utils.js'; import type { DatabaseIdentifier } from 'lib/types/database-identifier-types'; +import type { StoredHolders } from 'lib/types/holder-types'; import type { SQLiteAPI } from 'lib/types/sqlite-types.js'; import type { StoreOperations } from 'lib/types/store-ops-types'; import type { QRAuthBackupData } from 'lib/types/tunnelbroker/qr-code-auth-message-types.js'; @@ -27,6 +29,11 @@ getDatabaseVersion: commCoreModule.getDatabaseVersion, getSyncedMetadata: commCoreModule.getSyncedMetadata, + async getHolders(dbID: DatabaseIdentifier): Promise { + const dbHolders = await commCoreModule.getHolders(dbID); + return holderStoreOpsHandlers.translateClientDBData(dbHolders); + }, + // write operations removeInboundP2PMessages: commCoreModule.removeInboundP2PMessages, markOutboundP2PMessageAsSent: commCoreModule.markOutboundP2PMessageAsSent, diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js --- a/native/schema/CommCoreModuleSchema.js +++ b/native/schema/CommCoreModuleSchema.js @@ -16,6 +16,7 @@ EncryptedData, OutboundSessionCreationResult, } from 'lib/types/crypto-types.js'; +import type { ClientDBHolderItem } from 'lib/types/holder-types.js'; import type { ClientDBMessageInfo } from 'lib/types/message-types.js'; import type { SignedMessage } from 'lib/types/siwe-types.js'; import type { @@ -239,6 +240,7 @@ +getDMOperationsByType: (type: string) => Promise>; +migrateBackupSchema: () => Promise; +copyContentFromBackupDatabase: () => Promise; + +getHolders: (dbID: string) => Promise<$ReadOnlyArray>; } export interface CoreModuleSpec extends Spec { diff --git a/web/database/sqlite-api.js b/web/database/sqlite-api.js --- a/web/database/sqlite-api.js +++ b/web/database/sqlite-api.js @@ -1,8 +1,13 @@ // @flow import type { ClientDBDMOperation } from 'lib/ops/dm-operations-store-ops.js'; +import { holderStoreOpsHandlers } from 'lib/ops/holder-store-ops.js'; import { convertStoreOperationsToClientDBStoreOperations } from 'lib/shared/redux/client-db-utils.js'; import type { DatabaseIdentifier } from 'lib/types/database-identifier-types.js'; +import type { + ClientDBHolderItem, + StoredHolders, +} from 'lib/types/holder-types.js'; import type { IdentityAuthResult } from 'lib/types/identity-service-types.js'; import type { ClientDBMessageInfo } from 'lib/types/message-types.js'; import type { @@ -155,6 +160,16 @@ return data?.syncedMetadata ?? null; }, + async getHolders(dbID: DatabaseIdentifier): Promise { + const sharedWorker = await getCommSharedWorker(); + const data = await sharedWorker.schedule({ + type: workerRequestMessageTypes.GET_HOLDERS, + dbID, + }); + const dbHolders: $ReadOnlyArray = data?.holders ?? []; + return holderStoreOpsHandlers.translateClientDBData(dbHolders); + }, + // write operations async removeInboundP2PMessages(ids: $ReadOnlyArray): Promise { const sharedWorker = await getCommSharedWorker(); diff --git a/web/shared-worker/worker/shared-worker.js b/web/shared-worker/worker/shared-worker.js --- a/web/shared-worker/worker/shared-worker.js +++ b/web/shared-worker/worker/shared-worker.js @@ -415,6 +415,22 @@ type: workerResponseMessageTypes.GET_SYNCED_METADATA, syncedMetadata: sqliteQueryExecutor.getSyncedMetadata(message.entryName), }; + } else if (message.type === workerRequestMessageTypes.GET_HOLDERS) { + if (message.dbID && message.dbID === databaseIdentifier.RESTORED) { + const restoredQueryExecutor = getSQLiteQueryExecutorOrThrow( + databaseIdentifier.RESTORED, + message, + ); + return { + type: workerResponseMessageTypes.GET_HOLDERS, + holders: restoredQueryExecutor.getHolders(), + }; + } + + return { + type: workerResponseMessageTypes.GET_HOLDERS, + holders: sqliteQueryExecutor.getHolders(), + }; } // write operations 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 @@ -9,6 +9,7 @@ } from 'lib/types/crypto-types.js'; import type { DatabaseIdentifier } from 'lib/types/database-identifier-types.js'; import type { PlatformDetails } from 'lib/types/device-types.js'; +import type { ClientDBHolderItem } from 'lib/types/holder-types.js'; import type { IdentityServiceClient, IdentityServiceAuthLayer, @@ -57,6 +58,7 @@ COPY_CONTENT_FROM_BACKUP_DB: 29, GET_DATABASE_VERSION: 30, GET_SYNCED_METADATA: 31, + GET_HOLDERS: 32, }); export const workerWriteRequests: $ReadOnlyArray = [ @@ -266,6 +268,11 @@ +dbID: DatabaseIdentifier, }; +export type GetHoldersRequestMessage = { + +type: 32, + +dbID: DatabaseIdentifier, +}; + export type WorkerRequestMessage = | PingWorkerRequestMessage | InitWorkerRequestMessage @@ -298,7 +305,8 @@ | MigrateBackupSchemaRequestMessage | CopyContentFromBackupDatabaseRequestMessage | GetDatabaseVersionRequestMessage - | GetSyncedMetadataRequestMessage; + | GetSyncedMetadataRequestMessage + | GetHoldersRequestMessage; export type WorkerRequestProxyMessage = { +id: number, @@ -320,6 +328,7 @@ DM_OPERATIONS: 10, GET_DATABASE_VERSION: 11, GET_SYNCED_METADATA: 12, + GET_HOLDERS: 13, }); export type PongWorkerResponseMessage = { @@ -387,6 +396,11 @@ +syncedMetadata: ?string, }; +export type GetHoldersResponseMessage = { + +type: 13, + +holders: $ReadOnlyArray, +}; + export type WorkerResponseMessage = | PongWorkerResponseMessage | ClientStoreResponseMessage @@ -400,7 +414,8 @@ | ResetOutboundP2PMessagesResponseMessage | DMOperationsResponseMessage | GetDatabaseVersionResponseMessage - | GetSyncedMetadataResponseMessage; + | GetSyncedMetadataResponseMessage + | GetHoldersResponseMessage; export type WorkerResponseProxyMessage = { +id?: number,