pass_manager/src/handlers/commands/gen_password.rs

64 lines
2.2 KiB
Rust
Raw Normal View History

2023-05-09 17:27:58 +00:00
use crate::handlers::markups::deletion_markup;
2023-05-07 15:07:48 +00:00
use arrayvec::{ArrayString, ArrayVec};
use rand::{rngs::OsRng, seq::SliceRandom};
use std::{iter, str::from_utf8_unchecked};
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
use tokio::task::JoinSet;
2023-05-09 17:27:58 +00:00
const CHARS: &[u8] = br##"!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~"##;
2023-05-07 15:07:48 +00:00
2023-05-09 17:27:58 +00:00
/// Returns true if the generated master password is valid.
/// It checks that it has at least one lowercase, one lowercase and one punctuation char
2023-05-07 15:07:48 +00:00
#[inline]
fn check_generated_password(password: &[u8]) -> bool {
let mut flags: u8 = 0;
for &byte in password {
match byte {
b'a'..=b'z' => flags |= 0b1,
b'A'..=b'Z' => flags |= 0b10,
b'0'..=b'9' => flags |= 0b100,
b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~' => flags |= 0b1000,
_ => (),
}
if flags == 0b1111 {
return true;
}
}
false
}
2023-05-09 17:27:58 +00:00
/// Continuously generates the password until it passes the checks
2023-05-07 15:07:48 +00:00
fn generete_password() -> ArrayString<34> {
loop {
let password: ArrayVec<u8, 32> = iter::repeat_with(|| *CHARS.choose(&mut OsRng).unwrap())
.take(32)
.collect();
if check_generated_password(&password) {
let mut string = ArrayString::<34>::new_const();
string.push('`');
unsafe { string.push_str(from_utf8_unchecked(&password)) };
string.push('`');
return string;
}
}
}
2023-05-09 17:27:58 +00:00
/// Handles /gen_password command by generating 10 copyable passwords and sending them to the user
2023-05-07 15:07:48 +00:00
pub async fn gen_password(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
let mut message = ArrayString::<{ 11 + 35 * 10 }>::new();
message.push_str("Passwords:\n");
let mut join_set = JoinSet::new();
for _ in 0..10 {
2023-05-09 17:27:58 +00:00
join_set.spawn_blocking(generete_password);
2023-05-07 15:07:48 +00:00
}
while let Some(password) = join_set.join_next().await {
message.push_str(password?.as_str());
message.push('\n')
}
bot.send_message(msg.chat.id, message.as_str())
.parse_mode(ParseMode::MarkdownV2)
.reply_markup(deletion_markup())
.await?;
Ok(())
}