Split up MasterPass::verify into 2 functions: MasterPass::get and master_pass::Model::verify, refactored check_master_pass

This commit is contained in:
StNicolay 2023-05-26 14:40:28 +03:00
parent 1fb004f949
commit e39762916d
Signed by: StNicolay
GPG Key ID: 9693D04DCD962B0D
2 changed files with 26 additions and 27 deletions

View File

@ -1,7 +1,6 @@
use rand::{rngs::OsRng, RngCore};
use scrypt::{scrypt, Params};
use sea_orm::{entity::prelude::*, ActiveValue::Set, QuerySelect};
use tokio::task::spawn_blocking;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "master_pass")]
@ -28,6 +27,14 @@ fn hash_password(password: &[u8], salt: &[u8]) -> crate::Result<Vec<u8>> {
Ok(password_hash)
}
impl Model {
/// Checks that the given password hash matches the one of the model
pub fn verify(&self, password: &str) -> crate::Result<bool> {
let hashed = hash_password(password.as_bytes(), &self.salt)?;
Ok(hashed == self.password_hash)
}
}
impl ActiveModel {
/// Hashes the password and creates an ActiveModel with all fields set to Set variant
#[inline]
@ -44,21 +51,10 @@ impl ActiveModel {
}
impl Entity {
/// Verifies the provided master password against the one from DB
/// Gets the master password from the database
#[inline]
pub async fn verify_master_pass(
user_id: u64,
master_pass: String,
db: &DatabaseConnection,
) -> crate::Result<Option<bool>> {
let model = match Self::find_by_id(user_id).one(db).await? {
Some(model) => model,
None => return Ok(None),
};
let salt = model.salt;
let password_hash =
spawn_blocking(move || hash_password(master_pass.as_bytes(), &salt)).await??;
Ok(Some(password_hash == model.password_hash))
pub async fn get(user_id: u64, db: &DatabaseConnection) -> crate::Result<Option<Model>> {
Self::find_by_id(user_id).one(db).await.map_err(Into::into)
}
/// Checks if the master password for the user exists
@ -75,7 +71,7 @@ impl Entity {
/// Removes a master password of the user from the database
pub async fn remove(user_id: u64, db: &DatabaseConnection) -> crate::Result<()> {
Self::delete_by_id(user_id).exec(db)?;
Self::delete_by_id(user_id).exec(db).await?;
Ok(())
}
}

View File

@ -5,6 +5,7 @@ use crate::{
};
use sea_orm::prelude::*;
use teloxide::{adaptors::Throttle, prelude::*};
use tokio::task::spawn_blocking;
/// Returns true if the provided master password is valid
#[inline]
@ -15,23 +16,25 @@ pub async fn check_master_pass<'a>(
master_pass: &'a str,
) -> crate::Result<bool> {
let user_id = msg.from().ok_or(NoUserInfo)?.id.0;
let result = MasterPass::verify_master_pass(user_id, master_pass.to_owned(), db).await;
match result {
Ok(Some(true)) => Ok(true),
Ok(Some(false)) => {
bot.send_message(msg.chat.id, "Wrong master password")
.reply_markup(deletion_markup())
.await?;
Ok(false)
let model = MasterPass::get(user_id, db).await?;
let is_valid = match model {
Some(model) => {
let master_pass = master_pass.to_owned();
spawn_blocking(move || model.verify(&master_pass)).await??
}
Ok(None) => {
None => {
bot.send_message(msg.chat.id, "No master password set")
.reply_markup(deletion_markup())
.await?;
Ok(false)
return Ok(false);
}
Err(err) => Err(err),
};
if !is_valid {
bot.send_message(msg.chat.id, "Wrong master password")
.reply_markup(deletion_markup())
.await?;
}
Ok(is_valid)
}
pub async fn get_master_pass(