diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h @@ -43,7 +43,7 @@ const std::string &oneTimeKeys); std::string getIdentityKeys(); - std::string getOneTimeKeys(size_t oneTimeKeysAmount = 50); + std::string getOneTimeKeysForPublishing(size_t oneTimeKeysAmount = 10); // Prekey rotation methods for X3DH std::uint8_t getNumPrekeys(); diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp @@ -4,6 +4,8 @@ #include "olm/account.hh" #include "olm/session.hh" +#include +#include #include #include @@ -67,13 +69,12 @@ } void CryptoModule::generateOneTimeKeys(size_t oneTimeKeysAmount) { - size_t oneTimeKeysSize = ::olm_account_generate_one_time_keys_random_length( - this->getOlmAccount(), oneTimeKeysAmount); - if (this->keys.oneTimeKeys.size() == oneTimeKeysSize) { - return; - } + size_t numRandomBytesRequired = + ::olm_account_generate_one_time_keys_random_length( + this->getOlmAccount(), oneTimeKeysAmount); OlmBuffer random; - PlatformSpecificTools::generateSecureRandomBytes(random, oneTimeKeysSize); + PlatformSpecificTools::generateSecureRandomBytes( + random, numRandomBytesRequired); if (-1 == ::olm_account_generate_one_time_keys( @@ -133,17 +134,34 @@ this->keys.identityKeys.begin(), this->keys.identityKeys.end()}; } -std::string CryptoModule::getOneTimeKeys(size_t oneTimeKeysAmount) { - this->generateOneTimeKeys(oneTimeKeysAmount); - size_t publishedOneTimeKeys = this->publishOneTimeKeys(); - if (publishedOneTimeKeys != oneTimeKeysAmount) { +std::string +CryptoModule::getOneTimeKeysForPublishing(size_t oneTimeKeysAmount) { + OlmBuffer unpublishedOneTimeKeys; + unpublishedOneTimeKeys.resize( + ::olm_account_one_time_keys_length(this->getOlmAccount())); + if (-1 == + ::olm_account_one_time_keys( + this->getOlmAccount(), + unpublishedOneTimeKeys.data(), + unpublishedOneTimeKeys.size())) { throw std::runtime_error{ - "error generateKeys => invalid amount of one-time keys published. " - "Expected " + - std::to_string(oneTimeKeysAmount) + ", got " + - std::to_string(publishedOneTimeKeys)}; + "error getOneTimeKeysForPublishing => " + + std::string{::olm_account_last_error(this->getOlmAccount())}}; + } + std::string unpublishedKeysString = + std::string{unpublishedOneTimeKeys.begin(), unpublishedOneTimeKeys.end()}; + + folly::dynamic parsedUnpublishedKeys = + folly::parseJson(unpublishedKeysString); + + size_t numUnpublishedKeys = parsedUnpublishedKeys["curve25519"].size(); + + if (numUnpublishedKeys < oneTimeKeysAmount) { + this->generateOneTimeKeys(oneTimeKeysAmount - numUnpublishedKeys); } + this->publishOneTimeKeys(); + return std::string{ this->keys.oneTimeKeys.begin(), this->keys.oneTimeKeys.end()}; } 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 @@ -72,10 +72,7 @@ virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt) override; virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) override; virtual jsi::Value - getPrimaryOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override; - virtual jsi::Value getNotificationsOneTimeKeys( - jsi::Runtime &rt, - double oneTimeKeysAmount) override; + getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override; virtual jsi::Value generateAndGetPrekeys(jsi::Runtime &rt) override; virtual jsi::Value validateAndUploadPrekeys( jsi::Runtime &rt, 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 @@ -565,43 +565,42 @@ return jsiOneTimeKeys; } -jsi::Value CommCoreModule::getPrimaryOneTimeKeys( +jsi::Object parseOneTimeKeysResult( jsi::Runtime &rt, - double oneTimeKeysAmount) { - return createPromiseAsJSIValue( - rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { - taskType job = [=, &innerRt]() { - std::string error; - std::string result; - if (this->cryptoModule == nullptr) { - error = "user has not been initialized"; - } else { - result = this->cryptoModule->getOneTimeKeys(oneTimeKeysAmount); - this->persistCryptoModule(); - } - this->jsInvoker_->invokeAsync([=, &innerRt]() { - if (error.size()) { - promise->reject(error); - return; - } - promise->resolve(parseOLMOneTimeKeys(innerRt, result)); - }); - }; - this->cryptoThread->scheduleTask(job); - }); + 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::Value CommCoreModule::getNotificationsOneTimeKeys( - jsi::Runtime &rt, - double oneTimeKeysAmount) { +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 result; + std::string contentResult; + std::string notifResult; + if (this->cryptoModule == nullptr) { + this->jsInvoker_->invokeAsync([=, &innerRt]() { + promise->reject("user has not been initialized"); + }); + return; + } try { - result = NotificationsCryptoModule::getNotificationsOneTimeKeys( - oneTimeKeysAmount, "Comm"); + contentResult = this->cryptoModule->getOneTimeKeysForPublishing( + oneTimeKeysAmount); + this->persistCryptoModule(); + notifResult = NotificationsCryptoModule:: + getNotificationsOneTimeKeysForPublishing( + oneTimeKeysAmount, "Comm"); } catch (const std::exception &e) { error = e.what(); } @@ -610,7 +609,8 @@ promise->reject(error); return; } - promise->resolve(parseOLMOneTimeKeys(innerRt, result)); + promise->resolve( + parseOneTimeKeysResult(innerRt, contentResult, notifResult)); }); }; this->cryptoThread->scheduleTask(job); 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 @@ -38,7 +38,7 @@ generateAndGetNotificationsPrekey(const std::string &callingProcessName); static std::string getNotificationsPrekeySignature(const std::string &callingProcessName); - static std::string getNotificationsOneTimeKeys( + static std::string getNotificationsOneTimeKeysForPublishing( const size_t oneTimeKeysAmount, const std::string &callingProcessName); static crypto::EncryptedData initializeNotificationsSession( 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 @@ -236,13 +236,13 @@ return prekeySignature; } -std::string NotificationsCryptoModule::getNotificationsOneTimeKeys( +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->getOneTimeKeys(oneTimeKeysAmount); + oneTimeKeys = cryptoModule->getOneTimeKeysForPublishing(oneTimeKeysAmount); }; NotificationsCryptoModule::callCryptoModule(caller, callingProcessName); return oneTimeKeys; diff --git a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp --- a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp @@ -69,11 +69,8 @@ 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_getPrimaryOneTimeKeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - return static_cast(&turboModule)->getPrimaryOneTimeKeys(rt, args[0].asNumber()); -} -static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getNotificationsOneTimeKeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { - return static_cast(&turboModule)->getNotificationsOneTimeKeys(rt, args[0].asNumber()); +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_generateAndGetPrekeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->generateAndGetPrekeys(rt); @@ -181,8 +178,7 @@ methodMap_["processKeyserverStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processKeyserverStoreOperations}; methodMap_["initializeCryptoAccount"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount}; methodMap_["getUserPublicKey"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserPublicKey}; - methodMap_["getPrimaryOneTimeKeys"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getPrimaryOneTimeKeys}; - methodMap_["getNotificationsOneTimeKeys"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getNotificationsOneTimeKeys}; + methodMap_["getOneTimeKeys"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getOneTimeKeys}; methodMap_["generateAndGetPrekeys"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_generateAndGetPrekeys}; methodMap_["validateAndUploadPrekeys"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_validateAndUploadPrekeys}; methodMap_["initializeNotificationsSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsSession}; diff --git a/native/cpp/CommonCpp/_generated/commJSI.h b/native/cpp/CommonCpp/_generated/commJSI.h --- a/native/cpp/CommonCpp/_generated/commJSI.h +++ b/native/cpp/CommonCpp/_generated/commJSI.h @@ -38,8 +38,7 @@ virtual jsi::Value processKeyserverStoreOperations(jsi::Runtime &rt, jsi::Array operations) = 0; virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt) = 0; virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) = 0; - virtual jsi::Value getPrimaryOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) = 0; - virtual jsi::Value getNotificationsOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) = 0; + virtual jsi::Value getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) = 0; virtual jsi::Value generateAndGetPrekeys(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, jsi::String oneTimeKeys, jsi::String keyserverID) = 0; @@ -232,21 +231,13 @@ return bridging::callFromJs( rt, &T::getUserPublicKey, jsInvoker_, instance_); } - jsi::Value getPrimaryOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override { + jsi::Value getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override { static_assert( - bridging::getParameterCount(&T::getPrimaryOneTimeKeys) == 2, - "Expected getPrimaryOneTimeKeys(...) to have 2 parameters"); + bridging::getParameterCount(&T::getOneTimeKeys) == 2, + "Expected getOneTimeKeys(...) to have 2 parameters"); return bridging::callFromJs( - rt, &T::getPrimaryOneTimeKeys, jsInvoker_, instance_, std::move(oneTimeKeysAmount)); - } - jsi::Value getNotificationsOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) override { - static_assert( - bridging::getParameterCount(&T::getNotificationsOneTimeKeys) == 2, - "Expected getNotificationsOneTimeKeys(...) to have 2 parameters"); - - return bridging::callFromJs( - rt, &T::getNotificationsOneTimeKeys, jsInvoker_, instance_, std::move(oneTimeKeysAmount)); + rt, &T::getOneTimeKeys, jsInvoker_, instance_, std::move(oneTimeKeysAmount)); } jsi::Value generateAndGetPrekeys(jsi::Runtime &rt) override { static_assert( diff --git a/native/handlers/peer-to-peer-message-handler.js b/native/handlers/peer-to-peer-message-handler.js --- a/native/handlers/peer-to-peer-message-handler.js +++ b/native/handlers/peer-to-peer-message-handler.js @@ -46,12 +46,10 @@ await commCoreModule.initializeCryptoAccount(); const [ { userID, deviceID, accessToken }, - notificationsOneTimeKeys, - primaryOneTimeKeys, + { contentOneTimeKeys, notificationsOneTimeKeys }, ] = await Promise.all([ commCoreModule.getCommServicesAuthMetadata(), - commCoreModule.getNotificationsOneTimeKeys(message.numberOfKeys), - commCoreModule.getPrimaryOneTimeKeys(message.numberOfKeys), + commCoreModule.getOneTimeKeys(message.numberOfKeys), ]); if (!userID || !deviceID || !accessToken) { @@ -66,7 +64,7 @@ userID, deviceID, accessToken, - getOneTimeKeyArray(primaryOneTimeKeys), + getOneTimeKeyArray(contentOneTimeKeys), getOneTimeKeyArray(notificationsOneTimeKeys), ); } catch (e) { diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js --- a/native/identity-service/identity-service-context-provider.react.js +++ b/native/identity-service/identity-service-context-provider.react.js @@ -201,13 +201,11 @@ await commCoreModule.initializeCryptoAccount(); const [ { blobPayload, signature }, - notificationsOneTimeKeys, - primaryOneTimeKeys, + { contentOneTimeKeys, notificationsOneTimeKeys }, prekeys, ] = await Promise.all([ commCoreModule.getUserPublicKey(), - commCoreModule.getNotificationsOneTimeKeys(ONE_TIME_KEYS_NUMBER), - commCoreModule.getPrimaryOneTimeKeys(ONE_TIME_KEYS_NUMBER), + commCoreModule.getOneTimeKeys(ONE_TIME_KEYS_NUMBER), commCoreModule.generateAndGetPrekeys(), ]); const registrationResult = await commRustModule.registerUser( @@ -219,7 +217,7 @@ prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, - getOneTimeKeyArray(primaryOneTimeKeys), + getOneTimeKeyArray(contentOneTimeKeys), getOneTimeKeyArray(notificationsOneTimeKeys), ); const { userID, accessToken: token } = JSON.parse(registrationResult); diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js --- a/native/schema/CommCoreModuleSchema.js +++ b/native/schema/CommCoreModuleSchema.js @@ -42,6 +42,11 @@ +accessToken?: ?string, }; +type OneTimeKeysResult = { + contentOneTimeKeys: OLMOneTimeKeys, + notificationsOneTimeKeys: OLMOneTimeKeys, +}; + interface Spec extends TurboModule { +getDraft: (key: string) => Promise; +updateDraft: (key: string, text: string) => Promise; @@ -79,12 +84,7 @@ ) => Promise; +initializeCryptoAccount: () => Promise; +getUserPublicKey: () => Promise; - +getPrimaryOneTimeKeys: ( - oneTimeKeysAmount: number, - ) => Promise; - +getNotificationsOneTimeKeys: ( - oneTimeKeysAmount: number, - ) => Promise; + +getOneTimeKeys: (oneTimeKeysAmount: number) => Promise; +generateAndGetPrekeys: () => Promise; +validateAndUploadPrekeys: ( authUserID: string,