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 @@ -19,10 +19,10 @@ ACCESS_TOKEN_TABLE_PARTITION_KEY, ACCESS_TOKEN_TABLE_TOKEN_ATTRIBUTE, ACCESS_TOKEN_TABLE_VALID_ATTRIBUTE, USERS_TABLE, USERS_TABLE_DEVICES_ATTRIBUTE, USERS_TABLE_DEVICES_MAP_ATTRIBUTE_NAME, - USERS_TABLE_PARTITION_KEY, USERS_TABLE_REGISTRATION_ATTRIBUTE, - USERS_TABLE_USERNAME_ATTRIBUTE, USERS_TABLE_USERNAME_INDEX, - USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE, USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE, - USERS_TABLE_WALLET_ADDRESS_INDEX, + USERS_TABLE_DEVICE_ATTRIBUTE, USERS_TABLE_PARTITION_KEY, + USERS_TABLE_REGISTRATION_ATTRIBUTE, USERS_TABLE_USERNAME_ATTRIBUTE, + USERS_TABLE_USERNAME_INDEX, USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE, + USERS_TABLE_WALLET_ADDRESS_ATTRIBUTE, USERS_TABLE_WALLET_ADDRESS_INDEX, }; use crate::opaque::Cipher; use crate::token::{AccessTokenData, AuthType}; @@ -316,6 +316,73 @@ } } } + + pub async fn get_user_public_key( + &self, + user_id: String, + device_id: String, + ) -> Result, Error> { + let primary_key = create_simple_primary_key(( + USERS_TABLE_PARTITION_KEY.to_string(), + user_id.clone(), + )); + let get_item_result = self + .client + .get_item() + .table_name(USERS_TABLE) + .set_key(Some(primary_key)) + .consistent_read(true) + .send() + .await; + match get_item_result { + Ok(GetItemOutput { + item: Some(mut item), + .. + }) => { + // `devices` is a HashMap that maps device IDs to a HashMap of + // device-specific attributes + let mut devices = parse_map_attribute( + USERS_TABLE_DEVICES_ATTRIBUTE, + item.remove(USERS_TABLE_DEVICES_ATTRIBUTE), + )?; + let mut device = match parse_map_attribute( + USERS_TABLE_DEVICE_ATTRIBUTE, + devices.remove(&device_id), + ) { + Ok(map) => map, + Err(e) => { + // A device ID not being present is not necessarily an error; let + // the caller decide how to handle it + if matches!(e.attribute_error, DBItemAttributeError::Missing) { + return Ok(None); + } else { + return Err(Error::Attribute(e)); + } + } + }; + parse_string_attribute( + USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE, + device.remove(USERS_TABLE_USER_PUBLIC_KEY_ATTRIBUTE), + ) + .map(Some) + .map_err(Error::Attribute) + } + Ok(_) => { + info!( + "No item found for user {} and device {} in users table", + user_id, device_id + ); + Ok(None) + } + Err(e) => { + error!( + "DynamoDB client failed to get user public key for user {}: {}", + user_id, e + ); + Err(Error::AwsSdk(e.into())) + } + } + } } #[derive(