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 @@ -122,6 +122,9 @@ jsi::String notifPrekeySignature, jsi::Array contentOneTimeKeys, jsi::Array notifOneTimeKeys) override; + virtual jsi::Value findUserIDForWalletAddress( + jsi::Runtime &rt, + jsi::String walletAddress) 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 @@ -550,7 +550,6 @@ jsiStringToRustString(notifPrekeySignature, rt); auto contentOneTimeKeysRust = jsiStringArrayToRustVec(contentOneTimeKeys, rt); auto notifOneTimeKeysRust = jsiStringArrayToRustVec(notifOneTimeKeys, rt); - return createPromiseAsJSIValue( rt, [=, this](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; @@ -580,4 +579,25 @@ return jsi::Value::undefined(); } +jsi::Value CommRustModule::findUserIDForWalletAddress( + jsi::Runtime &rt, + jsi::String walletAddress) { + auto walletAddressRust = jsiStringToRustString(walletAddress, rt); + return createPromiseAsJSIValue( + rt, [=, this](jsi::Runtime &innerRt, std::shared_ptr promise) { + std::string error; + try { + auto currentID = RustPromiseManager::instance.addPromise( + {promise, this->jsInvoker_, innerRt}); + identityFindUserIDForWalletAddress(walletAddressRust, currentID); + } catch (const std::exception &e) { + error = e.what(); + }; + if (!error.empty()) { + this->jsInvoker_->invokeAsync( + [error, promise]() { promise->reject(error); }); + } + }); +} + } // 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 @@ -57,6 +57,9 @@ static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_uploadSecondaryDeviceKeysAndLogIn(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->uploadSecondaryDeviceKeysAndLogIn(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt), args[4].asString(rt), args[5].asString(rt), args[6].asString(rt), args[7].asString(rt), args[8].asObject(rt).asArray(rt), args[9].asObject(rt).asArray(rt)); } +static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_findUserIDForWalletAddress(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->findUserIDForWalletAddress(rt, args[0].asString(rt)); +} CommRustModuleSchemaCxxSpecJSI::CommRustModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommRustTurboModule", jsInvoker) { @@ -75,6 +78,7 @@ methodMap_["getDeviceListForUser"] = MethodMetadata {5, __hostFunction_CommRustModuleSchemaCxxSpecJSI_getDeviceListForUser}; methodMap_["updateDeviceList"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_updateDeviceList}; methodMap_["uploadSecondaryDeviceKeysAndLogIn"] = MethodMetadata {10, __hostFunction_CommRustModuleSchemaCxxSpecJSI_uploadSecondaryDeviceKeysAndLogIn}; + methodMap_["findUserIDForWalletAddress"] = MethodMetadata {1, __hostFunction_CommRustModuleSchemaCxxSpecJSI_findUserIDForWalletAddress}; } 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 @@ -35,6 +35,7 @@ virtual jsi::Value getDeviceListForUser(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String userID, std::optional sinceTimestamp) = 0; virtual jsi::Value updateDeviceList(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String updatePayload) = 0; virtual jsi::Value uploadSecondaryDeviceKeysAndLogIn(jsi::Runtime &rt, jsi::String userID, jsi::String challengeResponse, 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 findUserIDForWalletAddress(jsi::Runtime &rt, jsi::String walletAddress) = 0; }; @@ -176,6 +177,14 @@ return bridging::callFromJs( rt, &T::uploadSecondaryDeviceKeysAndLogIn, jsInvoker_, instance_, std::move(userID), std::move(challengeResponse), std::move(keyPayload), std::move(keyPayloadSignature), std::move(contentPrekey), std::move(contentPrekeySignature), std::move(notifPrekey), std::move(notifPrekeySignature), std::move(contentOneTimeKeys), std::move(notifOneTimeKeys)); } + jsi::Value findUserIDForWalletAddress(jsi::Runtime &rt, jsi::String walletAddress) override { + static_assert( + bridging::getParameterCount(&T::findUserIDForWalletAddress) == 2, + "Expected findUserIDForWalletAddress(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::findUserIDForWalletAddress, jsInvoker_, instance_, std::move(walletAddress)); + } private: T *instance_; diff --git a/native/native_rust_library/src/exact_user_search.rs b/native/native_rust_library/src/exact_user_search.rs new file mode 100644 --- /dev/null +++ b/native/native_rust_library/src/exact_user_search.rs @@ -0,0 +1,54 @@ +use crate::{ + handle_string_result_as_callback, Error, CODE_VERSION, DEVICE_TYPE, + IDENTITY_SOCKET_ADDR, RUNTIME, +}; +use grpc_clients::identity::{ + get_unauthenticated_client, + protos::unauth::{find_user_id_request, FindUserIdRequest}, +}; +use serde::Serialize; +use tracing::instrument; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct FindUserIDResponse { + #[serde(rename = "userID")] + user_id: Option, + is_reserved: bool, +} + +#[instrument] +pub fn find_user_id_for_wallet_address( + wallet_address: String, + promise_id: u32, +) { + RUNTIME.spawn(async move { + let result = find_user_id_helper(wallet_address).await; + handle_string_result_as_callback(result, promise_id); + }); +} + +async fn find_user_id_helper(wallet_address: String) -> Result { + use find_user_id_request::Identifier as RequestIdentifier; + let find_user_id_request = FindUserIdRequest { + identifier: Some(RequestIdentifier::WalletAddress(wallet_address)), + }; + + let mut identity_client = get_unauthenticated_client( + IDENTITY_SOCKET_ADDR, + CODE_VERSION, + DEVICE_TYPE.as_str_name().to_lowercase(), + ) + .await?; + + let response = identity_client + .find_user_id(find_user_id_request) + .await? + .into_inner(); + + let find_user_id_response = FindUserIDResponse { + user_id: response.user_id, + is_reserved: response.is_reserved, + }; + Ok(serde_json::to_string(&find_user_id_response)?) +} 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 @@ -1,6 +1,7 @@ use backup::ffi::*; use comm_opaque2::client::{Login, Registration}; use comm_opaque2::grpc::opaque_error_to_grpc_status as handle_error; +use exact_user_search::find_user_id_for_wallet_address; use ffi::{bool_callback, string_callback, void_callback}; use grpc_clients::identity::protos::auth::{ GetDeviceListRequest, UpdateDeviceListRequest, @@ -32,6 +33,7 @@ mod argon2_tools; mod backup; mod constants; +mod exact_user_search; mod wallet_registration; use argon2_tools::compute_backup_key_str; @@ -226,6 +228,9 @@ promise_id: u32, ); + #[cxx_name = "identityFindUserIDForWalletAddress"] + fn find_user_id_for_wallet_address(wallet_address: String, promise_id: u32); + // Argon2 #[cxx_name = "compute_backup_key"] fn compute_backup_key_str( diff --git a/native/schema/CommRustModuleSchema.js b/native/schema/CommRustModuleSchema.js --- a/native/schema/CommRustModuleSchema.js +++ b/native/schema/CommRustModuleSchema.js @@ -117,6 +117,7 @@ contentOneTimeKeys: $ReadOnlyArray, notifOneTimeKeys: $ReadOnlyArray, ) => Promise; + +findUserIDForWalletAddress: (walletAddress: string) => Promise; } export default (TurboModuleRegistry.getEnforcing(