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,6 +28,8 @@ const std::string secureStoreAccountDataKey = "cryptoAccountDataKey"; const std::string publicCryptoAccountID = "publicCryptoAccountID"; std::unique_ptr cryptoModule; + const std::string notifsCryptoAccountID = "notifsCryptoAccountID"; + std::unique_ptr notifsCryptoModule; DraftStore draftStore; ThreadStore threadStore; MessageStore messageStore; @@ -36,7 +38,8 @@ KeyserverStore keyserverStore; CommunityStore communityStore; - 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 @@ -333,7 +333,9 @@ TerminateApp::terminate(); } -void CommCoreModule::persistCryptoModule() { +void CommCoreModule::persistCryptoModules( + bool persistContentModule, + bool persistNotifsModule) { folly::Optional storedSecretKey = CommSecureStore::get(this->secureStoreAccountDataKey); if (!storedSecretKey.hasValue()) { @@ -342,20 +344,39 @@ this->secureStoreAccountDataKey, storedSecretKey.value()); } - crypto::Persist newPersist = - this->cryptoModule->storeAsB64(storedSecretKey.value()); + if (!persistContentModule && !persistNotifsModule) { + return; + } + + crypto::Persist newPersist; + if (persistContentModule) { + newPersist = this->cryptoModule->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(true, newPersist); - persistencePromise.set_value(); - } catch (std::system_error &e) { - persistencePromise.set_exception(std::make_exception_ptr(e)); - } - }); + GlobalDBSingleton::instance.scheduleOrRunCancellable( + [=, &persistencePromise]() { + try { + if (persistContentModule) { + DatabaseManager::getQueryExecutor().storeOlmPersistData( + true, newPersist); + } + if (persistNotifsModule) { + DatabaseManager::getQueryExecutor().storeOlmPersistData( + false, newNotifsPersist); + } + persistencePromise.set_value(); + } catch (std::system_error &e) { + persistencePromise.set_exception(std::make_exception_ptr(e)); + } + }); persistenceFuture.get(); } @@ -372,6 +393,7 @@ rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=]() { crypto::Persist persist; + crypto::Persist notifsPersist; std::string error; try { std::optional accountData = @@ -392,6 +414,15 @@ sessionsDataItem.target_user_id, sessionDataBuffer)); } } + + std::optional notifsAccountData = + DatabaseManager::getQueryExecutor().getOlmPersistAccountData( + false); + if (notifsAccountData.has_value()) { + notifsPersist.account = crypto::OlmBuffer( + notifsAccountData->begin(), notifsAccountData->end()); + } + } catch (std::system_error &e) { error = e.what(); } @@ -400,51 +431,38 @@ 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( - true, newPersist); - } catch (std::system_error &e) { - error = e.what(); - } - this->jsInvoker_->invokeAsync([=]() { - if (error.size()) { - promise->reject(error); - return; - } - }); - }, - promise, - this->jsInvoker_); - } else { - this->cryptoModule->restoreFromB64( - storedSecretKey.value(), persist); - this->jsInvoker_->invokeAsync([=]() { - if (error.size()) { - promise->reject(error); - return; - } - }); - } + this->notifsCryptoModule.reset(new crypto::CryptoModule( + this->notifsCryptoAccountID, + storedSecretKey.value(), + notifsPersist)); + try { - NotificationsCryptoModule::initializeNotificationsCryptoAccount( - "Comm"); + this->persistCryptoModules( + persist.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()); }); + + if (!persist.isEmpty()) { + this->cryptoModule->restoreFromB64( + storedSecretKey.value(), persist); + } + + if (!notifsPersist.isEmpty()) { + this->notifsCryptoModule->restoreFromB64( + storedSecretKey.value(), notifsPersist); + } + + this->jsInvoker_->invokeAsync( + [=]() { promise->resolve(jsi::Value::undefined()); }); }); }; GlobalDBSingleton::instance.scheduleOrRunCancellable( @@ -459,19 +477,12 @@ std::string error; std::string primaryKeysResult; std::string notificationsKeysResult; - if (this->cryptoModule == nullptr) { + if (this->cryptoModule == 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(); + notificationsKeysResult = this->cryptoModule->getIdentityKeys(); } std::string notificationsCurve25519Cpp, notificationsEd25519Cpp, @@ -607,7 +618,8 @@ std::string error; std::string contentResult; std::string notifResult; - if (this->cryptoModule == nullptr) { + if (this->cryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); @@ -616,10 +628,9 @@ try { contentResult = this->cryptoModule->getOneTimeKeysForPublishing( oneTimeKeysAmount); - this->persistCryptoModule(); - notifResult = NotificationsCryptoModule:: - getNotificationsOneTimeKeysForPublishing( - oneTimeKeysAmount, "Comm"); + notifResult = this->notifsCryptoModule->getOneTimeKeysForPublishing( + oneTimeKeysAmount); + this->persistCryptoModules(true, true); } catch (const std::exception &e) { error = e.what(); } @@ -636,18 +647,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, @@ -661,8 +660,10 @@ taskType job = [=, &innerRt]() { std::string error; std::optional maybePrekeyToUpload; + std::optional maybeNotifsPrekeyToUpload; - if (this->cryptoModule == nullptr) { + if (this->cryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); @@ -671,10 +672,17 @@ try { maybePrekeyToUpload = this->cryptoModule->validatePrekey(); - this->persistCryptoModule(); + maybeNotifsPrekeyToUpload = + this->notifsCryptoModule->validatePrekey(); + this->persistCryptoModules(true, true); + if (!maybePrekeyToUpload.has_value()) { maybePrekeyToUpload = this->cryptoModule->getUnpublishedPrekey(); } + if (!maybeNotifsPrekeyToUpload.has_value()) { + maybeNotifsPrekeyToUpload = + this->notifsCryptoModule->getUnpublishedPrekey(); + } } catch (const std::exception &e) { error = e.what(); } @@ -683,21 +691,23 @@ this->jsInvoker_->invokeAsync( [=, &innerRt]() { promise->reject(error); }); return; - } else if (!maybePrekeyToUpload.has_value()) { + } else if ( + !maybePrekeyToUpload.has_value() || + !maybeNotifsPrekeyToUpload.has_value()) { this->jsInvoker_->invokeAsync( [=]() { promise->resolve(jsi::Value::undefined()); }); return; } std::string prekeyToUpload = maybePrekeyToUpload.value(); + std::string notifsPrekeyToUpload = maybeNotifsPrekeyToUpload.value(); std::string prekeyUploadError; try { std::string prekeySignature = this->cryptoModule->getPrekeySignature(); - std::string notificationsPrekey, notificationsPrekeySignature; - std::tie(notificationsPrekey, notificationsPrekeySignature) = - getNotificationsPrekeyAndSignature(); + std::string notifsPrekeySignature = + this->notifsCryptoModule->getPrekeySignature(); try { std::promise prekeyPromise; @@ -713,8 +723,8 @@ authAccessTokenRust, rust::string(prekeyToUpload), rust::string(prekeySignature), - rust::string(notificationsPrekey), - rust::string(notificationsPrekeySignature), + rust::string(notifsPrekeyToUpload), + rust::string(notifsPrekeySignature), currentID); prekeyFuture.get(); } catch (const std::exception &e) { @@ -723,7 +733,8 @@ if (!prekeyUploadError.size()) { this->cryptoModule->markPrekeyAsPublished(); - this->persistCryptoModule(); + this->notifsCryptoModule->markPrekeyAsPublished(); + this->persistCryptoModules(true, true); } } catch (std::exception &e) { error = e.what(); @@ -750,10 +761,12 @@ rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { taskType job = [=, &innerRt]() { std::string error; - std::string contentPrekeySignature, notifPrekey, notifPrekeySignature; + std::string contentPrekeySignature, notifPrekeySignature; std::optional contentPrekey; + std::optional notifPrekey; - if (this->cryptoModule == nullptr) { + if (this->cryptoModule == nullptr || + this->notifsCryptoModule == nullptr) { this->jsInvoker_->invokeAsync([=, &innerRt]() { promise->reject("user has not been initialized"); }); @@ -767,12 +780,19 @@ if (!contentPrekey) { contentPrekey = this->cryptoModule->getPrekey(); } - this->persistCryptoModule(); - contentPrekeySignature = this->cryptoModule->getPrekeySignature(); + notifPrekey = this->notifsCryptoModule->validatePrekey(); + if (!notifPrekey) { + notifPrekey = this->notifsCryptoModule->getUnpublishedPrekey(); + } + if (!notifPrekey) { + notifPrekey = this->notifsCryptoModule->getPrekey(); + } + this->persistCryptoModules(true, true); - std::tie(notifPrekey, notifPrekeySignature) = - getNotificationsPrekeyAndSignature(); + contentPrekeySignature = this->cryptoModule->getPrekeySignature(); + notifPrekeySignature = + this->notifsCryptoModule->getPrekeySignature(); } catch (const std::exception &e) { error = e.what(); @@ -788,7 +808,7 @@ auto contentPrekeySignatureJSI = jsi::String::createFromUtf8(innerRt, contentPrekeySignature); auto notifPrekeyJSI = - jsi::String::createFromUtf8(innerRt, notifPrekey); + jsi::String::createFromUtf8(innerRt, notifPrekey.value()); auto notifPrekeySignatureJSI = jsi::String::createFromUtf8(innerRt, notifPrekeySignature); @@ -827,6 +847,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, @@ -970,7 +993,7 @@ const std::string initMessage = "{\"type\": \"init\"}"; initialEncryptedMessage = cryptoModule->encrypt(deviceIDCpp, initMessage); - this->persistCryptoModule(); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1014,7 +1037,7 @@ encryptedMessageCpp.begin(), encryptedMessageCpp.end())}; decryptedMessage = cryptoModule->decrypt(deviceIDCpp, encryptedData); - this->persistCryptoModule(); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1044,7 +1067,7 @@ crypto::EncryptedData encryptedMessage; try { encryptedMessage = cryptoModule->encrypt(deviceIDCpp, messageCpp); - this->persistCryptoModule(); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } @@ -1081,7 +1104,7 @@ ENCRYPTED_MESSAGE_TYPE}; decryptedMessage = cryptoModule->decrypt(deviceIDCpp, encryptedData); - this->persistCryptoModule(); + this->persistCryptoModules(true, false); } catch (const std::exception &e) { error = e.what(); } 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 @@ -30,15 +30,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,