diff --git a/services/identity/src/constants.rs b/services/identity/src/constants.rs --- a/services/identity/src/constants.rs +++ b/services/identity/src/constants.rs @@ -47,21 +47,6 @@ pub const USERS_TABLE_USERNAME_ATTRIBUTE: &str = "username"; pub const USERS_TABLE_DEVICES_MAP_DEVICE_TYPE_ATTRIBUTE_NAME: &str = "deviceType"; -pub const USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME: &str = - "keyPayload"; -pub const USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME: &str = - "keyPayloadSignature"; -pub const USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_ATTRIBUTE_NAME: &str = - "identityPreKey"; -pub const USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_SIGNATURE_ATTRIBUTE_NAME: - &str = "identityPreKeySignature"; -pub const USERS_TABLE_DEVICES_MAP_CONTENT_ONE_TIME_KEYS_ATTRIBUTE_NAME: &str = - "identityOneTimeKeys"; -pub const USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME: &str = "preKey"; -pub const USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME: &str = - "preKeySignature"; -pub const USERS_TABLE_DEVICES_MAP_NOTIF_ONE_TIME_KEYS_ATTRIBUTE_NAME: &str = - "notifOneTimeKeys"; pub const USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE: &str = "walletAddress"; pub const USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME: &str = "socialProof"; 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 @@ -16,7 +16,6 @@ use std::str::FromStr; use std::sync::Arc; -use crate::error::{consume_error, Error}; use crate::reserved_users::UserDetail; use crate::{ ddb_utils::{ @@ -25,6 +24,10 @@ }, grpc_services::protos, }; +use crate::{ + error::{consume_error, Error}, + grpc_utils::DeviceKeysInfo, +}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use tracing::{debug, error, info, warn}; @@ -35,11 +38,10 @@ ACCESS_TOKEN_SORT_KEY, ACCESS_TOKEN_TABLE, ACCESS_TOKEN_TABLE_AUTH_TYPE_ATTRIBUTE, ACCESS_TOKEN_TABLE_CREATED_ATTRIBUTE, ACCESS_TOKEN_TABLE_PARTITION_KEY, ACCESS_TOKEN_TABLE_TOKEN_ATTRIBUTE, - ACCESS_TOKEN_TABLE_VALID_ATTRIBUTE, CONTENT_ONE_TIME_KEY, NONCE_TABLE, + ACCESS_TOKEN_TABLE_VALID_ATTRIBUTE, NONCE_TABLE, NONCE_TABLE_CREATED_ATTRIBUTE, NONCE_TABLE_EXPIRATION_TIME_ATTRIBUTE, NONCE_TABLE_EXPIRATION_TIME_UNIX_ATTRIBUTE, NONCE_TABLE_PARTITION_KEY, - NOTIF_ONE_TIME_KEY, RESERVED_USERNAMES_TABLE, - RESERVED_USERNAMES_TABLE_PARTITION_KEY, + RESERVED_USERNAMES_TABLE, RESERVED_USERNAMES_TABLE_PARTITION_KEY, RESERVED_USERNAMES_TABLE_USER_ID_ATTRIBUTE, USERS_TABLE, USERS_TABLE_DEVICES_MAP_DEVICE_TYPE_ATTRIBUTE_NAME, USERS_TABLE_PARTITION_KEY, USERS_TABLE_REGISTRATION_ATTRIBUTE, @@ -53,7 +55,7 @@ pub use grpc_clients::identity::DeviceType; mod device_list; -pub use device_list::DeviceListRow; +pub use device_list::{DeviceListRow, DeviceRow}; use self::device_list::PreKey; @@ -856,21 +858,13 @@ } if get_one_time_keys { - for (device_id_key, device_info_map) in devices_response.iter_mut() { - if let Some(notif_one_time_key) = self + for (device_id_key, device_keys) in devices_response.iter_mut() { + device_keys.notif_one_time_key = self .get_one_time_key(device_id_key, OlmAccountType::Notification) - .await? - { - device_info_map - .insert(NOTIF_ONE_TIME_KEY.to_string(), notif_one_time_key); - } - if let Some(content_one_time_key) = self + .await?; + device_keys.content_one_time_key = self .get_one_time_key(device_id_key, OlmAccountType::Content) - .await? - { - device_info_map - .insert(CONTENT_ONE_TIME_KEY.to_string(), content_one_time_key); - } + .await?; } } @@ -1167,8 +1161,7 @@ } type AttributeName = String; -pub type DeviceKeys = HashMap; -type Devices = HashMap; +type Devices = HashMap; fn create_simple_primary_key( partition_key: (AttributeName, String), diff --git a/services/identity/src/database/device_list.rs b/services/identity/src/database/device_list.rs --- a/services/identity/src/database/device_list.rs +++ b/services/identity/src/database/device_list.rs @@ -21,18 +21,12 @@ constants::{ devices_table::{self, *}, USERS_TABLE, USERS_TABLE_DEVICELIST_TIMESTAMP_ATTRIBUTE_NAME, - 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, USERS_TABLE_PARTITION_KEY, }, ddb_utils::AttributesOptionExt, error::{DeviceListError, Error, FromAttributeValue}, grpc_services::protos::{self, unauth::DeviceType}, + grpc_utils::DeviceKeysInfo, }; use super::DatabaseClient; @@ -270,6 +264,16 @@ } } +impl From for protos::unauth::IdentityKeyInfo { + fn from(value: IdentityKeyInfo) -> Self { + Self { + payload: value.key_payload, + payload_signature: value.key_payload_signature, + social_proof: value.social_proof, + } + } +} + impl From for AttributeValue { fn from(value: IdentityKeyInfo) -> Self { let mut attrs = HashMap::from([ @@ -501,52 +505,10 @@ user_id: impl Into, ) -> Result { let user_devices = self.get_current_devices(user_id).await?; - - let user_devices_keys: super::Devices = user_devices + let user_devices_keys = user_devices .into_iter() - .map(|device| { - // convert this to the map type returned by DatabaseClient::get_keys_for_user - let mut device_keys: super::DeviceKeys = HashMap::from([ - ( - USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME.to_string(), - device.device_key_info.key_payload, - ), - ( - USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_SIGNATURE_ATTRIBUTE_NAME - .to_string(), - device.device_key_info.key_payload_signature, - ), - ( - USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_ATTRIBUTE_NAME.to_string(), - device.content_prekey.pre_key, - ), - ( - USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_SIGNATURE_ATTRIBUTE_NAME - .to_string(), - device.content_prekey.pre_key_signature, - ), - ( - USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME.to_string(), - device.notif_prekey.pre_key, - ), - ( - USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME - .to_string(), - device.notif_prekey.pre_key_signature, - ), - ]); - - if let Some(social_proof) = device.device_key_info.social_proof { - device_keys.insert( - USERS_TABLE_DEVICES_MAP_SOCIAL_PROOF_ATTRIBUTE_NAME.to_string(), - social_proof, - ); - } - - (device.device_id, device_keys) - }) + .map(|device| (device.device_id.clone(), DeviceKeysInfo::from(device))) .collect(); - Ok(user_devices_keys) } diff --git a/services/identity/src/grpc_services/authenticated.rs b/services/identity/src/grpc_services/authenticated.rs --- a/services/identity/src/grpc_services/authenticated.rs +++ b/services/identity/src/grpc_services/authenticated.rs @@ -2,7 +2,7 @@ use crate::config::CONFIG; use crate::database::DeviceListRow; -use crate::grpc_utils::DeviceInfoWithAuth; +use crate::ddb_utils::Identifier; use crate::{ client_service::{ handle_db_error, CacheExt, UpdateState, WorkflowInProgress, @@ -127,29 +127,18 @@ request: tonic::Request, ) -> Result, tonic::Status> { let message = request.into_inner(); + let user_id = &message.user_id; let devices_map = self .db_client - .get_keys_for_user(&message.user_id, true) + .get_keys_for_user(user_id, true) .await .map_err(handle_db_error)? .ok_or_else(|| tonic::Status::not_found("user not found"))?; let transformed_devices = devices_map .into_iter() - .filter_map(|(key, device_info)| { - let device_info_with_auth = DeviceInfoWithAuth { - device_info, - auth_type: None, - }; - match OutboundKeyInfo::try_from(device_info_with_auth) { - Ok(key_info) => Some((key, key_info)), - Err(_) => { - error!("Failed to transform device info for key {}", key); - None - } - } - }) + .map(|(key, device_info)| (key, OutboundKeyInfo::from(device_info))) .collect::>(); Ok(tonic::Response::new(OutboundKeysForUserResponse { @@ -164,34 +153,23 @@ use identity::IdentityInfo; let message = request.into_inner(); + let user_id = &message.user_id; let devices_map = self .db_client - .get_keys_for_user(&message.user_id, false) + .get_keys_for_user(user_id, false) .await .map_err(handle_db_error)? .ok_or_else(|| tonic::Status::not_found("user not found"))?; let transformed_devices = devices_map .into_iter() - .filter_map(|(key, device_info)| { - let device_info_with_auth = DeviceInfoWithAuth { - device_info, - auth_type: None, - }; - match InboundKeyInfo::try_from(device_info_with_auth) { - Ok(key_info) => Some((key, key_info)), - Err(_) => { - error!("Failed to transform device info for key {}", key); - None - } - } - }) + .map(|(key, device_info)| (key, InboundKeyInfo::from(device_info))) .collect::>(); let identifier = self .db_client - .get_user_identifier(&message.user_id) + .get_user_identifier(user_id) .await .map_err(handle_db_error)?; diff --git a/services/identity/src/grpc_utils.rs b/services/identity/src/grpc_utils.rs --- a/services/identity/src/grpc_utils.rs +++ b/services/identity/src/grpc_utils.rs @@ -1,139 +1,62 @@ -use std::collections::HashMap; - use tonic::Status; -use tracing::error; use crate::{ - constants::{ - CONTENT_ONE_TIME_KEY, NOTIF_ONE_TIME_KEY, - 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, + database::DeviceRow, ddb_utils::Identifier as DBIdentifier, grpc_services::protos::{ auth::{ identity::IdentityInfo, EthereumIdentity, InboundKeyInfo, OutboundKeyInfo, }, unauth::{ - DeviceKeyUpload, IdentityKeyInfo, OpaqueLoginStartRequest, Prekey, - RegistrationStartRequest, ReservedRegistrationStartRequest, - ReservedWalletLoginRequest, WalletLoginRequest, + DeviceKeyUpload, OpaqueLoginStartRequest, RegistrationStartRequest, + ReservedRegistrationStartRequest, ReservedWalletLoginRequest, + WalletLoginRequest, }, }, - token::AuthType, }; -pub struct DeviceInfoWithAuth<'a> { - pub device_info: HashMap, - pub auth_type: Option<&'a AuthType>, +pub struct DeviceKeysInfo { + pub device_info: DeviceRow, + pub content_one_time_key: Option, + pub notif_one_time_key: Option, } -impl TryFrom> for InboundKeyInfo { - type Error = Status; - - fn try_from(data: DeviceInfoWithAuth) -> Result { - let mut device_info = data.device_info; - - let identity_info = - extract_identity_info(&mut device_info, data.auth_type)?; - - Ok(InboundKeyInfo { - identity_info: Some(identity_info), - content_prekey: Some(create_prekey( - &mut device_info, - USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_ATTRIBUTE_NAME, - USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_SIGNATURE_ATTRIBUTE_NAME, - )?), - notif_prekey: Some(create_prekey( - &mut device_info, - USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME, - USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME, - )?), - }) +impl From for DeviceKeysInfo { + fn from(device_info: DeviceRow) -> Self { + Self { + device_info, + content_one_time_key: None, + notif_one_time_key: None, + } } } -impl TryFrom> for OutboundKeyInfo { - type Error = Status; - - fn try_from(data: DeviceInfoWithAuth) -> Result { - let mut device_info = data.device_info; - - let identity_info = - extract_identity_info(&mut device_info, data.auth_type)?; - - let content_one_time_key = device_info.remove(CONTENT_ONE_TIME_KEY); - let notif_one_time_key = device_info.remove(NOTIF_ONE_TIME_KEY); - - Ok(OutboundKeyInfo { - identity_info: Some(identity_info), - content_prekey: Some(create_prekey( - &mut device_info, - USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_ATTRIBUTE_NAME, - USERS_TABLE_DEVICES_MAP_CONTENT_PREKEY_SIGNATURE_ATTRIBUTE_NAME, - )?), - notif_prekey: Some(create_prekey( - &mut device_info, - USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_ATTRIBUTE_NAME, - USERS_TABLE_DEVICES_MAP_NOTIF_PREKEY_SIGNATURE_ATTRIBUTE_NAME, - )?), - one_time_content_prekey: content_one_time_key, - one_time_notif_prekey: notif_one_time_key, - }) +impl From for InboundKeyInfo { + fn from(info: DeviceKeysInfo) -> Self { + let DeviceKeysInfo { device_info, .. } = info; + InboundKeyInfo { + identity_info: Some(device_info.device_key_info.into()), + content_prekey: Some(device_info.content_prekey.into()), + notif_prekey: Some(device_info.notif_prekey.into()), + } } } -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") - }) -} - -fn extract_identity_info( - device_info: &mut HashMap, - auth_type: Option<&AuthType>, -) -> Result { - let payload = extract_key( - device_info, - USERS_TABLE_DEVICES_MAP_KEY_PAYLOAD_ATTRIBUTE_NAME, - )?; - let payload_signature = extract_key( - 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() && auth_type == Some(&AuthType::Wallet) { - error!("Social proof missing for wallet user"); - return Err(Status::failed_precondition("Database item malformed")); +impl From for OutboundKeyInfo { + fn from(info: DeviceKeysInfo) -> Self { + let DeviceKeysInfo { + device_info, + content_one_time_key, + notif_one_time_key, + } = info; + OutboundKeyInfo { + identity_info: Some(device_info.device_key_info.into()), + content_prekey: Some(device_info.content_prekey.into()), + notif_prekey: Some(device_info.notif_prekey.into()), + one_time_content_prekey: content_one_time_key, + one_time_notif_prekey: notif_one_time_key, + } } - - Ok(IdentityKeyInfo { - payload, - payload_signature, - social_proof, - }) -} - -fn create_prekey( - device_info: &mut HashMap, - key_attr: &str, - signature_attr: &str, -) -> Result { - Ok(Prekey { - prekey: extract_key(device_info, key_attr)?, - prekey_signature: extract_key(device_info, signature_attr)?, - }) } pub trait DeviceKeyUploadData {