From 8a2f482bbd118a53bdfce04e2d455b317676ef6c Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Mon, 13 Jul 2020 14:52:25 +0200 Subject: [PATCH] Can check the validity of a password reset token --- src/constants.rs | 8 +++++++- src/controllers/account_controller.rs | 20 +++++++++++++++++++- src/controllers/routes.rs | 1 + src/data/http_request_handler.rs | 12 ++++++++++++ src/helpers/account_helper.rs | 12 +++++++++++- 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 63d4a22..784bebf 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -82,4 +82,10 @@ pub const PATH_COMMENTS_IMAGES: &str = "imgcommentaire"; pub const MAX_REQUEST_SIZE: usize = 50000000; /// Maximum number of choices per survey -pub const MAXIMUM_NUMBER_SURVEY_CHOICES: usize = 20; \ No newline at end of file +pub const MAXIMUM_NUMBER_SURVEY_CHOICES: usize = 20; + +/// Length of password reset token +pub const PASSWORD_RESET_TOKEN_LENGTH: usize = 255; + +/// Duration of the validity of a password reset token (6 hours) +pub const PASSWORD_RESET_TOKEN_LIFETIME: u64 = 60 * 60 * 6; \ No newline at end of file diff --git a/src/controllers/account_controller.rs b/src/controllers/account_controller.rs index cfff084..8d443a9 100644 --- a/src/controllers/account_controller.rs +++ b/src/controllers/account_controller.rs @@ -6,11 +6,12 @@ use crate::api_data::res_check_email_exists::ResCheckEmailExists; use crate::api_data::res_check_security_answers::ResCheckSecurityAnswers; use crate::api_data::res_check_security_questions_exists::ResCheckSecurityQuestionsExists; use crate::api_data::res_get_security_questions::ResGetSecurityQuestions; +use crate::constants::PASSWORD_RESET_TOKEN_LENGTH; use crate::controllers::routes::RequestResult; use crate::data::error::ResultBoxError; use crate::data::http_request_handler::HttpRequestHandler; use crate::data::new_account::NewAccount; -use crate::data::user::User; +use crate::data::user::{User, UserID}; use crate::helpers::{account_helper, user_helper}; /// Account controller @@ -27,6 +28,17 @@ impl HttpRequestHandler { format!("Requested user in '{}' not found!", email).as_str(), ) } + + /// Get the ID of the user associated with a password reset token + pub fn post_user_id_from_password_reset_token(&mut self, field: &str) -> ResultBoxError { + let token = self.post_string_opt(field, PASSWORD_RESET_TOKEN_LENGTH, true)?; + let user_id = self.ok_or_forbidden( + account_helper::get_user_id_from_password_reset_token(&token), + "Invalid password reset token!", + )?; + + Ok(user_id) + } } /// Create a new account @@ -148,4 +160,10 @@ pub fn check_security_answers(r: &mut HttpRequestHandler) -> RequestResult { let token = account_helper::generate_password_reset_token(&user.id)?; r.set_response(ResCheckSecurityAnswers::new(token)) +} + +/// Check the validity of a password reset token +pub fn check_password_reset_token(r: &mut HttpRequestHandler) -> RequestResult { + r.post_user_id_from_password_reset_token("token")?; + r.success("The token is valid") } \ No newline at end of file diff --git a/src/controllers/routes.rs b/src/controllers/routes.rs index 8c61d73..62d7bed 100644 --- a/src/controllers/routes.rs +++ b/src/controllers/routes.rs @@ -79,6 +79,7 @@ pub fn get_routes() -> Vec { Route::post_without_login("/account/has_security_questions", Box::new(account_controller::has_security_questions)), Route::post_without_login("/account/get_security_questions", Box::new(account_controller::get_security_questions)), Route::post_without_login("/account/check_security_answers", Box::new(account_controller::check_security_answers)), + Route::post_without_login("/account/check_password_reset_token", Box::new(account_controller::check_password_reset_token)), // User controller Route::post_without_login("/user/getInfo", Box::new(user_controller::get_single)), diff --git a/src/data/http_request_handler.rs b/src/data/http_request_handler.rs index b23cd46..ea61665 100644 --- a/src/data/http_request_handler.rs +++ b/src/data/http_request_handler.rs @@ -156,6 +156,18 @@ impl HttpRequestHandler { } } + /// If result is not OK, return a bad request + pub fn ok_or_forbidden(&mut self, res: ResultBoxError, msg: &str) -> ResultBoxError { + match res { + Ok(e) => Ok(e), + Err(err) => { + println!("Error leading to access forbidden: {}", err); + self.forbidden(msg.to_string())?; + unreachable!() + } + } + } + /// If result is not OK, return a 404 not found error pub fn ok_or_not_found(&mut self, res: ResultBoxError, msg: &str) -> ResultBoxError { match res { diff --git a/src/helpers/account_helper.rs b/src/helpers/account_helper.rs index af214bf..0c5b4ab 100644 --- a/src/helpers/account_helper.rs +++ b/src/helpers/account_helper.rs @@ -1,3 +1,4 @@ +use crate::constants::{PASSWORD_RESET_TOKEN_LENGTH, PASSWORD_RESET_TOKEN_LIFETIME}; use crate::constants::database_tables_names::{USER_ACCESS_TOKENS_TABLE, USERS_TABLE}; use crate::data::api_client::APIClient; use crate::data::error::{ExecError, ResultBoxError}; @@ -116,7 +117,7 @@ pub fn destroy_all_user_tokens(id: &UserID) -> ResultBoxError { /// Generate a new password reset token pub fn generate_password_reset_token(user_id: &UserID) -> ResultBoxError { - let token = rand_str(255); + let token = rand_str(PASSWORD_RESET_TOKEN_LENGTH); database::UpdateInfo::new(USERS_TABLE) .cond_user_id("ID", user_id) @@ -127,6 +128,15 @@ pub fn generate_password_reset_token(user_id: &UserID) -> ResultBoxError Ok(token) } +/// Get the ID of a user based on a password reset token +pub fn get_user_id_from_password_reset_token(token: &str) -> ResultBoxError { + database::QueryInfo::new(USERS_TABLE) + .cond("password_reset_token", token) + .set_custom_where("password_reset_token_time_create > ?") + .add_custom_where_argument_u64(time() - PASSWORD_RESET_TOKEN_LIFETIME) + .query_row(|r| r.get_user_id("ID")) +} + /// Check out whether a virtual directory is taken by a user or not pub fn check_user_directory_availability(dir: &str, user_id: Option) -> ResultBoxError { let found_user = user_helper::find_user_by_virtual_directory(dir);