use axum::Form; use itertools::Itertools; use validator::{Validate, ValidationError}; use crate::{ auth::{HashedBytes, Token}, prelude::*, }; #[derive(Deserialize, Debug, Validate)] pub struct Params { #[validate(length(min = 3, max = 10))] username: String, #[validate(email)] email: String, #[validate(length(min = 6), custom(function = "validate_password"))] password: String, } fn validate_password(password: &str) -> Result<(), ValidationError> { let mut has_lower = false; let mut has_upper = false; let mut has_number = false; let mut has_special = false; for char in password.chars() { if char.is_lowercase() { has_lower = true; } else if char.is_uppercase() { has_upper = true; } else if char.is_ascii_digit() { has_number = true; } else { has_special = true; } } let msg = [has_lower, has_upper, has_number, has_special] .into_iter() .zip(["No lower", "No upper", "No numbers", "No special"]) .filter_map(|(param, msg)| (!param).then_some(msg)) .format(" ") .to_string(); if !msg.is_empty() { return Err(ValidationError::new("invalid_password").with_message(msg.into())); } Ok(()) } pub async fn register( State(pool): State, Form(params): Form, ) -> GeneralResult> { params.validate()?; let password = HashedBytes::hash_bytes(params.password.as_bytes()).as_bytes(); let id = db::users::create_user(¶ms.username, ¶ms.email, &password, &pool) .await .handle_internal("Error creating the user")? .handle( StatusCode::BAD_REQUEST, "The username or the email are taken", )?; Claims::new(id).encode().map(Json) }