From 200b479de6ad59123ed81767b6d8bfa2734dd15b Mon Sep 17 00:00:00 2001 From: H1ghBre4k3r Date: Fri, 1 Sep 2023 23:06:53 +0200 Subject: [PATCH] feat(auth): implement resend of verification email --- src/contexts/auth.rs | 6 +++++- src/functions/auth.rs | 46 ++++++++++++++++++++++++++++++++----------- src/views/login.rs | 42 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/contexts/auth.rs b/src/contexts/auth.rs index 170382a..c4f261c 100644 --- a/src/contexts/auth.rs +++ b/src/contexts/auth.rs @@ -3,7 +3,8 @@ use cfg_if::cfg_if; use leptos::*; use crate::functions::{ - Login, LoginResult, Logout, Register, RegistrationResult, VerificationResult, Verify, + Login, LoginResult, Logout, Register, RegistrationResult, ResendVerification, + VerificationResult, Verify, }; cfg_if! { @@ -18,6 +19,7 @@ pub struct AuthContext { pub register: Action>, pub logout: Action>, pub verify: Action>, + pub resend_verification_email: Action>, pub user: Resource<(usize, usize, usize), Result, ServerFnError>>, } @@ -27,6 +29,7 @@ impl AuthContext { let logout = create_server_action::(cx); let register = create_server_action::(cx); let verify = create_server_action::(cx); + let resend_verification_email = create_server_action::(cx); let user = create_resource( cx, @@ -45,6 +48,7 @@ impl AuthContext { logout, register, verify, + resend_verification_email, user, } } diff --git a/src/functions/auth.rs b/src/functions/auth.rs index 2ddd5c7..474ce74 100644 --- a/src/functions/auth.rs +++ b/src/functions/auth.rs @@ -7,12 +7,30 @@ use serde::{Deserialize, Serialize}; cfg_if! { if #[cfg(feature = "ssr")] { + use std::error::Error; use std::collections::BTreeMap; use actix_identity::IdentityExt; use crate::hooks::use_identity; use crate::utils::password::hash_password; use crate::model::{User, LoginError, Session}; use crate::services::{mail::Mail, jwt}; + + fn create_jwt(username: &str) -> Result> { + let mut claims = BTreeMap::new(); + claims.insert("sub".into(), username.to_string()); + jwt::sign(claims) + } + + fn send_verification_mail(username: String, email: String, token: String) -> Result<(), Box> { + + let mail = Mail { + subject: Some("Registration Mail".into()), + recipient: email, + content: Some(format!("Hey {username}! \nThank you for registering! To complete your registration, please use the following link: https://aoc.inf-cau.de/verify?token={token}")) + }; + + mail.send() + } } } @@ -50,9 +68,7 @@ pub async fn register( } // create JWT for verification mail - let mut claims = BTreeMap::new(); - claims.insert("sub".into(), username.clone()); - let token_str = match jwt::sign(claims) { + let token = match create_jwt(&username) { Ok(token) => token, Err(e) => { tracing::error!("failed to create JWT: {e:#?}"); @@ -75,13 +91,7 @@ pub async fn register( return Ok(e); }; - let mail = Mail { - subject: Some("Registration Mail".into()), - recipient: email, - content: Some(format!("Hey {username}! \nThank you for registering! To complete your registration, please use the following link: http://localhost:3000/verify?token={token_str}")) - }; - - if mail.send().is_err() { + if send_verification_mail(username, email, token).is_err() { return Ok(RegistrationResult::InternalServerError); } @@ -105,7 +115,7 @@ impl Display for LoginResult { Ok => f.write_str("Login Successful"), InternalServerError => f.write_str("Internal Server Error"), WrongCredentials => f.write_str("Wrong Credentials"), - VerifyEmail => f.write_str("Verify your Email bevore logging in"), + VerifyEmail => f.write_str("Verify your Email before logging in"), AlreadyLoggedIn => f.write_str("You are already logged in"), } } @@ -197,3 +207,17 @@ pub async fn verify_user(cx: Scope, token: String) -> Result Result<(), ServerFnError> { + let Some(user) = User::get_by_username(&username).await else { + return Ok(()); + }; + + let Ok(token) = create_jwt(&username) else { + return Ok(()); + }; + + let _ = send_verification_mail(username, user.email, token); + Ok(()) +} diff --git a/src/views/login.rs b/src/views/login.rs index fcde52c..29787e5 100644 --- a/src/views/login.rs +++ b/src/views/login.rs @@ -1,7 +1,10 @@ use leptos::*; use leptos_router::ActionForm; -use crate::{functions::LoginResult, hooks::use_auth}; +use crate::{ + functions::{LoginResult, ResendVerification}, + hooks::use_auth, +}; #[component] pub fn LoginView(cx: Scope) -> impl IntoView { @@ -30,6 +33,17 @@ pub fn LoginView(cx: Scope) -> impl IntoView { let is_ok = move || matches!(result(), Some(LoginResult::Ok)); + let need_to_verify_email = move || matches!(result(), Some(LoginResult::VerifyEmail)); + + let (username, set_username) = create_signal(cx, "".to_string()); + let (password, set_password) = create_signal(cx, "".to_string()); + + let resend_verification_email = move |_| { + auth.resend_verification_email.dispatch(ResendVerification { + username: username(), + }); + }; + view! { cx, @@ -55,15 +69,37 @@ pub fn LoginView(cx: Scope) -> impl IntoView { > {message()} + }> + "Resend Email" +

"Login"