diff --git a/services/identity/src/client_service.rs b/services/identity/src/client_service.rs --- a/services/identity/src/client_service.rs +++ b/services/identity/src/client_service.rs @@ -1,49 +1,49 @@ -pub mod client_proto { - tonic::include_proto!("identity.client"); -} - +// Standard library imports use std::str::FromStr; -use crate::database::{self, Device}; -use crate::error::Error as DBError; -use crate::{ - client_service::client_proto::{ - AddReservedUsernamesRequest, DeleteUserRequest, Empty, - GenerateNonceResponse, InboundKeysForUserRequest, - InboundKeysForUserResponse, LogoutRequest, OpaqueLoginFinishRequest, - OpaqueLoginFinishResponse, OpaqueLoginStartRequest, - OpaqueLoginStartResponse, OutboundKeysForUserRequest, - OutboundKeysForUserResponse, RefreshUserPreKeysRequest, - RegistrationFinishRequest, RegistrationFinishResponse, - RegistrationStartRequest, RegistrationStartResponse, - RemoveReservedUsernameRequest, ReservedRegistrationStartRequest, - UpdateUserPasswordFinishRequest, UpdateUserPasswordStartRequest, - UpdateUserPasswordStartResponse, UploadOneTimeKeysRequest, - VerifyUserAccessTokenRequest, VerifyUserAccessTokenResponse, - WalletLoginRequest, WalletLoginResponse, - }, - config::CONFIG, - database::{DatabaseClient, KeyPayload}, - id::generate_uuid, - nonce::generate_nonce_data, - reserved_users::{ - validate_add_reserved_usernames_message, - validate_remove_reserved_username_message, - validate_signed_account_ownership_message, - }, - siwe::parse_and_verify_siwe_message, - token::{AccessTokenData, AuthType}, -}; +// External crate imports use aws_sdk_dynamodb::Error as DynamoDBError; -pub use client_proto::identity_client_service_server::{ - IdentityClientService, IdentityClientServiceServer, -}; use comm_opaque2::grpc::protocol_error_to_grpc_status; use moka::future::Cache; use rand::rngs::OsRng; use tonic::Response; use tracing::{debug, error}; +// Workspace crate imports +use crate::client_service::client_proto::{ + AddReservedUsernamesRequest, DeleteUserRequest, Empty, GenerateNonceResponse, + InboundKeysForUserRequest, InboundKeysForUserResponse, LogoutRequest, + OpaqueLoginFinishRequest, OpaqueLoginFinishResponse, OpaqueLoginStartRequest, + OpaqueLoginStartResponse, OutboundKeysForUserRequest, + OutboundKeysForUserResponse, RefreshUserPreKeysRequest, + RegistrationFinishRequest, RegistrationFinishResponse, + RegistrationStartRequest, RegistrationStartResponse, + RemoveReservedUsernameRequest, ReservedRegistrationStartRequest, + UpdateUserPasswordFinishRequest, UpdateUserPasswordStartRequest, + UpdateUserPasswordStartResponse, UploadOneTimeKeysRequest, + VerifyUserAccessTokenRequest, VerifyUserAccessTokenResponse, + WalletLoginRequest, WalletLoginResponse, +}; +use crate::config::CONFIG; +use crate::database::{DatabaseClient, Device, KeyPayload}; +use crate::error::Error as DBError; +use crate::id::generate_uuid; +use crate::nonce::generate_nonce_data; +use crate::reserved_users::{ + validate_add_reserved_usernames_message, + validate_remove_reserved_username_message, + validate_signed_account_ownership_message, +}; +use crate::siwe::parse_and_verify_siwe_message; +use crate::token::{AccessTokenData, AuthType}; +pub use client_proto::identity_client_service_server::{ + IdentityClientService, IdentityClientServiceServer, +}; + +pub mod client_proto { + tonic::include_proto!("identity.client"); +} + #[derive(Clone)] pub enum WorkflowInProgress { Registration(Box), @@ -80,7 +80,7 @@ pub notif_prekey: String, pub notif_prekey_signature: String, pub notif_one_time_keys: Vec, - pub device_type: database::Device, + pub device_type: Device, } #[derive(derive_more::Constructor)] diff --git a/services/identity/src/database.rs b/services/identity/src/database.rs --- a/services/identity/src/database.rs +++ b/services/identity/src/database.rs @@ -1277,7 +1277,7 @@ } type AttributeName = String; -type DeviceKeys = HashMap; +pub type DeviceKeys = HashMap; type Devices = HashMap; fn create_simple_primary_key( diff --git a/services/identity/src/grpc_utils.rs b/services/identity/src/grpc_utils.rs new file mode 100644 --- /dev/null +++ b/services/identity/src/grpc_utils.rs @@ -0,0 +1,86 @@ +use std::collections::HashMap; + +use tonic::Status; +use tracing::error; + +use crate::{ + client_service::client_proto::{IdentityKeyInfo, InboundKeyInfo, PreKey}, + constants::{ + USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_SIGNATURE_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME, + }, + database::DeviceKeys, + token::AuthType, +}; + +struct DeviceInfoWithAuth<'a> { + device_info: HashMap, + auth_type: &'a AuthType, +} + +impl<'a> TryFrom> for InboundKeyInfo { + type Error = tonic::Status; + + fn try_from(data: DeviceInfoWithAuth) -> Result { + let mut device_info = data.device_info; + + let payload = extract_key( + &mut device_info, + USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME, + )?; + let payload_signature = extract_key( + &mut device_info, + USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME, + )?; + + let social_proof = + device_info.remove(USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME); + if social_proof.is_none() && data.auth_type == &AuthType::Wallet { + error!("Social proof missing for wallet user"); + return Err(tonic::Status::failed_precondition( + "Database item malformed", + )); + } + + let identity_info = IdentityKeyInfo { + payload, + payload_signature, + social_proof, + }; + + let mut create_prekey = + |key_attr, signature_attr| -> Result { + Ok(PreKey { + pre_key: extract_key(&mut device_info, key_attr)?, + pre_key_signature: extract_key(&mut device_info, signature_attr)?, + }) + }; + + Ok(InboundKeyInfo { + identity_info: Some(identity_info), + content_prekey: Some(create_prekey( + USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_SIGNATURE_ATTRIBUTE_NAME, + )?), + notif_prekey: Some(create_prekey( + USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME, + USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME, + )?), + }) + } +} + +fn extract_key( + device_info: &mut DeviceKeys, + key: &str, +) -> Result { + device_info.remove(key).ok_or_else(|| { + error!("{} missing from device info", key); + Status::failed_precondition("Database item malformed") + }) +} diff --git a/services/identity/src/main.rs b/services/identity/src/main.rs --- a/services/identity/src/main.rs +++ b/services/identity/src/main.rs @@ -12,6 +12,7 @@ pub mod ddb_utils; pub mod error; mod grpc_services; +mod grpc_utils; mod id; mod keygen; mod nonce; diff --git a/services/identity/src/token.rs b/services/identity/src/token.rs --- a/services/identity/src/token.rs +++ b/services/identity/src/token.rs @@ -6,7 +6,7 @@ use crate::constants::ACCESS_TOKEN_LENGTH; -#[derive(Clone)] +#[derive(Clone, Eq, PartialEq)] pub enum AuthType { Password, Wallet,