117 lines
4.0 KiB
Rust
117 lines
4.0 KiB
Rust
use std::iter;
|
|
|
|
use argon2::Config;
|
|
use chrono::{NaiveDateTime, Utc};
|
|
use diesel::{ExpressionMethods, RunQueryDsl};
|
|
use diesel::query_dsl::filter_dsl::FilterDsl;
|
|
use diesel::query_dsl::select_dsl::SelectDsl;
|
|
use rand::{Rng, thread_rng};
|
|
use rand::distributions::Alphanumeric;
|
|
use rocket::State;
|
|
|
|
use crate::database::controller::connector::establish_connection;
|
|
use crate::helper::settings::Settings;
|
|
use crate::logger::{add_entry, LogActions};
|
|
use crate::logger::entries::InsertableLogEntry;
|
|
use crate::schema::password_resets::dsl::password_resets;
|
|
use crate::schema::users::dsl::users;
|
|
|
|
/// Adds password reset token to database and returns it
|
|
pub fn add_token(settings: &State<Settings>, user_id: uuid::Uuid) -> Result<String, diesel::result::Error>{
|
|
let connection = establish_connection(settings);
|
|
|
|
let mut rng = thread_rng();
|
|
let token: String = iter::repeat(())
|
|
.map(|()| rng.sample(Alphanumeric))
|
|
.map(char::from)
|
|
.take(60)
|
|
.collect();
|
|
|
|
|
|
match diesel::insert_into(password_resets).values((crate::schema::password_resets::token.eq(token.clone()), crate::schema::password_resets::user_id.eq(user_id))).execute(&connection){
|
|
Ok(_) => Ok(token),
|
|
|
|
Err(e) => {
|
|
error!("Couldn't create password reset token: {}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn remove_token(settings: &State<Settings>, token2: String) -> Result<(), diesel::result::Error>{
|
|
let connection = establish_connection(settings);
|
|
|
|
match diesel::delete(password_resets).filter(crate::schema::password_resets::dsl::token.eq(token2)).execute(&connection){
|
|
Ok(_) => Ok(()),
|
|
Err(e) => {
|
|
error!("Couldn't delete token: {}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn validate_token(settings: &State<Settings>, token2: String) -> Result<uuid::Uuid, diesel::result::Error>{
|
|
let connection = establish_connection(settings);
|
|
|
|
match password_resets.select((crate::schema::password_resets::dsl::user_id, crate::schema::password_resets::issued)).filter(crate::schema::password_resets::dsl::token.eq(token2.clone())).get_result::<(uuid::Uuid, NaiveDateTime)>(&connection){
|
|
Ok(data) => {
|
|
let issued = data.1;
|
|
let now = Utc::now().naive_local();
|
|
let duration = now.signed_duration_since(issued).num_seconds();
|
|
if duration > settings.application.reset_password_token_valid_duration{
|
|
remove_token(settings, token2)?;
|
|
return Err(diesel::result::Error::NotFound)
|
|
}
|
|
Ok(data.0)
|
|
},
|
|
Err(e) => match e{
|
|
diesel::result::Error::NotFound => {
|
|
return Err(e)
|
|
},
|
|
_ => {
|
|
error!("Couldn't validate token: {}", e);
|
|
return Err(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn change_password_with_token(settings: &State<Settings>, token2: String, password: String) -> Result<(), ()>{
|
|
let user_id = match validate_token(settings, token2.clone()){
|
|
Ok(user_id) => user_id,
|
|
Err(_) => return Err(())
|
|
};
|
|
|
|
let connection =establish_connection(settings);
|
|
let salt = rand::thread_rng().gen::<[u8; 32]>();
|
|
let hashed_password = match argon2::hash_encoded(password.as_bytes(), &salt, &Config::default()){
|
|
Ok(pw) => pw,
|
|
Err(e) => {
|
|
error!("Couldn't hash password: {}", e);
|
|
return Err(())
|
|
}
|
|
};
|
|
|
|
match diesel::update(users).filter(crate::schema::users::dsl::id.eq(user_id)).set(crate::schema::users::dsl::password.eq(hashed_password)).execute(&connection){
|
|
Ok(_) => (),
|
|
Err(e) => {
|
|
error!("Couldn't set new password: {}", e);
|
|
return Err(())
|
|
}
|
|
};
|
|
|
|
add_entry(InsertableLogEntry::new(LogActions::PasswordReset, Some(user_id), None, None), settings);
|
|
|
|
match remove_token(settings, token2){
|
|
Ok(_) => Ok(()),
|
|
Err(_) => Err(())
|
|
}
|
|
}
|
|
|
|
pub fn validate_password(password: String) -> bool{
|
|
if password.len() < 10{
|
|
return false
|
|
}
|
|
|
|
true
|
|
} |