diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h @@ -28,7 +28,9 @@ const std::string secureStoreAccountDataKey = "cryptoAccountDataKey"; const std::string publicCryptoAccountID = "publicCryptoAccountID"; - std::unique_ptr cryptoModule; + std::unique_ptr contentCryptoModule; + const std::string notifsCryptoAccountID = "notifsCryptoAccountID"; + std::unique_ptr notifsCryptoModule; DraftStore draftStore; ThreadStore threadStore; MessageStore messageStore; @@ -38,7 +40,8 @@ CommunityStore communityStore; IntegrityStore integrityStore; - void persistCryptoModule(); + void + persistCryptoModules(bool persistContentModule, bool persistNotifsModule); virtual jsi::Value getDraft(jsi::Runtime &rt, jsi::String key) override; virtual jsi::Value diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp @@ -351,7 +351,9 @@ TerminateApp::terminate(); } -void CommCoreModule::persistCryptoModule() { +void CommCoreModule::persistCryptoModules( + bool persistContentModule, + bool persistNotifsModule) { folly::Optional storedSecretKey = CommSecureStore::get(this->secureStoreAccountDataKey); if (!storedSecretKey.hasValue()) { @@ -360,17 +362,37 @@ this->secureStoreAccountDataKey, storedSecretKey.value()); } - crypto::Persist newPersist = - this->cryptoModule->storeAsB64(storedSecretKey.value()); + if (!persistContentModule && !persistNotifsModule) { + return; + } + + crypto::Persist newContentPersist; + if (persistContentModule) { + newContentPersist = + this->contentCryptoModule->storeAsB64(storedSecretKey.value()); + } + + crypto::Persist newNotifsPersist; + if (persistNotifsModule) { + newNotifsPersist = + this->notifsCryptoModule->storeAsB64(storedSecretKey.value()); + } std::promise persistencePromise; std::future persistenceFuture = persistencePromise.get_future(); GlobalDBSingleton::instance.scheduleOrRunCancellable( [=, &persistencePromise]() { try { - DatabaseManager::getQueryExecutor().storeOlmPersistData( - DatabaseManager::getQueryExecutor().getContentAccountID(), - newPersist); + if (persistContentModule) { + DatabaseManager::getQueryExecutor().storeOlmPersistData( + DatabaseManager::getQueryExecutor().getContentAccountID(), + newContentPersist); + } + if (persistNotifsModule) { + DatabaseManager::getQueryExecutor().storeOlmPersistData( + DatabaseManager::getQueryExecutor().getNotifsAccountID(), + newNotifsPersist); + } persistencePromise.set_value(); } catch (std::system_error &e) { persistencePromise.set_exception(std::make_exception_ptr(e)); @@ -391,15 +413,16 @@ return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { - crypto::Persist persist; + crypto::Persist contentPersist; + crypto::Persist notifsPersist; std::string error; try { - std::optional accountData = + std::optional contentAccountData = DatabaseManager::getQueryExecutor().getOlmPersistAccountData( DatabaseManager::getQueryExecutor().getContentAccountID()); - if (accountData.has_value()) { - persist.account = - crypto::OlmBuffer(accountData->begin(), accountData->end()); + if (contentAccountData.has_value()) { + contentPersist.account = crypto::OlmBuffer( + contentAccountData->begin(), contentAccountData->end()); // handle sessions data std::vector sessionsData = DatabaseManager::getQueryExecutor() @@ -408,65 +431,51 @@ crypto::OlmBuffer sessionDataBuffer( sessionsDataItem.session_data.begin(), sessionsDataItem.session_data.end()); - persist.sessions.insert(std::make_pair( + contentPersist.sessions.insert(std::make_pair( sessionsDataItem.target_user_id, sessionDataBuffer)); } } + + std::optional notifsAccountData = + DatabaseManager::getQueryExecutor().getOlmPersistAccountData( + DatabaseManager::getQueryExecutor().getNotifsAccountID()); + if (notifsAccountData.has_value()) { + notifsPersist.account = crypto::OlmBuffer( + notifsAccountData->begin(), notifsAccountData->end()); + } + } catch (std::system_error &e) { error = e.what(); } this->cryptoThread->scheduleTask([=]() { std::string error; - this->cryptoModule.reset(new crypto::CryptoModule( - this->publicCryptoAccountID, storedSecretKey.value(), persist)); - if (persist.isEmpty()) { - crypto::Persist newPersist = - this->cryptoModule->storeAsB64(storedSecretKey.value()); - GlobalDBSingleton::instance.scheduleOrRunCancellable( - [=]() { - std::string error; - try { - DatabaseManager::getQueryExecutor().storeOlmPersistData( - DatabaseManager::getQueryExecutor() - .getContentAccountID(), - newPersist); - } catch (std::system_error &e) { - error = e.what(); - } - this->jsInvoker_->invokeAsync([=]() { - if (error.size()) { - promise->reject(error); - return; - } - }); - }, - promise, - this->jsInvoker_); + this->contentCryptoModule.reset(new crypto::CryptoModule( + this->publicCryptoAccountID, + storedSecretKey.value(), + contentPersist)); + + this->notifsCryptoModule.reset(new crypto::CryptoModule( + this->notifsCryptoAccountID, + storedSecretKey.value(), + notifsPersist)); - } else { - this->cryptoModule->restoreFromB64( - storedSecretKey.value(), persist); - this->jsInvoker_->invokeAsync([=]() { - if (error.size()) { - promise->reject(error); - return; - } - }); - } try { - NotificationsCryptoModule::initializeNotificationsCryptoAccount( - "Comm"); + this->persistCryptoModules( + contentPersist.isEmpty(), notifsPersist.isEmpty()); } catch (const std::exception &e) { error = e.what(); } + this->jsInvoker_->invokeAsync([=]() { if (error.size()) { promise->reject(error); return; } - promise->resolve(jsi::Value::undefined()); }); + + this->jsInvoker_->invokeAsync( + [=]() { promise->resolve(jsi::Value::undefined()); }); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( @@ -481,19 +490,13 @@ std::string error; std::string primaryKeysResult; std::string notificationsKeysResult; - if (this->cryptoModule == nullptr) { + if (this->contentCryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { error = "user has not been initialized"; } else { - primaryKeysResult = this->cryptoModule->getIdentityKeys(); - } - try { - if (!error.size()) { - notificationsKeysResult = - NotificationsCryptoModule::getNotificationsIdentityKeys( - "Comm"); - } - } catch (const std::exception &e) { - error = e.what(); + primaryKeysResult = this->contentCryptoModule->getIdentityKeys(); + notificationsKeysResult = + this->notifsCryptoModule->getIdentityKeys(); } std::string notificationsCurve25519Cpp, notificationsEd25519Cpp, @@ -534,7 +537,8 @@ "curve25519", notificationsCurve25519Cpp)); blobPayloadCpp = folly::toJson(blobPayloadJSON); - signatureCpp = this->cryptoModule->signMessage(blobPayloadCpp); + signatureCpp = + this->contentCryptoModule->signMessage(blobPayloadCpp); } } } @@ -650,19 +654,20 @@ std::string error; std::string contentResult; std::string notifResult; - if (this->cryptoModule == nullptr) { + if (this->contentCryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } try { - contentResult = this->cryptoModule->getOneTimeKeysForPublishing( + contentResult = + this->contentCryptoModule->getOneTimeKeysForPublishing( + oneTimeKeysAmount); + notifResult = this->notifsCryptoModule->getOneTimeKeysForPublishing( oneTimeKeysAmount); - this->persistCryptoModule(); - notifResult = NotificationsCryptoModule:: - getNotificationsOneTimeKeysForPublishing( - oneTimeKeysAmount, "Comm"); + this->persistCryptoModules(true, true); } catch (const std::exception &e) { error = e.what(); } @@ -679,18 +684,6 @@ }); } -std::pair getNotificationsPrekeyAndSignature() { - // TODO: Implement notifs prekey rotation. - // Notifications prekey is not rotated at this moment. It - // is fetched with signature to match identity service API. - std::string notificationsPrekey = - NotificationsCryptoModule::getNotificationsPrekey("Comm"); - std::string notificationsPrekeySignature = - NotificationsCryptoModule::getNotificationsPrekeySignature("Comm"); - - return std::make_pair(notificationsPrekey, notificationsPrekeySignature); -} - jsi::Value CommCoreModule::validateAndUploadPrekeys( jsi::Runtime &rt, jsi::String authUserID, @@ -703,9 +696,11 @@ rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; - std::optional maybePrekeyToUpload; + std::optional maybeContentPrekeyToUpload; + std::optional maybeNotifsPrekeyToUpload; - if (this->cryptoModule == nullptr) { + if (this->contentCryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); @@ -713,10 +708,19 @@ } try { - maybePrekeyToUpload = this->cryptoModule->validatePrekey(); - this->persistCryptoModule(); - if (!maybePrekeyToUpload.has_value()) { - maybePrekeyToUpload = this->cryptoModule->getUnpublishedPrekey(); + maybeContentPrekeyToUpload = + this->contentCryptoModule->validatePrekey(); + maybeNotifsPrekeyToUpload = + this->notifsCryptoModule->validatePrekey(); + this->persistCryptoModules(true, true); + + if (!maybeContentPrekeyToUpload.has_value()) { + maybeContentPrekeyToUpload = + this->contentCryptoModule->getUnpublishedPrekey(); + } + if (!maybeNotifsPrekeyToUpload.has_value()) { + maybeNotifsPrekeyToUpload = + this->notifsCryptoModule->getUnpublishedPrekey(); } } catch (const std::exception &e) { error = e.what(); @@ -726,21 +730,36 @@ this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(error); }); return; - } else if (!maybePrekeyToUpload.has_value()) { + } + + if (!maybeContentPrekeyToUpload.has_value() && + !maybeNotifsPrekeyToUpload.has_value()) { this->jsInvoker_->invokeAsync( [=]() { promise->resolve(jsi::Value::undefined()); }); return; } - std::string prekeyToUpload = maybePrekeyToUpload.value(); + 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 = this->notifsCryptoModule->getPrekey(); + } + std::string prekeyUploadError; try { - std::string prekeySignature = - this->cryptoModule->getPrekeySignature(); - std::string notificationsPrekey, notificationsPrekeySignature; - std::tie(notificationsPrekey, notificationsPrekeySignature) = - getNotificationsPrekeyAndSignature(); + std::string contentPrekeySignature = + this->contentCryptoModule->getPrekeySignature(); + std::string notifsPrekeySignature = + this->notifsCryptoModule->getPrekeySignature(); try { std::promise prekeyPromise; @@ -750,20 +769,20 @@ std::move(prekeyPromise)}; auto currentID = RustPromiseManager::instance.addPromise( std::move(promiseInfo)); - auto prekeyToUploadRust = - rust::String(parseOLMPrekey(prekeyToUpload)); - auto prekeySignatureRust = rust::string(prekeySignature); - auto notificationsPrekeyRust = - rust::String(parseOLMPrekey(notificationsPrekey)); + auto contentPrekeyToUploadRust = + rust::String(parseOLMPrekey(contentPrekeyToUpload)); + auto prekeySignatureRust = rust::string(contentPrekeySignature); + auto notifsPrekeyToUploadRust = + rust::String(parseOLMPrekey(notifsPrekeyToUpload)); auto notificationsPrekeySignatureRust = - rust::string(notificationsPrekeySignature); + rust::string(notifsPrekeySignature); ::identityRefreshUserPrekeys( authUserIDRust, authDeviceIDRust, authAccessTokenRust, - prekeyToUploadRust, + contentPrekeyToUploadRust, prekeySignatureRust, - notificationsPrekeyRust, + notifsPrekeyToUploadRust, notificationsPrekeySignatureRust, currentID); prekeyFuture.get(); @@ -772,8 +791,9 @@ } if (!prekeyUploadError.size()) { - this->cryptoModule->markPrekeyAsPublished(); - this->persistCryptoModule(); + this->contentCryptoModule->markPrekeyAsPublished(); + this->notifsCryptoModule->markPrekeyAsPublished(); + this->persistCryptoModules(true, true); } } catch (std::exception &e) { error = e.what(); @@ -801,32 +821,44 @@ taskType job = [=, &innerRt]() { std::string error; std::string contentPrekey, notifPrekey, contentPrekeySignature, - notifPrekeyBlob, notifPrekeySignature; + notifPrekeySignature; std::optional contentPrekeyBlob; + std::optional notifPrekeyBlob; - if (this->cryptoModule == nullptr) { + if (this->contentCryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); return; } try { - contentPrekeyBlob = this->cryptoModule->validatePrekey(); + contentPrekeyBlob = this->contentCryptoModule->validatePrekey(); if (!contentPrekeyBlob) { - contentPrekeyBlob = this->cryptoModule->getUnpublishedPrekey(); + contentPrekeyBlob = + this->contentCryptoModule->getUnpublishedPrekey(); } if (!contentPrekeyBlob) { - contentPrekeyBlob = this->cryptoModule->getPrekey(); + contentPrekeyBlob = this->contentCryptoModule->getPrekey(); } - this->persistCryptoModule(); - contentPrekeySignature = this->cryptoModule->getPrekeySignature(); + notifPrekeyBlob = this->notifsCryptoModule->validatePrekey(); + if (!notifPrekeyBlob) { + notifPrekeyBlob = + this->notifsCryptoModule->getUnpublishedPrekey(); + } + if (!notifPrekeyBlob) { + notifPrekeyBlob = this->notifsCryptoModule->getPrekey(); + } + this->persistCryptoModules(true, true); - std::tie(notifPrekeyBlob, notifPrekeySignature) = - getNotificationsPrekeyAndSignature(); + contentPrekeySignature = + this->contentCryptoModule->getPrekeySignature(); + notifPrekeySignature = + this->notifsCryptoModule->getPrekeySignature(); contentPrekey = parseOLMPrekey(contentPrekeyBlob.value()); - notifPrekey = parseOLMPrekey(notifPrekeyBlob); + notifPrekey = parseOLMPrekey(notifPrekeyBlob.value()); } catch (const std::exception &e) { error = e.what(); } @@ -880,6 +912,9 @@ std::string error; crypto::EncryptedData result; try { + // Introduced temporarily to make this diff non-breaking change + NotificationsCryptoModule::initializeNotificationsCryptoAccount( + "Comm"); result = NotificationsCryptoModule::initializeNotificationsSession( identityKeysCpp, prekeyCpp, @@ -1075,7 +1110,7 @@ std::string error; crypto::EncryptedData initialEncryptedMessage; try { - this->cryptoModule->initializeOutboundForSendingSession( + this->contentCryptoModule->initializeOutboundForSendingSession( deviceIDCpp, std::vector( identityKeysCpp.begin(), identityKeysCpp.end()), @@ -1087,8 +1122,8 @@ const std::string initMessage = "{\"type\": \"init\"}"; initialEncryptedMessage = - cryptoModule->encrypt(deviceIDCpp, initMessage); - this->persistCryptoModule(); + contentCryptoModule->encrypt(deviceIDCpp, initMessage); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1122,7 +1157,7 @@ std::string error; std::string decryptedMessage; try { - this->cryptoModule->initializeInboundForReceivingSession( + this->contentCryptoModule->initializeInboundForReceivingSession( deviceIDCpp, std::vector( encryptedMessageCpp.begin(), encryptedMessageCpp.end()), @@ -1131,8 +1166,8 @@ crypto::EncryptedData encryptedData{std::vector( encryptedMessageCpp.begin(), encryptedMessageCpp.end())}; decryptedMessage = - cryptoModule->decrypt(deviceIDCpp, encryptedData); - this->persistCryptoModule(); + this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1161,8 +1196,9 @@ std::string error; crypto::EncryptedData encryptedMessage; try { - encryptedMessage = cryptoModule->encrypt(deviceIDCpp, messageCpp); - this->persistCryptoModule(); + encryptedMessage = + contentCryptoModule->encrypt(deviceIDCpp, messageCpp); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1198,8 +1234,8 @@ std::vector(messageCpp.begin(), messageCpp.end()), ENCRYPTED_MESSAGE_TYPE}; decryptedMessage = - cryptoModule->decrypt(deviceIDCpp, encryptedData); - this->persistCryptoModule(); + this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1224,7 +1260,7 @@ std::string error; std::string signature; try { - signature = this->cryptoModule->signMessage(messageStr); + signature = this->contentCryptoModule->signMessage(messageStr); } catch (const std::exception &e) { error = "signing message failed with: " + std::string(e.what()); } @@ -1650,7 +1686,7 @@ try { pickleKey = crypto::Tools::generateRandomString(64); crypto::Persist persist = - this->cryptoModule->storeAsB64(pickleKey); + this->contentCryptoModule->storeAsB64(pickleKey); pickledAccount = std::string(persist.account.begin(), persist.account.end()); } catch (const std::exception &e) { diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h --- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h +++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h @@ -31,15 +31,6 @@ static void initializeNotificationsCryptoAccount(const std::string &callingProcessName); static void clearSensitiveData(); - static std::string - getNotificationsIdentityKeys(const std::string &callingProcessName); - static std::string - getNotificationsPrekey(const std::string &callingProcessName); - static std::string - getNotificationsPrekeySignature(const std::string &callingProcessName); - static std::string getNotificationsOneTimeKeysForPublishing( - const size_t oneTimeKeysAmount, - const std::string &callingProcessName); static crypto::EncryptedData initializeNotificationsSession( const std::string &identityKeys, const std::string &prekey, diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp --- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp +++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp @@ -192,51 +192,6 @@ callingProcessName); } -std::string NotificationsCryptoModule::getNotificationsIdentityKeys( - const std::string &callingProcessName) { - std::string identityKeys; - auto caller = [&identityKeys]( - const std::unique_ptr &cryptoModule) { - identityKeys = cryptoModule->getIdentityKeys(); - }; - NotificationsCryptoModule::callCryptoModule(caller, callingProcessName); - return identityKeys; -} - -std::string NotificationsCryptoModule::getNotificationsPrekey( - const std::string &callingProcessName) { - std::string prekey; - auto caller = - [&prekey](const std::unique_ptr &cryptoModule) { - prekey = cryptoModule->getPrekey(); - }; - NotificationsCryptoModule::callCryptoModule(caller, callingProcessName); - return prekey; -} - -std::string NotificationsCryptoModule::getNotificationsPrekeySignature( - const std::string &callingProcessName) { - std::string prekeySignature; - auto caller = [&prekeySignature]( - const std::unique_ptr &cryptoModule) { - prekeySignature = cryptoModule->getPrekeySignature(); - }; - NotificationsCryptoModule::callCryptoModule(caller, callingProcessName); - return prekeySignature; -} - -std::string NotificationsCryptoModule::getNotificationsOneTimeKeysForPublishing( - const size_t oneTimeKeysAmount, - const std::string &callingProcessName) { - std::string oneTimeKeys; - auto caller = [&oneTimeKeys, oneTimeKeysAmount]( - const std::unique_ptr &cryptoModule) { - oneTimeKeys = cryptoModule->getOneTimeKeysForPublishing(oneTimeKeysAmount); - }; - NotificationsCryptoModule::callCryptoModule(caller, callingProcessName); - return oneTimeKeys; -} - crypto::EncryptedData NotificationsCryptoModule::initializeNotificationsSession( const std::string &identityKeys, const std::string &prekey,