diff --git a/cryptography/src/lib.rs b/cryptography/src/lib.rs index db8f12f..113d516 100644 --- a/cryptography/src/lib.rs +++ b/cryptography/src/lib.rs @@ -2,7 +2,7 @@ pub mod account; pub mod master_pass; -pub mod password_generation; +pub mod passwords; pub mod prelude; #[derive(thiserror::Error, Debug)] diff --git a/cryptography/src/password_generation.rs b/cryptography/src/passwords.rs similarity index 71% rename from cryptography/src/password_generation.rs rename to cryptography/src/passwords.rs index d5a52cd..02b3bb3 100644 --- a/cryptography/src/password_generation.rs +++ b/cryptography/src/passwords.rs @@ -50,3 +50,28 @@ fn generate_password() -> ArrayString<32> { pub fn generate_passwords() -> [ArrayString<32>; 10] { array::from_fn(|_| generate_password()) } + +#[inline] +pub fn check_master_pass(password: &str) -> bool { + if password.chars().count() < 8 { + return false; + } + + let mut flags = PasswordFlags::empty(); + for char in password.chars() { + if char.is_lowercase() { + flags |= PasswordFlags::LOWERCASE + } else if char.is_uppercase() { + flags |= PasswordFlags::UPPERCASE + } else if char.is_ascii_digit() { + flags |= PasswordFlags::NUMBER; + } else if char.is_ascii_punctuation() { + flags |= PasswordFlags::SPECIAL_CHARACTER + } + + if flags.is_all() { + return true; + } + } + false +} diff --git a/src/commands/gen_password.rs b/src/commands/gen_password.rs index 1fc320d..e26abac 100644 --- a/src/commands/gen_password.rs +++ b/src/commands/gen_password.rs @@ -1,6 +1,6 @@ use crate::markups::deletion_markup; use arrayvec::ArrayString; -use cryptography::password_generation::generate_passwords; +use cryptography::passwords::generate_passwords; use std::fmt::Write; use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode}; use tokio::task::spawn_blocking; diff --git a/src/commands/set_master_pass.rs b/src/commands/set_master_pass.rs index ad8ebba..faf81bd 100644 --- a/src/commands/set_master_pass.rs +++ b/src/commands/set_master_pass.rs @@ -44,7 +44,10 @@ pub async fn set_master_pass( .send_message(msg.chat.id, "Send new master password") .await?; dialogue - .update(State::GetPassword(Handler::new(get_master_pass, previous))) + .update(State::GetNewMasterPass(Handler::new( + get_master_pass, + previous, + ))) .await?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 3e9bd0a..a5c84fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ pub fn get_dispatcher( .branch(case![State::GetExistingName(next)].endpoint(state::get_existing_name)) .branch(case![State::GetNewName(next)].endpoint(state::get_new_name)) .branch(case![State::GetMasterPass(next)].endpoint(state::get_master_pass)) + .branch(case![State::GetNewMasterPass(next)].endpoint(state::get_new_master_pass)) .branch(case![State::GetLogin(next)].endpoint(state::get_login)) .branch(case![State::GetPassword(next)].endpoint(state::get_password)) .branch(case![State::GetUser(next)].endpoint(state::get_user)) diff --git a/src/state/get_new_master_pass.rs b/src/state/get_new_master_pass.rs new file mode 100644 index 0000000..0ef136a --- /dev/null +++ b/src/state/get_new_master_pass.rs @@ -0,0 +1,44 @@ +use crate::MainDialogue; +use cryptography::passwords::check_master_pass; +use sea_orm::DatabaseConnection; +use teloxide::{adaptors::Throttle, prelude::*}; + +const INVALID_MASTER_PASS_MESSAGE: &str = "Master password is invalid. It must be at least 8 characters long. \ +It also has to contain at least one lowercase, one uppercase, one number and one punctuation character"; + +/// Checks that the account with that name exists +#[inline] +async fn check_new_master_pass( + bot: &Throttle, + msg: &Message, + password: &str, +) -> crate::Result> { + let is_valid = check_master_pass(password); + if !is_valid { + let msg = bot + .send_message(msg.chat.id, INVALID_MASTER_PASS_MESSAGE) + .await?; + return Ok(Some(msg)); + } + Ok(None) +} + +/// Handles GetNewMasterPass state +pub async fn get_new_master_pass( + bot: Throttle, + msg: Message, + db: DatabaseConnection, + dialogue: MainDialogue, + next: super::PackagedHandler, +) -> crate::Result<()> { + super::generic::generic( + bot, + msg, + db, + dialogue, + |bot, msg, _, password| Box::pin(check_new_master_pass(bot, msg, password)), + "Couldn't get the text of the message. Send the master password again", + next, + ) + .await +} diff --git a/src/state/mod.rs b/src/state/mod.rs index 354e2e0..a8168b1 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -4,6 +4,7 @@ mod generic; mod get_existing_name; mod get_login; mod get_master_pass; +mod get_new_master_pass; mod get_new_name; mod get_password; mod get_user; @@ -12,6 +13,7 @@ mod handler; pub use get_existing_name::get_existing_name; pub use get_login::get_login; pub use get_master_pass::get_master_pass; +pub use get_new_master_pass::get_new_master_pass; pub use get_new_name::get_new_name; pub use get_password::get_password; pub use get_user::get_user; @@ -27,6 +29,7 @@ pub enum State { GetExistingName(PackagedHandler), GetNewName(PackagedHandler), GetMasterPass(PackagedHandler), + GetNewMasterPass(PackagedHandler), GetLogin(PackagedHandler), GetPassword(PackagedHandler), GetUser(PackagedHandler),