diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp index c7c95af1b..8b45d2866 100644 --- a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp @@ -1,176 +1,202 @@ #include "CommRustModule.h" #include "InternalModules/RustPromiseManager.h" #include "JSIRust.h" #include "lib.rs.h" #include namespace comm { using namespace facebook::react; CommRustModule::CommRustModule(std::shared_ptr jsInvoker) : CommRustModuleSchemaCxxSpecJSI(jsInvoker) { } jsi::Value CommRustModule::generateNonce(jsi::Runtime &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); identityGenerateNonce(currentID); } catch (const std::exception &e) { error = e.what(); }; }); } jsi::Value CommRustModule::registerUser( 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) { return createPromiseAsJSIValue( rt, [this, &username, &password, &keyPayload, &keyPayloadSignature, &contentPrekey, &contentPrekeySignature, ¬ifPrekey, ¬ifPrekeySignature, &contentOneTimeKeys, ¬ifOneTimeKeys]( jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { auto currentID = RustPromiseManager::instance.addPromise( promise, this->jsInvoker_, innerRt); identityRegisterUser( jsiStringToRustString(username, innerRt), jsiStringToRustString(password, innerRt), jsiStringToRustString(keyPayload, innerRt), jsiStringToRustString(keyPayloadSignature, innerRt), jsiStringToRustString(contentPrekey, innerRt), jsiStringToRustString(contentPrekeySignature, innerRt), jsiStringToRustString(notifPrekey, innerRt), jsiStringToRustString(notifPrekeySignature, innerRt), jsiStringArrayToRustVec(contentOneTimeKeys, innerRt), jsiStringArrayToRustVec(notifOneTimeKeys, innerRt), currentID); } catch (const std::exception &e) { error = e.what(); }; }); } jsi::Value CommRustModule::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) { return createPromiseAsJSIValue( rt, [this, &username, &password, &keyPayload, &keyPayloadSignature, &contentPrekey, &contentPrekeySignature, ¬ifPrekey, ¬ifPrekeySignature, &contentOneTimeKeys, ¬ifOneTimeKeys]( jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { auto currentID = RustPromiseManager::instance.addPromise( promise, this->jsInvoker_, innerRt); identityLoginPasswordUser( jsiStringToRustString(username, innerRt), jsiStringToRustString(password, innerRt), jsiStringToRustString(keyPayload, innerRt), jsiStringToRustString(keyPayloadSignature, innerRt), jsiStringToRustString(contentPrekey, innerRt), jsiStringToRustString(contentPrekeySignature, innerRt), jsiStringToRustString(notifPrekey, innerRt), jsiStringToRustString(notifPrekeySignature, innerRt), jsiStringArrayToRustVec(contentOneTimeKeys, innerRt), jsiStringArrayToRustVec(notifOneTimeKeys, innerRt), currentID); } catch (const std::exception &e) { error = e.what(); }; }); } jsi::Value CommRustModule::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) { return createPromiseAsJSIValue( rt, [this, &siweMessage, &siweSignature, &keyPayload, &keyPayloadSignature, &contentPrekey, &contentPrekeySignature, ¬ifPrekey, ¬ifPrekeySignature, &contentOneTimeKeys, ¬ifOneTimeKeys, &socialProof](jsi::Runtime &innerRt, std::shared_ptr promise) { std::string error; try { auto currentID = RustPromiseManager::instance.addPromise( promise, this->jsInvoker_, innerRt); identityLoginWalletUser( jsiStringToRustString(siweMessage, innerRt), jsiStringToRustString(siweSignature, innerRt), jsiStringToRustString(keyPayload, innerRt), jsiStringToRustString(keyPayloadSignature, innerRt), jsiStringToRustString(contentPrekey, innerRt), jsiStringToRustString(contentPrekeySignature, innerRt), jsiStringToRustString(notifPrekey, innerRt), jsiStringToRustString(notifPrekeySignature, innerRt), jsiStringArrayToRustVec(contentOneTimeKeys, innerRt), jsiStringArrayToRustVec(notifOneTimeKeys, innerRt), jsiStringToRustString(socialProof, innerRt), currentID); } catch (const std::exception &e) { error = e.what(); }; }); } +jsi::Value CommRustModule::updatePassword( + jsi::Runtime &rt, + jsi::String userID, + jsi::String deviceID, + jsi::String accessToken, + jsi::String password) { + return createPromiseAsJSIValue( + rt, + [this, &userID, &deviceID, &accessToken, &password]( + jsi::Runtime &innerRt, std::shared_ptr promise) { + std::string error; + try { + auto currentID = RustPromiseManager::instance.addPromise( + promise, this->jsInvoker_, innerRt); + identityUpdateUserPassword( + jsiStringToRustString(userID, innerRt), + jsiStringToRustString(deviceID, innerRt), + jsiStringToRustString(accessToken, innerRt), + jsiStringToRustString(password, innerRt), + currentID); + } catch (const std::exception &e) { + error = e.what(); + }; + }); +} + } // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.h b/native/cpp/CommonCpp/NativeModules/CommRustModule.h index 5fb49544a..9e44baad4 100644 --- a/native/cpp/CommonCpp/NativeModules/CommRustModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.h @@ -1,57 +1,63 @@ #pragma once #include "../_generated/rustJSI.h" #include #include #include namespace comm { namespace jsi = facebook::jsi; class CommRustModule : public facebook::react::CommRustModuleSchemaCxxSpecJSI { virtual jsi::Value generateNonce(jsi::Runtime &rt) override; virtual jsi::Value registerUser( 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) override; 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) override; 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) override; + virtual jsi::Value updatePassword( + jsi::Runtime &rt, + jsi::String userID, + jsi::String deviceID, + jsi::String accessToken, + jsi::String password) override; public: CommRustModule(std::shared_ptr jsInvoker); }; } // namespace comm diff --git a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp index 2f1d3ddf0..b4a1c0036 100644 --- a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp @@ -1,38 +1,42 @@ /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). * * Do not edit this file as changes may cause incorrect behavior and will be lost * once the code is regenerated. * * @generated by codegen project: GenerateModuleH.js */ #include "rustJSI.h" namespace facebook { namespace react { static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_generateNonce(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->generateNonce(rt); } static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_registerUser(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->registerUser(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_loginPasswordUser(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->loginPasswordUser(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_loginWalletUser(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->loginWalletUser(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), args[10].asString(rt)); } +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)); +} CommRustModuleSchemaCxxSpecJSI::CommRustModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommRustTurboModule", jsInvoker) { methodMap_["generateNonce"] = MethodMetadata {0, __hostFunction_CommRustModuleSchemaCxxSpecJSI_generateNonce}; methodMap_["registerUser"] = MethodMetadata {10, __hostFunction_CommRustModuleSchemaCxxSpecJSI_registerUser}; methodMap_["loginPasswordUser"] = MethodMetadata {10, __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginPasswordUser}; methodMap_["loginWalletUser"] = MethodMetadata {11, __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginWalletUser}; + methodMap_["updatePassword"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_updatePassword}; } } // namespace react } // namespace facebook diff --git a/native/cpp/CommonCpp/_generated/rustJSI.h b/native/cpp/CommonCpp/_generated/rustJSI.h index ec6ae38f7..c9dd9f90e 100644 --- a/native/cpp/CommonCpp/_generated/rustJSI.h +++ b/native/cpp/CommonCpp/_generated/rustJSI.h @@ -1,89 +1,98 @@ /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). * * Do not edit this file as changes may cause incorrect behavior and will be lost * once the code is regenerated. * * @generated by codegen project: GenerateModuleH.js */ #pragma once #include #include namespace facebook { namespace react { class JSI_EXPORT CommRustModuleSchemaCxxSpecJSI : public TurboModule { protected: CommRustModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker); public: virtual jsi::Value generateNonce(jsi::Runtime &rt) = 0; virtual jsi::Value registerUser(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 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; }; template class JSI_EXPORT CommRustModuleSchemaCxxSpec : public TurboModule { public: jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { return delegate_.get(rt, propName); } protected: CommRustModuleSchemaCxxSpec(std::shared_ptr jsInvoker) : TurboModule("CommRustTurboModule", jsInvoker), delegate_(static_cast(this), jsInvoker) {} private: class Delegate : public CommRustModuleSchemaCxxSpecJSI { public: Delegate(T *instance, std::shared_ptr jsInvoker) : CommRustModuleSchemaCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} jsi::Value generateNonce(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::generateNonce) == 1, "Expected generateNonce(...) to have 1 parameters"); return bridging::callFromJs( rt, &T::generateNonce, jsInvoker_, instance_); } jsi::Value registerUser(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) override { static_assert( bridging::getParameterCount(&T::registerUser) == 11, "Expected registerUser(...) to have 11 parameters"); return bridging::callFromJs( rt, &T::registerUser, jsInvoker_, instance_, std::move(username), std::move(password), 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 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) override { static_assert( bridging::getParameterCount(&T::loginPasswordUser) == 11, "Expected loginPasswordUser(...) to have 11 parameters"); return bridging::callFromJs( rt, &T::loginPasswordUser, jsInvoker_, instance_, std::move(username), std::move(password), 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 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) override { static_assert( bridging::getParameterCount(&T::loginWalletUser) == 12, "Expected loginWalletUser(...) to have 12 parameters"); return bridging::callFromJs( rt, &T::loginWalletUser, jsInvoker_, instance_, std::move(siweMessage), std::move(siweSignature), std::move(keyPayload), std::move(keyPayloadSignature), std::move(contentPrekey), std::move(contentPrekeySignature), std::move(notifPrekey), std::move(notifPrekeySignature), std::move(contentOneTimeKeys), std::move(notifOneTimeKeys), std::move(socialProof)); } + jsi::Value updatePassword(jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken, jsi::String password) override { + static_assert( + bridging::getParameterCount(&T::updatePassword) == 5, + "Expected updatePassword(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::updatePassword, jsInvoker_, instance_, std::move(userID), std::move(deviceID), std::move(accessToken), std::move(password)); + } private: T *instance_; }; Delegate delegate_; }; } // namespace react } // namespace facebook diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs index ee3b0fa53..fa4e6a8ba 100644 --- a/native/native_rust_library/src/lib.rs +++ b/native/native_rust_library/src/lib.rs @@ -1,466 +1,554 @@ -use crate::ffi::string_callback; +use crate::ffi::{string_callback, void_callback}; use crate::identity::Empty; use comm_opaque2::client::{Login, Registration}; use comm_opaque2::grpc::opaque_error_to_grpc_status as handle_error; use lazy_static::lazy_static; use serde::Serialize; use std::sync::Arc; use tokio::runtime::{Builder, Runtime}; use tonic::{transport::Channel, Status}; use tracing::instrument; mod argon2_tools; mod crypto_tools; mod identity_client; mod identity { tonic::include_proto!("identity.client"); } use argon2_tools::compute_backup_key; use crypto_tools::generate_device_id; use identity::identity_client_service_client::IdentityClientServiceClient; use identity::{ DeviceKeyUpload, DeviceType, IdentityKeyInfo, OpaqueLoginFinishRequest, OpaqueLoginStartRequest, PreKey, RegistrationFinishRequest, - RegistrationStartRequest, WalletLoginRequest, + RegistrationStartRequest, UpdateUserPasswordFinishRequest, + UpdateUserPasswordStartRequest, WalletLoginRequest, }; #[cfg(not(feature = "android"))] pub const DEVICE_TYPE: DeviceType = DeviceType::Ios; #[cfg(feature = "android")] pub const DEVICE_TYPE: DeviceType = DeviceType::Android; lazy_static! { pub static ref RUNTIME: Arc = Arc::new( Builder::new_multi_thread() .worker_threads(1) .max_blocking_threads(1) .enable_all() .build() .unwrap() ); } #[cxx::bridge] mod ffi { enum DeviceType { KEYSERVER, WEB, MOBILE, } extern "Rust" { // Identity Service Client type IdentityClient; #[cxx_name = "identityInitializeClient"] fn initialize_identity_client(addr: String) -> Box; #[cxx_name = "identityRegisterUser"] fn register_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ); #[cxx_name = "identityLoginPasswordUser"] fn login_password_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ); #[cxx_name = "identityLoginWalletUser"] fn login_wallet_user( siwe_message: String, siwe_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, social_proof: String, promise_id: u32, ); + #[cxx_name = "identityUpdateUserPassword"] + fn update_user_password( + user_id: String, + device_id: String, + access_token: String, + password: String, + promise_id: u32, + ); + #[cxx_name = "identityGenerateNonce"] fn generate_nonce(promise_id: u32); // Crypto Tools fn generate_device_id(device_type: DeviceType) -> Result; // Argon2 fn compute_backup_key(password: &str, backup_id: &str) -> Result<[u8; 32]>; } unsafe extern "C++" { include!("RustCallback.h"); #[namespace = "comm"] #[cxx_name = "stringCallback"] fn string_callback(error: String, promise_id: u32, ret: String); + + #[namespace = "comm"] + #[cxx_name = "voidCallback"] + fn void_callback(error: String, promise_id: u32); } } fn handle_string_result_as_callback( result: Result, promise_id: u32, ) where E: std::fmt::Display, { match result { Err(e) => string_callback(e.to_string(), promise_id, "".to_string()), Ok(r) => string_callback("".to_string(), promise_id, r), } } +fn handle_void_result_as_callback(result: Result<(), E>, promise_id: u32) +where + E: std::fmt::Display, +{ + match result { + Err(e) => void_callback(e.to_string(), promise_id), + Ok(_) => void_callback("".to_string(), promise_id), + } +} + fn generate_nonce(promise_id: u32) { RUNTIME.spawn(async move { let result = fetch_nonce().await; handle_string_result_as_callback(result, promise_id); }); } async fn fetch_nonce() -> Result { let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; let nonce = identity_client .generate_nonce(Empty {}) .await? .into_inner() .nonce; Ok(nonce) } #[derive(Debug)] pub struct IdentityClient { identity_client: IdentityClientServiceClient, } fn initialize_identity_client(addr: String) -> Box { Box::new(IdentityClient { identity_client: RUNTIME .block_on(IdentityClientServiceClient::connect(addr)) .unwrap(), }) } #[instrument] fn register_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ) { RUNTIME.spawn(async move { let password_user_info = PasswordUserInfo { username, password, key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, }; let result = register_user_helper(password_user_info).await; handle_string_result_as_callback(result, promise_id); }); } struct PasswordUserInfo { username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct UserIDAndDeviceAccessToken { #[serde(rename = "userID")] user_id: String, access_token: String, } async fn register_user_helper( password_user_info: PasswordUserInfo, ) -> Result { let mut client_registration = Registration::new(); let opaque_registration_request = client_registration .start(&password_user_info.password) .map_err(handle_error)?; let registration_start_request = RegistrationStartRequest { opaque_registration_request, username: password_user_info.username, device_key_upload: Some(DeviceKeyUpload { device_key_info: Some(IdentityKeyInfo { payload: password_user_info.key_payload, payload_signature: password_user_info.key_payload_signature, social_proof: None, }), content_upload: Some(PreKey { pre_key: password_user_info.content_prekey, pre_key_signature: password_user_info.content_prekey_signature, }), notif_upload: Some(PreKey { pre_key: password_user_info.notif_prekey, pre_key_signature: password_user_info.notif_prekey_signature, }), one_time_content_prekeys: password_user_info.content_one_time_keys, one_time_notif_prekeys: password_user_info.notif_one_time_keys, device_type: DEVICE_TYPE.into(), }), }; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; let registration_start_response = identity_client .register_password_user_start(registration_start_request) .await? .into_inner(); let opaque_registration_upload = client_registration .finish( &password_user_info.password, ®istration_start_response.opaque_registration_response, ) .map_err(handle_error)?; let registration_finish_request = RegistrationFinishRequest { session_id: registration_start_response.session_id, opaque_registration_upload, }; let registration_finish_response = identity_client .register_password_user_finish(registration_finish_request) .await? .into_inner(); let user_id_and_access_token = UserIDAndDeviceAccessToken { user_id: registration_finish_response.user_id, access_token: registration_finish_response.access_token, }; Ok(serde_json::to_string(&user_id_and_access_token)?) } #[instrument] fn login_password_user( username: String, password: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, promise_id: u32, ) { RUNTIME.spawn(async move { let password_user_info = PasswordUserInfo { username, password, key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, }; let result = login_password_user_helper(password_user_info).await; handle_string_result_as_callback(result, promise_id); }); } async fn login_password_user_helper( password_user_info: PasswordUserInfo, ) -> Result { let mut client_login = Login::new(); let opaque_login_request = client_login .start(&password_user_info.password) .map_err(handle_error)?; let login_start_request = OpaqueLoginStartRequest { opaque_login_request, username: password_user_info.username, device_key_upload: Some(DeviceKeyUpload { device_key_info: Some(IdentityKeyInfo { payload: password_user_info.key_payload, payload_signature: password_user_info.key_payload_signature, social_proof: None, }), content_upload: Some(PreKey { pre_key: password_user_info.content_prekey, pre_key_signature: password_user_info.content_prekey_signature, }), notif_upload: Some(PreKey { pre_key: password_user_info.notif_prekey, pre_key_signature: password_user_info.notif_prekey_signature, }), one_time_content_prekeys: password_user_info.content_one_time_keys, one_time_notif_prekeys: password_user_info.notif_one_time_keys, device_type: DEVICE_TYPE.into(), }), }; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; let login_start_response = identity_client .login_password_user_start(login_start_request) .await? .into_inner(); let opaque_login_upload = client_login .finish(&login_start_response.opaque_login_response) .map_err(handle_error)?; let login_finish_request = OpaqueLoginFinishRequest { session_id: login_start_response.session_id, opaque_login_upload, }; let login_finish_response = identity_client .login_password_user_finish(login_finish_request) .await? .into_inner(); let user_id_and_access_token = UserIDAndDeviceAccessToken { user_id: login_finish_response.user_id, access_token: login_finish_response.access_token, }; Ok(serde_json::to_string(&user_id_and_access_token)?) } struct WalletUserInfo { siwe_message: String, siwe_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, social_proof: String, } #[instrument] fn login_wallet_user( siwe_message: String, siwe_signature: String, key_payload: String, key_payload_signature: String, content_prekey: String, content_prekey_signature: String, notif_prekey: String, notif_prekey_signature: String, content_one_time_keys: Vec, notif_one_time_keys: Vec, social_proof: String, promise_id: u32, ) { RUNTIME.spawn(async move { let wallet_user_info = WalletUserInfo { siwe_message, siwe_signature, key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, social_proof, }; let result = login_wallet_user_helper(wallet_user_info).await; handle_string_result_as_callback(result, promise_id); }); } async fn login_wallet_user_helper( wallet_user_info: WalletUserInfo, ) -> Result { let login_request = WalletLoginRequest { siwe_message: wallet_user_info.siwe_message, siwe_signature: wallet_user_info.siwe_signature, device_key_upload: Some(DeviceKeyUpload { device_key_info: Some(IdentityKeyInfo { payload: wallet_user_info.key_payload, payload_signature: wallet_user_info.key_payload_signature, social_proof: Some(wallet_user_info.social_proof), }), content_upload: Some(PreKey { pre_key: wallet_user_info.content_prekey, pre_key_signature: wallet_user_info.content_prekey_signature, }), notif_upload: Some(PreKey { pre_key: wallet_user_info.notif_prekey, pre_key_signature: wallet_user_info.notif_prekey_signature, }), one_time_content_prekeys: wallet_user_info.content_one_time_keys, one_time_notif_prekeys: wallet_user_info.notif_one_time_keys, device_type: DEVICE_TYPE.into(), }), }; let mut identity_client = IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; let login_response = identity_client .login_wallet_user(login_request) .await? .into_inner(); let user_id_and_access_token = UserIDAndDeviceAccessToken { user_id: login_response.user_id, access_token: login_response.access_token, }; Ok(serde_json::to_string(&user_id_and_access_token)?) } +struct UpdatePasswordInfo { + user_id: String, + device_id: String, + access_token: String, + password: String, +} + +fn update_user_password( + user_id: String, + device_id: String, + access_token: String, + password: String, + promise_id: u32, +) { + RUNTIME.spawn(async move { + let update_password_info = UpdatePasswordInfo { + access_token, + user_id, + device_id, + password, + }; + let result = update_user_password_helper(update_password_info).await; + handle_void_result_as_callback(result, promise_id); + }); +} + +async fn update_user_password_helper( + update_password_info: UpdatePasswordInfo, +) -> Result<(), Error> { + let mut client_registration = Registration::new(); + let opaque_registration_request = client_registration + .start(&update_password_info.password) + .map_err(handle_error)?; + let update_password_start_request = UpdateUserPasswordStartRequest { + opaque_registration_request, + access_token: update_password_info.access_token, + user_id: update_password_info.user_id, + device_id_key: update_password_info.device_id, + }; + let mut identity_client = + IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?; + let update_password_start_respone = identity_client + .update_user_password_start(update_password_start_request) + .await? + .into_inner(); + + let opaque_registration_upload = client_registration + .finish( + &update_password_info.password, + &update_password_start_respone.opaque_registration_response, + ) + .map_err(handle_error)?; + let update_password_finish_request = UpdateUserPasswordFinishRequest { + session_id: update_password_start_respone.session_id, + opaque_registration_upload, + }; + + identity_client + .update_user_password_finish(update_password_finish_request) + .await?; + + Ok(()) +} + #[derive( Debug, derive_more::Display, derive_more::From, derive_more::Error, )] pub enum Error { #[display(...)] TonicGRPC(Status), #[display(...)] TonicTransport(tonic::transport::Error), #[display(...)] SerdeJson(serde_json::Error), } diff --git a/native/schema/CommRustModuleSchema.js b/native/schema/CommRustModuleSchema.js index fec662125..01ba040f8 100644 --- a/native/schema/CommRustModuleSchema.js +++ b/native/schema/CommRustModuleSchema.js @@ -1,51 +1,57 @@ // @flow 'use strict'; import { TurboModuleRegistry } from 'react-native'; import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport.js'; export interface Spec extends TurboModule { +generateNonce: () => Promise; +registerUser: ( username: string, password: string, keyPayload: string, keyPayloadSignature: string, contentPrekey: string, contentPrekeySignature: string, notifPrekey: string, notifPrekeySignature: string, contentOneTimeKeys: $ReadOnlyArray, notifOneTimeKeys: $ReadOnlyArray, ) => Promise; +loginPasswordUser: ( username: string, password: string, keyPayload: string, keyPayloadSignature: string, contentPrekey: string, contentPrekeySignature: string, notifPrekey: string, notifPrekeySignature: string, contentOneTimeKeys: $ReadOnlyArray, notifOneTimeKeys: $ReadOnlyArray, ) => Promise; +loginWalletUser: ( siweMessage: string, siweSignature: string, keyPayload: string, keyPayloadSignature: string, contentPrekey: string, contentPrekeySignature: string, notifPrekey: string, notifPrekeySignature: string, contentOneTimeKeys: $ReadOnlyArray, notifOneTimeKeys: $ReadOnlyArray, socialProof: string, ) => Promise; + +updatePassword: ( + userID: string, + deviceID: string, + accessToken: string, + password: string, + ) => Promise; } export default (TurboModuleRegistry.getEnforcing( 'CommRustTurboModule', ): Spec);