diff --git a/lib/types/identity-service-types.js b/lib/types/identity-service-types.js --- a/lib/types/identity-service-types.js +++ b/lib/types/identity-service-types.js @@ -4,3 +4,17 @@ +userId: string, +accessToken: string, }; + +// This type should not be altered without also updating +// OutboundKeyInfoResponse in native/native_rust_library/src/lib.rs +export type OutboundKeyInfoResponse = { + +payload: string, + +payloadSignature: string, + +socialProof: ?string, + +contentPrekey: string, + +contentPrekeySignature: string, + +notifPrekey: string, + +notifPrekeySignature: string, + +oneTimeContentPrekey: ?string, + +oneTimeNotifPrekey: ?string, +}; diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.h b/native/cpp/CommonCpp/NativeModules/CommRustModule.h --- a/native/cpp/CommonCpp/NativeModules/CommRustModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.h @@ -55,6 +55,11 @@ jsi::String deviceID, jsi::String accessToken, jsi::String password) override; + virtual jsi::Value getOutboundKeysForUserDevice( + jsi::Runtime &rt, + jsi::String identifierType, + jsi::String identifierValue, + jsi::String deviceID) override; public: CommRustModule(std::shared_ptr jsInvoker); diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp --- a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp @@ -199,4 +199,28 @@ }); } +jsi::Value CommRustModule::getOutboundKeysForUserDevice( + jsi::Runtime &rt, + jsi::String identifierType, + jsi::String identifierValue, + jsi::String deviceID) { + return createPromiseAsJSIValue( + rt, + [this, &identifierType, &identifierValue, &deviceID]( + jsi::Runtime &innerRt, std::shared_ptr promise) { + std::string error; + try { + auto currentID = RustPromiseManager::instance.addPromise( + promise, this->jsInvoker_, innerRt); + identityGetOutboundKeysForUserDevice( + jsiStringToRustString(identifierType, innerRt), + jsiStringToRustString(identifierValue, innerRt), + jsiStringToRustString(deviceID, innerRt), + currentID); + } catch (const std::exception &e) { + error = e.what(); + }; + }); +} + } // namespace comm diff --git a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp --- a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp @@ -27,6 +27,9 @@ static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_updatePassword(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->updatePassword(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt)); } +static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_getOutboundKeysForUserDevice(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getOutboundKeysForUserDevice(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt)); +} CommRustModuleSchemaCxxSpecJSI::CommRustModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommRustTurboModule", jsInvoker) { @@ -35,6 +38,7 @@ methodMap_["loginPasswordUser"] = MethodMetadata {10, __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginPasswordUser}; methodMap_["loginWalletUser"] = MethodMetadata {11, __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginWalletUser}; methodMap_["updatePassword"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_updatePassword}; + methodMap_["getOutboundKeysForUserDevice"] = MethodMetadata {3, __hostFunction_CommRustModuleSchemaCxxSpecJSI_getOutboundKeysForUserDevice}; } diff --git a/native/cpp/CommonCpp/_generated/rustJSI.h b/native/cpp/CommonCpp/_generated/rustJSI.h --- a/native/cpp/CommonCpp/_generated/rustJSI.h +++ b/native/cpp/CommonCpp/_generated/rustJSI.h @@ -25,6 +25,7 @@ virtual jsi::Value loginPasswordUser(jsi::Runtime &rt, jsi::String username, jsi::String password, jsi::String keyPayload, jsi::String keyPayloadSignature, jsi::String contentPrekey, jsi::String contentPrekeySignature, jsi::String notifPrekey, jsi::String notifPrekeySignature, jsi::Array contentOneTimeKeys, jsi::Array notifOneTimeKeys) = 0; virtual jsi::Value loginWalletUser(jsi::Runtime &rt, jsi::String siweMessage, jsi::String siweSignature, jsi::String keyPayload, jsi::String keyPayloadSignature, jsi::String contentPrekey, jsi::String contentPrekeySignature, jsi::String notifPrekey, jsi::String notifPrekeySignature, jsi::Array contentOneTimeKeys, jsi::Array notifOneTimeKeys, jsi::String socialProof) = 0; virtual jsi::Value updatePassword(jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken, jsi::String password) = 0; + virtual jsi::Value getOutboundKeysForUserDevice(jsi::Runtime &rt, jsi::String identifierType, jsi::String identifierValue, jsi::String deviceID) = 0; }; @@ -86,6 +87,14 @@ return bridging::callFromJs( rt, &T::updatePassword, jsInvoker_, instance_, std::move(userID), std::move(deviceID), std::move(accessToken), std::move(password)); } + jsi::Value getOutboundKeysForUserDevice(jsi::Runtime &rt, jsi::String identifierType, jsi::String identifierValue, jsi::String deviceID) override { + static_assert( + bridging::getParameterCount(&T::getOutboundKeysForUserDevice) == 4, + "Expected getOutboundKeysForUserDevice(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::getOutboundKeysForUserDevice, jsInvoker_, instance_, std::move(identifierType), std::move(identifierValue), std::move(deviceID)); + } private: T *instance_; diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs --- a/native/native_rust_library/src/lib.rs +++ b/native/native_rust_library/src/lib.rs @@ -21,10 +21,12 @@ use crypto_tools::generate_device_id; use identity::identity_client_service_client::IdentityClientServiceClient; use identity::{ - DeviceKeyUpload, DeviceType, IdentityKeyInfo, OpaqueLoginFinishRequest, - OpaqueLoginStartRequest, PreKey, RegistrationFinishRequest, - RegistrationStartRequest, UpdateUserPasswordFinishRequest, - UpdateUserPasswordStartRequest, WalletLoginRequest, + outbound_keys_for_user_request::Identifier, DeviceKeyUpload, DeviceType, + IdentityKeyInfo, OpaqueLoginFinishRequest, OpaqueLoginStartRequest, + OutboundKeyInfo, OutboundKeysForUserRequest, PreKey, + RegistrationFinishRequest, RegistrationStartRequest, + UpdateUserPasswordFinishRequest, UpdateUserPasswordStartRequest, + WalletLoginRequest, }; #[cfg(not(feature = "android"))] @@ -114,6 +116,14 @@ promise_id: u32, ); + #[cxx_name = "identityGetOutboundKeysForUserDevice"] + fn get_outbound_keys_for_user_device( + identifier_type: String, + identifier_value: String, + device_id: String, + promise_id: u32, + ); + #[cxx_name = "identityGenerateNonce"] fn generate_nonce(promise_id: u32); @@ -518,7 +528,7 @@ }; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; - let update_password_start_respone = identity_client + let update_password_start_response = identity_client .update_user_password_start(update_password_start_request) .await? .into_inner(); @@ -526,11 +536,11 @@ let opaque_registration_upload = client_registration .finish( &update_password_info.password, - &update_password_start_respone.opaque_registration_response, + &update_password_start_response.opaque_registration_response, ) .map_err(handle_error)?; let update_password_finish_request = UpdateUserPasswordFinishRequest { - session_id: update_password_start_respone.session_id, + session_id: update_password_start_response.session_id, opaque_registration_upload, }; @@ -541,6 +551,128 @@ Ok(()) } +struct GetOutboundKeysRequestInfo { + identifier_type: String, + identifier_value: String, + device_id: String, +} + +// This struct should not be altered without also updating +// OutboundKeyInfoResponse in lib/types/identity-service-types.js +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct OutboundKeyInfoResponse { + pub payload: String, + pub payload_signature: String, + pub social_proof: Option, + pub content_prekey: String, + pub content_prekey_signature: String, + pub notif_prekey: String, + pub notif_prekey_signature: String, + pub one_time_content_prekey: Option, + pub one_time_notif_prekey: Option, +} + +impl TryFrom for OutboundKeyInfoResponse { + type Error = Error; + + fn try_from(key_info: OutboundKeyInfo) -> Result { + let identity_info = + key_info.identity_info.ok_or(Error::MissingResponseData)?; + + let IdentityKeyInfo { + payload, + payload_signature, + social_proof, + } = identity_info; + + let content_prekey = + key_info.content_prekey.ok_or(Error::MissingResponseData)?; + + let PreKey { + pre_key: content_prekey_value, + pre_key_signature: content_prekey_signature, + } = content_prekey; + + let notif_prekey = + key_info.notif_prekey.ok_or(Error::MissingResponseData)?; + + let PreKey { + pre_key: notif_prekey_value, + pre_key_signature: notif_prekey_signature, + } = notif_prekey; + + let one_time_content_prekey = key_info.one_time_content_prekey; + let one_time_notif_prekey = key_info.one_time_notif_prekey; + + Ok(Self { + payload, + payload_signature, + social_proof, + content_prekey: content_prekey_value, + content_prekey_signature, + notif_prekey: notif_prekey_value, + notif_prekey_signature, + one_time_content_prekey, + one_time_notif_prekey, + }) + } +} + +fn get_outbound_keys_for_user_device( + identifier_type: String, + identifier_value: String, + device_id: String, + promise_id: u32, +) { + RUNTIME.spawn(async move { + let get_outbound_keys_request_info = GetOutboundKeysRequestInfo { + identifier_type, + identifier_value, + device_id, + }; + let result = + get_outbound_keys_for_user_device_helper(get_outbound_keys_request_info) + .await; + handle_string_result_as_callback(result, promise_id); + }); +} + +async fn get_outbound_keys_for_user_device_helper( + get_outbound_keys_request_info: GetOutboundKeysRequestInfo, +) -> Result { + let identifier = match get_outbound_keys_request_info.identifier_type.as_str() + { + "walletAddress" => Some(Identifier::WalletAddress( + get_outbound_keys_request_info.identifier_value, + )), + "username" => Some(Identifier::Username( + get_outbound_keys_request_info.identifier_value, + )), + _ => { + return Err(Error::TonicGRPC(tonic::Status::invalid_argument( + "invalid identifier", + ))) + } + }; + + let mut identity_client = + IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; + let mut response = identity_client + .get_outbound_keys_for_user(OutboundKeysForUserRequest { identifier }) + .await? + .into_inner(); + + let outbound_key_info = OutboundKeyInfoResponse::try_from( + response + .devices + .remove(&get_outbound_keys_request_info.device_id) + .ok_or(Error::MissingResponseData)?, + )?; + + Ok(serde_json::to_string(&outbound_key_info)?) +} + #[derive( Debug, derive_more::Display, derive_more::From, derive_more::Error, )] @@ -551,4 +683,6 @@ TonicTransport(tonic::transport::Error), #[display(...)] SerdeJson(serde_json::Error), + #[display(...)] + MissingResponseData, } diff --git a/native/schema/CommRustModuleSchema.js b/native/schema/CommRustModuleSchema.js --- a/native/schema/CommRustModuleSchema.js +++ b/native/schema/CommRustModuleSchema.js @@ -50,6 +50,11 @@ accessToken: string, password: string, ) => Promise; + +getOutboundKeysForUserDevice: ( + identifierType: string, + identifierValue: string, + deviceID: string, + ) => Promise; } export default (TurboModuleRegistry.getEnforcing(