diff --git a/native/backup/restore-siwe-backup.react.js b/native/backup/restore-siwe-backup.react.js index 294f3d35c..ae990686a 100644 --- a/native/backup/restore-siwe-backup.react.js +++ b/native/backup/restore-siwe-backup.react.js @@ -1,83 +1,86 @@ // @flow import * as React from 'react'; import { Alert } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { type SIWEResult } from 'lib/types/siwe-types.js'; import { getMessageForException } from 'lib/utils/errors.js'; import { SignSIWEBackupMessageForRestore } from '../account/registration/siwe-backup-message-creation.react.js'; import { commCoreModule } from '../native-modules.js'; import { type RootNavigationProp } from '../navigation/root-navigator.react.js'; import { type NavigationRoute } from '../navigation/route-names.js'; import { persistConfig } from '../redux/persist.js'; import { useStyles } from '../themes/colors.js'; export type RestoreSIWEBackupParams = { +backupID: string, +siweNonce: string, +siweStatement: string, +siweIssuedAt: string, }; type Props = { +navigation: RootNavigationProp<'RestoreSIWEBackup'>, +route: NavigationRoute<'RestoreSIWEBackup'>, }; function RestoreSIWEBackup(props: Props): React.Node { const styles = useStyles(unboundStyles); const { goBack } = props.navigation; const { route } = props; const { - params: { backupID, siweStatement, siweIssuedAt, siweNonce }, + params: { siweStatement, siweIssuedAt, siweNonce }, } = route; const onSuccessfulWalletSignature = React.useCallback( (result: SIWEResult) => { void (async () => { + // eslint-disable-next-line no-unused-vars const { signature } = result; let message = 'success'; try { - await commCoreModule.restoreBackup( - signature, + //TODO add backup keys + await commCoreModule.restoreBackupData( + '', + '', + '', persistConfig.version.toString(), - backupID, ); } catch (e) { message = `Backup restore error: ${String( getMessageForException(e), )}`; console.error(message); } Alert.alert('Restore protocol result', message); goBack(); })(); }, - [goBack, backupID], + [goBack], ); return ( ); } const safeAreaEdges = ['top']; const unboundStyles = { container: { flex: 1, backgroundColor: 'panelBackground', justifyContent: 'space-between', }, }; export default RestoreSIWEBackup; diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp index 0d7d22864..afdc2f1cd 100644 --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp @@ -1,3369 +1,3348 @@ #include "CommCoreModule.h" #include "../Notifications/BackgroundDataStorage/NotificationsCryptoModule.h" #include "BaseDataStore.h" #include "CommServicesAuthMetadataEmitter.h" #include "DatabaseManager.h" #include "InternalModules/GlobalDBSingleton.h" #include "InternalModules/RustPromiseManager.h" #include "NativeModuleUtils.h" #include "TerminateApp.h" #include #include #include #include #include "JSIRust.h" #include "lib.rs.h" #include #include namespace comm { using namespace facebook::react; jsi::Value CommCoreModule::getDraft(jsi::Runtime &rt, jsi::String key) { std::string keyStr = key.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string draftStr; try { draftStr = DatabaseManager::getQueryExecutor().getDraft(keyStr); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } jsi::String draft = jsi::String::createFromUtf8(innerRt, draftStr); promise->resolve(std::move(draft)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::updateDraft( jsi::Runtime &rt, jsi::String key, jsi::String text) { std::string keyStr = key.utf8(rt); std::string textStr = text.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { std::string error; try { DatabaseManager::getQueryExecutor().updateDraft(keyStr, textStr); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); } else { promise->resolve(true); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::moveDraft( jsi::Runtime &rt, jsi::String oldKey, jsi::String newKey) { std::string oldKeyStr = oldKey.utf8(rt); std::string newKeyStr = newKey.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { std::string error; bool result = false; try { result = DatabaseManager::getQueryExecutor().moveDraft( oldKeyStr, newKeyStr); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); } else { promise->resolve(result); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getClientDBStore(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector draftsVector; std::vector threadsVector; std::vector messagesVector; std::vector messageStoreThreadsVector; std::vector reportStoreVector; std::vector userStoreVector; std::vector keyserverStoreVector; std::vector communityStoreVector; std::vector integrityStoreVector; std::vector syncedMetadataStoreVector; std::vector auxUserStoreVector; std::vector threadActivityStoreVector; std::vector entryStoreVector; std::vector messageStoreLocalMessageInfosVector; try { draftsVector = DatabaseManager::getQueryExecutor().getAllDrafts(); messagesVector = DatabaseManager::getQueryExecutor().getInitialMessages(); threadsVector = DatabaseManager::getQueryExecutor().getAllThreads(); messageStoreThreadsVector = DatabaseManager::getQueryExecutor().getAllMessageStoreThreads(); reportStoreVector = DatabaseManager::getQueryExecutor().getAllReports(); userStoreVector = DatabaseManager::getQueryExecutor().getAllUsers(); keyserverStoreVector = DatabaseManager::getQueryExecutor().getAllKeyservers(); communityStoreVector = DatabaseManager::getQueryExecutor().getAllCommunities(); integrityStoreVector = DatabaseManager::getQueryExecutor() .getAllIntegrityThreadHashes(); syncedMetadataStoreVector = DatabaseManager::getQueryExecutor().getAllSyncedMetadata(); auxUserStoreVector = DatabaseManager::getQueryExecutor().getAllAuxUserInfos(); threadActivityStoreVector = DatabaseManager::getQueryExecutor() .getAllThreadActivityEntries(); entryStoreVector = DatabaseManager::getQueryExecutor().getAllEntries(); messageStoreLocalMessageInfosVector = DatabaseManager::getQueryExecutor() .getAllMessageStoreLocalMessageInfos(); } catch (std::system_error &e) { error = e.what(); } auto draftsVectorPtr = std::make_shared>(std::move(draftsVector)); auto messagesVectorPtr = std::make_shared>( std::move(messagesVector)); auto threadsVectorPtr = std::make_shared>(std::move(threadsVector)); auto messageStoreThreadsVectorPtr = std::make_shared>( std::move(messageStoreThreadsVector)); auto reportStoreVectorPtr = std::make_shared>( std::move(reportStoreVector)); auto userStoreVectorPtr = std::make_shared>( std::move(userStoreVector)); auto keyserveStoreVectorPtr = std::make_shared>( std::move(keyserverStoreVector)); auto communityStoreVectorPtr = std::make_shared>( std::move(communityStoreVector)); auto integrityStoreVectorPtr = std::make_shared>( std::move(integrityStoreVector)); auto syncedMetadataStoreVectorPtr = std::make_shared>( std::move(syncedMetadataStoreVector)); auto auxUserStoreVectorPtr = std::make_shared>( std::move(auxUserStoreVector)); auto threadActivityStoreVectorPtr = std::make_shared>( std::move(threadActivityStoreVector)); auto entryStoreVectorPtr = std::make_shared>( std::move(entryStoreVector)); auto messageStoreLocalMessageInfosVectorPtr = std::make_shared>( std::move(messageStoreLocalMessageInfosVector)); this->jsInvoker_->invokeAsync([&innerRt, draftsVectorPtr, messagesVectorPtr, threadsVectorPtr, messageStoreThreadsVectorPtr, reportStoreVectorPtr, userStoreVectorPtr, keyserveStoreVectorPtr, communityStoreVectorPtr, integrityStoreVectorPtr, syncedMetadataStoreVectorPtr, auxUserStoreVectorPtr, threadActivityStoreVectorPtr, entryStoreVectorPtr, messageStoreLocalMessageInfosVectorPtr, error, promise, draftStore = this->draftStore, threadStore = this->threadStore, messageStore = this->messageStore, reportStore = this->reportStore, userStore = this->userStore, keyserverStore = this->keyserverStore, communityStore = this->communityStore, integrityStore = this->integrityStore, syncedMetadataStore = this->syncedMetadataStore, auxUserStore = this->auxUserStore, threadActivityStore = this->threadActivityStore, entryStore = this->entryStore]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiDrafts = draftStore.parseDBDataStore(innerRt, draftsVectorPtr); jsi::Array jsiMessages = messageStore.parseDBDataStore(innerRt, messagesVectorPtr); jsi::Array jsiThreads = threadStore.parseDBDataStore(innerRt, threadsVectorPtr); jsi::Array jsiMessageStoreThreads = messageStore.parseDBMessageStoreThreads( innerRt, messageStoreThreadsVectorPtr); jsi::Array jsiReportStore = reportStore.parseDBDataStore(innerRt, reportStoreVectorPtr); jsi::Array jsiUserStore = userStore.parseDBDataStore(innerRt, userStoreVectorPtr); jsi::Array jsiKeyserverStore = keyserverStore.parseDBDataStore( innerRt, keyserveStoreVectorPtr); jsi::Array jsiCommunityStore = communityStore.parseDBDataStore( innerRt, communityStoreVectorPtr); jsi::Array jsiIntegrityStore = integrityStore.parseDBDataStore( innerRt, integrityStoreVectorPtr); jsi::Array jsiSyncedMetadataStore = syncedMetadataStore.parseDBDataStore( innerRt, syncedMetadataStoreVectorPtr); jsi::Array jsiAuxUserStore = auxUserStore.parseDBDataStore(innerRt, auxUserStoreVectorPtr); jsi::Array jsiThreadActivityStore = threadActivityStore.parseDBDataStore( innerRt, threadActivityStoreVectorPtr); jsi::Array jsiEntryStore = entryStore.parseDBDataStore(innerRt, entryStoreVectorPtr); jsi::Array jsiMessageStoreLocalMessageInfos = messageStore.parseDBMessageStoreLocalMessageInfos( innerRt, messageStoreLocalMessageInfosVectorPtr); auto jsiClientDBStore = jsi::Object(innerRt); jsiClientDBStore.setProperty(innerRt, "messages", jsiMessages); jsiClientDBStore.setProperty(innerRt, "threads", jsiThreads); jsiClientDBStore.setProperty(innerRt, "drafts", jsiDrafts); jsiClientDBStore.setProperty( innerRt, "messageStoreThreads", jsiMessageStoreThreads); jsiClientDBStore.setProperty(innerRt, "reports", jsiReportStore); jsiClientDBStore.setProperty(innerRt, "users", jsiUserStore); jsiClientDBStore.setProperty( innerRt, "keyservers", jsiKeyserverStore); jsiClientDBStore.setProperty( innerRt, "communities", jsiCommunityStore); jsiClientDBStore.setProperty( innerRt, "integrityThreadHashes", jsiIntegrityStore); jsiClientDBStore.setProperty( innerRt, "syncedMetadata", jsiSyncedMetadataStore); jsiClientDBStore.setProperty( innerRt, "auxUserInfos", jsiAuxUserStore); jsiClientDBStore.setProperty( innerRt, "threadActivityEntries", jsiThreadActivityStore); jsiClientDBStore.setProperty(innerRt, "entries", jsiEntryStore); jsiClientDBStore.setProperty( innerRt, "messageStoreLocalMessageInfos", jsiMessageStoreLocalMessageInfos); promise->resolve(std::move(jsiClientDBStore)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::removeAllDrafts(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { std::string error; try { DatabaseManager::getQueryExecutor().removeAllDrafts(); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Array CommCoreModule::getInitialMessagesSync(jsi::Runtime &rt) { auto messagesVector = NativeModuleUtils::runSyncOrThrowJSError>( rt, []() { return DatabaseManager::getQueryExecutor().getInitialMessages(); }); auto messagesVectorPtr = std::make_shared>(std::move(messagesVector)); jsi::Array jsiMessages = this->messageStore.parseDBDataStore(rt, messagesVectorPtr); return jsiMessages; } void CommCoreModule::processMessageStoreOperationsSync( jsi::Runtime &rt, jsi::Array operations) { return this->messageStore.processStoreOperationsSync( rt, std::move(operations)); } jsi::Array CommCoreModule::getAllThreadsSync(jsi::Runtime &rt) { auto threadsVector = NativeModuleUtils::runSyncOrThrowJSError>(rt, []() { return DatabaseManager::getQueryExecutor().getAllThreads(); }); auto threadsVectorPtr = std::make_shared>(std::move(threadsVector)); jsi::Array jsiThreads = this->threadStore.parseDBDataStore(rt, threadsVectorPtr); return jsiThreads; } void CommCoreModule::processThreadStoreOperationsSync( jsi::Runtime &rt, jsi::Array operations) { this->threadStore.processStoreOperationsSync(rt, std::move(operations)); } void CommCoreModule::processReportStoreOperationsSync( jsi::Runtime &rt, jsi::Array operations) { this->reportStore.processStoreOperationsSync(rt, std::move(operations)); } template void CommCoreModule::appendDBStoreOps( jsi::Runtime &rt, jsi::Object &operations, const char *key, T &store, std::shared_ptr>> &destination) { auto opsObject = operations.getProperty(rt, key); if (opsObject.isObject()) { auto ops = store.createOperations(rt, opsObject.asObject(rt).asArray(rt)); std::move( std::make_move_iterator(ops.begin()), std::make_move_iterator(ops.end()), std::back_inserter(*destination)); } } jsi::Value CommCoreModule::processDBStoreOperations( jsi::Runtime &rt, jsi::Object operations) { std::string createOperationsError; auto storeOpsPtr = std::make_shared>>(); try { this->appendDBStoreOps( rt, operations, "draftStoreOperations", this->draftStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "threadStoreOperations", this->threadStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "messageStoreOperations", this->messageStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "reportStoreOperations", this->reportStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "userStoreOperations", this->userStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "keyserverStoreOperations", this->keyserverStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "communityStoreOperations", this->communityStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "integrityStoreOperations", this->integrityStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "syncedMetadataStoreOperations", this->syncedMetadataStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "auxUserStoreOperations", this->auxUserStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "threadActivityStoreOperations", this->threadActivityStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "entryStoreOperations", this->entryStore, storeOpsPtr); this->appendDBStoreOps( rt, operations, "messageSearchStoreOperations", this->messageSearchStore, storeOpsPtr); } catch (std::runtime_error &e) { createOperationsError = e.what(); } std::vector messages; try { auto messagesJSIObj = operations.getProperty(rt, "outboundP2PMessages"); if (messagesJSIObj.isObject()) { auto messagesJSI = messagesJSIObj.asObject(rt).asArray(rt); for (size_t idx = 0; idx < messagesJSI.size(rt); idx++) { jsi::Object msgObj = messagesJSI.getValueAtIndex(rt, idx).asObject(rt); std::string messageID = msgObj.getProperty(rt, "messageID").asString(rt).utf8(rt); std::string deviceID = msgObj.getProperty(rt, "deviceID").asString(rt).utf8(rt); std::string userID = msgObj.getProperty(rt, "userID").asString(rt).utf8(rt); std::string timestamp = msgObj.getProperty(rt, "timestamp").asString(rt).utf8(rt); std::string plaintext = msgObj.getProperty(rt, "plaintext").asString(rt).utf8(rt); std::string ciphertext = msgObj.getProperty(rt, "ciphertext").asString(rt).utf8(rt); std::string status = msgObj.getProperty(rt, "status").asString(rt).utf8(rt); bool supports_auto_retry = msgObj.getProperty(rt, "supportsAutoRetry").asBool(); OutboundP2PMessage outboundMessage{ messageID, deviceID, userID, timestamp, plaintext, ciphertext, status, supports_auto_retry}; messages.push_back(outboundMessage); } } } catch (std::runtime_error &e) { createOperationsError = e.what(); } return facebook::react::createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { std::string error = createOperationsError; if (!error.size()) { try { DatabaseManager::getQueryExecutor().beginTransaction(); for (const auto &operation : *storeOpsPtr) { operation->execute(); } if (messages.size() > 0) { DatabaseManager::getQueryExecutor().addOutboundP2PMessages( messages); } DatabaseManager::getQueryExecutor().commitTransaction(); } catch (std::system_error &e) { error = e.what(); DatabaseManager::getQueryExecutor().rollbackTransaction(); } } if (!error.size()) { ::triggerBackupFileUpload(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } void CommCoreModule::terminate(jsi::Runtime &rt) { TerminateApp::terminate(); } const std::string getAccountDataKey(const std::string secureStoreAccountDataKey) { folly::Optional storedSecretKey = CommSecureStore::get(secureStoreAccountDataKey); if (!storedSecretKey.hasValue()) { storedSecretKey = crypto::Tools::generateRandomString(64); CommSecureStore::set(secureStoreAccountDataKey, storedSecretKey.value()); } return storedSecretKey.value(); } void CommCoreModule::persistCryptoModules( bool persistContentModule, std::optional, std::string>> maybeUpdatedNotifsCryptoModule) { std::string storedSecretKey = getAccountDataKey(secureStoreAccountDataKey); if (!persistContentModule && !maybeUpdatedNotifsCryptoModule.has_value()) { return; } crypto::Persist newContentPersist; if (persistContentModule) { newContentPersist = this->contentCryptoModule->storeAsB64(storedSecretKey); } std::promise persistencePromise; std::future persistenceFuture = persistencePromise.get_future(); GlobalDBSingleton::instance.scheduleOrRunCancellable( [=, &persistencePromise]() { try { DatabaseManager::getQueryExecutor().beginTransaction(); if (persistContentModule) { DatabaseManager::getQueryExecutor().storeOlmPersistData( DatabaseManager::getQueryExecutor().getContentAccountID(), newContentPersist); } if (maybeUpdatedNotifsCryptoModule.has_value()) { NotificationsCryptoModule::persistNotificationsAccount( maybeUpdatedNotifsCryptoModule.value().first, maybeUpdatedNotifsCryptoModule.value().second, true); } DatabaseManager::getQueryExecutor().commitTransaction(); persistencePromise.set_value(); } catch (std::system_error &e) { DatabaseManager::getQueryExecutor().rollbackTransaction(); persistencePromise.set_exception(std::make_exception_ptr(e)); } }); persistenceFuture.get(); } jsi::Value CommCoreModule::initializeCryptoAccount(jsi::Runtime &rt) { folly::Optional storedSecretKey = CommSecureStore::get(this->secureStoreAccountDataKey); if (!storedSecretKey.hasValue()) { storedSecretKey = crypto::Tools::generateRandomString(64); CommSecureStore::set( this->secureStoreAccountDataKey, storedSecretKey.value()); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { crypto::Persist contentPersist; crypto::Persist notifsPersist; try { std::optional contentAccountData = DatabaseManager::getQueryExecutor().getOlmPersistAccountData( DatabaseManager::getQueryExecutor().getContentAccountID()); if (contentAccountData.has_value()) { contentPersist.account = crypto::OlmBuffer( contentAccountData->begin(), contentAccountData->end()); // handle sessions data std::vector sessionsData = DatabaseManager::getQueryExecutor() .getOlmPersistSessionsData(); for (OlmPersistSession &sessionsDataItem : sessionsData) { crypto::OlmBuffer sessionDataBuffer( sessionsDataItem.session_data.begin(), sessionsDataItem.session_data.end()); crypto::SessionPersist sessionPersist{ sessionDataBuffer, sessionsDataItem.version}; contentPersist.sessions.insert(std::make_pair( sessionsDataItem.target_device_id, sessionPersist)); } } std::optional notifsAccountData = DatabaseManager::getQueryExecutor().getOlmPersistAccountData( DatabaseManager::getQueryExecutor().getNotifsAccountID()); if (notifsAccountData.has_value()) { notifsPersist.account = crypto::OlmBuffer( notifsAccountData->begin(), notifsAccountData->end()); } } catch (std::exception &e) { std::string error = e.what(); this->jsInvoker_->invokeAsync([=]() { promise->reject(error); }); return; } taskType cryptoJob = [=]() { std::string error; this->contentCryptoModule.reset(new crypto::CryptoModule( this->publicCryptoAccountID, storedSecretKey.value(), contentPersist)); std::optional< std::pair, std::string>> maybeNotifsCryptoAccountToPersist; if (!NotificationsCryptoModule:: isNotificationsAccountInitialized()) { maybeNotifsCryptoAccountToPersist = { std::make_shared( this->notifsCryptoAccountID, storedSecretKey.value(), notifsPersist), storedSecretKey.value()}; } try { this->persistCryptoModules( contentPersist.isEmpty(), maybeNotifsCryptoAccountToPersist); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }; try { this->cryptoThread->scheduleTask(cryptoJob); } catch (const std::exception &e) { std::string error = e.what(); this->jsInvoker_->invokeAsync([=]() { promise->reject(error); }); } }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getUserPublicKey(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string primaryKeysResult; std::string notificationsKeysResult; if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { error = "user has not been initialized"; } else { primaryKeysResult = this->contentCryptoModule->getIdentityKeys(); notificationsKeysResult = NotificationsCryptoModule::getIdentityKeys(); } std::string notificationsCurve25519Cpp, notificationsEd25519Cpp, blobPayloadCpp, signatureCpp, primaryCurve25519Cpp, primaryEd25519Cpp; if (!error.size()) { folly::dynamic parsedPrimary; try { parsedPrimary = folly::parseJson(primaryKeysResult); } catch (const folly::json::parse_error &e) { error = "parsing identity keys failed with: " + std::string(e.what()); } if (!error.size()) { primaryCurve25519Cpp = parsedPrimary["curve25519"].asString(); primaryEd25519Cpp = parsedPrimary["ed25519"].asString(); folly::dynamic parsedNotifications; try { parsedNotifications = folly::parseJson(notificationsKeysResult); } catch (const folly::json::parse_error &e) { error = "parsing notifications keys failed with: " + std::string(e.what()); } if (!error.size()) { notificationsCurve25519Cpp = parsedNotifications["curve25519"].asString(); notificationsEd25519Cpp = parsedNotifications["ed25519"].asString(); folly::dynamic blobPayloadJSON = folly::dynamic::object( "primaryIdentityPublicKeys", folly::dynamic::object("ed25519", primaryEd25519Cpp)( "curve25519", primaryCurve25519Cpp))( "notificationIdentityPublicKeys", folly::dynamic::object("ed25519", notificationsEd25519Cpp)( "curve25519", notificationsCurve25519Cpp)); blobPayloadCpp = folly::toJson(blobPayloadJSON); signatureCpp = this->contentCryptoModule->signMessage(blobPayloadCpp); } } } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto primaryCurve25519{ jsi::String::createFromUtf8(innerRt, primaryCurve25519Cpp)}; auto primaryEd25519{ jsi::String::createFromUtf8(innerRt, primaryEd25519Cpp)}; auto jsiPrimaryIdentityPublicKeys = jsi::Object(innerRt); jsiPrimaryIdentityPublicKeys.setProperty( innerRt, "ed25519", primaryEd25519); jsiPrimaryIdentityPublicKeys.setProperty( innerRt, "curve25519", primaryCurve25519); auto notificationsCurve25519{jsi::String::createFromUtf8( innerRt, notificationsCurve25519Cpp)}; auto notificationsEd25519{ jsi::String::createFromUtf8(innerRt, notificationsEd25519Cpp)}; auto jsiNotificationIdentityPublicKeys = jsi::Object(innerRt); jsiNotificationIdentityPublicKeys.setProperty( innerRt, "ed25519", notificationsEd25519); jsiNotificationIdentityPublicKeys.setProperty( innerRt, "curve25519", notificationsCurve25519); auto blobPayload{ jsi::String::createFromUtf8(innerRt, blobPayloadCpp)}; auto signature{jsi::String::createFromUtf8(innerRt, signatureCpp)}; auto jsiClientPublicKeys = jsi::Object(innerRt); jsiClientPublicKeys.setProperty( innerRt, "primaryIdentityPublicKeys", jsiPrimaryIdentityPublicKeys); jsiClientPublicKeys.setProperty( innerRt, "notificationIdentityPublicKeys", jsiNotificationIdentityPublicKeys); jsiClientPublicKeys.setProperty( innerRt, "blobPayload", blobPayload); jsiClientPublicKeys.setProperty(innerRt, "signature", signature); promise->resolve(std::move(jsiClientPublicKeys)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Object parseOLMOneTimeKeys(jsi::Runtime &rt, std::string oneTimeKeysBlob) { folly::dynamic parsedOneTimeKeys = folly::parseJson(oneTimeKeysBlob); auto jsiOneTimeKeysInner = jsi::Object(rt); for (auto &kvPair : parsedOneTimeKeys["curve25519"].items()) { jsiOneTimeKeysInner.setProperty( rt, kvPair.first.asString().c_str(), jsi::String::createFromUtf8(rt, kvPair.second.asString())); } auto jsiOneTimeKeys = jsi::Object(rt); jsiOneTimeKeys.setProperty(rt, "curve25519", jsiOneTimeKeysInner); return jsiOneTimeKeys; } std::string parseOLMPrekey(std::string prekeyBlob) { folly::dynamic parsedPrekey; try { parsedPrekey = folly::parseJson(prekeyBlob); } catch (const folly::json::parse_error &e) { throw std::runtime_error( "parsing prekey failed with: " + std::string(e.what())); } folly::dynamic innerObject = parsedPrekey["curve25519"]; if (!innerObject.isObject()) { throw std::runtime_error("parsing prekey failed: inner object malformed"); } if (innerObject.values().begin() == innerObject.values().end()) { throw std::runtime_error("parsing prekey failed: prekey missing"); } return parsedPrekey["curve25519"].values().begin()->asString(); } jsi::Object parseOneTimeKeysResult( jsi::Runtime &rt, std::string contentOneTimeKeysBlob, std::string notifOneTimeKeysBlob) { auto contentOneTimeKeys = parseOLMOneTimeKeys(rt, contentOneTimeKeysBlob); auto notifOneTimeKeys = parseOLMOneTimeKeys(rt, notifOneTimeKeysBlob); auto jsiOneTimeKeysResult = jsi::Object(rt); jsiOneTimeKeysResult.setProperty( rt, "contentOneTimeKeys", contentOneTimeKeys); jsiOneTimeKeysResult.setProperty( rt, "notificationsOneTimeKeys", notifOneTimeKeys); return jsiOneTimeKeysResult; } jsi::Object parseEncryptedData( jsi::Runtime &rt, const crypto::EncryptedData &encryptedData) { auto encryptedDataJSI = jsi::Object(rt); auto message = std::string{encryptedData.message.begin(), encryptedData.message.end()}; auto messageJSI = jsi::String::createFromUtf8(rt, message); encryptedDataJSI.setProperty(rt, "message", messageJSI); encryptedDataJSI.setProperty( rt, "messageType", static_cast(encryptedData.messageType)); if (encryptedData.sessionVersion.has_value()) { encryptedDataJSI.setProperty( rt, "sessionVersion", static_cast(encryptedData.sessionVersion.value())); } return encryptedDataJSI; } jsi::Array parseInboundingMessages( jsi::Runtime &rt, std::shared_ptr> messagesPtr) { jsi::Array jsiMessages = jsi::Array(rt, messagesPtr->size()); size_t writeIdx = 0; for (const InboundP2PMessage &msg : *messagesPtr) { jsi::Object jsiMsg = jsi::Object(rt); jsiMsg.setProperty(rt, "messageID", msg.message_id); jsiMsg.setProperty(rt, "senderDeviceID", msg.sender_device_id); jsiMsg.setProperty(rt, "plaintext", msg.plaintext); jsiMsg.setProperty(rt, "status", msg.status); jsiMsg.setProperty(rt, "senderUserID", msg.sender_user_id); jsiMessages.setValueAtIndex(rt, writeIdx++, jsiMsg); } return jsiMessages; } jsi::Value CommCoreModule::getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string contentResult; std::string notifResult; if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } try { contentResult = this->contentCryptoModule->getOneTimeKeysForPublishing( oneTimeKeysAmount); std::pair, std::string> notifsCryptoModuleWithPicklingKey = NotificationsCryptoModule::fetchNotificationsAccount() .value(); notifResult = notifsCryptoModuleWithPicklingKey.first ->getOneTimeKeysForPublishing(oneTimeKeysAmount); this->persistCryptoModules(true, notifsCryptoModuleWithPicklingKey); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve( parseOneTimeKeysResult(innerRt, contentResult, notifResult)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::validateAndUploadPrekeys( jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken) { auto authUserIDRust = jsiStringToRustString(authUserID, rt); auto authDeviceIDRust = jsiStringToRustString(authDeviceID, rt); auto authAccessTokenRust = jsiStringToRustString(authAccessToken, rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::optional maybeContentPrekeyToUpload; std::optional maybeNotifsPrekeyToUpload; if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } std::optional< std::pair, std::string>> notifsCryptoModuleWithPicklingKey; try { notifsCryptoModuleWithPicklingKey = NotificationsCryptoModule::fetchNotificationsAccount(); maybeContentPrekeyToUpload = this->contentCryptoModule->validatePrekey(); maybeNotifsPrekeyToUpload = notifsCryptoModuleWithPicklingKey.value() .first->validatePrekey(); this->persistCryptoModules(true, notifsCryptoModuleWithPicklingKey); if (!maybeContentPrekeyToUpload.has_value()) { maybeContentPrekeyToUpload = this->contentCryptoModule->getUnpublishedPrekey(); } if (!maybeNotifsPrekeyToUpload.has_value()) { maybeNotifsPrekeyToUpload = notifsCryptoModuleWithPicklingKey.value() .first->getUnpublishedPrekey(); } } catch (const std::exception &e) { error = e.what(); } if (error.size()) { this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(error); }); return; } if (!maybeContentPrekeyToUpload.has_value() && !maybeNotifsPrekeyToUpload.has_value()) { this->jsInvoker_->invokeAsync( [=]() { promise->resolve(jsi::Value::undefined()); }); return; } std::string contentPrekeyToUpload; if (maybeContentPrekeyToUpload.has_value()) { contentPrekeyToUpload = maybeContentPrekeyToUpload.value(); } else { contentPrekeyToUpload = this->contentCryptoModule->getPrekey(); } std::string notifsPrekeyToUpload; if (maybeNotifsPrekeyToUpload.has_value()) { notifsPrekeyToUpload = maybeNotifsPrekeyToUpload.value(); } else { notifsPrekeyToUpload = notifsCryptoModuleWithPicklingKey.value().first->getPrekey(); } std::string prekeyUploadError; try { std::string contentPrekeySignature = this->contentCryptoModule->getPrekeySignature(); std::string notifsPrekeySignature = notifsCryptoModuleWithPicklingKey.value() .first->getPrekeySignature(); try { std::promise prekeyPromise; std::future prekeyFuture = prekeyPromise.get_future(); RustPromiseManager::CPPPromiseInfo promiseInfo = { std::move(prekeyPromise)}; auto currentID = RustPromiseManager::instance.addPromise( std::move(promiseInfo)); auto contentPrekeyToUploadRust = rust::String(parseOLMPrekey(contentPrekeyToUpload)); auto prekeySignatureRust = rust::string(contentPrekeySignature); auto notifsPrekeyToUploadRust = rust::String(parseOLMPrekey(notifsPrekeyToUpload)); auto notificationsPrekeySignatureRust = rust::string(notifsPrekeySignature); ::identityRefreshUserPrekeys( authUserIDRust, authDeviceIDRust, authAccessTokenRust, contentPrekeyToUploadRust, prekeySignatureRust, notifsPrekeyToUploadRust, notificationsPrekeySignatureRust, currentID); prekeyFuture.get(); } catch (const std::exception &e) { prekeyUploadError = e.what(); } if (!prekeyUploadError.size()) { this->contentCryptoModule->markPrekeyAsPublished(); notifsCryptoModuleWithPicklingKey.value() .first->markPrekeyAsPublished(); this->persistCryptoModules( true, notifsCryptoModuleWithPicklingKey); } } catch (std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); return; } if (prekeyUploadError.size()) { promise->reject(prekeyUploadError); return; } promise->resolve(jsi::Value::undefined()); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::validateAndGetPrekeys(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string contentPrekey, notifPrekey, contentPrekeySignature, notifPrekeySignature; std::optional contentPrekeyBlob; std::optional notifPrekeyBlob; if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } std::optional< std::pair, std::string>> notifsCryptoModuleWithPicklingKey; try { notifsCryptoModuleWithPicklingKey = NotificationsCryptoModule::fetchNotificationsAccount(); contentPrekeyBlob = this->contentCryptoModule->validatePrekey(); if (!contentPrekeyBlob) { contentPrekeyBlob = this->contentCryptoModule->getUnpublishedPrekey(); } if (!contentPrekeyBlob) { contentPrekeyBlob = this->contentCryptoModule->getPrekey(); } notifPrekeyBlob = notifsCryptoModuleWithPicklingKey.value() .first->validatePrekey(); if (!notifPrekeyBlob) { notifPrekeyBlob = notifsCryptoModuleWithPicklingKey.value() .first->getUnpublishedPrekey(); } if (!notifPrekeyBlob) { notifPrekeyBlob = notifsCryptoModuleWithPicklingKey.value().first->getPrekey(); } this->persistCryptoModules(true, notifsCryptoModuleWithPicklingKey); contentPrekeySignature = this->contentCryptoModule->getPrekeySignature(); notifPrekeySignature = notifsCryptoModuleWithPicklingKey.value() .first->getPrekeySignature(); contentPrekey = parseOLMPrekey(contentPrekeyBlob.value()); notifPrekey = parseOLMPrekey(notifPrekeyBlob.value()); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto contentPrekeyJSI = jsi::String::createFromUtf8(innerRt, contentPrekey); auto contentPrekeySignatureJSI = jsi::String::createFromUtf8(innerRt, contentPrekeySignature); auto notifPrekeyJSI = jsi::String::createFromUtf8(innerRt, notifPrekey); auto notifPrekeySignatureJSI = jsi::String::createFromUtf8(innerRt, notifPrekeySignature); auto signedPrekeysJSI = jsi::Object(innerRt); signedPrekeysJSI.setProperty( innerRt, "contentPrekey", contentPrekeyJSI); signedPrekeysJSI.setProperty( innerRt, "contentPrekeySignature", contentPrekeySignatureJSI); signedPrekeysJSI.setProperty( innerRt, "notifPrekey", notifPrekeyJSI); signedPrekeysJSI.setProperty( innerRt, "notifPrekeySignature", notifPrekeySignatureJSI); promise->resolve(std::move(signedPrekeysJSI)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::initializeNotificationsSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String keyserverID) { auto identityKeysCpp{identityKeys.utf8(rt)}; auto prekeyCpp{prekey.utf8(rt)}; auto prekeySignatureCpp{prekeySignature.utf8(rt)}; auto keyserverIDCpp{keyserverID.utf8(rt)}; std::optional oneTimeKeyCpp; if (oneTimeKey) { oneTimeKeyCpp = oneTimeKey->utf8(rt); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; crypto::EncryptedData result; std::optional< std::pair, std::string>> notifsCryptoModuleWithPicklingKey; try { notifsCryptoModuleWithPicklingKey = NotificationsCryptoModule::fetchNotificationsAccount(); std::optional oneTimeKeyBuffer; if (oneTimeKeyCpp) { oneTimeKeyBuffer = crypto::OlmBuffer( oneTimeKeyCpp->begin(), oneTimeKeyCpp->end()); } notifsCryptoModuleWithPicklingKey.value() .first->initializeOutboundForSendingSession( keyserverIDCpp, std::vector( identityKeysCpp.begin(), identityKeysCpp.end()), std::vector(prekeyCpp.begin(), prekeyCpp.end()), std::vector( prekeySignatureCpp.begin(), prekeySignatureCpp.end()), oneTimeKeyBuffer); result = notifsCryptoModuleWithPicklingKey.value().first->encrypt( keyserverIDCpp, NotificationsCryptoModule::initialEncryptedMessageContent); std::shared_ptr keyserverNotificationsSession = notifsCryptoModuleWithPicklingKey.value() .first->getSessionByDeviceId(keyserverIDCpp); NotificationsCryptoModule::persistNotificationsSession( keyserverIDCpp, keyserverNotificationsSession); // Session is removed from the account since it is persisted // at different location that the account after serialization notifsCryptoModuleWithPicklingKey.value() .first->removeSessionByDeviceId(keyserverIDCpp); this->persistCryptoModules( false, notifsCryptoModuleWithPicklingKey); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::String::createFromUtf8( innerRt, std::string{result.message.begin(), result.message.end()})); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::isNotificationsSessionInitialized(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; bool result; try { result = NotificationsCryptoModule::isNotificationsSessionInitialized( "Comm"); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(result); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::isDeviceNotificationsSessionInitialized( jsi::Runtime &rt, jsi::String deviceID) { auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } std::string error; bool result; try { result = NotificationsCryptoModule:: isDeviceNotificationsSessionInitialized(deviceIDCpp); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(result); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::isNotificationsSessionInitializedWithDevices( jsi::Runtime &rt, jsi::Array deviceIDs) { std::vector deviceIDsCpp; for (auto idx = 0; idx < deviceIDs.size(rt); idx++) { std::string deviceIDCpp = deviceIDs.getValueAtIndex(rt, idx).asString(rt).utf8(rt); deviceIDsCpp.push_back(deviceIDCpp); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } std::string error; std::vector> result; try { result = NotificationsCryptoModule:: isNotificationsSessionInitializedWithDevices(deviceIDsCpp); } catch (const std::exception &e) { error = e.what(); } auto resultPtr = std::make_shared>>( std::move(result)); this->jsInvoker_->invokeAsync( [&innerRt, resultPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } jsi::Object jsiResult = jsi::Object(innerRt); for (const auto &deviceResult : *resultPtr) { jsiResult.setProperty( innerRt, deviceResult.first.c_str(), deviceResult.second); } promise->resolve(std::move(jsiResult)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::updateKeyserverDataInNotifStorage( jsi::Runtime &rt, jsi::Array keyserversData) { std::vector> keyserversDataCpp; for (auto idx = 0; idx < keyserversData.size(rt); idx++) { auto data = keyserversData.getValueAtIndex(rt, idx).asObject(rt); std::string keyserverID = data.getProperty(rt, "id").asString(rt).utf8(rt); std::string keyserverUnreadCountKey = "KEYSERVER." + keyserverID + ".UNREAD_COUNT"; int unreadCount = data.getProperty(rt, "unreadCount").asNumber(); keyserversDataCpp.push_back({keyserverUnreadCountKey, unreadCount}); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { for (const auto &keyserverData : keyserversDataCpp) { CommMMKV::setInt(keyserverData.first, keyserverData.second); } } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }); } jsi::Value CommCoreModule::removeKeyserverDataFromNotifStorage( jsi::Runtime &rt, jsi::Array keyserverIDsToDelete) { std::vector keyserverIDsToDeleteCpp{}; for (auto idx = 0; idx < keyserverIDsToDelete.size(rt); idx++) { std::string keyserverID = keyserverIDsToDelete.getValueAtIndex(rt, idx).asString(rt).utf8(rt); std::string keyserverUnreadCountKey = "KEYSERVER." + keyserverID + ".UNREAD_COUNT"; keyserverIDsToDeleteCpp.push_back(keyserverUnreadCountKey); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { CommMMKV::removeKeys(keyserverIDsToDeleteCpp); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }); } jsi::Value CommCoreModule::getKeyserverDataFromNotifStorage( jsi::Runtime &rt, jsi::Array keyserverIDs) { std::vector keyserverIDsCpp{}; for (auto idx = 0; idx < keyserverIDs.size(rt); idx++) { std::string keyserverID = keyserverIDs.getValueAtIndex(rt, idx).asString(rt).utf8(rt); keyserverIDsCpp.push_back(keyserverID); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; std::vector> keyserversDataVector{}; try { for (const auto &keyserverID : keyserverIDsCpp) { std::string keyserverUnreadCountKey = "KEYSERVER." + keyserverID + ".UNREAD_COUNT"; std::optional unreadCount = CommMMKV::getInt(keyserverUnreadCountKey, -1); if (!unreadCount.has_value()) { continue; } keyserversDataVector.push_back({keyserverID, unreadCount.value()}); } } catch (const std::exception &e) { error = e.what(); } auto keyserversDataVectorPtr = std::make_shared>>( std::move(keyserversDataVector)); this->jsInvoker_->invokeAsync( [&innerRt, keyserversDataVectorPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } size_t numKeyserversData = keyserversDataVectorPtr->size(); jsi::Array jsiKeyserversData = jsi::Array(innerRt, numKeyserversData); size_t writeIdx = 0; for (const auto &keyserverData : *keyserversDataVectorPtr) { jsi::Object jsiKeyserverData = jsi::Object(innerRt); jsiKeyserverData.setProperty( innerRt, "id", keyserverData.first); jsiKeyserverData.setProperty( innerRt, "unreadCount", keyserverData.second); jsiKeyserversData.setValueAtIndex( innerRt, writeIdx++, jsiKeyserverData); } promise->resolve(std::move(jsiKeyserversData)); }); }); } jsi::Value CommCoreModule::updateUnreadThickThreadsInNotifsStorage( jsi::Runtime &rt, jsi::Array unreadThickThreadIDs) { std::vector unreadThickThreadIDsCpp{}; for (auto idx = 0; idx < unreadThickThreadIDs.size(rt); idx++) { std::string thickThreadID = unreadThickThreadIDs.getValueAtIndex(rt, idx).asString(rt).utf8(rt); unreadThickThreadIDsCpp.push_back(thickThreadID); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { CommMMKV::setStringSet( CommMMKV::notifsStorageUnreadThickThreadsKey, unreadThickThreadIDsCpp); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }); } jsi::Value CommCoreModule::getUnreadThickThreadIDsFromNotifsStorage(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; std::vector unreadThickThreadIDs{}; try { unreadThickThreadIDs = CommMMKV::getStringSet( CommMMKV::notifsStorageUnreadThickThreadsKey); } catch (const std::exception &e) { error = e.what(); } auto unreadThreadThickThreadIDsPtr = std::make_shared>( std::move(unreadThickThreadIDs)); this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiUnreadThickThreadIDs = jsi::Array(innerRt, unreadThreadThickThreadIDsPtr->size()); size_t writeIdx = 0; for (const auto &thickThreadID : *unreadThreadThickThreadIDsPtr) { jsi::String jsiThickThreadID = jsi::String::createFromUtf8(innerRt, thickThreadID); jsiUnreadThickThreadIDs.setValueAtIndex( innerRt, writeIdx++, jsiThickThreadID); } promise->resolve(std::move(jsiUnreadThickThreadIDs)); }); }); } jsi::Value CommCoreModule::initializeContentOutboundSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) { auto identityKeysCpp{identityKeys.utf8(rt)}; auto prekeyCpp{prekey.utf8(rt)}; auto prekeySignatureCpp{prekeySignature.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; std::optional oneTimeKeyCpp; if (oneTimeKey) { oneTimeKeyCpp = oneTimeKey->utf8(rt); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; crypto::EncryptedData initialEncryptedData; int sessionVersion; try { std::optional oneTimeKeyBuffer; if (oneTimeKeyCpp) { oneTimeKeyBuffer = crypto::OlmBuffer( oneTimeKeyCpp->begin(), oneTimeKeyCpp->end()); } sessionVersion = this->contentCryptoModule->initializeOutboundForSendingSession( deviceIDCpp, std::vector( identityKeysCpp.begin(), identityKeysCpp.end()), std::vector(prekeyCpp.begin(), prekeyCpp.end()), std::vector( prekeySignatureCpp.begin(), prekeySignatureCpp.end()), oneTimeKeyBuffer); const std::string initMessage = "{\"type\": \"init\"}"; initialEncryptedData = contentCryptoModule->encrypt(deviceIDCpp, initMessage); this->persistCryptoModules(true, std::nullopt); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto initialEncryptedDataJSI = parseEncryptedData(innerRt, initialEncryptedData); auto outboundSessionCreationResultJSI = jsi::Object(innerRt); outboundSessionCreationResultJSI.setProperty( innerRt, "encryptedData", initialEncryptedDataJSI); outboundSessionCreationResultJSI.setProperty( innerRt, "sessionVersion", sessionVersion); promise->resolve(std::move(outboundSessionCreationResultJSI)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::initializeContentInboundSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::Object encryptedDataJSI, jsi::String deviceID, double sessionVersion, bool overwrite) { auto identityKeysCpp{identityKeys.utf8(rt)}; size_t messageType = std::lround(encryptedDataJSI.getProperty(rt, "messageType").asNumber()); std::string encryptedMessageCpp = encryptedDataJSI.getProperty(rt, "message").asString(rt).utf8(rt); auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string decryptedMessage; try { this->contentCryptoModule->initializeInboundForReceivingSession( deviceIDCpp, std::vector( encryptedMessageCpp.begin(), encryptedMessageCpp.end()), std::vector( identityKeysCpp.begin(), identityKeysCpp.end()), static_cast(sessionVersion), overwrite); crypto::EncryptedData encryptedData{ std::vector( encryptedMessageCpp.begin(), encryptedMessageCpp.end()), messageType}; decryptedMessage = this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData); this->persistCryptoModules(true, std::nullopt); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve( jsi::String::createFromUtf8(innerRt, decryptedMessage)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::isContentSessionInitialized( jsi::Runtime &rt, jsi::String deviceID) { auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; bool result; if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } try { result = this->contentCryptoModule->hasSessionFor(deviceIDCpp); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(result); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::initializeNotificationsOutboundSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) { auto identityKeysCpp{identityKeys.utf8(rt)}; auto prekeyCpp{prekey.utf8(rt)}; auto prekeySignatureCpp{prekeySignature.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; std::optional oneTimeKeyCpp; if (oneTimeKey) { oneTimeKeyCpp = oneTimeKey->utf8(rt); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; crypto::EncryptedData result; std::optional< std::pair, std::string>> notifsCryptoModuleWithPicklingKey; try { notifsCryptoModuleWithPicklingKey = NotificationsCryptoModule::fetchNotificationsAccount(); std::optional oneTimeKeyBuffer; if (oneTimeKeyCpp) { oneTimeKeyBuffer = crypto::OlmBuffer( oneTimeKeyCpp->begin(), oneTimeKeyCpp->end()); } notifsCryptoModuleWithPicklingKey.value() .first->initializeOutboundForSendingSession( deviceIDCpp, std::vector( identityKeysCpp.begin(), identityKeysCpp.end()), std::vector(prekeyCpp.begin(), prekeyCpp.end()), std::vector( prekeySignatureCpp.begin(), prekeySignatureCpp.end()), oneTimeKeyBuffer); result = notifsCryptoModuleWithPicklingKey.value().first->encrypt( deviceIDCpp, NotificationsCryptoModule::initialEncryptedMessageContent); std::shared_ptr peerNotificationsSession = notifsCryptoModuleWithPicklingKey.value() .first->getSessionByDeviceId(deviceIDCpp); NotificationsCryptoModule::persistDeviceNotificationsSession( deviceIDCpp, peerNotificationsSession); // Session is removed from the account since it is persisted // at different location that the account after serialization notifsCryptoModuleWithPicklingKey.value() .first->removeSessionByDeviceId(deviceIDCpp); this->persistCryptoModules( false, notifsCryptoModuleWithPicklingKey); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto initialEncryptedDataJSI = parseEncryptedData(innerRt, result); promise->resolve(std::move(initialEncryptedDataJSI)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::encrypt( jsi::Runtime &rt, jsi::String message, jsi::String deviceID) { auto messageCpp{message.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; crypto::EncryptedData encryptedMessage; try { encryptedMessage = contentCryptoModule->encrypt(deviceIDCpp, messageCpp); this->persistCryptoModules(true, std::nullopt); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto encryptedDataJSI = parseEncryptedData(innerRt, encryptedMessage); promise->resolve(std::move(encryptedDataJSI)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::encryptNotification( jsi::Runtime &rt, jsi::String payload, jsi::String deviceID) { auto payloadCpp{payload.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; crypto::EncryptedData result; try { result = NotificationsCryptoModule::encrypt(deviceIDCpp, payloadCpp); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto encryptedDataJSI = parseEncryptedData(innerRt, result); promise->resolve(std::move(encryptedDataJSI)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::encryptAndPersist( jsi::Runtime &rt, jsi::String message, jsi::String deviceID, jsi::String messageID) { auto messageCpp{message.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; auto messageIDCpp{messageID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; crypto::EncryptedData encryptedMessage; try { encryptedMessage = contentCryptoModule->encrypt(deviceIDCpp, messageCpp); std::string storedSecretKey = getAccountDataKey(secureStoreAccountDataKey); crypto::Persist newContentPersist = this->contentCryptoModule->storeAsB64(storedSecretKey); std::promise persistencePromise; std::future persistenceFuture = persistencePromise.get_future(); GlobalDBSingleton::instance.scheduleOrRunCancellable( [=, &persistencePromise]() { try { folly::dynamic jsonObject = folly::dynamic::object; std::string messageStr( encryptedMessage.message.begin(), encryptedMessage.message.end()); jsonObject["message"] = messageStr; jsonObject["messageType"] = encryptedMessage.messageType; std::string ciphertext = folly::toJson(jsonObject); DatabaseManager::getQueryExecutor().beginTransaction(); DatabaseManager::getQueryExecutor() .setCiphertextForOutboundP2PMessage( messageIDCpp, deviceIDCpp, ciphertext); DatabaseManager::getQueryExecutor().storeOlmPersistData( DatabaseManager::getQueryExecutor() .getContentAccountID(), newContentPersist); DatabaseManager::getQueryExecutor().commitTransaction(); persistencePromise.set_value(); } catch (std::system_error &e) { DatabaseManager::getQueryExecutor().rollbackTransaction(); persistencePromise.set_exception( std::make_exception_ptr(e)); } }); persistenceFuture.get(); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto encryptedDataJSI = parseEncryptedData(innerRt, encryptedMessage); promise->resolve(std::move(encryptedDataJSI)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::decrypt( jsi::Runtime &rt, jsi::Object encryptedDataJSI, jsi::String deviceID) { size_t messageType = std::lround(encryptedDataJSI.getProperty(rt, "messageType").asNumber()); std::string message = encryptedDataJSI.getProperty(rt, "message").asString(rt).utf8(rt); auto deviceIDCpp{deviceID.utf8(rt)}; std::optional sessionVersion; if (encryptedDataJSI.hasProperty(rt, "sessionVersion")) { sessionVersion = std::lround( encryptedDataJSI.getProperty(rt, "sessionVersion").asNumber()); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string decryptedMessage; try { crypto::EncryptedData encryptedData{ std::vector(message.begin(), message.end()), messageType, sessionVersion}; decryptedMessage = this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData); this->persistCryptoModules(true, std::nullopt); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve( jsi::String::createFromUtf8(innerRt, decryptedMessage)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::decryptAndPersist( jsi::Runtime &rt, jsi::Object encryptedDataJSI, jsi::String deviceID, jsi::String userID, jsi::String messageID) { size_t messageType = std::lround(encryptedDataJSI.getProperty(rt, "messageType").asNumber()); std::string message = encryptedDataJSI.getProperty(rt, "message").asString(rt).utf8(rt); std::optional sessionVersion; if (encryptedDataJSI.hasProperty(rt, "sessionVersion")) { sessionVersion = std::lround( encryptedDataJSI.getProperty(rt, "sessionVersion").asNumber()); } auto deviceIDCpp{deviceID.utf8(rt)}; auto messageIDCpp{messageID.utf8(rt)}; auto userIDCpp{userID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string decryptedMessage; try { crypto::EncryptedData encryptedData{ std::vector(message.begin(), message.end()), messageType, sessionVersion}; decryptedMessage = this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData); std::string storedSecretKey = getAccountDataKey(secureStoreAccountDataKey); crypto::Persist newContentPersist = this->contentCryptoModule->storeAsB64(storedSecretKey); std::promise persistencePromise; std::future persistenceFuture = persistencePromise.get_future(); GlobalDBSingleton::instance.scheduleOrRunCancellable( [=, &persistencePromise]() { try { InboundP2PMessage message{ messageIDCpp, deviceIDCpp, decryptedMessage, "decrypted", userIDCpp}; DatabaseManager::getQueryExecutor().beginTransaction(); DatabaseManager::getQueryExecutor().addInboundP2PMessage( message); DatabaseManager::getQueryExecutor().storeOlmPersistData( DatabaseManager::getQueryExecutor() .getContentAccountID(), newContentPersist); DatabaseManager::getQueryExecutor().commitTransaction(); persistencePromise.set_value(); } catch (std::system_error &e) { DatabaseManager::getQueryExecutor().rollbackTransaction(); persistencePromise.set_exception( std::make_exception_ptr(e)); } }); persistenceFuture.get(); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve( jsi::String::createFromUtf8(innerRt, decryptedMessage)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::signMessage(jsi::Runtime &rt, jsi::String message) { std::string messageStr = message.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string signature; try { signature = this->contentCryptoModule->signMessage(messageStr); } catch (const std::exception &e) { error = "signing message failed with: " + std::string(e.what()); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto jsiSignature{jsi::String::createFromUtf8(innerRt, signature)}; promise->resolve(std::move(jsiSignature)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::verifySignature( jsi::Runtime &rt, jsi::String publicKey, jsi::String message, jsi::String signature) { std::string keyStr = publicKey.utf8(rt); std::string messageStr = message.utf8(rt); std::string signatureStr = signature.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; try { crypto::CryptoModule::verifySignature( keyStr, messageStr, signatureStr); } catch (const std::exception &e) { error = "verifying signature failed with: " + std::string(e.what()); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }; this->cryptoThread->scheduleTask(job); }); } CommCoreModule::CommCoreModule( std::shared_ptr jsInvoker) : facebook::react::CommCoreModuleSchemaCxxSpecJSI(jsInvoker), cryptoThread(std::make_unique("crypto")), draftStore(jsInvoker), threadStore(jsInvoker), messageStore(jsInvoker), reportStore(jsInvoker), userStore(jsInvoker), keyserverStore(jsInvoker), communityStore(jsInvoker), integrityStore(jsInvoker), syncedMetadataStore(jsInvoker), auxUserStore(jsInvoker), threadActivityStore(jsInvoker), entryStore(jsInvoker), messageSearchStore(jsInvoker) { GlobalDBSingleton::instance.enableMultithreading(); } double CommCoreModule::getCodeVersion(jsi::Runtime &rt) { return this->codeVersion; } jsi::Value CommCoreModule::setNotifyToken(jsi::Runtime &rt, jsi::String token) { auto notifyToken{token.utf8(rt)}; return createPromiseAsJSIValue( rt, [this, notifyToken](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, notifyToken, promise]() { std::string error; try { DatabaseManager::getQueryExecutor().setNotifyToken(notifyToken); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::clearNotifyToken(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, promise]() { std::string error; try { DatabaseManager::getQueryExecutor().clearNotifyToken(); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); }; jsi::Value CommCoreModule::stampSQLiteDBUserID(jsi::Runtime &rt, jsi::String userID) { auto currentUserID{userID.utf8(rt)}; return createPromiseAsJSIValue( rt, [this, currentUserID](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, promise, currentUserID]() { std::string error; try { DatabaseManager::getQueryExecutor().stampSQLiteDBUserID( currentUserID); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getSQLiteStampedUserID(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, &innerRt, promise]() { std::string error; std::string result; try { result = DatabaseManager::getQueryExecutor().getSQLiteStampedUserID(); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([&innerRt, error, result, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::String::createFromUtf8(innerRt, result)); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::clearSensitiveData(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { GlobalDBSingleton::instance.setTasksCancelled(true); taskType job = [this, promise]() { std::string error; try { this->innerClearCommServicesAuthMetadata(); DatabaseManager::clearSensitiveData(); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); GlobalDBSingleton::instance.scheduleOrRun( []() { GlobalDBSingleton::instance.setTasksCancelled(false); }); }; GlobalDBSingleton::instance.scheduleOrRun(job); }); } bool CommCoreModule::checkIfDatabaseNeedsDeletion(jsi::Runtime &rt) { return DatabaseManager::checkIfDatabaseNeedsDeletion(); } void CommCoreModule::reportDBOperationsFailure(jsi::Runtime &rt) { DatabaseManager::reportDBOperationsFailure(); } jsi::Value CommCoreModule::computeBackupKey( jsi::Runtime &rt, jsi::String password, jsi::String backupID) { std::string passwordStr = password.utf8(rt); std::string backupIDStr = backupID.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::array<::std::uint8_t, 32> backupKey; try { backupKey = compute_backup_key(passwordStr, backupIDStr); } catch (const std::exception &e) { error = std::string{"Failed to compute backup key: "} + e.what(); } this->jsInvoker_->invokeAsync([=, &innerRt]() { if (error.size()) { promise->reject(error); return; } auto size = backupKey.size(); auto arrayBuffer = innerRt.global() .getPropertyAsFunction(innerRt, "ArrayBuffer") .callAsConstructor(innerRt, {static_cast(size)}) .asObject(innerRt) .getArrayBuffer(innerRt); auto bufferPtr = arrayBuffer.data(innerRt); memcpy(bufferPtr, backupKey.data(), size); promise->resolve(std::move(arrayBuffer)); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::generateRandomString(jsi::Runtime &rt, double size) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::string randomString; try { randomString = crypto::Tools::generateRandomString(static_cast(size)); } catch (const std::exception &e) { error = "Failed to generate random string for size " + std::to_string(size) + ": " + e.what(); } this->jsInvoker_->invokeAsync( [&innerRt, error, randomString, promise]() { if (error.size()) { promise->reject(error); } else { jsi::String jsiRandomString = jsi::String::createFromUtf8(innerRt, randomString); promise->resolve(std::move(jsiRandomString)); } }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::setCommServicesAuthMetadata( jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken) { auto userIDStr{userID.utf8(rt)}; auto deviceIDStr{deviceID.utf8(rt)}; auto accessTokenStr{accessToken.utf8(rt)}; return createPromiseAsJSIValue( rt, [this, userIDStr, deviceIDStr, accessTokenStr]( jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { this->innerSetCommServicesAuthMetadata( userIDStr, deviceIDStr, accessTokenStr); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }); } void CommCoreModule::innerSetCommServicesAuthMetadata( std::string userID, std::string deviceID, std::string accessToken) { CommSecureStore::set(CommSecureStore::userID, userID); CommSecureStore::set(CommSecureStore::deviceID, deviceID); CommSecureStore::set(CommSecureStore::commServicesAccessToken, accessToken); CommServicesAuthMetadataEmitter::sendAuthMetadataToJS(accessToken, userID); } jsi::Value CommCoreModule::getCommServicesAuthMetadata(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; std::string userID; std::string deviceID; std::string accessToken; try { folly::Optional userIDOpt = CommSecureStore::get(CommSecureStore::userID); if (userIDOpt.hasValue()) { userID = userIDOpt.value(); } folly::Optional deviceIDOpt = CommSecureStore::get(CommSecureStore::deviceID); if (deviceIDOpt.hasValue()) { deviceID = deviceIDOpt.value(); } folly::Optional accessTokenOpt = CommSecureStore::get(CommSecureStore::commServicesAccessToken); if (accessTokenOpt.hasValue()) { accessToken = accessTokenOpt.value(); } } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync( [&innerRt, error, userID, deviceID, accessToken, promise]() { if (error.size()) { promise->reject(error); } else { auto authMetadata = jsi::Object(innerRt); if (!userID.empty()) { authMetadata.setProperty( innerRt, "userID", jsi::String::createFromUtf8(innerRt, userID)); } if (!deviceID.empty()) { authMetadata.setProperty( innerRt, "deviceID", jsi::String::createFromUtf8(innerRt, deviceID)); } if (!accessToken.empty()) { authMetadata.setProperty( innerRt, "accessToken", jsi::String::createFromUtf8(innerRt, accessToken)); } promise->resolve(std::move(authMetadata)); } }); }); } jsi::Value CommCoreModule::clearCommServicesAuthMetadata(jsi::Runtime &rt) { return this->setCommServicesAuthMetadata( rt, jsi::String::createFromUtf8(rt, ""), jsi::String::createFromUtf8(rt, ""), jsi::String::createFromUtf8(rt, "")); } void CommCoreModule::innerClearCommServicesAuthMetadata() { return this->innerSetCommServicesAuthMetadata("", "", ""); } jsi::Value CommCoreModule::setCommServicesAccessToken( jsi::Runtime &rt, jsi::String accessToken) { auto accessTokenStr{accessToken.utf8(rt)}; return createPromiseAsJSIValue( rt, [this, accessTokenStr]( jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { CommSecureStore::set( CommSecureStore::commServicesAccessToken, accessTokenStr); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }); } jsi::Value CommCoreModule::clearCommServicesAccessToken(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { CommSecureStore::set(CommSecureStore::commServicesAccessToken, ""); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }); } void CommCoreModule::startBackupHandler(jsi::Runtime &rt) { try { ::startBackupHandler(); } catch (const std::exception &e) { throw jsi::JSError(rt, e.what()); } } void CommCoreModule::stopBackupHandler(jsi::Runtime &rt) { try { ::stopBackupHandler(); } catch (const std::exception &e) { throw jsi::JSError(rt, e.what()); } } std::string getSIWEBackupMessage() { std::promise backupSIWEMessagePromise; std::future backupSIWEMessageFuture = backupSIWEMessagePromise.get_future(); GlobalDBSingleton::instance.scheduleOrRunCancellable( [&backupSIWEMessagePromise]() { try { std::string backupSecrets = DatabaseManager::getQueryExecutor().getMetadata( "siweBackupSecrets"); if (!backupSecrets.size()) { backupSIWEMessagePromise.set_value(""); } else { folly::dynamic backupSecretsJSON = folly::parseJson(backupSecrets); std::string message = backupSecretsJSON["message"].asString(); backupSIWEMessagePromise.set_value(message); } } catch (std::system_error &e) { backupSIWEMessagePromise.set_exception(std::make_exception_ptr(e)); } }); return backupSIWEMessageFuture.get(); } jsi::Value CommCoreModule::createFullBackup(jsi::Runtime &rt, jsi::String backupSecret) { std::string backupSecretStr = backupSecret.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string backupMessage; try { backupMessage = getSIWEBackupMessage(); } catch (std::system_error &e) { this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(e.what()); }); return; } this->cryptoThread->scheduleTask([=, &innerRt]() { std::string error; std::string backupID; try { backupID = crypto::Tools::generateRandomURLSafeString(32); } catch (const std::exception &e) { error = "Failed to generate backupID"; } std::string pickleKey; std::string pickledAccount; if (!error.size()) { try { pickleKey = crypto::Tools::generateRandomString(64); crypto::Persist persist = this->contentCryptoModule->storeAsB64(pickleKey); pickledAccount = std::string(persist.account.begin(), persist.account.end()); } catch (const std::exception &e) { error = "Failed to pickle crypto account"; } } if (!error.size()) { auto currentID = RustPromiseManager::instance.addPromise( {promise, this->jsInvoker_, innerRt}); ::createBackup( rust::string(backupID), rust::string(backupSecretStr), rust::string(pickleKey), rust::string(pickledAccount), rust::string(backupMessage), currentID); } else { this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(error); }); } }); }); } jsi::Value CommCoreModule::createUserKeysBackup( jsi::Runtime &rt, jsi::String backupSecret) { std::string backupSecretStr = backupSecret.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string backupMessage; try { backupMessage = getSIWEBackupMessage(); } catch (std::system_error &e) { this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(e.what()); }); return; } this->cryptoThread->scheduleTask([=, &innerRt]() { std::string error; std::string backupID; try { backupID = crypto::Tools::generateRandomURLSafeString(32); } catch (const std::exception &e) { error = "Failed to generate backupID"; } std::string pickleKey; std::string pickledAccount; if (!error.size()) { try { pickleKey = crypto::Tools::generateRandomString(64); crypto::Persist persist = this->contentCryptoModule->storeAsB64(pickleKey); pickledAccount = std::string(persist.account.begin(), persist.account.end()); } catch (const std::exception &e) { error = "Failed to pickle crypto account"; } } if (!error.size()) { auto currentID = RustPromiseManager::instance.addPromise( {promise, this->jsInvoker_, innerRt}); ::createUserKeysBackup( rust::string(backupID), rust::string(backupSecretStr), rust::string(pickleKey), rust::string(pickledAccount), rust::string(backupMessage), currentID); } else { this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(error); }); } }); }); } -jsi::Value CommCoreModule::restoreBackup( - jsi::Runtime &rt, - jsi::String backupSecret, - jsi::String maxVersion, - jsi::String backupID) { - std::string backupSecretStr = backupSecret.utf8(rt); - std::string maxVersionStr = maxVersion.utf8(rt); - std::string backupIDStr = backupID.utf8(rt); - - return createPromiseAsJSIValue( - rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { - auto currentID = RustPromiseManager::instance.addPromise( - {promise, this->jsInvoker_, innerRt}); - ::restoreBackup( - rust::string(backupSecretStr), - rust::string(backupIDStr), - rust::string(maxVersionStr), - currentID); - }); -} - jsi::Value CommCoreModule::restoreBackupData( jsi::Runtime &rt, jsi::String backupID, jsi::String backupDataKey, jsi::String backupLogDataKey, jsi::String maxVersion) { std::string backupIDStr = backupID.utf8(rt); std::string backupDataKeyStr = backupDataKey.utf8(rt); std::string backupLogDataKeyStr = backupLogDataKey.utf8(rt); std::string maxVersionStr = maxVersion.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { auto currentID = RustPromiseManager::instance.addPromise( {promise, this->jsInvoker_, innerRt}); ::restoreBackupData( rust::string(backupIDStr), rust::string(backupDataKeyStr), rust::string(backupLogDataKeyStr), rust::string(maxVersionStr), currentID); }); } jsi::Value CommCoreModule::getQRAuthBackupData(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, &innerRt, promise]() { std::string error; std::string backupID; std::string backupDataKey; std::string backupLogDataKey; try { backupID = DatabaseManager::getQueryExecutor().getMetadata("backupID"); folly::Optional backupDataKeyOpt = CommSecureStore::get(CommSecureStore::encryptionKey); if (backupDataKeyOpt.hasValue()) { backupDataKey = backupDataKeyOpt.value(); } else { throw std::runtime_error("missing backupDataKey"); } folly::Optional backupLogDataKeyOpt = CommSecureStore::get(CommSecureStore::backupLogsEncryptionKey); if (backupLogDataKeyOpt.hasValue()) { backupLogDataKey = backupLogDataKeyOpt.value(); } else { throw std::runtime_error("missing backupLogDataKey"); } } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([&innerRt, error, backupID, backupDataKey, backupLogDataKey, promise]() { if (error.size()) { promise->reject(error); } else { auto backupKeys = jsi::Object(innerRt); backupKeys.setProperty( innerRt, "backupID", jsi::String::createFromUtf8(innerRt, backupID)); backupKeys.setProperty( innerRt, "backupDataKey", jsi::String::createFromUtf8(innerRt, backupDataKey)); backupKeys.setProperty( innerRt, "backupLogDataKey", jsi::String::createFromUtf8(innerRt, backupLogDataKey)); promise->resolve(std::move(backupKeys)); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::retrieveLatestBackupInfo( jsi::Runtime &rt, jsi::String userIdentifier) { std::string userIdentifierStr = userIdentifier.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { auto currentID = RustPromiseManager::instance.addPromise( {promise, this->jsInvoker_, innerRt}); ::retrieveLatestBackupInfo(rust::string(userIdentifierStr), currentID); }); } jsi::Value CommCoreModule::setSIWEBackupSecrets( jsi::Runtime &rt, jsi::Object siweBackupSecrets) { std::string message = siweBackupSecrets.getProperty(rt, "message").asString(rt).utf8(rt); std::string signature = siweBackupSecrets.getProperty(rt, "signature").asString(rt).utf8(rt); folly::dynamic backupSecretsJSON = folly::dynamic::object("message", message)("signature", signature); std::string backupSecrets = folly::toJson(backupSecretsJSON); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, promise, backupSecrets]() { std::string error; try { DatabaseManager::getQueryExecutor().setMetadata( "siweBackupSecrets", backupSecrets); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getSIWEBackupSecrets(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, &innerRt, promise]() { std::string error; std::string backupSecrets; try { backupSecrets = DatabaseManager::getQueryExecutor().getMetadata( "siweBackupSecrets"); } catch (const std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync( [&innerRt, error, backupSecrets, promise]() { if (error.size()) { promise->reject(error); } else if (!backupSecrets.size()) { promise->resolve(jsi::Value::undefined()); } else { folly::dynamic backupSecretsJSON = folly::parseJson(backupSecrets); std::string message = backupSecretsJSON["message"].asString(); std::string signature = backupSecretsJSON["signature"].asString(); auto siweBackupSecrets = jsi::Object(innerRt); siweBackupSecrets.setProperty( innerRt, "message", jsi::String::createFromUtf8(innerRt, message)); siweBackupSecrets.setProperty( innerRt, "signature", jsi::String::createFromUtf8(innerRt, signature)); promise->resolve(std::move(siweBackupSecrets)); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getAllInboundP2PMessages(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector messages; try { messages = DatabaseManager::getQueryExecutor().getAllInboundP2PMessage(); } catch (std::system_error &e) { error = e.what(); } auto messagesPtr = std::make_shared>( std::move(messages)); this->jsInvoker_->invokeAsync( [&innerRt, messagesPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = parseInboundingMessages(innerRt, messagesPtr); promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::removeInboundP2PMessages(jsi::Runtime &rt, jsi::Array ids) { std::vector msgIDsCPP{}; for (auto idx = 0; idx < ids.size(rt); idx++) { std::string msgID = ids.getValueAtIndex(rt, idx).asString(rt).utf8(rt); msgIDsCPP.push_back(msgID); } return createPromiseAsJSIValue( rt, [this, msgIDsCPP](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [this, promise, msgIDsCPP]() { std::string error; try { DatabaseManager::getQueryExecutor().removeInboundP2PMessages( msgIDsCPP); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getInboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) { std::vector msgIDsCPP{}; for (auto idx = 0; idx < ids.size(rt); idx++) { std::string msgID = ids.getValueAtIndex(rt, idx).asString(rt).utf8(rt); msgIDsCPP.push_back(msgID); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector messages; try { messages = DatabaseManager::getQueryExecutor().getInboundP2PMessagesByID( msgIDsCPP); } catch (std::system_error &e) { error = e.what(); } auto messagesPtr = std::make_shared>( std::move(messages)); this->jsInvoker_->invokeAsync( [&innerRt, messagesPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = parseInboundingMessages(innerRt, messagesPtr); promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getOutboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) { std::vector msgIDsCPP{}; for (auto idx = 0; idx < ids.size(rt); idx++) { std::string msgID = ids.getValueAtIndex(rt, idx).asString(rt).utf8(rt); msgIDsCPP.push_back(msgID); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector messages; try { messages = DatabaseManager::getQueryExecutor().getOutboundP2PMessagesByID( msgIDsCPP); } catch (std::system_error &e) { error = e.what(); } auto messagesPtr = std::make_shared>( std::move(messages)); this->jsInvoker_->invokeAsync( [&innerRt, messagesPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = jsi::Array(innerRt, messagesPtr->size()); size_t writeIdx = 0; for (const OutboundP2PMessage &msg : *messagesPtr) { jsi::Object jsiMsg = jsi::Object(innerRt); jsiMsg.setProperty(innerRt, "messageID", msg.message_id); jsiMsg.setProperty(innerRt, "deviceID", msg.device_id); jsiMsg.setProperty(innerRt, "userID", msg.user_id); jsiMsg.setProperty(innerRt, "timestamp", msg.timestamp); jsiMsg.setProperty(innerRt, "plaintext", msg.plaintext); jsiMsg.setProperty(innerRt, "ciphertext", msg.ciphertext); jsiMsg.setProperty(innerRt, "status", msg.status); jsiMsg.setProperty( innerRt, "supportsAutoRetry", msg.supports_auto_retry); jsiMessages.setValueAtIndex(innerRt, writeIdx++, jsiMsg); } promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getUnsentOutboundP2PMessages(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector messages; try { messages = DatabaseManager::getQueryExecutor() .getUnsentOutboundP2PMessages(); } catch (std::system_error &e) { error = e.what(); } auto messagesPtr = std::make_shared>( std::move(messages)); this->jsInvoker_->invokeAsync( [&innerRt, messagesPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = jsi::Array(innerRt, messagesPtr->size()); size_t writeIdx = 0; for (const OutboundP2PMessage &msg : *messagesPtr) { jsi::Object jsiMsg = jsi::Object(innerRt); jsiMsg.setProperty(innerRt, "messageID", msg.message_id); jsiMsg.setProperty(innerRt, "deviceID", msg.device_id); jsiMsg.setProperty(innerRt, "userID", msg.user_id); jsiMsg.setProperty(innerRt, "timestamp", msg.timestamp); jsiMsg.setProperty(innerRt, "plaintext", msg.plaintext); jsiMsg.setProperty(innerRt, "ciphertext", msg.ciphertext); jsiMsg.setProperty(innerRt, "status", msg.status); jsiMsg.setProperty( innerRt, "supportsAutoRetry", msg.supports_auto_retry); jsiMessages.setValueAtIndex(innerRt, writeIdx++, jsiMsg); } promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::markOutboundP2PMessageAsSent( jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) { auto messageIDCpp{messageID.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { std::string error; try { DatabaseManager::getQueryExecutor().markOutboundP2PMessageAsSent( messageIDCpp, deviceIDCpp); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::removeOutboundP2PMessage( jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) { auto messageIDCpp{messageID.utf8(rt)}; auto deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { std::string error; try { DatabaseManager::getQueryExecutor().removeOutboundP2PMessage( messageIDCpp, deviceIDCpp); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([error, promise]() { if (error.size()) { promise->reject(error); } else { promise->resolve(jsi::Value::undefined()); } }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::resetOutboundP2PMessagesForDevice( jsi::Runtime &rt, jsi::String deviceID) { std::string deviceIDCpp{deviceID.utf8(rt)}; return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector messageIDs; try { DatabaseManager::getQueryExecutor().beginTransaction(); messageIDs = DatabaseManager::getQueryExecutor() .resetOutboundP2PMessagesForDevice(deviceIDCpp); DatabaseManager::getQueryExecutor().commitTransaction(); } catch (std::system_error &e) { error = e.what(); DatabaseManager::getQueryExecutor().rollbackTransaction(); } auto messageIDsPtr = std::make_shared>(std::move(messageIDs)); this->jsInvoker_->invokeAsync( [&innerRt, messageIDsPtr, error, promise]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessageIDs = jsi::Array(innerRt, messageIDsPtr->size()); size_t writeIdx = 0; for (const std::string &id : *messageIDsPtr) { jsi::String jsiString = jsi::String::createFromUtf8(innerRt, id); jsiMessageIDs.setValueAtIndex(innerRt, writeIdx++, jsiString); } promise->resolve(std::move(jsiMessageIDs)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::getSyncedDatabaseVersion(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::vector syncedMetadataStoreVector; try { syncedMetadataStoreVector = DatabaseManager::getQueryExecutor().getAllSyncedMetadata(); } catch (std::system_error &e) { error = e.what(); } std::string version; for (auto &entry : syncedMetadataStoreVector) { if (entry.name == "db_version") { version = entry.data; } } this->jsInvoker_->invokeAsync([&innerRt, error, promise, version]() { if (error.size()) { promise->reject(error); return; } jsi::String jsiVersion = jsi::String::createFromUtf8(innerRt, version); promise->resolve(std::move(jsiVersion)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::markPrekeysAsPublished(jsi::Runtime &rt) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; if (this->contentCryptoModule == nullptr || !NotificationsCryptoModule::isNotificationsAccountInitialized()) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } std::optional< std::pair, std::string>> notifsCryptoModuleWithPicklingKey; try { notifsCryptoModuleWithPicklingKey = NotificationsCryptoModule::fetchNotificationsAccount(); this->contentCryptoModule->markPrekeyAsPublished(); notifsCryptoModuleWithPicklingKey.value() .first->markPrekeyAsPublished(); this->persistCryptoModules(true, notifsCryptoModuleWithPicklingKey); } catch (std::exception &e) { error = e.what(); } this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); return; } promise->resolve(jsi::Value::undefined()); }); }; this->cryptoThread->scheduleTask(job); }); } jsi::Value CommCoreModule::getRelatedMessages(jsi::Runtime &rt, jsi::String messageID) { std::string messageIDStr = messageID.utf8(rt); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::shared_ptr> messages; try { messages = std::make_shared>( DatabaseManager::getQueryExecutor().getRelatedMessages( messageIDStr)); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([&innerRt, error, promise, messages, messageStore = this->messageStore]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = messageStore.parseDBDataStore(innerRt, messages); promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } jsi::Value CommCoreModule::searchMessages( jsi::Runtime &rt, jsi::String query, jsi::String threadID, std::optional timestampCursor, std::optional messageIDCursor) { std::string queryStr = query.utf8(rt); std::string threadIDStr = threadID.utf8(rt); std::optional timestampCursorCpp; if (timestampCursor) { timestampCursorCpp = timestampCursor->utf8(rt); } std::optional messageIDCursorCpp; if (messageIDCursor) { messageIDCursorCpp = messageIDCursor->utf8(rt); } return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::shared_ptr> messages; try { messages = std::make_shared>( DatabaseManager::getQueryExecutor().searchMessages( queryStr, threadIDStr, timestampCursorCpp, messageIDCursorCpp)); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([&innerRt, error, promise, messages, messageStore = this->messageStore]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = messageStore.parseDBDataStore(innerRt, messages); promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); }; jsi::Value CommCoreModule::fetchMessages( jsi::Runtime &rt, jsi::String threadID, double limit, double offset) { std::string threadIDCpp = threadID.utf8(rt); int limitInt = std::lround(limit); int offsetInt = std::lround(offset); return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; std::shared_ptr> messages; try { messages = std::make_shared>( DatabaseManager::getQueryExecutor().fetchMessages( threadIDCpp, limitInt, offsetInt)); } catch (std::system_error &e) { error = e.what(); } this->jsInvoker_->invokeAsync([&innerRt, error, promise, messages, messageStore = this->messageStore]() { if (error.size()) { promise->reject(error); return; } jsi::Array jsiMessages = messageStore.parseDBDataStore(innerRt, messages); promise->resolve(std::move(jsiMessages)); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( job, promise, this->jsInvoker_); }); } } // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h index 8793173e4..cc877e3bc 100644 --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h @@ -1,280 +1,275 @@ #pragma once #include "../CryptoTools/CryptoModule.h" #include "../DatabaseManagers/entities/Message.h" #include "../Tools/CommMMKV.h" #include "../Tools/CommSecureStore.h" #include "../Tools/WorkerThread.h" #include "../_generated/commJSI.h" #include "PersistentStorageUtilities/DataStores/AuxUserStore.h" #include "PersistentStorageUtilities/DataStores/CommunityStore.h" #include "PersistentStorageUtilities/DataStores/DraftStore.h" #include "PersistentStorageUtilities/DataStores/EntryStore.h" #include "PersistentStorageUtilities/DataStores/IntegrityStore.h" #include "PersistentStorageUtilities/DataStores/KeyserverStore.h" #include "PersistentStorageUtilities/DataStores/MessageSearchStore.h" #include "PersistentStorageUtilities/DataStores/MessageStore.h" #include "PersistentStorageUtilities/DataStores/ReportStore.h" #include "PersistentStorageUtilities/DataStores/SyncedMetadataStore.h" #include "PersistentStorageUtilities/DataStores/ThreadActivityStore.h" #include "PersistentStorageUtilities/DataStores/ThreadStore.h" #include "PersistentStorageUtilities/DataStores/UserStore.h" #include #include #include #include namespace comm { namespace jsi = facebook::jsi; class CommCoreModule : public facebook::react::CommCoreModuleSchemaCxxSpecJSI { const int codeVersion{444}; std::unique_ptr cryptoThread; const std::string secureStoreAccountDataKey = "cryptoAccountDataKey"; const std::string publicCryptoAccountID = "publicCryptoAccountID"; std::unique_ptr contentCryptoModule; const std::string notifsCryptoAccountID = "notifsCryptoAccountID"; DraftStore draftStore; ThreadStore threadStore; MessageStore messageStore; ReportStore reportStore; UserStore userStore; KeyserverStore keyserverStore; CommunityStore communityStore; IntegrityStore integrityStore; SyncedMetadataStore syncedMetadataStore; AuxUserStore auxUserStore; ThreadActivityStore threadActivityStore; EntryStore entryStore; MessageSearchStore messageSearchStore; void persistCryptoModules( bool persistContentModule, std::optional< std::pair, std::string>> maybeUpdatedNotifsCryptoModule); jsi::Value createNewBackupInternal( jsi::Runtime &rt, std::string backupSecret, std::string backupMessage); virtual jsi::Value getDraft(jsi::Runtime &rt, jsi::String key) override; virtual jsi::Value updateDraft(jsi::Runtime &rt, jsi::String key, jsi::String text) override; virtual jsi::Value moveDraft(jsi::Runtime &rt, jsi::String oldKey, jsi::String newKey) override; virtual jsi::Value getClientDBStore(jsi::Runtime &rt) override; virtual jsi::Value removeAllDrafts(jsi::Runtime &rt) override; virtual jsi::Array getInitialMessagesSync(jsi::Runtime &rt) override; virtual void processReportStoreOperationsSync( jsi::Runtime &rt, jsi::Array operations) override; virtual void processMessageStoreOperationsSync( jsi::Runtime &rt, jsi::Array operations) override; virtual jsi::Array getAllThreadsSync(jsi::Runtime &rt) override; virtual void processThreadStoreOperationsSync( jsi::Runtime &rt, jsi::Array operations) override; virtual jsi::Value processDBStoreOperations(jsi::Runtime &rt, jsi::Object operations) override; template void appendDBStoreOps( jsi::Runtime &rt, jsi::Object &operations, const char *key, T &store, std::shared_ptr>> &destination); virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt) override; virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) override; virtual jsi::Value getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override; virtual jsi::Value validateAndUploadPrekeys( jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken) override; virtual jsi::Value validateAndGetPrekeys(jsi::Runtime &rt) override; virtual jsi::Value initializeNotificationsSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String keyserverID) override; virtual jsi::Value isNotificationsSessionInitialized(jsi::Runtime &rt) override; virtual jsi::Value isDeviceNotificationsSessionInitialized( jsi::Runtime &rt, jsi::String deviceID) override; virtual jsi::Value isNotificationsSessionInitializedWithDevices( jsi::Runtime &rt, jsi::Array deviceIDs) override; virtual jsi::Value updateKeyserverDataInNotifStorage( jsi::Runtime &rt, jsi::Array keyserversData) override; virtual jsi::Value removeKeyserverDataFromNotifStorage( jsi::Runtime &rt, jsi::Array keyserverIDsToDelete) override; virtual jsi::Value getKeyserverDataFromNotifStorage( jsi::Runtime &rt, jsi::Array keyserverIDs) override; virtual jsi::Value updateUnreadThickThreadsInNotifsStorage( jsi::Runtime &rt, jsi::Array unreadThickThreadIDs) override; virtual jsi::Value getUnreadThickThreadIDsFromNotifsStorage(jsi::Runtime &rt) override; virtual jsi::Value initializeContentOutboundSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) override; virtual jsi::Value initializeContentInboundSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::Object encryptedDataJSI, jsi::String deviceID, double sessionVersion, bool overwrite) override; virtual jsi::Value isContentSessionInitialized(jsi::Runtime &rt, jsi::String deviceID) override; virtual jsi::Value initializeNotificationsOutboundSession( jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) override; virtual jsi::Value encrypt(jsi::Runtime &rt, jsi::String message, jsi::String deviceID) override; virtual jsi::Value encryptNotification( jsi::Runtime &rt, jsi::String payload, jsi::String deviceID) override; virtual jsi::Value encryptAndPersist( jsi::Runtime &rt, jsi::String message, jsi::String deviceID, jsi::String messageID) override; virtual jsi::Value decrypt( jsi::Runtime &rt, jsi::Object encryptedDataJSI, jsi::String deviceID) override; virtual jsi::Value decryptAndPersist( jsi::Runtime &rt, jsi::Object encryptedDataJSI, jsi::String deviceID, jsi::String userID, jsi::String messageID) override; virtual jsi::Value signMessage(jsi::Runtime &rt, jsi::String message) override; virtual jsi::Value verifySignature( jsi::Runtime &rt, jsi::String publicKey, jsi::String message, jsi::String signature) override; virtual void terminate(jsi::Runtime &rt) override; virtual double getCodeVersion(jsi::Runtime &rt) override; virtual jsi::Value setNotifyToken(jsi::Runtime &rt, jsi::String token) override; virtual jsi::Value clearNotifyToken(jsi::Runtime &rt) override; virtual jsi::Value stampSQLiteDBUserID(jsi::Runtime &rt, jsi::String userID) override; virtual jsi::Value getSQLiteStampedUserID(jsi::Runtime &rt) override; virtual jsi::Value clearSensitiveData(jsi::Runtime &rt) override; virtual bool checkIfDatabaseNeedsDeletion(jsi::Runtime &rt) override; virtual void reportDBOperationsFailure(jsi::Runtime &rt) override; virtual jsi::Value computeBackupKey( jsi::Runtime &rt, jsi::String password, jsi::String backupID) override; virtual jsi::Value generateRandomString(jsi::Runtime &rt, double size) override; virtual jsi::Value setCommServicesAuthMetadata( jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken) override; virtual void innerSetCommServicesAuthMetadata( std::string userID, std::string deviceID, std::string accessToken); virtual jsi::Value getCommServicesAuthMetadata(jsi::Runtime &rt) override; virtual jsi::Value clearCommServicesAuthMetadata(jsi::Runtime &rt) override; virtual void innerClearCommServicesAuthMetadata(); virtual jsi::Value setCommServicesAccessToken( jsi::Runtime &rt, jsi::String accessToken) override; virtual jsi::Value clearCommServicesAccessToken(jsi::Runtime &rt) override; virtual void startBackupHandler(jsi::Runtime &rt) override; virtual void stopBackupHandler(jsi::Runtime &rt) override; virtual jsi::Value createFullBackup(jsi::Runtime &rt, jsi::String backupSecret) override; virtual jsi::Value createUserKeysBackup(jsi::Runtime &rt, jsi::String backupSecret) override; - virtual jsi::Value restoreBackup( - jsi::Runtime &rt, - jsi::String backupSecret, - jsi::String maxVersion, - jsi::String backupID) override; virtual jsi::Value restoreBackupData( jsi::Runtime &rt, jsi::String backupID, jsi::String backupDataKey, jsi::String backupLogDataKey, jsi::String maxVersion) override; virtual jsi::Value getQRAuthBackupData(jsi::Runtime &rt) override; virtual jsi::Value retrieveLatestBackupInfo( jsi::Runtime &rt, jsi::String userIdentifier) override; virtual jsi::Value setSIWEBackupSecrets( jsi::Runtime &rt, jsi::Object siweBackupSecrets) override; virtual jsi::Value getSIWEBackupSecrets(jsi::Runtime &rt) override; virtual jsi::Value getAllInboundP2PMessages(jsi::Runtime &rt) override; virtual jsi::Value removeInboundP2PMessages(jsi::Runtime &rt, jsi::Array ids) override; virtual jsi::Value getInboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) override; virtual jsi::Value getOutboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) override; virtual jsi::Value getUnsentOutboundP2PMessages(jsi::Runtime &rt) override; virtual jsi::Value markOutboundP2PMessageAsSent( jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) override; virtual jsi::Value removeOutboundP2PMessage( jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) override; virtual jsi::Value resetOutboundP2PMessagesForDevice( jsi::Runtime &rt, jsi::String deviceID) override; virtual jsi::Value getSyncedDatabaseVersion(jsi::Runtime &rt) override; virtual jsi::Value markPrekeysAsPublished(jsi::Runtime &rt) override; virtual jsi::Value getRelatedMessages(jsi::Runtime &rt, jsi::String messageID) override; virtual jsi::Value searchMessages( jsi::Runtime &rt, jsi::String query, jsi::String threadID, std::optional timestampCursor, std::optional messageIDCursor) override; virtual jsi::Value fetchMessages( jsi::Runtime &rt, jsi::String threadID, double limit, double offset) override; public: CommCoreModule(std::shared_ptr jsInvoker); }; } // namespace comm diff --git a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp index 4fef196c9..6e7cce678 100644 --- a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp @@ -1,329 +1,325 @@ /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). * * Do not edit this file as changes may cause incorrect behavior and will be lost * once the code is regenerated. * * @generated by codegen project: GenerateModuleH.js */ #include "commJSI.h" namespace facebook { namespace react { static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getDraft(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getDraft(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateDraft(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->updateDraft(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_moveDraft(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->moveDraft(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getClientDBStore(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getClientDBStore(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeAllDrafts(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->removeAllDrafts(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getInitialMessagesSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getInitialMessagesSync(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processMessageStoreOperationsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->processMessageStoreOperationsSync(rt, args[0].asObject(rt).asArray(rt)); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllThreadsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getAllThreadsSync(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processReportStoreOperationsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->processReportStoreOperationsSync(rt, args[0].asObject(rt).asArray(rt)); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processThreadStoreOperationsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->processThreadStoreOperationsSync(rt, args[0].asObject(rt).asArray(rt)); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processDBStoreOperations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->processDBStoreOperations(rt, args[0].asObject(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->initializeCryptoAccount(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserPublicKey(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getUserPublicKey(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getOneTimeKeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getOneTimeKeys(rt, args[0].asNumber()); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_validateAndGetPrekeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->validateAndGetPrekeys(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_validateAndUploadPrekeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->validateAndUploadPrekeys(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsSession(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->initializeNotificationsSession(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].isNull() || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asString(rt)), args[4].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isNotificationsSessionInitialized(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->isNotificationsSessionInitialized(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isDeviceNotificationsSessionInitialized(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->isDeviceNotificationsSessionInitialized(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isNotificationsSessionInitializedWithDevices(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->isNotificationsSessionInitializedWithDevices(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateKeyserverDataInNotifStorage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->updateKeyserverDataInNotifStorage(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeKeyserverDataFromNotifStorage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->removeKeyserverDataFromNotifStorage(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getKeyserverDataFromNotifStorage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getKeyserverDataFromNotifStorage(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateUnreadThickThreadsInNotifsStorage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->updateUnreadThickThreadsInNotifsStorage(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUnreadThickThreadIDsFromNotifsStorage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getUnreadThickThreadIDsFromNotifsStorage(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentOutboundSession(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->initializeContentOutboundSession(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].isNull() || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asString(rt)), args[4].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentInboundSession(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->initializeContentInboundSession(rt, args[0].asString(rt), args[1].asObject(rt), args[2].asString(rt), args[3].asNumber(), args[4].asBool()); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isContentSessionInitialized(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->isContentSessionInitialized(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsOutboundSession(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->initializeNotificationsOutboundSession(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].isNull() || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asString(rt)), args[4].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encrypt(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->encrypt(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encryptNotification(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->encryptNotification(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encryptAndPersist(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->encryptAndPersist(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_decrypt(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->decrypt(rt, args[0].asObject(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_decryptAndPersist(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->decryptAndPersist(rt, args[0].asObject(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_signMessage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->signMessage(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_verifySignature(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->verifySignature(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCodeVersion(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getCodeVersion(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_terminate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->terminate(rt); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setNotifyToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->setNotifyToken(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearNotifyToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->clearNotifyToken(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_stampSQLiteDBUserID(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->stampSQLiteDBUserID(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getSQLiteStampedUserID(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getSQLiteStampedUserID(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearSensitiveData(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->clearSensitiveData(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_checkIfDatabaseNeedsDeletion(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->checkIfDatabaseNeedsDeletion(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_reportDBOperationsFailure(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->reportDBOperationsFailure(rt); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_computeBackupKey(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->computeBackupKey(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_generateRandomString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->generateRandomString(rt, args[0].asNumber()); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setCommServicesAuthMetadata(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->setCommServicesAuthMetadata(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCommServicesAuthMetadata(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getCommServicesAuthMetadata(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearCommServicesAuthMetadata(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->clearCommServicesAuthMetadata(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setCommServicesAccessToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->setCommServicesAccessToken(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearCommServicesAccessToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->clearCommServicesAccessToken(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_startBackupHandler(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->startBackupHandler(rt); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_stopBackupHandler(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { static_cast(&turboModule)->stopBackupHandler(rt); return jsi::Value::undefined(); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createUserKeysBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->createUserKeysBackup(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createFullBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->createFullBackup(rt, args[0].asString(rt)); } -static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - return static_cast(&turboModule)->restoreBackup(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt)); -} static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackupData(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->restoreBackupData(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getQRAuthBackupData(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getQRAuthBackupData(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_retrieveLatestBackupInfo(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->retrieveLatestBackupInfo(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setSIWEBackupSecrets(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->setSIWEBackupSecrets(rt, args[0].asObject(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getSIWEBackupSecrets(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getSIWEBackupSecrets(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllInboundP2PMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getAllInboundP2PMessages(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeInboundP2PMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->removeInboundP2PMessages(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getInboundP2PMessagesByID(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getInboundP2PMessagesByID(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getOutboundP2PMessagesByID(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getOutboundP2PMessagesByID(rt, args[0].asObject(rt).asArray(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUnsentOutboundP2PMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getUnsentOutboundP2PMessages(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_markOutboundP2PMessageAsSent(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->markOutboundP2PMessageAsSent(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeOutboundP2PMessage(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->removeOutboundP2PMessage(rt, args[0].asString(rt), args[1].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_resetOutboundP2PMessagesForDevice(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->resetOutboundP2PMessagesForDevice(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getSyncedDatabaseVersion(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getSyncedDatabaseVersion(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_markPrekeysAsPublished(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->markPrekeysAsPublished(rt); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getRelatedMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getRelatedMessages(rt, args[0].asString(rt)); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_searchMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->searchMessages(rt, args[0].asString(rt), args[1].asString(rt), args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asString(rt)), args[3].isNull() || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asString(rt))); } static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_fetchMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->fetchMessages(rt, args[0].asString(rt), args[1].asNumber(), args[2].asNumber()); } CommCoreModuleSchemaCxxSpecJSI::CommCoreModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommTurboModule", jsInvoker) { methodMap_["getDraft"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getDraft}; methodMap_["updateDraft"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateDraft}; methodMap_["moveDraft"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_moveDraft}; methodMap_["getClientDBStore"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getClientDBStore}; methodMap_["removeAllDrafts"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeAllDrafts}; methodMap_["getInitialMessagesSync"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getInitialMessagesSync}; methodMap_["processMessageStoreOperationsSync"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processMessageStoreOperationsSync}; methodMap_["getAllThreadsSync"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllThreadsSync}; methodMap_["processReportStoreOperationsSync"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processReportStoreOperationsSync}; methodMap_["processThreadStoreOperationsSync"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processThreadStoreOperationsSync}; methodMap_["processDBStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processDBStoreOperations}; methodMap_["initializeCryptoAccount"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount}; methodMap_["getUserPublicKey"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserPublicKey}; methodMap_["getOneTimeKeys"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getOneTimeKeys}; methodMap_["validateAndGetPrekeys"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_validateAndGetPrekeys}; methodMap_["validateAndUploadPrekeys"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_validateAndUploadPrekeys}; methodMap_["initializeNotificationsSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsSession}; methodMap_["isNotificationsSessionInitialized"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isNotificationsSessionInitialized}; methodMap_["isDeviceNotificationsSessionInitialized"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isDeviceNotificationsSessionInitialized}; methodMap_["isNotificationsSessionInitializedWithDevices"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isNotificationsSessionInitializedWithDevices}; methodMap_["updateKeyserverDataInNotifStorage"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateKeyserverDataInNotifStorage}; methodMap_["removeKeyserverDataFromNotifStorage"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeKeyserverDataFromNotifStorage}; methodMap_["getKeyserverDataFromNotifStorage"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getKeyserverDataFromNotifStorage}; methodMap_["updateUnreadThickThreadsInNotifsStorage"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateUnreadThickThreadsInNotifsStorage}; methodMap_["getUnreadThickThreadIDsFromNotifsStorage"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUnreadThickThreadIDsFromNotifsStorage}; methodMap_["initializeContentOutboundSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentOutboundSession}; methodMap_["initializeContentInboundSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentInboundSession}; methodMap_["isContentSessionInitialized"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_isContentSessionInitialized}; methodMap_["initializeNotificationsOutboundSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsOutboundSession}; methodMap_["encrypt"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encrypt}; methodMap_["encryptNotification"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encryptNotification}; methodMap_["encryptAndPersist"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encryptAndPersist}; methodMap_["decrypt"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_decrypt}; methodMap_["decryptAndPersist"] = MethodMetadata {4, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_decryptAndPersist}; methodMap_["signMessage"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_signMessage}; methodMap_["verifySignature"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_verifySignature}; methodMap_["getCodeVersion"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCodeVersion}; methodMap_["terminate"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_terminate}; methodMap_["setNotifyToken"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setNotifyToken}; methodMap_["clearNotifyToken"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearNotifyToken}; methodMap_["stampSQLiteDBUserID"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_stampSQLiteDBUserID}; methodMap_["getSQLiteStampedUserID"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getSQLiteStampedUserID}; methodMap_["clearSensitiveData"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearSensitiveData}; methodMap_["checkIfDatabaseNeedsDeletion"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_checkIfDatabaseNeedsDeletion}; methodMap_["reportDBOperationsFailure"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_reportDBOperationsFailure}; methodMap_["computeBackupKey"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_computeBackupKey}; methodMap_["generateRandomString"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_generateRandomString}; methodMap_["setCommServicesAuthMetadata"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setCommServicesAuthMetadata}; methodMap_["getCommServicesAuthMetadata"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCommServicesAuthMetadata}; methodMap_["clearCommServicesAuthMetadata"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearCommServicesAuthMetadata}; methodMap_["setCommServicesAccessToken"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setCommServicesAccessToken}; methodMap_["clearCommServicesAccessToken"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearCommServicesAccessToken}; methodMap_["startBackupHandler"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_startBackupHandler}; methodMap_["stopBackupHandler"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_stopBackupHandler}; methodMap_["createUserKeysBackup"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createUserKeysBackup}; methodMap_["createFullBackup"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createFullBackup}; - methodMap_["restoreBackup"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackup}; methodMap_["restoreBackupData"] = MethodMetadata {4, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackupData}; methodMap_["getQRAuthBackupData"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getQRAuthBackupData}; methodMap_["retrieveLatestBackupInfo"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_retrieveLatestBackupInfo}; methodMap_["setSIWEBackupSecrets"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setSIWEBackupSecrets}; methodMap_["getSIWEBackupSecrets"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getSIWEBackupSecrets}; methodMap_["getAllInboundP2PMessages"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllInboundP2PMessages}; methodMap_["removeInboundP2PMessages"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeInboundP2PMessages}; methodMap_["getInboundP2PMessagesByID"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getInboundP2PMessagesByID}; methodMap_["getOutboundP2PMessagesByID"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getOutboundP2PMessagesByID}; methodMap_["getUnsentOutboundP2PMessages"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUnsentOutboundP2PMessages}; methodMap_["markOutboundP2PMessageAsSent"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_markOutboundP2PMessageAsSent}; methodMap_["removeOutboundP2PMessage"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeOutboundP2PMessage}; methodMap_["resetOutboundP2PMessagesForDevice"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_resetOutboundP2PMessagesForDevice}; methodMap_["getSyncedDatabaseVersion"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getSyncedDatabaseVersion}; methodMap_["markPrekeysAsPublished"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_markPrekeysAsPublished}; methodMap_["getRelatedMessages"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getRelatedMessages}; methodMap_["searchMessages"] = MethodMetadata {4, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_searchMessages}; methodMap_["fetchMessages"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_fetchMessages}; } } // namespace react } // namespace facebook diff --git a/native/cpp/CommonCpp/_generated/commJSI.h b/native/cpp/CommonCpp/_generated/commJSI.h index ad0e2557f..6a526b453 100644 --- a/native/cpp/CommonCpp/_generated/commJSI.h +++ b/native/cpp/CommonCpp/_generated/commJSI.h @@ -1,728 +1,719 @@ /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). * * Do not edit this file as changes may cause incorrect behavior and will be lost * once the code is regenerated. * * @generated by codegen project: GenerateModuleH.js */ #pragma once #include #include namespace facebook { namespace react { class JSI_EXPORT CommCoreModuleSchemaCxxSpecJSI : public TurboModule { protected: CommCoreModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker); public: virtual jsi::Value getDraft(jsi::Runtime &rt, jsi::String key) = 0; virtual jsi::Value updateDraft(jsi::Runtime &rt, jsi::String key, jsi::String text) = 0; virtual jsi::Value moveDraft(jsi::Runtime &rt, jsi::String oldKey, jsi::String newKey) = 0; virtual jsi::Value getClientDBStore(jsi::Runtime &rt) = 0; virtual jsi::Value removeAllDrafts(jsi::Runtime &rt) = 0; virtual jsi::Array getInitialMessagesSync(jsi::Runtime &rt) = 0; virtual void processMessageStoreOperationsSync(jsi::Runtime &rt, jsi::Array operations) = 0; virtual jsi::Array getAllThreadsSync(jsi::Runtime &rt) = 0; virtual void processReportStoreOperationsSync(jsi::Runtime &rt, jsi::Array operations) = 0; virtual void processThreadStoreOperationsSync(jsi::Runtime &rt, jsi::Array operations) = 0; virtual jsi::Value processDBStoreOperations(jsi::Runtime &rt, jsi::Object operations) = 0; virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt) = 0; virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) = 0; virtual jsi::Value getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) = 0; virtual jsi::Value validateAndGetPrekeys(jsi::Runtime &rt) = 0; virtual jsi::Value validateAndUploadPrekeys(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken) = 0; virtual jsi::Value initializeNotificationsSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String keyserverID) = 0; virtual jsi::Value isNotificationsSessionInitialized(jsi::Runtime &rt) = 0; virtual jsi::Value isDeviceNotificationsSessionInitialized(jsi::Runtime &rt, jsi::String deviceID) = 0; virtual jsi::Value isNotificationsSessionInitializedWithDevices(jsi::Runtime &rt, jsi::Array deviceIDs) = 0; virtual jsi::Value updateKeyserverDataInNotifStorage(jsi::Runtime &rt, jsi::Array keyserversData) = 0; virtual jsi::Value removeKeyserverDataFromNotifStorage(jsi::Runtime &rt, jsi::Array keyserverIDsToDelete) = 0; virtual jsi::Value getKeyserverDataFromNotifStorage(jsi::Runtime &rt, jsi::Array keyserverIDs) = 0; virtual jsi::Value updateUnreadThickThreadsInNotifsStorage(jsi::Runtime &rt, jsi::Array unreadThickThreadIDs) = 0; virtual jsi::Value getUnreadThickThreadIDsFromNotifsStorage(jsi::Runtime &rt) = 0; virtual jsi::Value initializeContentOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) = 0; virtual jsi::Value initializeContentInboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::Object encryptedContent, jsi::String deviceID, double sessionVersion, bool overwrite) = 0; virtual jsi::Value isContentSessionInitialized(jsi::Runtime &rt, jsi::String deviceID) = 0; virtual jsi::Value initializeNotificationsOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) = 0; virtual jsi::Value encrypt(jsi::Runtime &rt, jsi::String message, jsi::String deviceID) = 0; virtual jsi::Value encryptNotification(jsi::Runtime &rt, jsi::String payload, jsi::String deviceID) = 0; virtual jsi::Value encryptAndPersist(jsi::Runtime &rt, jsi::String message, jsi::String deviceID, jsi::String messageID) = 0; virtual jsi::Value decrypt(jsi::Runtime &rt, jsi::Object encryptedData, jsi::String deviceID) = 0; virtual jsi::Value decryptAndPersist(jsi::Runtime &rt, jsi::Object encryptedData, jsi::String deviceID, jsi::String userID, jsi::String messageID) = 0; virtual jsi::Value signMessage(jsi::Runtime &rt, jsi::String message) = 0; virtual jsi::Value verifySignature(jsi::Runtime &rt, jsi::String publicKey, jsi::String message, jsi::String signature) = 0; virtual double getCodeVersion(jsi::Runtime &rt) = 0; virtual void terminate(jsi::Runtime &rt) = 0; virtual jsi::Value setNotifyToken(jsi::Runtime &rt, jsi::String token) = 0; virtual jsi::Value clearNotifyToken(jsi::Runtime &rt) = 0; virtual jsi::Value stampSQLiteDBUserID(jsi::Runtime &rt, jsi::String userID) = 0; virtual jsi::Value getSQLiteStampedUserID(jsi::Runtime &rt) = 0; virtual jsi::Value clearSensitiveData(jsi::Runtime &rt) = 0; virtual bool checkIfDatabaseNeedsDeletion(jsi::Runtime &rt) = 0; virtual void reportDBOperationsFailure(jsi::Runtime &rt) = 0; virtual jsi::Value computeBackupKey(jsi::Runtime &rt, jsi::String password, jsi::String backupID) = 0; virtual jsi::Value generateRandomString(jsi::Runtime &rt, double size) = 0; virtual jsi::Value setCommServicesAuthMetadata(jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken) = 0; virtual jsi::Value getCommServicesAuthMetadata(jsi::Runtime &rt) = 0; virtual jsi::Value clearCommServicesAuthMetadata(jsi::Runtime &rt) = 0; virtual jsi::Value setCommServicesAccessToken(jsi::Runtime &rt, jsi::String accessToken) = 0; virtual jsi::Value clearCommServicesAccessToken(jsi::Runtime &rt) = 0; virtual void startBackupHandler(jsi::Runtime &rt) = 0; virtual void stopBackupHandler(jsi::Runtime &rt) = 0; virtual jsi::Value createUserKeysBackup(jsi::Runtime &rt, jsi::String backupSecret) = 0; virtual jsi::Value createFullBackup(jsi::Runtime &rt, jsi::String backupSecret) = 0; - virtual jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret, jsi::String maxVersion, jsi::String backupID) = 0; virtual jsi::Value restoreBackupData(jsi::Runtime &rt, jsi::String backupID, jsi::String backupDataKey, jsi::String backupLogDataKey, jsi::String maxVersion) = 0; virtual jsi::Value getQRAuthBackupData(jsi::Runtime &rt) = 0; virtual jsi::Value retrieveLatestBackupInfo(jsi::Runtime &rt, jsi::String userIdentifier) = 0; virtual jsi::Value setSIWEBackupSecrets(jsi::Runtime &rt, jsi::Object siweBackupSecrets) = 0; virtual jsi::Value getSIWEBackupSecrets(jsi::Runtime &rt) = 0; virtual jsi::Value getAllInboundP2PMessages(jsi::Runtime &rt) = 0; virtual jsi::Value removeInboundP2PMessages(jsi::Runtime &rt, jsi::Array ids) = 0; virtual jsi::Value getInboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) = 0; virtual jsi::Value getOutboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) = 0; virtual jsi::Value getUnsentOutboundP2PMessages(jsi::Runtime &rt) = 0; virtual jsi::Value markOutboundP2PMessageAsSent(jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) = 0; virtual jsi::Value removeOutboundP2PMessage(jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) = 0; virtual jsi::Value resetOutboundP2PMessagesForDevice(jsi::Runtime &rt, jsi::String deviceID) = 0; virtual jsi::Value getSyncedDatabaseVersion(jsi::Runtime &rt) = 0; virtual jsi::Value markPrekeysAsPublished(jsi::Runtime &rt) = 0; virtual jsi::Value getRelatedMessages(jsi::Runtime &rt, jsi::String messageID) = 0; virtual jsi::Value searchMessages(jsi::Runtime &rt, jsi::String query, jsi::String threadID, std::optional timestampCursor, std::optional messageIDCursor) = 0; virtual jsi::Value fetchMessages(jsi::Runtime &rt, jsi::String threadID, double limit, double offset) = 0; }; template class JSI_EXPORT CommCoreModuleSchemaCxxSpec : public TurboModule { public: jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { return delegate_.get(rt, propName); } protected: CommCoreModuleSchemaCxxSpec(std::shared_ptr jsInvoker) : TurboModule("CommTurboModule", jsInvoker), delegate_(static_cast(this), jsInvoker) {} private: class Delegate : public CommCoreModuleSchemaCxxSpecJSI { public: Delegate(T *instance, std::shared_ptr jsInvoker) : CommCoreModuleSchemaCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} jsi::Value getDraft(jsi::Runtime &rt, jsi::String key) override { static_assert( bridging::getParameterCount(&T::getDraft) == 2, "Expected getDraft(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::getDraft, jsInvoker_, instance_, std::move(key)); } jsi::Value updateDraft(jsi::Runtime &rt, jsi::String key, jsi::String text) override { static_assert( bridging::getParameterCount(&T::updateDraft) == 3, "Expected updateDraft(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::updateDraft, jsInvoker_, instance_, std::move(key), std::move(text)); } jsi::Value moveDraft(jsi::Runtime &rt, jsi::String oldKey, jsi::String newKey) override { static_assert( bridging::getParameterCount(&T::moveDraft) == 3, "Expected moveDraft(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::moveDraft, jsInvoker_, instance_, std::move(oldKey), std::move(newKey)); } jsi::Value getClientDBStore(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getClientDBStore) == 1, "Expected getClientDBStore(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getClientDBStore, jsInvoker_, instance_); } jsi::Value removeAllDrafts(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::removeAllDrafts) == 1, "Expected removeAllDrafts(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::removeAllDrafts, jsInvoker_, instance_); } jsi::Array getInitialMessagesSync(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getInitialMessagesSync) == 1, "Expected getInitialMessagesSync(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getInitialMessagesSync, jsInvoker_, instance_); } void processMessageStoreOperationsSync(jsi::Runtime &rt, jsi::Array operations) override { static_assert( bridging::getParameterCount(&T::processMessageStoreOperationsSync) == 2, "Expected processMessageStoreOperationsSync(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::processMessageStoreOperationsSync, jsInvoker_, instance_, std::move(operations)); } jsi::Array getAllThreadsSync(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getAllThreadsSync) == 1, "Expected getAllThreadsSync(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getAllThreadsSync, jsInvoker_, instance_); } void processReportStoreOperationsSync(jsi::Runtime &rt, jsi::Array operations) override { static_assert( bridging::getParameterCount(&T::processReportStoreOperationsSync) == 2, "Expected processReportStoreOperationsSync(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::processReportStoreOperationsSync, jsInvoker_, instance_, std::move(operations)); } void processThreadStoreOperationsSync(jsi::Runtime &rt, jsi::Array operations) override { static_assert( bridging::getParameterCount(&T::processThreadStoreOperationsSync) == 2, "Expected processThreadStoreOperationsSync(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::processThreadStoreOperationsSync, jsInvoker_, instance_, std::move(operations)); } jsi::Value processDBStoreOperations(jsi::Runtime &rt, jsi::Object operations) override { static_assert( bridging::getParameterCount(&T::processDBStoreOperations) == 2, "Expected processDBStoreOperations(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::processDBStoreOperations, jsInvoker_, instance_, std::move(operations)); } jsi::Value initializeCryptoAccount(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::initializeCryptoAccount) == 1, "Expected initializeCryptoAccount(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::initializeCryptoAccount, jsInvoker_, instance_); } jsi::Value getUserPublicKey(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getUserPublicKey) == 1, "Expected getUserPublicKey(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getUserPublicKey, jsInvoker_, instance_); } jsi::Value getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override { static_assert( bridging::getParameterCount(&T::getOneTimeKeys) == 2, "Expected getOneTimeKeys(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::getOneTimeKeys, jsInvoker_, instance_, std::move(oneTimeKeysAmount)); } jsi::Value validateAndGetPrekeys(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::validateAndGetPrekeys) == 1, "Expected validateAndGetPrekeys(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::validateAndGetPrekeys, jsInvoker_, instance_); } jsi::Value validateAndUploadPrekeys(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken) override { static_assert( bridging::getParameterCount(&T::validateAndUploadPrekeys) == 4, "Expected validateAndUploadPrekeys(...) to have 4 parameters"); return bridging::callFromJs( rt, &T::validateAndUploadPrekeys, jsInvoker_, instance_, std::move(authUserID), std::move(authDeviceID), std::move(authAccessToken)); } jsi::Value initializeNotificationsSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String keyserverID) override { static_assert( bridging::getParameterCount(&T::initializeNotificationsSession) == 6, "Expected initializeNotificationsSession(...) to have 6 parameters"); return bridging::callFromJs( rt, &T::initializeNotificationsSession, jsInvoker_, instance_, std::move(identityKeys), std::move(prekey), std::move(prekeySignature), std::move(oneTimeKey), std::move(keyserverID)); } jsi::Value isNotificationsSessionInitialized(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::isNotificationsSessionInitialized) == 1, "Expected isNotificationsSessionInitialized(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::isNotificationsSessionInitialized, jsInvoker_, instance_); } jsi::Value isDeviceNotificationsSessionInitialized(jsi::Runtime &rt, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::isDeviceNotificationsSessionInitialized) == 2, "Expected isDeviceNotificationsSessionInitialized(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::isDeviceNotificationsSessionInitialized, jsInvoker_, instance_, std::move(deviceID)); } jsi::Value isNotificationsSessionInitializedWithDevices(jsi::Runtime &rt, jsi::Array deviceIDs) override { static_assert( bridging::getParameterCount(&T::isNotificationsSessionInitializedWithDevices) == 2, "Expected isNotificationsSessionInitializedWithDevices(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::isNotificationsSessionInitializedWithDevices, jsInvoker_, instance_, std::move(deviceIDs)); } jsi::Value updateKeyserverDataInNotifStorage(jsi::Runtime &rt, jsi::Array keyserversData) override { static_assert( bridging::getParameterCount(&T::updateKeyserverDataInNotifStorage) == 2, "Expected updateKeyserverDataInNotifStorage(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::updateKeyserverDataInNotifStorage, jsInvoker_, instance_, std::move(keyserversData)); } jsi::Value removeKeyserverDataFromNotifStorage(jsi::Runtime &rt, jsi::Array keyserverIDsToDelete) override { static_assert( bridging::getParameterCount(&T::removeKeyserverDataFromNotifStorage) == 2, "Expected removeKeyserverDataFromNotifStorage(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::removeKeyserverDataFromNotifStorage, jsInvoker_, instance_, std::move(keyserverIDsToDelete)); } jsi::Value getKeyserverDataFromNotifStorage(jsi::Runtime &rt, jsi::Array keyserverIDs) override { static_assert( bridging::getParameterCount(&T::getKeyserverDataFromNotifStorage) == 2, "Expected getKeyserverDataFromNotifStorage(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::getKeyserverDataFromNotifStorage, jsInvoker_, instance_, std::move(keyserverIDs)); } jsi::Value updateUnreadThickThreadsInNotifsStorage(jsi::Runtime &rt, jsi::Array unreadThickThreadIDs) override { static_assert( bridging::getParameterCount(&T::updateUnreadThickThreadsInNotifsStorage) == 2, "Expected updateUnreadThickThreadsInNotifsStorage(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::updateUnreadThickThreadsInNotifsStorage, jsInvoker_, instance_, std::move(unreadThickThreadIDs)); } jsi::Value getUnreadThickThreadIDsFromNotifsStorage(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getUnreadThickThreadIDsFromNotifsStorage) == 1, "Expected getUnreadThickThreadIDsFromNotifsStorage(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getUnreadThickThreadIDsFromNotifsStorage, jsInvoker_, instance_); } jsi::Value initializeContentOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::initializeContentOutboundSession) == 6, "Expected initializeContentOutboundSession(...) to have 6 parameters"); return bridging::callFromJs( rt, &T::initializeContentOutboundSession, jsInvoker_, instance_, std::move(identityKeys), std::move(prekey), std::move(prekeySignature), std::move(oneTimeKey), std::move(deviceID)); } jsi::Value initializeContentInboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::Object encryptedContent, jsi::String deviceID, double sessionVersion, bool overwrite) override { static_assert( bridging::getParameterCount(&T::initializeContentInboundSession) == 6, "Expected initializeContentInboundSession(...) to have 6 parameters"); return bridging::callFromJs( rt, &T::initializeContentInboundSession, jsInvoker_, instance_, std::move(identityKeys), std::move(encryptedContent), std::move(deviceID), std::move(sessionVersion), std::move(overwrite)); } jsi::Value isContentSessionInitialized(jsi::Runtime &rt, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::isContentSessionInitialized) == 2, "Expected isContentSessionInitialized(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::isContentSessionInitialized, jsInvoker_, instance_, std::move(deviceID)); } jsi::Value initializeNotificationsOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional oneTimeKey, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::initializeNotificationsOutboundSession) == 6, "Expected initializeNotificationsOutboundSession(...) to have 6 parameters"); return bridging::callFromJs( rt, &T::initializeNotificationsOutboundSession, jsInvoker_, instance_, std::move(identityKeys), std::move(prekey), std::move(prekeySignature), std::move(oneTimeKey), std::move(deviceID)); } jsi::Value encrypt(jsi::Runtime &rt, jsi::String message, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::encrypt) == 3, "Expected encrypt(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::encrypt, jsInvoker_, instance_, std::move(message), std::move(deviceID)); } jsi::Value encryptNotification(jsi::Runtime &rt, jsi::String payload, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::encryptNotification) == 3, "Expected encryptNotification(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::encryptNotification, jsInvoker_, instance_, std::move(payload), std::move(deviceID)); } jsi::Value encryptAndPersist(jsi::Runtime &rt, jsi::String message, jsi::String deviceID, jsi::String messageID) override { static_assert( bridging::getParameterCount(&T::encryptAndPersist) == 4, "Expected encryptAndPersist(...) to have 4 parameters"); return bridging::callFromJs( rt, &T::encryptAndPersist, jsInvoker_, instance_, std::move(message), std::move(deviceID), std::move(messageID)); } jsi::Value decrypt(jsi::Runtime &rt, jsi::Object encryptedData, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::decrypt) == 3, "Expected decrypt(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::decrypt, jsInvoker_, instance_, std::move(encryptedData), std::move(deviceID)); } jsi::Value decryptAndPersist(jsi::Runtime &rt, jsi::Object encryptedData, jsi::String deviceID, jsi::String userID, jsi::String messageID) override { static_assert( bridging::getParameterCount(&T::decryptAndPersist) == 5, "Expected decryptAndPersist(...) to have 5 parameters"); return bridging::callFromJs( rt, &T::decryptAndPersist, jsInvoker_, instance_, std::move(encryptedData), std::move(deviceID), std::move(userID), std::move(messageID)); } jsi::Value signMessage(jsi::Runtime &rt, jsi::String message) override { static_assert( bridging::getParameterCount(&T::signMessage) == 2, "Expected signMessage(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::signMessage, jsInvoker_, instance_, std::move(message)); } jsi::Value verifySignature(jsi::Runtime &rt, jsi::String publicKey, jsi::String message, jsi::String signature) override { static_assert( bridging::getParameterCount(&T::verifySignature) == 4, "Expected verifySignature(...) to have 4 parameters"); return bridging::callFromJs( rt, &T::verifySignature, jsInvoker_, instance_, std::move(publicKey), std::move(message), std::move(signature)); } double getCodeVersion(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getCodeVersion) == 1, "Expected getCodeVersion(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getCodeVersion, jsInvoker_, instance_); } void terminate(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::terminate) == 1, "Expected terminate(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::terminate, jsInvoker_, instance_); } jsi::Value setNotifyToken(jsi::Runtime &rt, jsi::String token) override { static_assert( bridging::getParameterCount(&T::setNotifyToken) == 2, "Expected setNotifyToken(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::setNotifyToken, jsInvoker_, instance_, std::move(token)); } jsi::Value clearNotifyToken(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::clearNotifyToken) == 1, "Expected clearNotifyToken(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::clearNotifyToken, jsInvoker_, instance_); } jsi::Value stampSQLiteDBUserID(jsi::Runtime &rt, jsi::String userID) override { static_assert( bridging::getParameterCount(&T::stampSQLiteDBUserID) == 2, "Expected stampSQLiteDBUserID(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::stampSQLiteDBUserID, jsInvoker_, instance_, std::move(userID)); } jsi::Value getSQLiteStampedUserID(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getSQLiteStampedUserID) == 1, "Expected getSQLiteStampedUserID(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getSQLiteStampedUserID, jsInvoker_, instance_); } jsi::Value clearSensitiveData(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::clearSensitiveData) == 1, "Expected clearSensitiveData(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::clearSensitiveData, jsInvoker_, instance_); } bool checkIfDatabaseNeedsDeletion(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::checkIfDatabaseNeedsDeletion) == 1, "Expected checkIfDatabaseNeedsDeletion(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::checkIfDatabaseNeedsDeletion, jsInvoker_, instance_); } void reportDBOperationsFailure(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::reportDBOperationsFailure) == 1, "Expected reportDBOperationsFailure(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::reportDBOperationsFailure, jsInvoker_, instance_); } jsi::Value computeBackupKey(jsi::Runtime &rt, jsi::String password, jsi::String backupID) override { static_assert( bridging::getParameterCount(&T::computeBackupKey) == 3, "Expected computeBackupKey(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::computeBackupKey, jsInvoker_, instance_, std::move(password), std::move(backupID)); } jsi::Value generateRandomString(jsi::Runtime &rt, double size) override { static_assert( bridging::getParameterCount(&T::generateRandomString) == 2, "Expected generateRandomString(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::generateRandomString, jsInvoker_, instance_, std::move(size)); } jsi::Value setCommServicesAuthMetadata(jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken) override { static_assert( bridging::getParameterCount(&T::setCommServicesAuthMetadata) == 4, "Expected setCommServicesAuthMetadata(...) to have 4 parameters"); return bridging::callFromJs( rt, &T::setCommServicesAuthMetadata, jsInvoker_, instance_, std::move(userID), std::move(deviceID), std::move(accessToken)); } jsi::Value getCommServicesAuthMetadata(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getCommServicesAuthMetadata) == 1, "Expected getCommServicesAuthMetadata(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getCommServicesAuthMetadata, jsInvoker_, instance_); } jsi::Value clearCommServicesAuthMetadata(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::clearCommServicesAuthMetadata) == 1, "Expected clearCommServicesAuthMetadata(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::clearCommServicesAuthMetadata, jsInvoker_, instance_); } jsi::Value setCommServicesAccessToken(jsi::Runtime &rt, jsi::String accessToken) override { static_assert( bridging::getParameterCount(&T::setCommServicesAccessToken) == 2, "Expected setCommServicesAccessToken(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::setCommServicesAccessToken, jsInvoker_, instance_, std::move(accessToken)); } jsi::Value clearCommServicesAccessToken(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::clearCommServicesAccessToken) == 1, "Expected clearCommServicesAccessToken(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::clearCommServicesAccessToken, jsInvoker_, instance_); } void startBackupHandler(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::startBackupHandler) == 1, "Expected startBackupHandler(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::startBackupHandler, jsInvoker_, instance_); } void stopBackupHandler(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::stopBackupHandler) == 1, "Expected stopBackupHandler(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::stopBackupHandler, jsInvoker_, instance_); } jsi::Value createUserKeysBackup(jsi::Runtime &rt, jsi::String backupSecret) override { static_assert( bridging::getParameterCount(&T::createUserKeysBackup) == 2, "Expected createUserKeysBackup(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::createUserKeysBackup, jsInvoker_, instance_, std::move(backupSecret)); } jsi::Value createFullBackup(jsi::Runtime &rt, jsi::String backupSecret) override { static_assert( bridging::getParameterCount(&T::createFullBackup) == 2, "Expected createFullBackup(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::createFullBackup, jsInvoker_, instance_, std::move(backupSecret)); } - jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret, jsi::String maxVersion, jsi::String backupID) override { - static_assert( - bridging::getParameterCount(&T::restoreBackup) == 4, - "Expected restoreBackup(...) to have 4 parameters"); - - return bridging::callFromJs( - rt, &T::restoreBackup, jsInvoker_, instance_, std::move(backupSecret), std::move(maxVersion), std::move(backupID)); - } jsi::Value restoreBackupData(jsi::Runtime &rt, jsi::String backupID, jsi::String backupDataKey, jsi::String backupLogDataKey, jsi::String maxVersion) override { static_assert( bridging::getParameterCount(&T::restoreBackupData) == 5, "Expected restoreBackupData(...) to have 5 parameters"); return bridging::callFromJs( rt, &T::restoreBackupData, jsInvoker_, instance_, std::move(backupID), std::move(backupDataKey), std::move(backupLogDataKey), std::move(maxVersion)); } jsi::Value getQRAuthBackupData(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getQRAuthBackupData) == 1, "Expected getQRAuthBackupData(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getQRAuthBackupData, jsInvoker_, instance_); } jsi::Value retrieveLatestBackupInfo(jsi::Runtime &rt, jsi::String userIdentifier) override { static_assert( bridging::getParameterCount(&T::retrieveLatestBackupInfo) == 2, "Expected retrieveLatestBackupInfo(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::retrieveLatestBackupInfo, jsInvoker_, instance_, std::move(userIdentifier)); } jsi::Value setSIWEBackupSecrets(jsi::Runtime &rt, jsi::Object siweBackupSecrets) override { static_assert( bridging::getParameterCount(&T::setSIWEBackupSecrets) == 2, "Expected setSIWEBackupSecrets(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::setSIWEBackupSecrets, jsInvoker_, instance_, std::move(siweBackupSecrets)); } jsi::Value getSIWEBackupSecrets(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getSIWEBackupSecrets) == 1, "Expected getSIWEBackupSecrets(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getSIWEBackupSecrets, jsInvoker_, instance_); } jsi::Value getAllInboundP2PMessages(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getAllInboundP2PMessages) == 1, "Expected getAllInboundP2PMessages(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getAllInboundP2PMessages, jsInvoker_, instance_); } jsi::Value removeInboundP2PMessages(jsi::Runtime &rt, jsi::Array ids) override { static_assert( bridging::getParameterCount(&T::removeInboundP2PMessages) == 2, "Expected removeInboundP2PMessages(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::removeInboundP2PMessages, jsInvoker_, instance_, std::move(ids)); } jsi::Value getInboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) override { static_assert( bridging::getParameterCount(&T::getInboundP2PMessagesByID) == 2, "Expected getInboundP2PMessagesByID(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::getInboundP2PMessagesByID, jsInvoker_, instance_, std::move(ids)); } jsi::Value getOutboundP2PMessagesByID(jsi::Runtime &rt, jsi::Array ids) override { static_assert( bridging::getParameterCount(&T::getOutboundP2PMessagesByID) == 2, "Expected getOutboundP2PMessagesByID(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::getOutboundP2PMessagesByID, jsInvoker_, instance_, std::move(ids)); } jsi::Value getUnsentOutboundP2PMessages(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getUnsentOutboundP2PMessages) == 1, "Expected getUnsentOutboundP2PMessages(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getUnsentOutboundP2PMessages, jsInvoker_, instance_); } jsi::Value markOutboundP2PMessageAsSent(jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::markOutboundP2PMessageAsSent) == 3, "Expected markOutboundP2PMessageAsSent(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::markOutboundP2PMessageAsSent, jsInvoker_, instance_, std::move(messageID), std::move(deviceID)); } jsi::Value removeOutboundP2PMessage(jsi::Runtime &rt, jsi::String messageID, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::removeOutboundP2PMessage) == 3, "Expected removeOutboundP2PMessage(...) to have 3 parameters"); return bridging::callFromJs( rt, &T::removeOutboundP2PMessage, jsInvoker_, instance_, std::move(messageID), std::move(deviceID)); } jsi::Value resetOutboundP2PMessagesForDevice(jsi::Runtime &rt, jsi::String deviceID) override { static_assert( bridging::getParameterCount(&T::resetOutboundP2PMessagesForDevice) == 2, "Expected resetOutboundP2PMessagesForDevice(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::resetOutboundP2PMessagesForDevice, jsInvoker_, instance_, std::move(deviceID)); } jsi::Value getSyncedDatabaseVersion(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::getSyncedDatabaseVersion) == 1, "Expected getSyncedDatabaseVersion(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::getSyncedDatabaseVersion, jsInvoker_, instance_); } jsi::Value markPrekeysAsPublished(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::markPrekeysAsPublished) == 1, "Expected markPrekeysAsPublished(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::markPrekeysAsPublished, jsInvoker_, instance_); } jsi::Value getRelatedMessages(jsi::Runtime &rt, jsi::String messageID) override { static_assert( bridging::getParameterCount(&T::getRelatedMessages) == 2, "Expected getRelatedMessages(...) to have 2 parameters"); return bridging::callFromJs( rt, &T::getRelatedMessages, jsInvoker_, instance_, std::move(messageID)); } jsi::Value searchMessages(jsi::Runtime &rt, jsi::String query, jsi::String threadID, std::optional timestampCursor, std::optional messageIDCursor) override { static_assert( bridging::getParameterCount(&T::searchMessages) == 5, "Expected searchMessages(...) to have 5 parameters"); return bridging::callFromJs( rt, &T::searchMessages, jsInvoker_, instance_, std::move(query), std::move(threadID), std::move(timestampCursor), std::move(messageIDCursor)); } jsi::Value fetchMessages(jsi::Runtime &rt, jsi::String threadID, double limit, double offset) override { static_assert( bridging::getParameterCount(&T::fetchMessages) == 4, "Expected fetchMessages(...) to have 4 parameters"); return bridging::callFromJs( rt, &T::fetchMessages, jsInvoker_, instance_, std::move(threadID), std::move(limit), std::move(offset)); } private: T *instance_; }; Delegate delegate_; }; } // namespace react } // namespace facebook diff --git a/native/native_rust_library/src/backup.rs b/native/native_rust_library/src/backup.rs index 10415cfa8..d2397ccad 100644 --- a/native/native_rust_library/src/backup.rs +++ b/native/native_rust_library/src/backup.rs @@ -1,578 +1,492 @@ mod compaction_upload_promises; mod file_info; mod upload_handler; use crate::argon2_tools::{compute_backup_key, compute_backup_key_str}; use crate::constants::{aes, secure_store}; use crate::ffi::{ create_main_compaction, get_backup_directory_path, get_backup_user_keys_file_path, get_siwe_backup_message_path, restore_from_backup_log, restore_from_main_compaction, secure_store_get, set_backup_id, string_callback, void_callback, }; use crate::utils::future_manager; use crate::utils::jsi_callbacks::handle_string_result_as_callback; use crate::BACKUP_SOCKET_ADDR; use crate::RUNTIME; use backup_client::{ BackupClient, BackupDescriptor, LatestBackupInfoResponse, RequestedData, TryStreamExt, UserIdentity, }; use serde::{Deserialize, Serialize}; use siwe::Message; use std::error::Error; use std::path::PathBuf; pub mod ffi { use super::*; pub use upload_handler::ffi::*; fn handle_backup_creation_error(backup_id: String, err: String) { compaction_upload_promises::resolve(&backup_id, Err(err)); tokio::spawn(upload_handler::compaction::cleanup_files(backup_id)); } async fn prepare_user_keys_backup( backup_id: String, backup_secret: String, pickle_key: String, pickled_account: String, siwe_backup_msg: String, ) -> Result<(), String> { let result = create_user_keys_compaction( backup_id.clone(), backup_secret, pickle_key, pickled_account, ) .await .map_err(|err| err.to_string()); if let Err(err) = result { handle_backup_creation_error(backup_id.clone(), err.to_string()); return Err(err); } if !siwe_backup_msg.is_empty() { if let Err(err) = create_siwe_backup_msg_compaction(&backup_id, siwe_backup_msg).await { handle_backup_creation_error(backup_id.clone(), err.to_string()); return Err(err.to_string()); } } Ok(()) } pub fn create_backup( backup_id: String, backup_secret: String, pickle_key: String, pickled_account: String, siwe_backup_msg: String, promise_id: u32, ) { compaction_upload_promises::insert(backup_id.clone(), promise_id); RUNTIME.spawn(async move { if (prepare_user_keys_backup( backup_id.clone(), backup_secret, pickle_key, pickled_account, siwe_backup_msg.clone(), ) .await) .is_err() { return; } let (future_id, future) = future_manager::new_future::<()>().await; create_main_compaction(&backup_id, future_id); if let Err(err) = future.await { handle_backup_creation_error(backup_id.clone(), err.to_string()); return; } trigger_backup_file_upload(); // The promise will be resolved when the backup is uploaded }); } pub fn create_user_keys_backup( backup_id: String, backup_secret: String, pickle_key: String, pickled_account: String, siwe_backup_msg: String, promise_id: u32, ) { compaction_upload_promises::insert(backup_id.clone(), promise_id); RUNTIME.spawn(async move { if (prepare_user_keys_backup( backup_id.clone(), backup_secret, pickle_key, pickled_account, siwe_backup_msg.clone(), ) .await) .is_err() { return; } let (future_id, future) = future_manager::new_future::<()>().await; set_backup_id(&backup_id, future_id); if let Err(err) = future.await { handle_backup_creation_error(backup_id.clone(), err.to_string()); return; } trigger_backup_file_upload(); // The promise will be resolved when the backup is uploaded }); } - pub fn restore_backup( - backup_secret: String, - backup_id: String, - max_version: String, - promise_id: u32, - ) { - RUNTIME.spawn(async move { - let result = download_backup(backup_secret, backup_id) - .await - .map_err(|err| err.to_string()); - - let result = match result { - Ok(result) => result, - Err(error) => { - void_callback(error, promise_id); - return; - } - }; - - let (future_id, future) = future_manager::new_future::<()>().await; - restore_from_main_compaction( - &result.backup_restoration_path.to_string_lossy(), - &result.backup_data_key, - &max_version, - future_id, - ); - - if let Err(error) = future.await { - void_callback(error, promise_id); - return; - } - - if let Err(error) = - download_and_apply_logs(&result.backup_id, result.backup_log_data_key) - .await - { - void_callback(error.to_string(), promise_id); - return; - } - - void_callback(String::new(), promise_id); - }); - } - pub fn retrieve_backup_keys( backup_secret: String, backup_id: String, promise_id: u32, ) { RUNTIME.spawn(async move { let result = download_backup_keys(backup_id, backup_secret) .await .map_err(|err| err.to_string()); let result = match result { Ok(result) => result, Err(error) => { string_callback(error, promise_id, "".to_string()); return; } }; let serialize_result = serde_json::to_string(&result); handle_string_result_as_callback(serialize_result, promise_id); }); } pub fn restore_backup_data( backup_id: String, backup_data_key: String, backup_log_data_key: String, max_version: String, promise_id: u32, ) { RUNTIME.spawn(async move { - let backup_keys = BackupKeysResult { - backup_id, - backup_data_key, - backup_log_data_key, - }; - let result = download_backup_data(backup_keys) + let result = download_backup_data(backup_id.clone()) .await .map_err(|err| err.to_string()); let result = match result { Ok(result) => result, Err(error) => { void_callback(error, promise_id); return; } }; let (future_id, future) = future_manager::new_future::<()>().await; restore_from_main_compaction( &result.backup_restoration_path.to_string_lossy(), - &result.backup_data_key, + &backup_data_key, &max_version, future_id, ); if let Err(error) = future.await { void_callback(error, promise_id); return; } if let Err(error) = - download_and_apply_logs(&result.backup_id, result.backup_log_data_key) - .await + download_and_apply_logs(&backup_id, backup_log_data_key).await { void_callback(error.to_string(), promise_id); return; } void_callback(String::new(), promise_id); }); } fn get_siwe_backup_data_from_msg( siwe_backup_msg: String, ) -> Result { let siwe_backup_msg_obj: Message = match siwe_backup_msg.parse() { Ok(siwe_backup_msg_obj) => siwe_backup_msg_obj, Err(error) => { return Err(error.to_string()); } }; let siwe_backup_msg_nonce = siwe_backup_msg_obj.nonce; let siwe_backup_msg_statement = match siwe_backup_msg_obj.statement { Some(statement) => statement, None => { return Err("Backup message invalid: missing statement".to_string()); } }; let siwe_backup_msg_issued_at = siwe_backup_msg_obj.issued_at.to_string(); Ok(SIWEBackupData { siwe_backup_msg_nonce, siwe_backup_msg_statement, siwe_backup_msg_issued_at, }) } pub fn retrieve_latest_backup_info(user_identifier: String, promise_id: u32) { RUNTIME.spawn(async move { let latest_backup_id_response = download_latest_backup_info(user_identifier) .await .map_err(|err| err.to_string()); let result = match latest_backup_id_response { Ok(result) => result, Err(error) => { string_callback(error, promise_id, "".to_string()); return; } }; let LatestBackupInfoResponse { backup_id, user_id, siwe_backup_msg, } = result; let siwe_backup_data = match siwe_backup_msg { Some(siwe_backup_msg_value) => { match get_siwe_backup_data_from_msg(siwe_backup_msg_value) { Ok(data) => Some(data), Err(err) => { string_callback(err, promise_id, "".to_string()); return; } } } None => None, }; let result = LatestBackupInfo { backup_id, user_id, siwe_backup_data, }; let serialize_result = serde_json::to_string(&result); handle_string_result_as_callback(serialize_result, promise_id); }); } } pub async fn create_user_keys_compaction( backup_id: String, backup_secret: String, pickle_key: String, pickled_account: String, ) -> Result<(), Box> { let mut backup_key = compute_backup_key(backup_secret.as_bytes(), backup_id.as_bytes())?; let backup_data_key = secure_store_get(secure_store::SECURE_STORE_ENCRYPTION_KEY_ID)?; let backup_log_data_key = secure_store_get(secure_store::SECURE_STORE_BACKUP_LOGS_ENCRYPTION_KEY_ID)?; let user_keys = UserKeys { backup_data_key, backup_log_data_key, pickle_key, pickled_account, }; let encrypted_user_keys = user_keys.encrypt(&mut backup_key)?; let user_keys_file = get_backup_user_keys_file_path(&backup_id)?; tokio::fs::write(user_keys_file, encrypted_user_keys).await?; Ok(()) } pub async fn create_siwe_backup_msg_compaction( backup_id: &str, siwe_backup_msg: String, ) -> Result<(), Box> { let siwe_backup_msg_file = get_siwe_backup_message_path(backup_id)?; tokio::fs::write(siwe_backup_msg_file, siwe_backup_msg).await?; Ok(()) } -async fn download_backup( - backup_secret: String, - backup_id: String, -) -> Result> { - let backup_keys = download_backup_keys(backup_id, backup_secret).await?; - download_backup_data(backup_keys).await -} - async fn download_latest_backup_info( user_identifier: String, ) -> Result> { let backup_client = BackupClient::new(BACKUP_SOCKET_ADDR)?; let latest_backup_descriptor = BackupDescriptor::Latest { user_identifier }; let backup_info_response = backup_client .download_backup_data(&latest_backup_descriptor, RequestedData::BackupInfo) .await?; let LatestBackupInfoResponse { backup_id, user_id, siwe_backup_msg, } = serde_json::from_slice(&backup_info_response)?; Ok(LatestBackupInfoResponse { backup_id, user_id, siwe_backup_msg, }) } async fn download_backup_keys( backup_id: String, backup_secret: String, -) -> Result> { +) -> Result> { let backup_client = BackupClient::new(BACKUP_SOCKET_ADDR)?; let user_identity = get_user_identity_from_secure_store()?; let backup_descriptor = BackupDescriptor::BackupID { backup_id: backup_id.clone(), user_identity: user_identity.clone(), }; let mut encrypted_user_keys = backup_client .download_backup_data(&backup_descriptor, RequestedData::UserKeys) .await?; let mut backup_key = compute_backup_key_str(&backup_secret, &backup_id)?; - let user_keys = - UserKeys::from_encrypted(&mut encrypted_user_keys, &mut backup_key)?; - - Ok(BackupKeysResult { - backup_id, - backup_data_key: user_keys.backup_data_key, - backup_log_data_key: user_keys.backup_log_data_key, - }) + UserKeys::from_encrypted(&mut encrypted_user_keys, &mut backup_key) } async fn download_backup_data( - backup_keys: BackupKeysResult, + backup_id: String, ) -> Result> { let backup_client = BackupClient::new(BACKUP_SOCKET_ADDR)?; let user_identity = get_user_identity_from_secure_store()?; - let BackupKeysResult { - backup_id, - backup_data_key, - backup_log_data_key, - } = backup_keys; - let backup_data_descriptor = BackupDescriptor::BackupID { backup_id: backup_id.clone(), user_identity: user_identity.clone(), }; let encrypted_user_data = backup_client .download_backup_data(&backup_data_descriptor, RequestedData::UserData) .await?; let backup_restoration_path = PathBuf::from(get_backup_directory_path()?).join("restore_compaction"); tokio::fs::write(&backup_restoration_path, encrypted_user_data).await?; Ok(CompactionDownloadResult { backup_restoration_path, - backup_id, - backup_data_key, - backup_log_data_key, }) } async fn download_and_apply_logs( backup_id: &str, backup_log_data_key: String, ) -> Result<(), Box> { let mut backup_log_data_key = backup_log_data_key.into_bytes(); let backup_client = BackupClient::new(BACKUP_SOCKET_ADDR)?; let user_identity = get_user_identity_from_secure_store()?; let stream = backup_client.download_logs(&user_identity, backup_id).await; let mut stream = Box::pin(stream); while let Some(mut log) = stream.try_next().await? { let data = decrypt( backup_log_data_key.as_mut_slice(), log.content.as_mut_slice(), )?; let (future_id, future) = future_manager::new_future::<()>().await; restore_from_backup_log(data, future_id); future.await?; } Ok(()) } fn get_user_identity_from_secure_store() -> Result { Ok(UserIdentity { user_id: secure_store_get(secure_store::USER_ID)?, access_token: secure_store_get(secure_store::COMM_SERVICES_ACCESS_TOKEN)?, device_id: secure_store_get(secure_store::DEVICE_ID)?, }) } -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct BackupKeysResult { - #[serde(rename = "backupID")] - backup_id: String, - backup_data_key: String, - backup_log_data_key: String, -} - // This struct should match `SIWEBackupData` in `lib/types/backup-types.js` #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct SIWEBackupData { siwe_backup_msg_statement: String, siwe_backup_msg_nonce: String, siwe_backup_msg_issued_at: String, } // This struct should match `LatestBackupInfo` in `lib/types/backup-types.js` #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct LatestBackupInfo { #[serde(rename = "backupID")] pub backup_id: String, #[serde(rename = "userID")] pub user_id: String, pub siwe_backup_data: Option, } struct CompactionDownloadResult { - backup_id: String, backup_restoration_path: PathBuf, - backup_data_key: String, - backup_log_data_key: String, } /// Stores the Olm account in `pickled_account`. However, Olm account /// information might be out of date. We have decided we don't need /// to update this when one-time keys (OTKs) or prekeys change. /// The reasoning behind this decision is that the backed-up Olm account /// is primarily used for signing an update to the device list. For these /// operations only the identity signing key is necessary. #[derive(Debug, Serialize, Deserialize)] struct UserKeys { backup_data_key: String, backup_log_data_key: String, pickle_key: String, pickled_account: String, } impl UserKeys { fn encrypt(&self, backup_key: &mut [u8]) -> Result, Box> { let mut json = serde_json::to_vec(self)?; encrypt(backup_key, &mut json) } fn from_encrypted( data: &mut [u8], backup_key: &mut [u8], ) -> Result> { let decrypted = decrypt(backup_key, data)?; Ok(serde_json::from_slice(&decrypted)?) } } fn encrypt(key: &mut [u8], data: &mut [u8]) -> Result, Box> { let encrypted_len = data.len() + aes::IV_LENGTH + aes::TAG_LENGTH; let mut encrypted = vec![0; encrypted_len]; crate::ffi::encrypt(key, data, &mut encrypted)?; Ok(encrypted) } fn decrypt(key: &mut [u8], data: &mut [u8]) -> Result, Box> { let decrypted_len = data.len() - aes::IV_LENGTH - aes::TAG_LENGTH; let mut decrypted = vec![0; decrypted_len]; crate::ffi::decrypt(key, data, &mut decrypted)?; Ok(decrypted) } diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs index 0144aa816..584b4d227 100644 --- a/native/native_rust_library/src/lib.rs +++ b/native/native_rust_library/src/lib.rs @@ -1,574 +1,566 @@ use comm_opaque2::grpc::opaque_error_to_grpc_status as handle_error; use grpc_clients::identity::protos::unauth::DeviceType; use lazy_static::lazy_static; use std::sync::Arc; use tokio::runtime::{Builder, Runtime}; use tonic::Status; mod argon2_tools; mod backup; mod constants; mod identity; mod utils; use crate::argon2_tools::compute_backup_key_str; use crate::utils::jsi_callbacks::{ handle_string_result_as_callback, handle_void_result_as_callback, }; mod generated { // We get the CODE_VERSION from this generated file include!(concat!(env!("OUT_DIR"), "/version.rs")); // We get the IDENTITY_SOCKET_ADDR from this generated file include!(concat!(env!("OUT_DIR"), "/socket_config.rs")); } pub use generated::CODE_VERSION; pub use generated::{BACKUP_SOCKET_ADDR, IDENTITY_SOCKET_ADDR}; #[cfg(not(target_os = "android"))] pub const DEVICE_TYPE: DeviceType = DeviceType::Ios; #[cfg(target_os = "android")] pub const DEVICE_TYPE: DeviceType = DeviceType::Android; lazy_static! { static ref RUNTIME: Arc = Arc::new(Builder::new_multi_thread().enable_all().build().unwrap()); } // ffi uses use backup::ffi::*; use identity::ffi::*; use utils::future_manager::ffi::*; #[allow(clippy::too_many_arguments)] #[cxx::bridge] mod ffi { // Identity Service APIs extern "Rust" { #[cxx_name = "identityRegisterPasswordUser"] fn register_password_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, farcaster_id: String, initial_device_list: String, promise_id: u32, ); #[cxx_name = "identityRegisterReservedPasswordUser"] fn register_reserved_password_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, keyserver_message: String, keyserver_signature: String, initial_device_list: String, promise_id: u32, ); #[cxx_name = "identityLogInPasswordUser"] fn log_in_password_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ); #[cxx_name = "identityRegisterWalletUser"] fn register_wallet_user( siwe_message: String, siwe_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, farcaster_id: String, initial_device_list: String, promise_id: u32, ); #[cxx_name = "identityLogInWalletUser"] fn log_in_wallet_user( siwe_message: String, siwe_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ); #[cxx_name = "identityRestoreUser"] fn restore_user( user_id: String, siwe_message: String, siwe_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, device_list: String, promise_id: u32, ); #[cxx_name = "identityUpdateUserPassword"] fn update_user_password( user_id: String, device_id: String, access_token: String, old_password: String, new_password: String, promise_id: u32, ); #[cxx_name = "identityDeleteWalletUser"] fn delete_wallet_user( user_id: String, device_id: String, access_token: String, promise_id: u32, ); #[cxx_name = "identityDeletePasswordUser"] fn delete_password_user( user_id: String, device_id: String, access_token: String, password: String, promise_id: u32, ); #[cxx_name = "identityLogOut"] fn log_out( user_id: String, device_id: String, access_token: String, promise_id: u32, ); #[cxx_name = "identityLogOutPrimaryDevice"] fn log_out_primary_device( user_id: String, device_id: String, access_token: String, signed_device_list: String, promise_id: u32, ); #[cxx_name = "identityLogOutSecondaryDevice"] fn log_out_secondary_device( user_id: String, device_id: String, access_token: String, promise_id: u32, ); #[cxx_name = "identityGetOutboundKeysForUser"] fn get_outbound_keys_for_user( auth_user_id: String, auth_device_id: String, auth_access_token: String, user_id: String, promise_id: u32, ); #[cxx_name = "identityGetInboundKeysForUser"] fn get_inbound_keys_for_user( auth_user_id: String, auth_device_id: String, auth_access_token: String, user_id: String, promise_id: u32, ); #[cxx_name = "identityRefreshUserPrekeys"] fn refresh_user_prekeys( auth_user_id: String, auth_device_id: String, auth_access_token: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, promise_id: u32, ); #[cxx_name = "identityGenerateNonce"] fn generate_nonce(promise_id: u32); #[cxx_name = "identityVersionSupported"] fn version_supported(promise_id: u32); #[cxx_name = "identityUploadOneTimeKeys"] fn upload_one_time_keys( auth_user_id: String, auth_device_id: String, auth_access_token: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ); #[cxx_name = "identityGetKeyserverKeys"] fn get_keyserver_keys( user_id: String, device_id: String, access_token: String, keyserver_id: String, promise_id: u32, ); #[cxx_name = "identityGetDeviceListForUser"] fn get_device_list_for_user( auth_user_id: String, auth_device_id: String, auth_access_token: String, user_id: String, since_timestamp: i64, promise_id: u32, ); #[cxx_name = "identityGetDeviceListsForUsers"] fn get_device_lists_for_users( auth_user_id: String, auth_device_id: String, auth_access_token: String, user_ids: Vec, promise_id: u32, ); #[cxx_name = "identityUpdateDeviceList"] fn update_device_list( auth_user_id: String, auth_device_id: String, auth_access_token: String, update_payload: String, promise_id: u32, ); #[cxx_name = "identitySyncPlatformDetails"] fn sync_platform_details( auth_user_id: String, auth_device_id: String, auth_access_token: String, promise_id: u32, ); #[cxx_name = "identityUploadSecondaryDeviceKeysAndLogIn"] fn upload_secondary_device_keys_and_log_in( user_id: String, nonce: String, nonce_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ); #[cxx_name = "identityLogInExistingDevice"] fn log_in_existing_device( user_id: String, device_id: String, nonce: String, nonce_signature: String, promise_id: u32, ); #[cxx_name = "identityFindUserIDForWalletAddress"] fn find_user_id_for_wallet_address(wallet_address: String, promise_id: u32); #[cxx_name = "identityFindUserIDForUsername"] fn find_user_id_for_username(username: String, promise_id: u32); // Farcaster #[cxx_name = "identityGetFarcasterUsers"] fn get_farcaster_users(farcaster_ids: Vec, promise_id: u32); #[cxx_name = "identityLinkFarcasterAccount"] fn link_farcaster_account( user_id: String, device_id: String, access_token: String, farcaster_id: String, promise_id: u32, ); #[cxx_name = "identityUnlinkFarcasterAccount"] fn unlink_farcaster_account( user_id: String, device_id: String, access_token: String, promise_id: u32, ); #[cxx_name = "identityFindUserIdentities"] fn find_user_identities( user_id: String, device_id: String, access_token: String, user_ids: Vec, promise_id: u32, ); // Argon2 #[cxx_name = "compute_backup_key"] fn compute_backup_key_str( password: &str, backup_id: &str, ) -> Result<[u8; 32]>; } unsafe extern "C++" { include!("RustCallback.h"); #[namespace = "comm"] #[cxx_name = "stringCallback"] fn string_callback(error: String, promise_id: u32, ret: String); #[namespace = "comm"] #[cxx_name = "voidCallback"] fn void_callback(error: String, promise_id: u32); #[namespace = "comm"] #[cxx_name = "boolCallback"] fn bool_callback(error: String, promise_id: u32, ret: bool); } // AES cryptography #[namespace = "comm"] unsafe extern "C++" { include!("RustAESCrypto.h"); #[allow(unused)] #[cxx_name = "aesGenerateKey"] fn generate_key(buffer: &mut [u8]) -> Result<()>; /// The first two argument aren't mutated but creation of Java ByteBuffer /// requires the underlying bytes to be mutable. #[allow(unused)] #[cxx_name = "aesEncrypt"] fn encrypt( key: &mut [u8], plaintext: &mut [u8], sealed_data: &mut [u8], ) -> Result<()>; /// The first two argument aren't mutated but creation of Java ByteBuffer /// requires the underlying bytes to be mutable. #[allow(unused)] #[cxx_name = "aesDecrypt"] fn decrypt( key: &mut [u8], sealed_data: &mut [u8], plaintext: &mut [u8], ) -> Result<()>; } // Comm Services Auth Metadata Emission #[namespace = "comm"] unsafe extern "C++" { include!("RustCSAMetadataEmitter.h"); #[allow(unused)] #[cxx_name = "sendAuthMetadataToJS"] fn send_auth_metadata_to_js( access_token: String, user_id: String, ) -> Result<()>; } // Backup extern "Rust" { #[cxx_name = "startBackupHandler"] fn start_backup_handler() -> Result<()>; #[cxx_name = "stopBackupHandler"] fn stop_backup_handler() -> Result<()>; #[cxx_name = "triggerBackupFileUpload"] fn trigger_backup_file_upload(); #[cxx_name = "createBackup"] fn create_backup( backup_id: String, backup_secret: String, pickle_key: String, pickled_account: String, siwe_backup_msg: String, promise_id: u32, ); #[cxx_name = "createUserKeysBackup"] fn create_user_keys_backup( backup_id: String, backup_secret: String, pickle_key: String, pickled_account: String, siwe_backup_msg: String, promise_id: u32, ); - #[cxx_name = "restoreBackup"] - fn restore_backup( - backup_secret: String, - backup_id: String, - max_version: String, - promise_id: u32, - ); - #[cxx_name = "restoreBackupData"] fn restore_backup_data( backup_id: String, backup_data_key: String, backup_log_data_key: String, max_version: String, promise_id: u32, ); #[cxx_name = "retrieveBackupKeys"] fn retrieve_backup_keys( backup_secret: String, backup_id: String, promise_id: u32, ); #[cxx_name = "retrieveLatestBackupInfo"] fn retrieve_latest_backup_info(user_identifier: String, promise_id: u32); } // Secure store #[namespace = "comm"] unsafe extern "C++" { include!("RustSecureStore.h"); #[allow(unused)] #[cxx_name = "secureStoreSet"] fn secure_store_set(key: &str, value: String) -> Result<()>; #[cxx_name = "secureStoreGet"] fn secure_store_get(key: &str) -> Result; } // C++ Backup creation #[namespace = "comm"] unsafe extern "C++" { include!("RustBackupExecutor.h"); #[cxx_name = "getBackupDirectoryPath"] fn get_backup_directory_path() -> Result; #[cxx_name = "getBackupFilePath"] fn get_backup_file_path( backup_id: &str, is_attachments: bool, ) -> Result; #[cxx_name = "getBackupLogFilePath"] fn get_backup_log_file_path( backup_id: &str, log_id: &str, is_attachments: bool, ) -> Result; #[cxx_name = "getBackupUserKeysFilePath"] fn get_backup_user_keys_file_path(backup_id: &str) -> Result; #[cxx_name = "getSIWEBackupMessagePath"] fn get_siwe_backup_message_path(backup_id: &str) -> Result; #[cxx_name = "createMainCompaction"] fn create_main_compaction(backup_id: &str, future_id: usize); #[cxx_name = "restoreFromMainCompaction"] fn restore_from_main_compaction( main_compaction_path: &str, main_compaction_encryption_key: &str, max_version: &str, future_id: usize, ); #[cxx_name = "restoreFromBackupLog"] fn restore_from_backup_log(backup_log: Vec, future_id: usize); #[cxx_name = "setBackupID"] fn set_backup_id(backup_id: &str, future_id: usize); } // Future handling from C++ extern "Rust" { #[cxx_name = "resolveUnitFuture"] fn resolve_unit_future(future_id: usize); #[cxx_name = "rejectFuture"] fn reject_future(future_id: usize, error: String); } } #[derive( Debug, derive_more::Display, derive_more::From, derive_more::Error, )] pub enum Error { #[display(fmt = "{}", "_0.message()")] TonicGRPC(Status), #[display(fmt = "{}", "_0")] SerdeJson(serde_json::Error), #[display(fmt = "Missing response data")] MissingResponseData, #[display(fmt = "{}", "_0")] GRPClient(grpc_clients::error::Error), } #[cfg(test)] #[allow(clippy::assertions_on_constants)] mod tests { use super::{BACKUP_SOCKET_ADDR, CODE_VERSION, IDENTITY_SOCKET_ADDR}; #[test] fn test_code_version_exists() { assert!(CODE_VERSION > 0); } #[test] fn test_identity_socket_addr_exists() { assert!(!IDENTITY_SOCKET_ADDR.is_empty()); assert!(!BACKUP_SOCKET_ADDR.is_empty()); } } diff --git a/native/profile/backup-menu.react.js b/native/profile/backup-menu.react.js index 86646b720..57cdd4175 100644 --- a/native/profile/backup-menu.react.js +++ b/native/profile/backup-menu.react.js @@ -1,258 +1,261 @@ // @flow import { useNavigation } from '@react-navigation/native'; import * as React from 'react'; import { Switch, Text, View } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; import { accountHasPassword } from 'lib/shared/account-utils.js'; import { getMessageForException } from 'lib/utils/errors.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import type { ProfileNavigationProp } from './profile.react.js'; import { useClientBackup } from '../backup/use-client-backup.js'; import { useGetBackupSecretForLoggedInUser } from '../backup/use-get-backup-secret.js'; import Button from '../components/button.react.js'; import { commCoreModule } from '../native-modules.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { RestoreSIWEBackupRouteName } from '../navigation/route-names.js'; import { setLocalSettingsActionType } from '../redux/action-types.js'; import { persistConfig } from '../redux/persist.js'; import { useSelector } from '../redux/redux-utils.js'; import { useColors, useStyles } from '../themes/colors.js'; import Alert from '../utils/alert.js'; type Props = { +navigation: ProfileNavigationProp<'BackupMenu'>, +route: NavigationRoute<'BackupMenu'>, }; // eslint-disable-next-line no-unused-vars function BackupMenu(props: Props): React.Node { const styles = useStyles(unboundStyles); const dispatch = useDispatch(); const colors = useColors(); const currentUserInfo = useSelector(state => state.currentUserInfo); const navigation = useNavigation(); const getBackupSecret = useGetBackupSecretForLoggedInUser(); const isBackupEnabled = useSelector( state => state.localSettings.isBackupEnabled, ); const { createFullBackup, retrieveLatestBackupInfo, createUserKeysBackup } = useClientBackup(); const uploadBackup = React.useCallback(async () => { let message; try { const backupID = await createFullBackup(); message = `Success!\n` + `Backup ID: ${backupID}`; } catch (e) { message = `Backup upload error: ${String(getMessageForException(e))}`; console.error(message); } Alert.alert('Upload protocol result', message); }, [createFullBackup]); const uploadUserKeys = React.useCallback(async () => { let message; try { const backupID = await createUserKeysBackup(); message = `Success!\n` + `Backup ID: ${backupID}`; } catch (e) { message = `User Keys upload error: ${String(getMessageForException(e))}`; console.error(message); } Alert.alert('Upload User Keys result', message); }, [createUserKeysBackup]); const testRestoreForPasswordUser = React.useCallback(async () => { let message = 'success'; try { + // eslint-disable-next-line no-unused-vars const [latestBackupInfo, backupSecret] = await Promise.all([ retrieveLatestBackupInfo(), getBackupSecret(), ]); - await commCoreModule.restoreBackup( - backupSecret, - persistConfig.version.toString(), + //TODO add backup keys + await commCoreModule.restoreBackupData( latestBackupInfo.backupID, + '', + '', + persistConfig.version.toString(), ); console.info('Backup restored.'); } catch (e) { message = `Backup restore error: ${String(getMessageForException(e))}`; console.error(message); } Alert.alert('Restore protocol result', message); }, [getBackupSecret, retrieveLatestBackupInfo]); const testLatestBackupInfo = React.useCallback(async () => { let message; try { const backupInfo = await retrieveLatestBackupInfo(); const { backupID, userID } = backupInfo; message = `Success!\n` + `Backup ID: ${backupID},\n` + `userID: ${userID},\n` + `userID check: ${currentUserInfo?.id === userID ? 'true' : 'false'}`; } catch (e) { message = `Latest backup info error: ${String( getMessageForException(e), )}`; console.error(message); } Alert.alert('Latest backup info result', message); }, [currentUserInfo?.id, retrieveLatestBackupInfo]); const testRestoreForSIWEUser = React.useCallback(async () => { let message = 'success'; try { const backupInfo = await retrieveLatestBackupInfo(); const { siweBackupData, backupID } = backupInfo; if (!siweBackupData) { throw new Error('Missing SIWE message for Wallet user backup'); } const { siweBackupMsgNonce, siweBackupMsgIssuedAt, siweBackupMsgStatement, } = siweBackupData; navigation.navigate<'RestoreSIWEBackup'>({ name: RestoreSIWEBackupRouteName, params: { backupID, siweNonce: siweBackupMsgNonce, siweStatement: siweBackupMsgStatement, siweIssuedAt: siweBackupMsgIssuedAt, }, }); } catch (e) { message = `Backup restore error: ${String(getMessageForException(e))}`; console.error(message); } }, [navigation, retrieveLatestBackupInfo]); const onBackupToggled = React.useCallback( (value: boolean) => { dispatch({ type: setLocalSettingsActionType, payload: { isBackupEnabled: value }, }); }, [dispatch], ); const onPressRestoreButton = accountHasPassword(currentUserInfo) ? testRestoreForPasswordUser : testRestoreForSIWEUser; return ( SETTINGS Toggle automatic backup ACTIONS ); } const unboundStyles = { scrollViewContentContainer: { paddingTop: 24, }, scrollView: { backgroundColor: 'panelBackground', }, section: { backgroundColor: 'panelForeground', borderBottomWidth: 1, borderColor: 'panelForegroundBorder', borderTopWidth: 1, marginBottom: 24, marginVertical: 2, }, header: { color: 'panelBackgroundLabel', fontSize: 12, fontWeight: '400', paddingBottom: 3, paddingHorizontal: 24, }, submenuButton: { flexDirection: 'row', paddingHorizontal: 24, paddingVertical: 10, alignItems: 'center', }, submenuText: { color: 'panelForegroundLabel', flex: 1, fontSize: 16, }, row: { flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 24, paddingVertical: 14, }, }; export default BackupMenu; diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js index f33e97f44..21fbecd54 100644 --- a/native/schema/CommCoreModuleSchema.js +++ b/native/schema/CommCoreModuleSchema.js @@ -1,246 +1,241 @@ // @flow 'use strict'; import { TurboModuleRegistry } from 'react-native'; import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport.js'; import type { ClientDBMessageStoreOperation } from 'lib/ops/message-store-ops.js'; import type { ClientDBReportStoreOperation } from 'lib/ops/report-store-ops.js'; import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; import type { OneTimeKeysResult, SignedPrekeys, ClientPublicKeys, EncryptedData, OutboundSessionCreationResult, } from 'lib/types/crypto-types.js'; import type { ClientDBMessageInfo } from 'lib/types/message-types.js'; import type { SIWEBackupSecrets } from 'lib/types/siwe-types.js'; import type { InboundP2PMessage, OutboundP2PMessage, } from 'lib/types/sqlite-types.js'; import type { ClientDBStore, ClientDBStoreOperations, } from 'lib/types/store-ops-types'; import type { ClientDBThreadInfo } from 'lib/types/thread-types.js'; import type { QRAuthBackupData } from 'lib/types/tunnelbroker/qr-code-auth-message-types.js'; type CommServicesAuthMetadata = { +userID?: ?string, +deviceID?: ?string, +accessToken?: ?string, }; interface Spec extends TurboModule { +getDraft: (key: string) => Promise; +updateDraft: (key: string, text: string) => Promise; +moveDraft: (oldKey: string, newKey: string) => Promise; +getClientDBStore: () => Promise; +removeAllDrafts: () => Promise; +getInitialMessagesSync: () => $ReadOnlyArray; +processMessageStoreOperationsSync: ( operations: $ReadOnlyArray, ) => void; +getAllThreadsSync: () => $ReadOnlyArray; +processReportStoreOperationsSync: ( operations: $ReadOnlyArray, ) => void; +processThreadStoreOperationsSync: ( operations: $ReadOnlyArray, ) => void; +processDBStoreOperations: (operations: Object) => Promise; +initializeCryptoAccount: () => Promise; +getUserPublicKey: () => Promise; +getOneTimeKeys: (oneTimeKeysAmount: number) => Promise; +validateAndGetPrekeys: () => Promise; +validateAndUploadPrekeys: ( authUserID: string, authDeviceID: string, authAccessToken: string, ) => Promise; +initializeNotificationsSession: ( identityKeys: string, prekey: string, prekeySignature: string, oneTimeKey: ?string, keyserverID: string, ) => Promise; +isNotificationsSessionInitialized: () => Promise; +isDeviceNotificationsSessionInitialized: ( deviceID: string, ) => Promise; +isNotificationsSessionInitializedWithDevices: ( deviceIDs: $ReadOnlyArray, ) => Promise<{ +[deviceID: string]: boolean }>; +updateKeyserverDataInNotifStorage: ( keyserversData: $ReadOnlyArray<{ +id: string, +unreadCount: number }>, ) => Promise; +removeKeyserverDataFromNotifStorage: ( keyserverIDsToDelete: $ReadOnlyArray, ) => Promise; +getKeyserverDataFromNotifStorage: ( keyserverIDs: $ReadOnlyArray, ) => Promise<$ReadOnlyArray<{ +id: string, +unreadCount: number }>>; +updateUnreadThickThreadsInNotifsStorage: ( unreadThickThreadIDs: $ReadOnlyArray, ) => Promise; +getUnreadThickThreadIDsFromNotifsStorage: () => Promise< $ReadOnlyArray, >; +initializeContentOutboundSession: ( identityKeys: string, prekey: string, prekeySignature: string, oneTimeKey: ?string, deviceID: string, ) => Promise; +initializeContentInboundSession: ( identityKeys: string, encryptedContent: Object, deviceID: string, sessionVersion: number, overwrite: boolean, ) => Promise; +isContentSessionInitialized: (deviceID: string) => Promise; +initializeNotificationsOutboundSession: ( identityKeys: string, prekey: string, prekeySignature: string, oneTimeKey: ?string, deviceID: string, ) => Promise; +encrypt: (message: string, deviceID: string) => Promise; +encryptNotification: ( payload: string, deviceID: string, ) => Promise; +encryptAndPersist: ( message: string, deviceID: string, messageID: string, ) => Promise; +decrypt: (encryptedData: Object, deviceID: string) => Promise; +decryptAndPersist: ( encryptedData: Object, deviceID: string, userID: string, messageID: string, ) => Promise; +signMessage: (message: string) => Promise; +verifySignature: ( publicKey: string, message: string, signature: string, ) => Promise; +getCodeVersion: () => number; +terminate: () => void; +setNotifyToken: (token: string) => Promise; +clearNotifyToken: () => Promise; +stampSQLiteDBUserID: (userID: string) => Promise; +getSQLiteStampedUserID: () => Promise; +clearSensitiveData: () => Promise; +checkIfDatabaseNeedsDeletion: () => boolean; +reportDBOperationsFailure: () => void; +computeBackupKey: (password: string, backupID: string) => Promise; +generateRandomString: (size: number) => Promise; +setCommServicesAuthMetadata: ( userID: string, deviceID: string, accessToken: string, ) => Promise; +getCommServicesAuthMetadata: () => Promise; +clearCommServicesAuthMetadata: () => Promise; +setCommServicesAccessToken: (accessToken: string) => Promise; +clearCommServicesAccessToken: () => Promise; +startBackupHandler: () => void; +stopBackupHandler: () => void; +createUserKeysBackup: (backupSecret: string) => Promise; +createFullBackup: (backupSecret: string) => Promise; - +restoreBackup: ( - backupSecret: string, - maxVersion: string, - backupID: string, - ) => Promise; +restoreBackupData: ( backupID: string, backupDataKey: string, backupLogDataKey: string, maxVersion: string, ) => Promise; +getQRAuthBackupData: () => Promise; +retrieveLatestBackupInfo: (userIdentifier: string) => Promise; +setSIWEBackupSecrets: (siweBackupSecrets: Object) => Promise; +getSIWEBackupSecrets: () => Promise; +getAllInboundP2PMessages: () => Promise>; +removeInboundP2PMessages: (ids: $ReadOnlyArray) => Promise; +getInboundP2PMessagesByID: ( ids: $ReadOnlyArray, ) => Promise>; +getOutboundP2PMessagesByID: ( ids: $ReadOnlyArray, ) => Promise>; +getUnsentOutboundP2PMessages: () => Promise>; +markOutboundP2PMessageAsSent: ( messageID: string, deviceID: string, ) => Promise; +removeOutboundP2PMessage: ( messageID: string, deviceID: string, ) => Promise; +resetOutboundP2PMessagesForDevice: ( deviceID: string, ) => Promise>; +getSyncedDatabaseVersion: () => Promise; +markPrekeysAsPublished: () => Promise; +getRelatedMessages: ( messageID: string, ) => Promise>; +searchMessages: ( query: string, threadID: string, timestampCursor: ?string, messageIDCursor: ?string, ) => Promise>; +fetchMessages: ( threadID: string, limit: number, offset: number, ) => Promise>; } export interface CoreModuleSpec extends Spec { +computeBackupKey: ( password: string, backupID: string, ) => Promise; +decrypt: (encryptedData: EncryptedData, deviceID: string) => Promise; +decryptAndPersist: ( encryptedData: EncryptedData, deviceID: string, userID: string, messageID: string, ) => Promise; +initializeContentInboundSession: ( identityKeys: string, encryptedContent: EncryptedData, deviceID: string, sessionVersion: number, overwrite: boolean, ) => Promise; +setSIWEBackupSecrets: ( siweBackupSecrets: SIWEBackupSecrets, ) => Promise; +getSIWEBackupSecrets: () => Promise; +processDBStoreOperations: ( operations: ClientDBStoreOperations, ) => Promise; +getQRAuthBackupData: () => Promise; } export default (TurboModuleRegistry.getEnforcing( 'CommTurboModule', ): Spec);