diff --git a/Cargo.lock b/Cargo.lock --- a/Cargo.lock +++ b/Cargo.lock @@ -1266,6 +1266,7 @@ "clap", "comm-lib", "derive_more", + "grpc_clients", "once_cell", "reqwest", "serde", diff --git a/services/backup/Cargo.toml b/services/backup/Cargo.toml --- a/services/backup/Cargo.toml +++ b/services/backup/Cargo.toml @@ -20,6 +20,7 @@ "grpc_clients", "crypto" ] } +grpc_clients = { path = "../../shared/grpc_clients" } once_cell = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tokio-stream = { workspace = true } diff --git a/services/backup/src/error.rs b/services/backup/src/error.rs --- a/services/backup/src/error.rs +++ b/services/backup/src/error.rs @@ -8,6 +8,7 @@ pub use aws_sdk_dynamodb::Error as DynamoDBError; use comm_lib::database::Error as DBError; use comm_lib::{auth::AuthServiceError, blob::client::BlobServiceError}; +use grpc_clients::error::Error as IdentityError; use reqwest::StatusCode; use tracing::{error, trace, warn}; @@ -16,9 +17,11 @@ )] pub enum BackupError { NoBackup, + NoUserID, BlobError(BlobServiceError), AuthError(AuthServiceError), DB(comm_lib::database::Error), + IdentityError(IdentityError), } impl From<&BackupError> for actix_web::Error { @@ -65,6 +68,11 @@ ErrorInternalServerError("server error") } }, + BackupError::IdentityError(err) => { + warn!("Transient identity error occurred: {err}"); + ErrorServiceUnavailable("please retry") + } + BackupError::NoUserID => ErrorBadRequest("bad request"), } } } diff --git a/services/backup/src/identity/mod.rs b/services/backup/src/identity/mod.rs new file mode 100644 --- /dev/null +++ b/services/backup/src/identity/mod.rs @@ -0,0 +1,51 @@ +use comm_lib::crypto::siwe; +use grpc_clients::{ + error::Error, + identity::{ + get_unauthenticated_client, protos::unauth::FindUserIdRequest, + protos::unauthenticated::find_user_id_request::Identifier, + PlatformMetadata, + }, + tonic::Request, +}; + +use crate::config::CONFIG; +use crate::error::BackupError; + +// Identity service gRPC clients require a code version and device type. +// We can supply some placeholder values for services for the time being, since +// this metadata is only relevant for devices. +const PLACEHOLDER_CODE_VERSION: u64 = 0; +const DEVICE_TYPE: &str = "service"; + +/// Returns `userID` for both Password and Wallet users. +pub async fn find_user_id( + public_user_identifier: &str, +) -> Result { + let mut grpc_client = get_unauthenticated_client( + &CONFIG.identity_endpoint, + PlatformMetadata::new(PLACEHOLDER_CODE_VERSION, DEVICE_TYPE), + ) + .await?; + + let identifier = if siwe::is_valid_ethereum_address(public_user_identifier) { + Identifier::WalletAddress(public_user_identifier.to_string()) + } else { + Identifier::Username(public_user_identifier.to_string()) + }; + + let request = FindUserIdRequest { + identifier: Some(identifier), + }; + let request = Request::new(request); + let response = grpc_client + .find_user_id(request) + .await + .map_err(Error::GrpcStatus)? + .into_inner(); + + match response.user_id { + Some(user_id) => Ok(user_id), + None => Err(BackupError::NoUserID), + } +} diff --git a/services/backup/src/main.rs b/services/backup/src/main.rs --- a/services/backup/src/main.rs +++ b/services/backup/src/main.rs @@ -8,6 +8,7 @@ pub mod database; pub mod error; pub mod http; +pub mod identity; // re-export this to be available as crate::CONFIG pub use config::CONFIG;