From 6d5e2ed6989c0edca8ef0dd4dc1da60a0bf0cb45 Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Wed, 26 Apr 2023 21:37:33 +0200 Subject: [PATCH] dev: fix clippy warnings for: src/routes/user.rs --- src/routes/user.rs | 69 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/src/routes/user.rs b/src/routes/user.rs index 7b195030..d07f7310 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -22,7 +22,7 @@ pub fn init(cfg: &mut web::ServiceConfig) { .service(web::resource("/register").route(web::post().to(register))) .service(web::resource("/login").route(web::post().to(login))) // code-review: should not this be a POST method? We add the user to the blacklist. We do not delete the user. - .service(web::resource("/ban/{user}").route(web::delete().to(ban_user))) + .service(web::resource("/ban/{user}").route(web::delete().to(ban))) .service(web::resource("/token/verify").route(web::post().to(verify_token))) .service(web::resource("/token/renew").route(web::post().to(renew_token))) .service(web::resource("/email/verify/{token}").route(web::get().to(verify_email))), @@ -48,6 +48,19 @@ pub struct Token { pub token: String, } +/// Register a User in the Index +/// +/// # Errors +/// +/// This function will return a `ServiceError::EmailMissing` if email is required, but missing. +/// This function will return a `ServiceError::EmailInvalid` if supplied email is badly formatted. +/// This function will return a `ServiceError::PasswordsDontMatch` if the supplied passwords do not match. +/// This function will return a `ServiceError::PasswordTooShort` if the supplied password is too short. +/// This function will return a `ServiceError::PasswordTooLong` if the supplied password is too long. +/// This function will return a `ServiceError::UsernameInvalid` if the supplied username is badly formatted. +/// This function will return an error if unable to successfully hash the password. +/// This function will return an error if unable to insert user into the database. +/// This function will return a `ServiceError::FailedToSendVerificationEmail` if unable to send the required verification email. pub async fn register(req: HttpRequest, mut payload: web::Json, app_data: WebAppData) -> ServiceResult { info!("registering user: {}", payload.username); @@ -60,7 +73,7 @@ pub async fn register(req: HttpRequest, mut payload: web::Json, app_da } } EmailOnSignup::None => payload.email = None, - _ => {} + EmailOnSignup::Optional => {} } if let Some(email) = &payload.email { @@ -108,13 +121,13 @@ pub async fn register(req: HttpRequest, mut payload: web::Json, app_da let _ = app_data.database.grant_admin_role(user_id).await; } - let conn_info = req.connection_info(); + let conn_info = req.connection_info().clone(); if settings.mail.email_verification_enabled && payload.email.is_some() { let mail_res = app_data .mailer .send_verification_mail( - payload.email.as_ref().unwrap(), + payload.email.as_ref().expect("variable `email` is checked above"), &payload.username, user_id, format!("{}://{}", conn_info.scheme(), conn_info.host()).as_str(), @@ -130,6 +143,15 @@ pub async fn register(req: HttpRequest, mut payload: web::Json, app_da Ok(HttpResponse::Ok()) } +/// Login user to Index +/// +/// # Errors +/// +/// This function will return a `ServiceError::WrongPasswordOrUsername` if unable to get user profile. +/// This function will return a `ServiceError::InternalServerError` if unable to get user authentication data from the user id. +/// This function will return an error if unable to verify the password. +/// This function will return a `ServiceError::EmailNotVerified` if the email should be, but is not verified. +/// This function will return an error if unable to get the user data from the database. pub async fn login(payload: web::Json, app_data: WebAppData) -> ServiceResult { // get the user profile from database let user_profile = app_data @@ -172,6 +194,11 @@ pub async fn login(payload: web::Json, app_data: WebAppData) -> ServiceRe } /// Verify if the user supplied and the database supplied passwords match +/// +/// # Errors +/// +/// This function will return an error if unable to parse password hash from the stored user authentication value. +/// This function will return a `ServiceError::WrongPasswordOrUsername` if unable to match the password with either `argon2id` or `pbkdf2-sha256`. pub fn verify_password(password: &[u8], user_authentication: &UserAuthentication) -> Result<(), ServiceError> { // wrap string of the hashed password into a PasswordHash struct for verification let parsed_hash = PasswordHash::new(&user_authentication.password_hash)?; @@ -195,6 +222,11 @@ pub fn verify_password(password: &[u8], user_authentication: &UserAuthentication } } +/// Verify a supplied JWT. +/// +/// # Errors +/// +/// This function will return an error if unable to verify the supplied payload as a valid jwt. pub async fn verify_token(payload: web::Json, app_data: WebAppData) -> ServiceResult { // verify if token is valid let _claims = app_data.auth.verify_jwt(&payload.token).await?; @@ -204,14 +236,20 @@ pub async fn verify_token(payload: web::Json, app_data: WebAppData) -> Se })) } +/// Renew a supplied JWT. +/// +/// # Errors +/// +/// This function will return an error if unable to verify the supplied payload as a valid jwt. +/// This function will return an error if unable to get user data from the database. pub async fn renew_token(payload: web::Json, app_data: WebAppData) -> ServiceResult { + const ONE_WEEK_IN_SECONDS: u64 = 604_800; + // verify if token is valid let claims = app_data.auth.verify_jwt(&payload.token).await?; let user_compact = app_data.database.get_user_compact_from_id(claims.user.user_id).await?; - const ONE_WEEK_IN_SECONDS: u64 = 604_800; - // renew token if it is valid for less than one week let token = match claims.exp - current_time() { x if x < ONE_WEEK_IN_SECONDS => app_data.auth.sign_jwt(user_compact.clone()).await, @@ -229,7 +267,10 @@ pub async fn renew_token(payload: web::Json, app_data: WebAppData) -> Ser pub async fn verify_email(req: HttpRequest, app_data: WebAppData) -> String { let settings = app_data.cfg.settings.read().await; - let token = req.match_info().get("token").unwrap(); + let token = match req.match_info().get("token").ok_or(ServiceError::InternalServerError) { + Ok(token) => token, + Err(err) => return err.to_string(), + }; let token_data = match decode::( token, @@ -255,8 +296,16 @@ pub async fn verify_email(req: HttpRequest, app_data: WebAppData) -> String { String::from("Email verified, you can close this page.") } -// TODO: add reason and date_expiry parameters to request -pub async fn ban_user(req: HttpRequest, app_data: WebAppData) -> ServiceResult { +/// Ban a user from the Index +/// +/// TODO: add reason and `date_expiry` parameters to request +/// +/// # Errors +/// +/// This function will return a `ServiceError::InternalServerError` if unable get user from the request. +/// This function will return an error if unable to get user profile from supplied username. +/// This function will return an error if unable to ser the ban of the user in the database. +pub async fn ban(req: HttpRequest, app_data: WebAppData) -> ServiceResult { debug!("banning user"); let user = app_data.auth.get_user_compact_from_request(&req).await?; @@ -266,7 +315,7 @@ pub async fn ban_user(req: HttpRequest, app_data: WebAppData) -> ServiceResult