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,5 +1,6 @@ +use std::collections::HashMap; // Standard library imports -use std::{str::FromStr}; +use std::str::FromStr; // External crate imports use aws_sdk_dynamodb::Error as DynamoDBError; @@ -11,7 +12,8 @@ // Workspace crate imports use crate::client_service::client_proto::{ - AddReservedUsernamesRequest, DeleteUserRequest, Empty, GenerateNonceResponse, InboundKeysForUserRequest, + inbound_keys_for_user_request::Identifier, AddReservedUsernamesRequest, + DeleteUserRequest, Empty, GenerateNonceResponse, InboundKeysForUserRequest, InboundKeysForUserResponse, LogoutRequest, OpaqueLoginFinishRequest, OpaqueLoginFinishResponse, OpaqueLoginStartRequest, OpaqueLoginStartResponse, OutboundKeysForUserRequest, OutboundKeysForUserResponse, @@ -27,6 +29,7 @@ use crate::database::{DatabaseClient, Device, KeyPayload}; use crate::error::Error as DBError; +use crate::grpc_utils::DeviceInfoWithAuth; use crate::id::generate_uuid; use crate::nonce::generate_nonce_data; use crate::reserved_users::{ @@ -40,6 +43,8 @@ IdentityClientService, IdentityClientServiceServer, }; +use self::client_proto::InboundKeyInfo; + pub mod client_proto { tonic::include_proto!("identity.client"); } @@ -790,9 +795,50 @@ async fn get_inbound_keys_for_user( &self, - _request: tonic::Request, + request: tonic::Request, ) -> Result, tonic::Status> { - unimplemented!(); + let message = request.into_inner(); + + let (user_ident, auth_type) = match message.identifier { + None => { + return Err(tonic::Status::invalid_argument("no identifier provided")) + } + Some(Identifier::Username(username)) => (username, AuthType::Password), + Some(Identifier::WalletAddress(address)) => (address, AuthType::Wallet), + }; + + let devices_map = self + .client + .get_keys_for_user(user_ident, &auth_type) + .await + .map_err(handle_db_error)? + .ok_or_else(|| match auth_type { + AuthType::Password => tonic::Status::not_found("username not found"), + AuthType::Wallet => { + tonic::Status::not_found("wallet address not found") + } + })?; + + let transformed_devices = devices_map + .into_iter() + .filter_map(|(key, device_info)| { + let device_info_with_auth = DeviceInfoWithAuth { + device_info, + auth_type: &auth_type, + }; + match InboundKeyInfo::try_from(device_info_with_auth) { + Ok(key_info) => Some(Ok((key, key_info))), + Err(_) => { + error!("Failed to transform device info for key {}", key); + None + } + } + }) + .collect::, tonic::Status>>()?; + + Ok(tonic::Response::new(InboundKeysForUserResponse { + devices: transformed_devices, + })) } async fn upload_one_time_keys( 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 @@ -18,12 +18,12 @@ token::AuthType, }; -struct DeviceInfoWithAuth<'a> { - device_info: HashMap, - auth_type: &'a AuthType, +pub struct DeviceInfoWithAuth<'a> { + pub device_info: HashMap, + pub auth_type: &'a AuthType, } -impl<'a> TryFrom> for InboundKeyInfo { +impl TryFrom> for InboundKeyInfo { type Error = tonic::Status; fn try_from(data: DeviceInfoWithAuth) -> Result {