use std::sync::Arc;
use uuid::Uuid;
use crate::actix_web::HttpResponse;
use crate::biome::credentials::rest_api::actix_web_1::BiomeCredentialsRestConfig;
use crate::biome::credentials::rest_api::resources::credentials::{NewUser, UsernamePassword};
use crate::biome::credentials::store::{
CredentialsBuilder, CredentialsStore, CredentialsStoreError,
};
use crate::futures::{Future, IntoFuture};
#[cfg(feature = "authorization")]
use crate::rest_api::auth::authorization::Permission;
use crate::rest_api::{
actix_web_1::{into_bytes, Method, ProtocolVersionRangeGuard, Resource},
ErrorResponse, SPLINTER_PROTOCOL_VERSION,
};
const UUID_NAMESPACE: Uuid = Uuid::from_u128(140899893353887994607859851180695869034);
const BIOME_REGISTER_PROTOCOL_MIN: u32 = 1;
pub fn make_register_route(
credentials_store: Arc<dyn CredentialsStore>,
rest_config: Arc<BiomeCredentialsRestConfig>,
) -> Resource {
let resource = Resource::build("/biome/register").add_request_guard(
ProtocolVersionRangeGuard::new(BIOME_REGISTER_PROTOCOL_MIN, SPLINTER_PROTOCOL_VERSION),
);
#[cfg(feature = "authorization")]
{
resource.add_method(
Method::Post,
Permission::AllowUnauthenticated,
move |_, payload| {
let credentials_store = credentials_store.clone();
let rest_config = rest_config.clone();
Box::new(into_bytes(payload).and_then(move |bytes| {
let username_password = match serde_json::from_slice::<UsernamePassword>(&bytes)
{
Ok(val) => val,
Err(err) => {
debug!("Error parsing payload {}", err);
return HttpResponse::BadRequest()
.json(ErrorResponse::bad_request(&format!(
"Failed to parse payload: {}",
err
)))
.into_future();
}
};
let user_id =
Uuid::new_v5(&UUID_NAMESPACE, Uuid::new_v4().as_bytes()).to_string();
let credentials_builder = CredentialsBuilder::default();
let credentials = match credentials_builder
.with_user_id(&user_id)
.with_username(&username_password.username)
.with_password(&username_password.hashed_password)
.with_password_encryption_cost(rest_config.password_encryption_cost())
.build()
{
Ok(credential) => credential,
Err(err) => {
debug!("Failed to create credentials {}", err);
return HttpResponse::InternalServerError()
.json(ErrorResponse::internal_error())
.into_future();
}
};
match credentials_store.add_credentials(credentials) {
Ok(()) => {
let new_user = NewUser {
user_id: &user_id,
username: &username_password.username,
};
HttpResponse::Ok()
.json(json!({
"message": "User created successfully",
"data": new_user,
}))
.into_future()
}
Err(err) => {
debug!("Failed to add new credentials to database {}", err);
match err {
CredentialsStoreError::DuplicateError(err) => {
HttpResponse::BadRequest()
.json(ErrorResponse::bad_request(&format!(
"Failed to create user: {}",
err
)))
.into_future()
}
_ => HttpResponse::InternalServerError()
.json(ErrorResponse::internal_error())
.into_future(),
}
}
}
}))
},
)
}
#[cfg(not(feature = "authorization"))]
{
resource.add_method(Method::Post, move |_, payload| {
let credentials_store = credentials_store.clone();
let rest_config = rest_config.clone();
Box::new(into_bytes(payload).and_then(move |bytes| {
let username_password = match serde_json::from_slice::<UsernamePassword>(&bytes) {
Ok(val) => val,
Err(err) => {
debug!("Error parsing payload {}", err);
return HttpResponse::BadRequest()
.json(ErrorResponse::bad_request(&format!(
"Failed to parse payload: {}",
err
)))
.into_future();
}
};
let user_id = Uuid::new_v5(&UUID_NAMESPACE, Uuid::new_v4().as_bytes()).to_string();
let credentials_builder = CredentialsBuilder::default();
let credentials = match credentials_builder
.with_user_id(&user_id)
.with_username(&username_password.username)
.with_password(&username_password.hashed_password)
.with_password_encryption_cost(rest_config.password_encryption_cost())
.build()
{
Ok(credential) => credential,
Err(err) => {
debug!("Failed to create credentials {}", err);
return HttpResponse::InternalServerError()
.json(ErrorResponse::internal_error())
.into_future();
}
};
match credentials_store.add_credentials(credentials) {
Ok(()) => {
let new_user = NewUser {
user_id: &user_id,
username: &username_password.username,
};
HttpResponse::Ok()
.json(json!({
"message": "User created successfully",
"data": new_user,
}))
.into_future()
}
Err(err) => {
debug!("Failed to add new credentials to database {}", err);
match err {
CredentialsStoreError::DuplicateError(err) => {
HttpResponse::BadRequest()
.json(ErrorResponse::bad_request(&format!(
"Failed to create user: {}",
err
)))
.into_future()
}
_ => HttpResponse::InternalServerError()
.json(ErrorResponse::internal_error())
.into_future(),
}
}
}
}))
})
}
}