diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js index 229e60bad..d7dd83f93 100644 --- a/native/identity-service/identity-service-context-provider.react.js +++ b/native/identity-service/identity-service-context-provider.react.js @@ -1,729 +1,709 @@ // @flow import * as React from 'react'; import { getOneTimeKeyValues } from 'lib/shared/crypto-utils.js'; import { createAndSignInitialDeviceList } from 'lib/shared/device-list-utils.js'; import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; import { type IdentityKeysBlob, identityKeysBlobValidator, type OneTimeKeysResultValues, } from 'lib/types/crypto-types.js'; import { type DeviceOlmInboundKeys, deviceOlmInboundKeysValidator, type DeviceOlmOutboundKeys, deviceOlmOutboundKeysValidator, farcasterUsersValidator, identityAuthResultValidator, type IdentityServiceClient, ONE_TIME_KEYS_NUMBER, type SignedDeviceList, signedDeviceListHistoryValidator, type SignedNonce, type UserAuthMetadata, userDeviceOlmInboundKeysValidator, type UserDevicesOlmInboundKeys, type UserDevicesOlmOutboundKeys, type UsersSignedDeviceLists, usersSignedDeviceListsValidator, identitiesValidator, } from 'lib/types/identity-service-types.js'; import { getContentSigningKey } from 'lib/utils/crypto-utils.js'; import { assertWithValidator } from 'lib/utils/validation-utils.js'; import { getCommServicesAuthMetadataEmitter } from '../event-emitters/csa-auth-metadata-emitter.js'; import { commCoreModule, commRustModule } from '../native-modules.js'; import { useSelector } from '../redux/redux-utils.js'; type Props = { +children: React.Node, }; function IdentityServiceContextProvider(props: Props): React.Node { const { children } = props; const userIDPromiseRef = React.useRef>(); if (!userIDPromiseRef.current) { userIDPromiseRef.current = (async () => { const { userID } = await commCoreModule.getCommServicesAuthMetadata(); return userID; })(); } React.useEffect(() => { const metadataEmitter = getCommServicesAuthMetadataEmitter(); const subscription = metadataEmitter.addListener( 'commServicesAuthMetadata', (authMetadata: UserAuthMetadata) => { userIDPromiseRef.current = Promise.resolve(authMetadata.userID); }, ); return () => subscription.remove(); }, []); const accessToken = useSelector(state => state.commServicesAccessToken); const getAuthMetadata = React.useCallback< () => Promise<{ +deviceID: string, +userID: string, +accessToken: string, }>, >(async () => { const deviceID = await getContentSigningKey(); const userID = await userIDPromiseRef.current; if (!deviceID || !userID || !accessToken) { throw new Error('Identity service client is not initialized'); } return { deviceID, userID, accessToken }; }, [accessToken]); - const processAuthResult = async ( - authResult: string, - username: string, - deviceID: string, - ) => { - const { userID, accessToken: token } = JSON.parse(authResult); + const processAuthResult = async (authResult: string, deviceID: string) => { + const { userID, accessToken: token, username } = JSON.parse(authResult); const identityAuthResult = { accessToken: token, userID, username, }; const validatedResult = assertWithValidator( identityAuthResult, identityAuthResultValidator, ); await commCoreModule.setCommServicesAuthMetadata( validatedResult.userID, deviceID, validatedResult.accessToken, ); return validatedResult; }; const client = React.useMemo( () => ({ deleteWalletUser: async () => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); return commRustModule.deleteWalletUser(userID, deviceID, token); }, deletePasswordUser: async (password: string) => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); return commRustModule.deletePasswordUser( userID, deviceID, token, password, ); }, logOut: async () => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); return commRustModule.logOut(userID, deviceID, token); }, getKeyserverKeys: async ( keyserverID: string, ): Promise => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); const result = await commRustModule.getKeyserverKeys( userID, deviceID, token, keyserverID, ); const resultObject = JSON.parse(result); const payload = resultObject?.payload; const keyserverKeys = { identityKeysBlob: payload ? JSON.parse(payload) : null, contentInitializationInfo: { prekey: resultObject?.contentPrekey, prekeySignature: resultObject?.contentPrekeySignature, oneTimeKey: resultObject?.oneTimeContentPrekey, }, notifInitializationInfo: { prekey: resultObject?.notifPrekey, prekeySignature: resultObject?.notifPrekeySignature, oneTimeKey: resultObject?.oneTimeNotifPrekey, }, payloadSignature: resultObject?.payloadSignature, }; if (!keyserverKeys.contentInitializationInfo.oneTimeKey) { throw new Error('Missing content one time key'); } if (!keyserverKeys.notifInitializationInfo.oneTimeKey) { throw new Error('Missing notif one time key'); } return assertWithValidator( keyserverKeys, deviceOlmOutboundKeysValidator, ); }, getOutboundKeysForUser: async ( targetUserID: string, ): Promise => { const { deviceID: authDeviceID, userID, accessToken: token, } = await getAuthMetadata(); const result = await commRustModule.getOutboundKeysForUser( userID, authDeviceID, token, targetUserID, ); const resultArray = JSON.parse(result); return resultArray .map(outboundKeysInfo => { try { const payload = outboundKeysInfo?.payload; const identityKeysBlob: IdentityKeysBlob = assertWithValidator( payload ? JSON.parse(payload) : null, identityKeysBlobValidator, ); const deviceID = identityKeysBlob.primaryIdentityPublicKeys.ed25519; if ( !outboundKeysInfo.oneTimeContentPrekey || !outboundKeysInfo.oneTimeNotifPrekey ) { console.log(`Missing one time key for device ${deviceID}`); return { deviceID, keys: null, }; } const deviceKeys = { identityKeysBlob, contentInitializationInfo: { prekey: outboundKeysInfo?.contentPrekey, prekeySignature: outboundKeysInfo?.contentPrekeySignature, oneTimeKey: outboundKeysInfo?.oneTimeContentPrekey, }, notifInitializationInfo: { prekey: outboundKeysInfo?.notifPrekey, prekeySignature: outboundKeysInfo?.notifPrekeySignature, oneTimeKey: outboundKeysInfo?.oneTimeNotifPrekey, }, payloadSignature: outboundKeysInfo?.payloadSignature, }; try { const validatedKeys = assertWithValidator( deviceKeys, deviceOlmOutboundKeysValidator, ); return { deviceID, keys: validatedKeys, }; } catch (e) { console.log(e); return { deviceID, keys: null, }; } } catch (e) { console.log(e); return null; } }) .filter(Boolean); }, getInboundKeysForUser: async ( targetUserID: string, ): Promise => { const { deviceID: authDeviceID, userID, accessToken: token, } = await getAuthMetadata(); const result = await commRustModule.getInboundKeysForUser( userID, authDeviceID, token, targetUserID, ); const resultArray = JSON.parse(result); const devicesKeys: { [deviceID: string]: ?DeviceOlmInboundKeys, } = {}; resultArray.forEach(inboundKeysInfo => { try { const payload = inboundKeysInfo?.payload; const identityKeysBlob: IdentityKeysBlob = assertWithValidator( payload ? JSON.parse(payload) : null, identityKeysBlobValidator, ); const deviceID = identityKeysBlob.primaryIdentityPublicKeys.ed25519; const deviceKeys = { identityKeysBlob, signedPrekeys: { contentPrekey: inboundKeysInfo?.contentPrekey, contentPrekeySignature: inboundKeysInfo?.contentPrekeySignature, notifPrekey: inboundKeysInfo?.notifPrekey, notifPrekeySignature: inboundKeysInfo?.notifPrekeySignature, }, payloadSignature: inboundKeysInfo?.payloadSignature, }; try { devicesKeys[deviceID] = assertWithValidator( deviceKeys, deviceOlmInboundKeysValidator, ); } catch (e) { console.log(e); devicesKeys[deviceID] = null; } } catch (e) { console.log(e); } }); const device = resultArray?.[0]; const inboundUserKeys = { keys: devicesKeys, username: device?.username, walletAddress: device?.walletAddress, }; return assertWithValidator( inboundUserKeys, userDeviceOlmInboundKeysValidator, ); }, uploadOneTimeKeys: async (oneTimeKeys: OneTimeKeysResultValues) => { const { deviceID: authDeviceID, userID, accessToken: token, } = await getAuthMetadata(); await commRustModule.uploadOneTimeKeys( userID, authDeviceID, token, oneTimeKeys.contentOneTimeKeys, oneTimeKeys.notificationsOneTimeKeys, ); }, registerPasswordUser: async ( username: string, password: string, fid: ?string, ) => { await commCoreModule.initializeCryptoAccount(); const [ { blobPayload, signature, primaryIdentityPublicKeys }, { contentOneTimeKeys, notificationsOneTimeKeys }, prekeys, ] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.getOneTimeKeys(ONE_TIME_KEYS_NUMBER), commCoreModule.validateAndGetPrekeys(), ]); const initialDeviceList = await createAndSignInitialDeviceList( primaryIdentityPublicKeys.ed25519, ); const registrationResult = await commRustModule.registerPasswordUser( username, password, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, getOneTimeKeyValues(contentOneTimeKeys), getOneTimeKeyValues(notificationsOneTimeKeys), fid ?? '', JSON.stringify(initialDeviceList), ); return await processAuthResult( registrationResult, - username, primaryIdentityPublicKeys.ed25519, ); }, registerReservedPasswordUser: async ( username: string, password: string, keyserverMessage: string, keyserverSignature: string, ) => { await commCoreModule.initializeCryptoAccount(); const [ { blobPayload, signature, primaryIdentityPublicKeys }, { contentOneTimeKeys, notificationsOneTimeKeys }, prekeys, ] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.getOneTimeKeys(ONE_TIME_KEYS_NUMBER), commCoreModule.validateAndGetPrekeys(), ]); const initialDeviceList = await createAndSignInitialDeviceList( primaryIdentityPublicKeys.ed25519, ); const registrationResult = await commRustModule.registerReservedPasswordUser( username, password, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, getOneTimeKeyValues(contentOneTimeKeys), getOneTimeKeyValues(notificationsOneTimeKeys), keyserverMessage, keyserverSignature, JSON.stringify(initialDeviceList), ); return await processAuthResult( registrationResult, - username, primaryIdentityPublicKeys.ed25519, ); }, logInPasswordUser: async (username: string, password: string) => { await commCoreModule.initializeCryptoAccount(); const [{ blobPayload, signature, primaryIdentityPublicKeys }, prekeys] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.validateAndGetPrekeys(), ]); const loginResult = await commRustModule.logInPasswordUser( username, password, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, ); return await processAuthResult( loginResult, - username, primaryIdentityPublicKeys.ed25519, ); }, registerWalletUser: async ( walletAddress: string, siweMessage: string, siweSignature: string, fid: ?string, ) => { await commCoreModule.initializeCryptoAccount(); const [ { blobPayload, signature, primaryIdentityPublicKeys }, { contentOneTimeKeys, notificationsOneTimeKeys }, prekeys, ] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.getOneTimeKeys(ONE_TIME_KEYS_NUMBER), commCoreModule.validateAndGetPrekeys(), ]); const initialDeviceList = await createAndSignInitialDeviceList( primaryIdentityPublicKeys.ed25519, ); const registrationResult = await commRustModule.registerWalletUser( siweMessage, siweSignature, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, getOneTimeKeyValues(contentOneTimeKeys), getOneTimeKeyValues(notificationsOneTimeKeys), fid ?? '', JSON.stringify(initialDeviceList), ); return await processAuthResult( registrationResult, - walletAddress, primaryIdentityPublicKeys.ed25519, ); }, registerReservedWalletUser: async ( walletAddress: string, siweMessage: string, siweSignature: string, keyserverMessage: string, keyserverSignature: string, ) => { await commCoreModule.initializeCryptoAccount(); const [ { blobPayload, signature, primaryIdentityPublicKeys }, { contentOneTimeKeys, notificationsOneTimeKeys }, prekeys, ] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.getOneTimeKeys(ONE_TIME_KEYS_NUMBER), commCoreModule.validateAndGetPrekeys(), ]); const initialDeviceList = await createAndSignInitialDeviceList( primaryIdentityPublicKeys.ed25519, ); const registrationResult = await commRustModule.registerReservedWalletUser( siweMessage, siweSignature, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, getOneTimeKeyValues(contentOneTimeKeys), getOneTimeKeyValues(notificationsOneTimeKeys), keyserverMessage, keyserverSignature, JSON.stringify(initialDeviceList), ); return await processAuthResult( registrationResult, - walletAddress, primaryIdentityPublicKeys.ed25519, ); }, logInWalletUser: async ( walletAddress: string, siweMessage: string, siweSignature: string, ) => { await commCoreModule.initializeCryptoAccount(); const [{ blobPayload, signature, primaryIdentityPublicKeys }, prekeys] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.validateAndGetPrekeys(), ]); const loginResult = await commRustModule.logInWalletUser( siweMessage, siweSignature, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, ); return await processAuthResult( loginResult, - walletAddress, primaryIdentityPublicKeys.ed25519, ); }, uploadKeysForRegisteredDeviceAndLogIn: async ( userID: string, nonceChallengeResponse: SignedNonce, ) => { await commCoreModule.initializeCryptoAccount(); const [ { blobPayload, signature, primaryIdentityPublicKeys }, { contentOneTimeKeys, notificationsOneTimeKeys }, prekeys, ] = await Promise.all([ commCoreModule.getUserPublicKey(), commCoreModule.getOneTimeKeys(ONE_TIME_KEYS_NUMBER), commCoreModule.validateAndGetPrekeys(), ]); const { nonce, nonceSignature } = nonceChallengeResponse; const registrationResult = await commRustModule.uploadSecondaryDeviceKeysAndLogIn( userID, nonce, nonceSignature, blobPayload, signature, prekeys.contentPrekey, prekeys.contentPrekeySignature, prekeys.notifPrekey, prekeys.notifPrekeySignature, getOneTimeKeyValues(contentOneTimeKeys), getOneTimeKeyValues(notificationsOneTimeKeys), ); - const { accessToken: token } = JSON.parse(registrationResult); - - const identityAuthResult = { accessToken: token, userID, username: '' }; - const validatedResult = assertWithValidator( - identityAuthResult, - identityAuthResultValidator, - ); - await commCoreModule.setCommServicesAuthMetadata( - validatedResult.userID, + return await processAuthResult( + registrationResult, primaryIdentityPublicKeys.ed25519, - validatedResult.accessToken, ); - - return validatedResult; }, generateNonce: commRustModule.generateNonce, getDeviceListHistoryForUser: async ( userID: string, sinceTimestamp?: number, ) => { const { deviceID: authDeviceID, userID: authUserID, accessToken: token, } = await getAuthMetadata(); const result = await commRustModule.getDeviceListForUser( authUserID, authDeviceID, token, userID, sinceTimestamp, ); const rawPayloads: string[] = JSON.parse(result); const deviceLists: SignedDeviceList[] = rawPayloads.map(payload => JSON.parse(payload), ); return assertWithValidator( deviceLists, signedDeviceListHistoryValidator, ); }, getDeviceListsForUsers: async (userIDs: $ReadOnlyArray) => { const { deviceID: authDeviceID, userID: authUserID, accessToken: token, } = await getAuthMetadata(); const result = await commRustModule.getDeviceListsForUsers( authUserID, authDeviceID, token, userIDs, ); const rawPayloads: { +[userID: string]: string } = JSON.parse(result); let usersDeviceLists: UsersSignedDeviceLists = {}; for (const userID in rawPayloads) { usersDeviceLists = { ...usersDeviceLists, [userID]: JSON.parse(rawPayloads[userID]), }; } return assertWithValidator( usersDeviceLists, usersSignedDeviceListsValidator, ); }, updateDeviceList: async (newDeviceList: SignedDeviceList) => { const { deviceID: authDeviceID, userID, accessToken: authAccessToken, } = await getAuthMetadata(); const payload = JSON.stringify(newDeviceList); await commRustModule.updateDeviceList( userID, authDeviceID, authAccessToken, payload, ); }, getFarcasterUsers: async (farcasterIDs: $ReadOnlyArray) => { const farcasterUsersJSONString = await commRustModule.getFarcasterUsers(farcasterIDs); const farcasterUsers = JSON.parse(farcasterUsersJSONString); return assertWithValidator(farcasterUsers, farcasterUsersValidator); }, linkFarcasterAccount: async (farcasterID: string) => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); return commRustModule.linkFarcasterAccount( userID, deviceID, token, farcasterID, ); }, unlinkFarcasterAccount: async () => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); return commRustModule.unlinkFarcasterAccount(userID, deviceID, token); }, findUserIdentities: async (userIDs: $ReadOnlyArray) => { const { deviceID, userID, accessToken: token, } = await getAuthMetadata(); const result = await commRustModule.findUserIdentities( userID, deviceID, token, userIDs, ); const identities = JSON.parse(result); return assertWithValidator(identities, identitiesValidator); }, }), [getAuthMetadata], ); const value = React.useMemo( () => ({ identityClient: client, getAuthMetadata, }), [client, getAuthMetadata], ); return ( {children} ); } export default IdentityServiceContextProvider; diff --git a/native/native_rust_library/src/identity.rs b/native/native_rust_library/src/identity.rs index 1ad4fc928..3e53d4604 100644 --- a/native/native_rust_library/src/identity.rs +++ b/native/native_rust_library/src/identity.rs @@ -1,203 +1,207 @@ use grpc_clients::identity::get_unauthenticated_client; use grpc_clients::identity::protos::unauth::{ AuthResponse, DeviceKeyUpload, Empty, IdentityKeyInfo, Prekey, }; use serde::Serialize; use crate::utils::jsi_callbacks::{ handle_bool_result_as_callback, handle_string_result_as_callback, }; use crate::{Error, RUNTIME}; use crate::{CODE_VERSION, DEVICE_TYPE, IDENTITY_SOCKET_ADDR}; pub mod account_actions; pub mod device_list; pub mod exact_user_search; pub mod farcaster; pub mod find_user_identities; pub mod login; pub mod registration; pub mod x3dh; pub mod ffi { use super::*; pub use account_actions::ffi::*; pub use device_list::ffi::*; pub use exact_user_search::ffi::*; pub use farcaster::ffi::*; pub use find_user_identities::ffi::*; pub use login::ffi::*; pub use registration::ffi::*; pub use x3dh::ffi::*; pub fn generate_nonce(promise_id: u32) { RUNTIME.spawn(async move { let result = fetch_nonce().await; handle_string_result_as_callback(result, promise_id); }); } pub fn version_supported(promise_id: u32) { RUNTIME.spawn(async move { let result = version_supported_helper().await; handle_bool_result_as_callback(result, promise_id); }); } } // helper structs pub struct AuthInfo { pub user_id: String, pub device_id: String, pub access_token: String, } pub struct DeviceKeys { pub key_payload: String, pub key_payload_signature: String, pub content_prekey: String, pub content_prekey_signature: String, pub notif_prekey: String, pub notif_prekey_signature: String, pub content_one_time_keys: Vec, pub notif_one_time_keys: Vec, } impl From for DeviceKeyUpload { fn from(value: DeviceKeys) -> Self { let DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, } = value; Self { device_key_info: Some(IdentityKeyInfo { payload: key_payload, payload_signature: key_payload_signature, }), content_upload: Some(Prekey { prekey: content_prekey, prekey_signature: content_prekey_signature, }), notif_upload: Some(Prekey { prekey: notif_prekey, prekey_signature: notif_prekey_signature, }), one_time_content_prekeys: content_one_time_keys, one_time_notif_prekeys: notif_one_time_keys, device_type: DEVICE_TYPE.into(), } } } pub struct LogInPasswordUserInfo { pub username: String, pub password: String, pub device_keys: DeviceKeys, } pub struct RegisterPasswordUserInfo { pub username: String, pub password: String, pub device_keys: DeviceKeys, pub farcaster_id: Option, pub initial_device_list: String, } pub struct RegisterReservedPasswordUserInfo { pub username: String, pub password: String, pub device_keys: DeviceKeys, pub keyserver_message: String, pub keyserver_signature: String, pub initial_device_list: String, } pub struct LogInWalletUserInfo { pub siwe_message: String, pub siwe_signature: String, pub device_keys: DeviceKeys, } pub struct RegisterWalletUserInfo { pub siwe_message: String, pub siwe_signature: String, pub device_keys: DeviceKeys, pub farcaster_id: Option, pub initial_device_list: String, } pub struct RegisterReservedWalletUserInfo { pub siwe_message: String, pub siwe_signature: String, pub device_keys: DeviceKeys, pub keyserver_message: String, pub keyserver_signature: String, pub initial_device_list: String, } +/// Counterpart of proto [`AuthResponse`] message +/// that implements the `Serialize` trait. #[derive(Serialize)] #[serde(rename_all = "camelCase")] -pub struct UserIDAndDeviceAccessToken { +pub struct IdentityAuthResult { #[serde(rename = "userID")] user_id: String, access_token: String, + username: String, } -impl From for UserIDAndDeviceAccessToken { +impl From for IdentityAuthResult { fn from(value: AuthResponse) -> Self { let AuthResponse { user_id, access_token, - .. + username, } = value; Self { user_id, access_token, + username, } } } // API implementation helpers async fn fetch_nonce() -> Result { let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let nonce = identity_client .generate_nonce(Empty {}) .await? .into_inner() .nonce; Ok(nonce) } async fn version_supported_helper() -> Result { let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let response = identity_client.ping(Empty {}).await; match response { Ok(_) => Ok(true), Err(e) => { if grpc_clients::error::is_version_unsupported(&e) { Ok(false) } else { Err(e.into()) } } } } diff --git a/native/native_rust_library/src/identity/login.rs b/native/native_rust_library/src/identity/login.rs index 9dc10025f..6f858c40e 100644 --- a/native/native_rust_library/src/identity/login.rs +++ b/native/native_rust_library/src/identity/login.rs @@ -1,283 +1,279 @@ use comm_opaque2::client::Login; use grpc_clients::identity::{ get_unauthenticated_client, protos::unauth::{ DeviceKeyUpload, ExistingDeviceLoginRequest, IdentityKeyInfo, OpaqueLoginFinishRequest, OpaqueLoginStartRequest, Prekey, SecondaryDeviceKeysUploadRequest, WalletAuthRequest, }, }; use tracing::instrument; -use super::{ - LogInPasswordUserInfo, LogInWalletUserInfo, UserIDAndDeviceAccessToken, -}; +use super::{IdentityAuthResult, LogInPasswordUserInfo, LogInWalletUserInfo}; use crate::utils::jsi_callbacks::handle_string_result_as_callback; use crate::{Error, CODE_VERSION, DEVICE_TYPE, IDENTITY_SOCKET_ADDR, RUNTIME}; pub mod ffi { use crate::identity::{ DeviceKeys, LogInPasswordUserInfo, LogInWalletUserInfo, }; use super::*; #[instrument] pub fn log_in_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, promise_id: u32, ) { RUNTIME.spawn(async move { let password_user_info = LogInPasswordUserInfo { username, password, device_keys: DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys: Vec::new(), notif_one_time_keys: Vec::new(), }, }; let result = log_in_password_user_helper(password_user_info).await; handle_string_result_as_callback(result, promise_id); }); } #[instrument] pub fn log_in_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, promise_id: u32, ) { RUNTIME.spawn(async move { let wallet_user_info = LogInWalletUserInfo { siwe_message, siwe_signature, device_keys: DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys: Vec::new(), notif_one_time_keys: Vec::new(), }, }; let result = log_in_wallet_user_helper(wallet_user_info).await; handle_string_result_as_callback(result, promise_id); }); } // QR code device log in pub fn upload_secondary_device_keys_and_log_in( user_id: String, nonce: String, nonce_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, promise_id: u32, ) { RUNTIME.spawn(async move { let device_key_upload = DeviceKeyUpload { device_key_info: Some(IdentityKeyInfo { payload: key_payload, payload_signature: key_payload_signature, }), content_upload: Some(Prekey { prekey: content_prekey, prekey_signature: content_prekey_signature, }), notif_upload: Some(Prekey { prekey: notif_prekey, prekey_signature: notif_prekey_signature, }), one_time_content_prekeys: content_one_time_keys, one_time_notif_prekeys: notif_one_time_keys, device_type: DEVICE_TYPE.into(), }; let result = upload_secondary_device_keys_and_log_in_helper( user_id, nonce, nonce_signature, device_key_upload, ) .await; handle_string_result_as_callback(result, promise_id); }); } pub fn log_in_existing_device( user_id: String, device_id: String, nonce: String, nonce_signature: String, promise_id: u32, ) { RUNTIME.spawn(async move { let result = log_in_existing_device_helper( user_id, device_id, nonce, nonce_signature, ) .await; handle_string_result_as_callback(result, promise_id); }); } } async fn log_in_password_user_helper( password_user_info: LogInPasswordUserInfo, ) -> Result { let mut client_login = Login::new(); let opaque_login_request = client_login .start(&password_user_info.password) .map_err(crate::handle_error)?; let login_start_request = OpaqueLoginStartRequest { opaque_login_request, username: password_user_info.username, device_key_upload: Some(password_user_info.device_keys.into()), force: None, }; let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let response = identity_client .log_in_password_user_start(login_start_request) .await?; let login_start_response = response.into_inner(); let opaque_login_upload = client_login .finish(&login_start_response.opaque_login_response) .map_err(crate::handle_error)?; let login_finish_request = OpaqueLoginFinishRequest { session_id: login_start_response.session_id, opaque_login_upload, }; let login_finish_response = identity_client .log_in_password_user_finish(login_finish_request) .await? .into_inner(); - let user_id_and_access_token = - UserIDAndDeviceAccessToken::from(login_finish_response); - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(login_finish_response); + Ok(serde_json::to_string(&auth_result)?) } async fn log_in_wallet_user_helper( wallet_user_info: LogInWalletUserInfo, ) -> Result { let login_request = WalletAuthRequest { siwe_message: wallet_user_info.siwe_message, siwe_signature: wallet_user_info.siwe_signature, device_key_upload: Some(wallet_user_info.device_keys.into()), farcaster_id: None, initial_device_list: "".to_string(), }; let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let login_response = identity_client .log_in_wallet_user(login_request) .await? .into_inner(); - let user_id_and_access_token = - UserIDAndDeviceAccessToken::from(login_response); - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(login_response); + Ok(serde_json::to_string(&auth_result)?) } async fn upload_secondary_device_keys_and_log_in_helper( user_id: String, nonce: String, nonce_signature: String, device_key_upload: DeviceKeyUpload, ) -> Result { let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let request = SecondaryDeviceKeysUploadRequest { user_id, nonce, nonce_signature, device_key_upload: Some(device_key_upload), }; let response = identity_client .upload_keys_for_registered_device_and_log_in(request) .await? .into_inner(); - let user_id_and_access_token = UserIDAndDeviceAccessToken::from(response); - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(response); + Ok(serde_json::to_string(&auth_result)?) } async fn log_in_existing_device_helper( user_id: String, device_id: String, nonce: String, nonce_signature: String, ) -> Result { let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let request = ExistingDeviceLoginRequest { user_id, device_id, nonce, nonce_signature, }; let response = identity_client .log_in_existing_device(request) .await? .into_inner(); - let user_id_and_access_token = UserIDAndDeviceAccessToken::from(response); - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(response); + Ok(serde_json::to_string(&auth_result)?) } diff --git a/native/native_rust_library/src/identity/registration.rs b/native/native_rust_library/src/identity/registration.rs index 8dae0edc6..26992c1e7 100644 --- a/native/native_rust_library/src/identity/registration.rs +++ b/native/native_rust_library/src/identity/registration.rs @@ -1,344 +1,336 @@ use crate::{ utils::jsi_callbacks::handle_string_result_as_callback, Error, CODE_VERSION, DEVICE_TYPE, IDENTITY_SOCKET_ADDR, RUNTIME, }; use comm_opaque2::client::Registration; use grpc_clients::identity::{ get_unauthenticated_client, protos::unauth::{ RegistrationFinishRequest, RegistrationStartRequest, ReservedRegistrationStartRequest, ReservedWalletRegistrationRequest, WalletAuthRequest, }, }; use tracing::instrument; use super::{ - farcaster::farcaster_id_string_to_option, RegisterPasswordUserInfo, - RegisterReservedPasswordUserInfo, RegisterReservedWalletUserInfo, - RegisterWalletUserInfo, UserIDAndDeviceAccessToken, + farcaster::farcaster_id_string_to_option, IdentityAuthResult, + RegisterPasswordUserInfo, RegisterReservedPasswordUserInfo, + RegisterReservedWalletUserInfo, RegisterWalletUserInfo, }; pub mod ffi { use crate::identity::{ DeviceKeys, RegisterPasswordUserInfo, RegisterReservedPasswordUserInfo, RegisterWalletUserInfo, }; use super::*; #[instrument] pub fn register_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, farcaster_id: String, initial_device_list: String, promise_id: u32, ) { RUNTIME.spawn(async move { let password_user_info = RegisterPasswordUserInfo { username, password, device_keys: DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, }, farcaster_id: farcaster_id_string_to_option(&farcaster_id), initial_device_list, }; let result = register_password_user_helper(password_user_info).await; handle_string_result_as_callback(result, promise_id); }); } #[instrument] pub fn register_reserved_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, keyserver_message: String, keyserver_signature: String, initial_device_list: String, promise_id: u32, ) { RUNTIME.spawn(async move { let password_user_info = RegisterReservedPasswordUserInfo { username, password, device_keys: DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, }, keyserver_message, keyserver_signature, initial_device_list, }; let result = register_reserved_password_user_helper(password_user_info).await; handle_string_result_as_callback(result, promise_id); }); } #[instrument] pub fn register_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, farcaster_id: String, initial_device_list: String, promise_id: u32, ) { RUNTIME.spawn(async move { let wallet_user_info = RegisterWalletUserInfo { siwe_message, siwe_signature, device_keys: DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, }, farcaster_id: farcaster_id_string_to_option(&farcaster_id), initial_device_list, }; let result = register_wallet_user_helper(wallet_user_info).await; handle_string_result_as_callback(result, promise_id); }); } #[instrument] pub fn register_reserved_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, keyserver_message: String, keyserver_signature: String, initial_device_list: String, promise_id: u32, ) { RUNTIME.spawn(async move { let wallet_user_info = RegisterReservedWalletUserInfo { siwe_message, siwe_signature, device_keys: DeviceKeys { key_payload, key_payload_signature, content_prekey, content_prekey_signature, notif_prekey, notif_prekey_signature, content_one_time_keys, notif_one_time_keys, }, keyserver_message, keyserver_signature, initial_device_list, }; let result = register_reserved_wallet_user_helper(wallet_user_info).await; handle_string_result_as_callback(result, promise_id); }); } } async fn register_password_user_helper( password_user_info: RegisterPasswordUserInfo, ) -> Result { let mut client_registration = Registration::new(); let opaque_registration_request = client_registration .start(&password_user_info.password) .map_err(crate::handle_error)?; let registration_start_request = RegistrationStartRequest { opaque_registration_request, username: password_user_info.username, device_key_upload: Some(password_user_info.device_keys.into()), farcaster_id: password_user_info.farcaster_id, initial_device_list: password_user_info.initial_device_list, }; let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let response = identity_client .register_password_user_start(registration_start_request) .await?; let registration_start_response = response.into_inner(); let opaque_registration_upload = client_registration .finish( &password_user_info.password, ®istration_start_response.opaque_registration_response, ) .map_err(crate::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::from(registration_finish_response); - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(registration_finish_response); + Ok(serde_json::to_string(&auth_result)?) } async fn register_reserved_password_user_helper( password_user_info: RegisterReservedPasswordUserInfo, ) -> Result { let mut client_registration = Registration::new(); let opaque_registration_request = client_registration .start(&password_user_info.password) .map_err(crate::handle_error)?; let registration_start_request = ReservedRegistrationStartRequest { opaque_registration_request, username: password_user_info.username, device_key_upload: Some(password_user_info.device_keys.into()), keyserver_message: password_user_info.keyserver_message, keyserver_signature: password_user_info.keyserver_signature, initial_device_list: password_user_info.initial_device_list, }; let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let response = identity_client .register_reserved_password_user_start(registration_start_request) .await?; let registration_start_response = response.into_inner(); let opaque_registration_upload = client_registration .finish( &password_user_info.password, ®istration_start_response.opaque_registration_response, ) .map_err(crate::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::from(registration_finish_response); - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(registration_finish_response); + Ok(serde_json::to_string(&auth_result)?) } async fn register_wallet_user_helper( wallet_user_info: RegisterWalletUserInfo, ) -> Result { let registration_request = WalletAuthRequest { siwe_message: wallet_user_info.siwe_message, siwe_signature: wallet_user_info.siwe_signature, device_key_upload: Some(wallet_user_info.device_keys.into()), farcaster_id: wallet_user_info.farcaster_id, initial_device_list: wallet_user_info.initial_device_list, }; let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let registration_response = identity_client .register_wallet_user(registration_request) .await? .into_inner(); - let user_id_and_access_token = UserIDAndDeviceAccessToken { - user_id: registration_response.user_id, - access_token: registration_response.access_token, - }; - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(registration_response); + Ok(serde_json::to_string(&auth_result)?) } async fn register_reserved_wallet_user_helper( wallet_user_info: RegisterReservedWalletUserInfo, ) -> Result { let registration_request = ReservedWalletRegistrationRequest { siwe_message: wallet_user_info.siwe_message, siwe_signature: wallet_user_info.siwe_signature, device_key_upload: Some(wallet_user_info.device_keys.into()), keyserver_message: wallet_user_info.keyserver_message, keyserver_signature: wallet_user_info.keyserver_signature, initial_device_list: wallet_user_info.initial_device_list, }; let mut identity_client = get_unauthenticated_client( IDENTITY_SOCKET_ADDR, CODE_VERSION, DEVICE_TYPE.as_str_name().to_lowercase(), ) .await?; let registration_response = identity_client .register_reserved_wallet_user(registration_request) .await? .into_inner(); - let user_id_and_access_token = UserIDAndDeviceAccessToken { - user_id: registration_response.user_id, - access_token: registration_response.access_token, - }; - Ok(serde_json::to_string(&user_id_and_access_token)?) + let auth_result = IdentityAuthResult::from(registration_response); + Ok(serde_json::to_string(&auth_result)?) }