Sepparated the code out into 3 more library crates: cryptography, entity and pass_manager
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use crate::handlers::markups::deletion_markup;
|
||||
use crate::markups::deletion_markup;
|
||||
use teloxide::{adaptors::Throttle, dispatching::DpHandlerDescription, prelude::*};
|
||||
|
||||
/// Deletes the message from the callback
|
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
errors::NoUserInfo,
|
||||
handlers::{markups::deletion_markup, state::NameCheckKind, Handler, MainDialogue, State},
|
||||
models::DecryptedAccount,
|
||||
errors::NoUserInfo, markups::deletion_markup, models::DecryptedAccount, state::NameCheckKind,
|
||||
Handler, MainDialogue, State,
|
||||
};
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
@ -1,4 +1,4 @@
|
||||
use crate::handlers::markups::deletion_markup;
|
||||
use crate::markups::deletion_markup;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
/// Handles /cancel command when there's no active state
|
@ -1,12 +1,10 @@
|
||||
use crate::{
|
||||
entity::prelude::Account,
|
||||
errors::NoUserInfo,
|
||||
handlers::{
|
||||
markups::{self, deletion_markup},
|
||||
state::NameCheckKind,
|
||||
Handler, MainDialogue, State,
|
||||
},
|
||||
markups::{self, deletion_markup},
|
||||
state::NameCheckKind,
|
||||
Handler, MainDialogue, State,
|
||||
};
|
||||
use entity::prelude::*;
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
@ -1,9 +1,6 @@
|
||||
use crate::{
|
||||
entity::prelude::*,
|
||||
errors::NoUserInfo,
|
||||
handlers::{markups::deletion_markup, Handler, MainDialogue, State},
|
||||
};
|
||||
use sea_orm::prelude::*;
|
||||
use crate::{errors::NoUserInfo, markups::deletion_markup, Handler, MainDialogue, State};
|
||||
use entity::prelude::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
use tokio::join;
|
||||
|
||||
@ -23,7 +20,7 @@ async fn get_master_pass(
|
||||
MasterPass::remove(user_id, &db),
|
||||
) {
|
||||
(Ok(_), Ok(_)) => (),
|
||||
(Err(err), _) | (Ok(_), Err(err)) => return Err(err),
|
||||
(Err(err), _) | (Ok(_), Err(err)) => return Err(err.into()),
|
||||
};
|
||||
bot.send_message(msg.chat.id, "Everything was deleted")
|
||||
.reply_markup(deletion_markup())
|
@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
entity::prelude::Account,
|
||||
errors::NoUserInfo,
|
||||
handlers::{markups::deletion_markup, Handler, MainDialogue, State},
|
||||
markups::deletion_markup,
|
||||
models::{DecryptedAccount, User},
|
||||
Handler, MainDialogue, State,
|
||||
};
|
||||
use entity::prelude::*;
|
||||
use futures::TryStreamExt;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use serde_json::to_vec_pretty;
|
||||
@ -26,6 +27,7 @@ async fn get_master_pass(
|
||||
let master_pass: Arc<str> = master_pass.into();
|
||||
Account::get_all(user_id, &db)
|
||||
.await?
|
||||
.err_into::<crate::Error>()
|
||||
.try_for_each_concurrent(None, |account| {
|
||||
let master_pass = Arc::clone(&master_pass);
|
||||
async move {
|
20
src/commands/gen_password.rs
Normal file
20
src/commands/gen_password.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use crate::markups::deletion_markup;
|
||||
use arrayvec::ArrayString;
|
||||
use cryptography::password_generation::generate_passwords;
|
||||
use std::fmt::Write;
|
||||
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
/// Handles /gen_password command by generating 10 copyable passwords and sending them to the user
|
||||
pub async fn gen_password(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
||||
let mut message: ArrayString<{ 10 + 35 * 10 }> = "Passwords:".try_into().unwrap();
|
||||
let passwords = spawn_blocking(generate_passwords).await?;
|
||||
for password in passwords {
|
||||
write!(message, "\n`{password}`").unwrap();
|
||||
}
|
||||
bot.send_message(msg.chat.id, message.as_str())
|
||||
.parse_mode(ParseMode::MarkdownV2)
|
||||
.reply_markup(deletion_markup())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
use crate::{
|
||||
entity::prelude::Account,
|
||||
errors::NoUserInfo,
|
||||
handlers::{
|
||||
markups::{self, deletion_markup},
|
||||
state::NameCheckKind,
|
||||
Handler, MainDialogue, State,
|
||||
},
|
||||
markups::{self, deletion_markup},
|
||||
state::NameCheckKind,
|
||||
Handler, MainDialogue, State,
|
||||
};
|
||||
use sea_orm::prelude::*;
|
||||
use cryptography::prelude::*;
|
||||
use entity::prelude::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
|
||||
use tokio::task::spawn_blocking;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{entity::prelude::Account, errors::NoUserInfo, handlers::markups::deletion_markup};
|
||||
use crate::{errors::NoUserInfo, markups::deletion_markup};
|
||||
use entity::prelude::*;
|
||||
use futures::TryStreamExt;
|
||||
use sea_orm::prelude::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use std::fmt::Write;
|
||||
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::handlers::{markups::deletion_markup, Command};
|
||||
use crate::{markups::deletion_markup, Command};
|
||||
use teloxide::{adaptors::Throttle, prelude::*, utils::command::BotCommands};
|
||||
|
||||
/// Handles the help command by sending the passwords descryptions
|
@ -1,7 +1,5 @@
|
||||
use crate::{
|
||||
errors::NoUserInfo,
|
||||
handlers::{markups::deletion_markup, Handler, MainDialogue, State},
|
||||
models::User,
|
||||
errors::NoUserInfo, markups::deletion_markup, models::User, Handler, MainDialogue, State,
|
||||
};
|
||||
use futures::{future, stream::FuturesUnordered, StreamExt};
|
||||
use itertools::Itertools;
|
@ -1,8 +1,6 @@
|
||||
use crate::{
|
||||
entity::prelude::*,
|
||||
errors::NoUserInfo,
|
||||
handlers::{markups::deletion_markup, Handler, MainDialogue, State},
|
||||
};
|
||||
use crate::{errors::NoUserInfo, markups::deletion_markup, Handler, MainDialogue, State};
|
||||
use cryptography::prelude::*;
|
||||
use entity::prelude::*;
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
use tokio::task;
|
||||
@ -20,7 +18,7 @@ async fn get_master_pass(
|
||||
let model = task::spawn_blocking(move || {
|
||||
master_pass::ActiveModel::from_unencrypted(user_id, &master_password)
|
||||
})
|
||||
.await??;
|
||||
.await?;
|
||||
model.insert(&db).await?;
|
||||
bot.send_message(msg.chat.id, "Success")
|
||||
.reply_markup(deletion_markup())
|
@ -1,4 +1,4 @@
|
||||
use crate::handlers::markups::deletion_markup;
|
||||
use crate::markups::deletion_markup;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
/// Handles the messages which weren't matched by any commands or states
|
@ -1,166 +0,0 @@
|
||||
use chacha20poly1305::{aead::Aead, AeadCore, ChaCha20Poly1305, KeyInit};
|
||||
use futures::{Stream, TryStreamExt};
|
||||
use pbkdf2::pbkdf2_hmac_array;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use sea_orm::{prelude::*, ActiveValue::Set, QueryOrder, QuerySelect};
|
||||
use sha2::Sha256;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "account")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub user_id: u64,
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub name: String,
|
||||
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(64)))")]
|
||||
pub salt: Vec<u8>,
|
||||
#[sea_orm(column_type = "VarBinary(256)")]
|
||||
pub enc_login: Vec<u8>,
|
||||
#[sea_orm(column_type = "VarBinary(256)")]
|
||||
pub enc_password: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
struct Cipher {
|
||||
chacha: ChaCha20Poly1305,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
/// Creates a new cipher from a master password and the salt
|
||||
#[inline]
|
||||
fn new(password: &[u8], salt: &[u8]) -> Self {
|
||||
let key = pbkdf2_hmac_array::<Sha256, 32>(password, salt, 480000);
|
||||
|
||||
Self {
|
||||
chacha: ChaCha20Poly1305::new(&key.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Encrypts the value with the current cipher. The 12 byte nonce is appended to the result
|
||||
#[inline]
|
||||
pub fn encrypt(&self, value: &[u8]) -> crate::Result<Vec<u8>> {
|
||||
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
|
||||
let mut result = self.chacha.encrypt(&nonce, value)?;
|
||||
result.extend(nonce);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Decrypts the value with the current cipher. The 12 byte nonce is expected to be at the end of the value
|
||||
#[inline]
|
||||
fn decrypt(&self, value: &[u8]) -> crate::Result<Vec<u8>> {
|
||||
let (data, nonce) = value.split_at(value.len() - 12);
|
||||
self.chacha.decrypt(nonce.into(), data).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModel {
|
||||
/// Encryptes the provided data by the master password and creates the ActiveModel with all fields set to Set variant
|
||||
#[inline]
|
||||
pub fn from_unencrypted(
|
||||
user_id: u64,
|
||||
name: String,
|
||||
login: &str,
|
||||
password: &str,
|
||||
master_pass: &str,
|
||||
) -> crate::Result<Self> {
|
||||
let mut salt = vec![0; 64];
|
||||
OsRng.fill_bytes(&mut salt);
|
||||
let cipher = Cipher::new(master_pass.as_bytes(), &salt);
|
||||
let enc_login = Set(cipher.encrypt(login.as_bytes())?);
|
||||
let enc_password = Set(cipher.encrypt(password.as_bytes())?);
|
||||
Ok(Self {
|
||||
name: Set(name),
|
||||
user_id: Set(user_id),
|
||||
salt: Set(salt),
|
||||
enc_login,
|
||||
enc_password,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
/// Returns the decrypted login and password of the account
|
||||
#[inline]
|
||||
pub fn decrypt(&self, master_pass: &str) -> crate::Result<(String, String)> {
|
||||
let cipher = Cipher::new(master_pass.as_bytes(), &self.salt);
|
||||
let login = String::from_utf8(cipher.decrypt(&self.enc_login)?)?;
|
||||
let password = String::from_utf8(cipher.decrypt(&self.enc_password)?)?;
|
||||
Ok((login, password))
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
/// Gets all user's account from DB
|
||||
#[inline]
|
||||
pub async fn get_all(
|
||||
user_id: u64,
|
||||
db: &DatabaseConnection,
|
||||
) -> crate::Result<impl Stream<Item = crate::Result<Model>> + '_> {
|
||||
let result = Self::find()
|
||||
.filter(Column::UserId.eq(user_id))
|
||||
.stream(db)
|
||||
.await?;
|
||||
Ok(result.err_into())
|
||||
}
|
||||
|
||||
/// Gets a list of account names of a user
|
||||
#[inline]
|
||||
pub async fn get_names(
|
||||
user_id: u64,
|
||||
db: &DatabaseConnection,
|
||||
ordered: bool,
|
||||
) -> crate::Result<impl Stream<Item = crate::Result<String>> + '_> {
|
||||
let mut select = Self::find()
|
||||
.select_only()
|
||||
.column(Column::Name)
|
||||
.filter(Column::UserId.eq(user_id));
|
||||
if ordered {
|
||||
select = select.order_by_asc(Column::Name);
|
||||
}
|
||||
let result = select.into_tuple().stream(db).await?;
|
||||
Ok(result.err_into())
|
||||
}
|
||||
|
||||
/// Checks if the account exists
|
||||
#[inline]
|
||||
pub async fn exists(
|
||||
user_id: u64,
|
||||
account_name: impl Into<String>,
|
||||
db: &DatabaseConnection,
|
||||
) -> crate::Result<bool> {
|
||||
let result = Self::find_by_id((user_id, account_name.into()))
|
||||
.select_only()
|
||||
.column(Column::UserId)
|
||||
.into_tuple::<u64>()
|
||||
.one(db)
|
||||
.await?;
|
||||
Ok(result.is_some())
|
||||
}
|
||||
|
||||
/// Gets the account from the DB
|
||||
#[inline]
|
||||
pub async fn get(
|
||||
user_id: u64,
|
||||
account_name: impl Into<String>,
|
||||
db: &DatabaseConnection,
|
||||
) -> crate::Result<Option<Model>> {
|
||||
Self::find_by_id((user_id, account_name.into()))
|
||||
.one(db)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Deletes all the user's accounts from DB
|
||||
#[inline]
|
||||
pub async fn delete_all(user_id: u64, db: &DatabaseConnection) -> crate::Result<()> {
|
||||
Self::delete_many()
|
||||
.filter(Column::UserId.eq(user_id))
|
||||
.exec(db)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use scrypt::{scrypt, Params};
|
||||
use sea_orm::{entity::prelude::*, ActiveValue::Set, QuerySelect};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "master_pass")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub user_id: u64,
|
||||
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(64)))")]
|
||||
pub salt: Vec<u8>,
|
||||
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(64)))")]
|
||||
pub password_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
/// Hashes the password with Scrypt with the given salt
|
||||
#[inline]
|
||||
fn hash_password(password: &[u8], salt: &[u8]) -> crate::Result<[u8; 64]> {
|
||||
let params = Params::new(14, Params::RECOMMENDED_R, Params::RECOMMENDED_P, 64)?;
|
||||
let mut password_hash = [0; 64];
|
||||
scrypt(password, salt, ¶ms, &mut password_hash)?;
|
||||
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.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModel {
|
||||
/// Hashes the password and creates an ActiveModel with all fields set to Set variant
|
||||
#[inline]
|
||||
pub fn from_unencrypted(user_id: u64, password: &str) -> crate::Result<Self> {
|
||||
let mut salt = vec![0; 64];
|
||||
OsRng.fill_bytes(&mut salt);
|
||||
let password_hash = Set(hash_password(password.as_bytes(), &salt)?.to_vec());
|
||||
Ok(Self {
|
||||
user_id: Set(user_id),
|
||||
salt: Set(salt),
|
||||
password_hash,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
/// Gets the master password from the database
|
||||
#[inline]
|
||||
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
|
||||
#[inline]
|
||||
pub async fn exists(user_id: u64, db: &DatabaseConnection) -> crate::Result<bool> {
|
||||
let id = Self::find_by_id(user_id)
|
||||
.select_only()
|
||||
.column(Column::UserId)
|
||||
.into_tuple::<u64>()
|
||||
.one(db)
|
||||
.await?;
|
||||
Ok(id.is_some())
|
||||
}
|
||||
|
||||
/// 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).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
//! Entities to work with the database
|
||||
|
||||
pub mod account;
|
||||
pub mod master_pass;
|
||||
pub mod prelude;
|
@ -1,4 +0,0 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.2
|
||||
|
||||
pub use super::account::{self, Entity as Account};
|
||||
pub use super::master_pass::{self, Entity as MasterPass};
|
@ -1,71 +0,0 @@
|
||||
use crate::handlers::markups::deletion_markup;
|
||||
use arrayvec::{ArrayString, ArrayVec};
|
||||
use rand::{rngs::OsRng, seq::SliceRandom};
|
||||
use std::{fmt::Write, str::from_utf8_unchecked};
|
||||
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
const CHARS: &[u8] = br##"!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~"##;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(PartialEq)]
|
||||
struct PasswordFlags: u8 {
|
||||
const LOWERCASE = 0b0001;
|
||||
const UPPERCASE = 0b0010;
|
||||
const NUMBER = 0b0100;
|
||||
const SPECIAL_CHARACTER = 0b1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the generated master password is valid.
|
||||
/// It checks that it has at least one lowercase, one lowercase and one punctuation char
|
||||
#[inline]
|
||||
fn check_generated_password(password: &[u8]) -> bool {
|
||||
let mut flags = PasswordFlags::empty();
|
||||
for &byte in password {
|
||||
match byte {
|
||||
b'a'..=b'z' => flags |= PasswordFlags::LOWERCASE,
|
||||
b'A'..=b'Z' => flags |= PasswordFlags::UPPERCASE,
|
||||
b'0'..=b'9' => flags |= PasswordFlags::NUMBER,
|
||||
b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~' => {
|
||||
flags |= PasswordFlags::SPECIAL_CHARACTER
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if flags == PasswordFlags::all() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Continuously generates the password until it passes the checks
|
||||
#[inline]
|
||||
fn generate_passwords() -> [ArrayString<32>; 10] {
|
||||
let mut passwords = ArrayVec::new_const();
|
||||
while !passwords.is_full() {
|
||||
let password: ArrayVec<u8, 32> = (0..32)
|
||||
.map(|_| *CHARS.choose(&mut OsRng).unwrap())
|
||||
.collect();
|
||||
if check_generated_password(&password) {
|
||||
let mut string = ArrayString::<32>::new_const();
|
||||
unsafe { string.push_str(from_utf8_unchecked(&password)) };
|
||||
passwords.push(string)
|
||||
}
|
||||
}
|
||||
unsafe { passwords.into_inner_unchecked() }
|
||||
}
|
||||
|
||||
/// Handles /gen_password command by generating 10 copyable passwords and sending them to the user
|
||||
pub async fn gen_password(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
||||
let mut message: ArrayString<{ 10 + 35 * 10 }> = "Passwords:".try_into().unwrap();
|
||||
let passwords = spawn_blocking(generate_passwords).await?;
|
||||
for password in passwords {
|
||||
write!(message, "\n`{password}`").unwrap();
|
||||
}
|
||||
bot.send_message(msg.chat.id, message.as_str())
|
||||
.parse_mode(ParseMode::MarkdownV2)
|
||||
.reply_markup(deletion_markup())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
mod callbacks;
|
||||
mod commands;
|
||||
mod default;
|
||||
mod errors;
|
||||
mod markups;
|
||||
mod master_password_check;
|
||||
mod models;
|
||||
mod state;
|
||||
mod utils;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use commands::Command;
|
||||
use futures::future::BoxFuture as PinnedFuture;
|
||||
use sea_orm::prelude::*;
|
||||
use state::{Handler, MainDialogue, State};
|
||||
use teloxide::{
|
10
src/main.rs
10
src/main.rs
@ -1,13 +1,7 @@
|
||||
mod entity;
|
||||
mod errors;
|
||||
mod handlers;
|
||||
mod models;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use anyhow::Result;
|
||||
use dotenv::dotenv;
|
||||
use futures::future::BoxFuture as PinnedFuture;
|
||||
use handlers::get_dispatcher;
|
||||
use migration::{Migrator, MigratorTrait};
|
||||
use pass_manager::get_dispatcher;
|
||||
use sea_orm::Database;
|
||||
use std::env;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::entity::prelude::Account;
|
||||
use entity::prelude::Account;
|
||||
use futures::TryStreamExt;
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, KeyboardMarkup};
|
@ -1,5 +1,6 @@
|
||||
use crate::{entity::prelude::MasterPass, errors::NoUserInfo};
|
||||
use sea_orm::prelude::*;
|
||||
use crate::errors::NoUserInfo;
|
||||
use entity::prelude::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use teloxide::{adaptors::Throttle, dispatching::DpHandlerDescription, prelude::*};
|
||||
|
||||
use super::markups::deletion_markup;
|
@ -1,6 +1,7 @@
|
||||
//! Models to export and import the accounts
|
||||
|
||||
use crate::entity::prelude::*;
|
||||
use cryptography::prelude::*;
|
||||
use entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -36,6 +37,7 @@ impl DecryptedAccount {
|
||||
&self.password,
|
||||
master_pass,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns true if the account's fields are valid
|
||||
|
@ -1,8 +1,4 @@
|
||||
use crate::{
|
||||
errors::HandlerUsed,
|
||||
handlers::{markups::deletion_markup, utils::delete_optional},
|
||||
PinnedFuture,
|
||||
};
|
||||
use crate::{errors::HandlerUsed, markups::deletion_markup, utils::delete_optional, PinnedFuture};
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
@ -12,7 +8,7 @@ pub async fn generic<F>(
|
||||
bot: Throttle<Bot>,
|
||||
msg: Message,
|
||||
db: DatabaseConnection,
|
||||
dialogue: crate::handlers::MainDialogue,
|
||||
dialogue: crate::MainDialogue,
|
||||
check: F,
|
||||
no_text_message: impl Into<String>,
|
||||
next: super::PackagedHandler<String>,
|
@ -1,13 +1,11 @@
|
||||
use crate::{
|
||||
entity::prelude::Account,
|
||||
errors::{HandlerUsed, NoUserInfo},
|
||||
handlers::{
|
||||
markups::{account_markup, deletion_markup},
|
||||
utils::{delete_optional, validate_field},
|
||||
MainDialogue,
|
||||
},
|
||||
markups::{account_markup, deletion_markup},
|
||||
utils::{delete_optional, validate_field},
|
||||
MainDialogue,
|
||||
};
|
||||
use sea_orm::prelude::*;
|
||||
use entity::prelude::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
/// Specifies the kind of checks to be run during the account name validation
|
@ -1,4 +1,4 @@
|
||||
use crate::handlers::{utils::validate_field, MainDialogue};
|
||||
use crate::{utils::validate_field, MainDialogue};
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::{entity::prelude::MasterPass, errors::NoUserInfo, handlers::MainDialogue};
|
||||
use crate::{errors::NoUserInfo, MainDialogue};
|
||||
use cryptography::prelude::*;
|
||||
use entity::prelude::*;
|
||||
use log::error;
|
||||
use sea_orm::prelude::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
@ -18,7 +20,7 @@ async fn check_master_pass(
|
||||
let is_valid = match model {
|
||||
Some(model) => {
|
||||
let master_pass = master_pass.to_owned();
|
||||
spawn_blocking(move || model.verify(&master_pass)).await??
|
||||
spawn_blocking(move || model.verify(&master_pass)).await?
|
||||
}
|
||||
None => {
|
||||
error!("User was put into the GetMasterPass state with no master password set");
|
@ -1,7 +1,7 @@
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
use crate::handlers::{utils::validate_field, MainDialogue};
|
||||
use crate::{utils::validate_field, MainDialogue};
|
||||
|
||||
/// Function to handle GetPassword state
|
||||
pub async fn get_password(
|
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
errors::HandlerUsed,
|
||||
handlers::{markups::deletion_markup, utils::delete_optional, MainDialogue},
|
||||
models::User,
|
||||
errors::HandlerUsed, markups::deletion_markup, models::User, utils::delete_optional,
|
||||
MainDialogue,
|
||||
};
|
||||
use futures::TryStreamExt;
|
||||
use sea_orm::prelude::*;
|
@ -1,4 +1,4 @@
|
||||
use crate::handlers::MainDialogue;
|
||||
use crate::MainDialogue;
|
||||
use sea_orm::prelude::*;
|
||||
use std::{future::Future, sync::Arc};
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
Reference in New Issue
Block a user