Split up MasterPass::verify into 2 functions: MasterPass::get and master_pass::Model::verify, refactored check_master_pass
This commit is contained in:
		@@ -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(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user