Skip to content

Commit

Permalink
Merge pull request #63 from Rajdip019/dashboard-setup
Browse files Browse the repository at this point in the history
Forget password Server page added
  • Loading branch information
Rajdip019 authored Jul 24, 2024
2 parents 6aa99be + ec15878 commit 2eca702
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 15 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"./Cargo.toml",
],
"cSpell.words": [
"blazingly",
"bson",
"chrono",
"deks",
Expand Down
9 changes: 8 additions & 1 deletion src/core/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ impl User {
&user.name,
&user.email,
&"Reset Password",
&format!("Please click on the link to reset your password: http://localhost:8080/forget-password-reset/{}", new_doc.id),
&format!("Please click on the link to reset your password: http://localhost:8080/forget-reset/{}", new_doc.id),
).send().await;

Ok("Forget password request sent to email successfully".to_string())
Expand All @@ -702,6 +702,10 @@ impl User {
let forget_password_requests_collection: Collection<ForgetPasswordRequest> =
db.collection("forget_password_requests");

println!("Forget Password Request ID {:?}", req_id);
println!("Forget Password Request Email {:?}", email);
println!("Forget Password Request New Password {:?}", new_password);

// find the dek with the email
let dek_data = match Dek::get(&mongo_client, &email).await {
Ok(dek) => dek,
Expand All @@ -717,6 +721,8 @@ impl User {
.unwrap()
.unwrap();

println!("Forget Password Request {:?}", forget_password_request);

if forget_password_request.is_used {
return Err(Error::ResetPasswordLinkExpired {
message: "The link has already been used. Please request a new link.".to_string(),
Expand Down Expand Up @@ -789,6 +795,7 @@ impl User {
).send().await;

Ok("Password updated successfully".to_string())

}

pub async fn delete(mongo_client: &Client, email: &str) -> Result<String> {
Expand Down
93 changes: 90 additions & 3 deletions src/handlers/password_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use crate::{
AppState,
};
use axum::{
extract::{Path, State},
Json,
extract::{Path, State}, response::{Html, IntoResponse}, Json
};
use axum_macros::debug_handler;
use bson::doc;
Expand Down Expand Up @@ -83,7 +82,7 @@ pub async fn forget_password_reset_handler(
// check if payload is valid
if payload.email.is_empty() | payload.password.is_empty() {
return Err(Error::InvalidPayload {
message: "Email is required.".to_string(),
message: "Invalid Payload".to_string(),
});
}
match User::forget_password_reset(&state.mongo_client, &id, &payload.email, &payload.password)
Expand All @@ -97,3 +96,91 @@ pub async fn forget_password_reset_handler(
Err(e) => return Err(e),
}
}

#[debug_handler] //forget_password_form
pub async fn forget_password_form(Path(id): Path<String>) -> impl IntoResponse {
Html(format!(r#"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Password</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 0; background-color: #060A13 }}
.navbar {{ background-color: #060A13; overflow: hidden; border-bottom: 0.5px solid #1E293B; }}
.navbar a {{ float: left; display: block; color: #f2f2f2; text-align: center; padding: 14px 16px; text-decoration: none; }}
.navbar a:hover {{ background-color: #ddd; color: black; }}
.form-div {{ margin: 0 auto; display: flex; justify-content: center; align-items: center }}
form {{ margin-top: 20px; display: flex; flex-direction: column; align-items: left; width: 40%; }}
label {{ display: block; margin-top: 10px; text-align: left; color: #f2f2f2; }}
input {{ width: 100%; padding: 8px; margin-top: 5px; margin-bottom: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }}
button {{ padding: 10px 20px; background-color: #3B81F6; color: #f2f2f2; border: none; cursor: pointer; border-radius: 5px; width: 100%; }}
h1 {{ color: #f2f2f2; text-align: center; padding: 14px 0px; }}
h2 {{ text-align: center; color: #f2f2f2; }}
p {{ color: #f2f2f2; margin-top: 30px; }}
</style>
</head>
<body>
<div class='navbar'>
<h1>FlexAuth</h1>
</div>
<h2>Reset Password</h2>
<div class='form-div'>
<form id="resetForm">
<label for="email">Enter Email:</label>
<input type="email" id="email" name="email" required placeholder="Enter email">
<label for="password">Enter Password:</label>
<input type="password" id="password" name="password" required placeholder="Enter new password">
<label for="confirm_password">Confirm Password:</label>
<input type="password" id="confirm_password" name="confirm_password" required placeholder="Confirm new password">
<br />
<button type="submit">Submit</button>
<p><b>Note:</b> Password must be at least 8 characters long and include at least one uppercase letter, one lowercase letter, one number, and one special character.</p>
</form>
</div>
<script>
document.getElementById('resetForm').addEventListener('submit', function(event) {{
event.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
const confirmPassword = document.getElementById('confirm_password').value;
const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{{8,}}$/;
if (!passwordPattern.test(password)) {{
alert('Password must be at least 8 characters long and include at least one uppercase letter, one lowercase letter, one number, and one special character.');
}} else if (password !== confirmPassword) {{
alert('Passwords do not match.');
}} else {{
fetch(`/api/password/forget-reset/{id}`, {{
method: 'POST',
headers: {{
'Content-Type': 'application/json',
'x-api-key': '{api_key}'
}},
body: JSON.stringify({{
email: email,
password: password
}})
}}).then(response => {{
if (response.ok) {{
alert('Password reset successful!');
}} else {{
response.json().then(res => {{
alert('Error: ' + res.error.type);
}}).catch(error => {{
alert('An error occurred: ' + error.message);
}});
}}
}}).catch(error => {{
alert('An error occurred: ' + error.message);
}});
}}
}});
</script>
</body>
</html>
"#, id = id, api_key = dotenv::var("X_API_KEY").unwrap()))
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use axum::response::Html;
use axum::routing::get;
use axum::{middleware, Router};
use dotenv::dotenv;
use handlers::password_handler::forget_password_form;
use middlewares::res_log::main_response_mapper;
use middlewares::with_api_key::with_api_key;
use mongodb::Client;
Expand Down Expand Up @@ -43,6 +44,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Define routes where middleware is not applied
let public_routes = Router::new()
.route("/", get(root_handler))
.route("/forget-reset/:id", get(forget_password_form))
.merge(routes::health_check_routes::routes())
.layer(middleware::map_response(main_response_mapper));

Expand Down
3 changes: 1 addition & 2 deletions src/routes/auth_routes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use axum::{extract::State, routing::post, Router};

use crate::{
handlers::auth_handler::{signin_handler, signout_handler, signup_handler},
AppState,
handlers::auth_handler::{signin_handler, signout_handler, signup_handler}, AppState
};

pub fn routes(State(state): State<AppState>) -> Router {
Expand Down
3 changes: 2 additions & 1 deletion src/routes/password_routes.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use axum::{extract::State, routing::post, Router};

use crate::{handlers::password_handler::{forget_password_reset_handler, forget_password_request_handler, reset_password_handler}, AppState};
use crate::{handlers::password_handler::{forget_password_request_handler, forget_password_reset_handler, reset_password_handler}, AppState};

pub fn routes(State(state): State<AppState>) -> Router {
let password_rotes = Router::new()
.route("/reset", post(reset_password_handler))
.route("/forget-request", post(forget_password_request_handler))
.route("/forget-reset/:id", post(forget_password_reset_handler));


Router::new().nest("/password", password_rotes).with_state(state)
}
5 changes: 2 additions & 3 deletions src/routes/session_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use axum::{extract::State, routing::{get, post}, Router};

use crate::{
handlers::session_handler::{
delete_handler, delete_all_handler, get_all_from_uid_handler, get_details_handler, refresh_session_handler, revoke_handler, revoke_all_handler, verify_session_handler, get_all_handler
},
AppState,
delete_all_handler, delete_handler, get_all_from_uid_handler, get_all_handler, get_details_handler, refresh_session_handler, revoke_all_handler, revoke_handler, verify_session_handler
}, AppState
};

pub fn routes(State(state): State<AppState>) -> Router {
Expand Down
7 changes: 2 additions & 5 deletions src/routes/user_routes.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use axum::{
extract::State,
routing::{get, post},
Router,
extract::State, routing::{get, post}, Router
};

use crate::{
handlers::user_handler::{
delete_user_handler, get_all_users_handler, get_recent_users_handler, get_user_email_handler, get_user_id_handler, toggle_user_activation_status, update_user_handler, update_user_role_handler
},
AppState,
}, AppState
};

pub fn routes(State(state): State<AppState>) -> Router {
Expand Down

0 comments on commit 2eca702

Please sign in to comment.