Extended functionality
This commit is contained in:
parent
b92ce0b0fa
commit
e8fc43f9ad
244
Cargo.lock
generated
244
Cargo.lock
generated
@ -480,9 +480,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.23"
|
||||
version = "3.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
|
||||
checksum = "eef2b3ded6a26dfaec672a742c93c8cf6b689220324da509ec5caa20de55dc83"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
@ -494,9 +494,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.18"
|
||||
version = "3.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
|
||||
checksum = "d756c5824fc5c0c1ee8e36000f576968dbcb2081def956c83fad6f40acd46f96"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro-error",
|
||||
@ -545,16 +545,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
@ -835,21 +825,6 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.1.0"
|
||||
@ -1178,16 +1153,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
name = "hyper-rustls"
|
||||
version = "0.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"hyper",
|
||||
"native-tls",
|
||||
"rustls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1430,24 +1405,6 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "never"
|
||||
version = "0.1.0"
|
||||
@ -1545,50 +1502,6 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97ea2d98598bf9ada7ea6ee8a30fb74f9156b63bbe495d64ec2b87c269d2dda3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "992bac49bdbab4423199c654a5515bd2a6c6a23bf03f2dd3bdb7e5ae6259bc69"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.5.0"
|
||||
@ -1644,7 +1557,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
@ -1660,11 +1573,11 @@ dependencies = [
|
||||
"migration",
|
||||
"pbkdf2",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"scrypt",
|
||||
"sea-orm",
|
||||
"sha2",
|
||||
"teloxide",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -1764,12 +1677,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.8.0"
|
||||
@ -1938,15 +1845,6 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.1"
|
||||
@ -2003,21 +1901,22 @@ dependencies = [
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"hyper-rustls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
"url",
|
||||
@ -2025,6 +1924,7 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
@ -2117,9 +2017,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.14"
|
||||
version = "0.37.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b864d3c18a5785a05953adeed93e2dca37ed30f18e69bba9f30079d51f363f"
|
||||
checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@ -2171,15 +2071,6 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||
dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@ -2383,29 +2274,6 @@ version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.17"
|
||||
@ -2771,6 +2639,7 @@ dependencies = [
|
||||
"tokio-util",
|
||||
"url",
|
||||
"uuid",
|
||||
"vecrem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2785,19 +2654,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
@ -2887,9 +2743,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.27.0"
|
||||
version = "1.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001"
|
||||
checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
@ -2900,30 +2756,20 @@ dependencies = [
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce"
|
||||
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.23.4"
|
||||
@ -2937,9 +2783,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.12"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
|
||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
@ -2948,9 +2794,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.7"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@ -2977,11 +2823,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
version = "0.1.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
checksum = "cf9cf6a813d3f40c88b0b6b6f29a5c95c6cdbf97c1f9cc53fb820200f5ad814d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
@ -2990,13 +2835,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3132,10 +2977,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
name = "vecrem"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
checksum = "c4808a28789238714a29163e4cb8031f0f050dd670f7a0cc74b6d80f3ce343fa"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
@ -3313,21 +3158,6 @@ dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
|
@ -19,9 +19,9 @@ log = "0.4.17"
|
||||
migration = { version = "0.1.0", path = "migration" }
|
||||
pbkdf2 = "0.12.1"
|
||||
pretty_env_logger = "0.4.0"
|
||||
scrypt = "0.11.0"
|
||||
rand = { version = "0.8.5", default-features = false, features = ["std_rng"] }
|
||||
scrypt = { version = "0.11.0", default-features = false, features = ["std"] }
|
||||
sea-orm = { version = "0.11.2", features = ["sqlx-mysql", "runtime-tokio-rustls"] }
|
||||
sha2 = "0.10.6"
|
||||
teloxide = { version = "0.12.2", features = ["macros"] }
|
||||
thiserror = "1.0.40"
|
||||
tokio = { version = "1.27.0", features = ["macros"] }
|
||||
teloxide = { version = "0.12.2", features = ["macros", "ctrlc_handler", "rustls", "throttle"], default-features = false }
|
||||
tokio = { version = "1.27.0", features = ["macros", "rt-multi-thread"] }
|
||||
|
@ -1,6 +1,10 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.2
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use chacha20poly1305::{aead::Aead, AeadCore, ChaCha20Poly1305, KeyInit};
|
||||
use pbkdf2::pbkdf2_hmac_array;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use sea_orm::{prelude::*, ActiveValue::Set, QuerySelect};
|
||||
use sha2::Sha256;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "account")]
|
||||
@ -21,3 +25,82 @@ pub struct Model {
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
struct Cipher {
|
||||
chacha: ChaCha20Poly1305,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
fn new(password: &[u8], salt: &[u8]) -> Self {
|
||||
let key = pbkdf2_hmac_array::<Sha256, 32>(password, salt, 480000);
|
||||
|
||||
Self {
|
||||
chacha: ChaCha20Poly1305::new(&key.into()),
|
||||
}
|
||||
}
|
||||
|
||||
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).unwrap();
|
||||
result.extend(nonce);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
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(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModel {
|
||||
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_ref(), &salt);
|
||||
let enc_login = Set(cipher.encrypt(login.as_ref())?);
|
||||
let enc_password = Set(cipher.encrypt(password.as_ref())?);
|
||||
Ok(Self {
|
||||
name: Set(name),
|
||||
user_id: Set(user_id),
|
||||
salt: Set(salt),
|
||||
enc_login,
|
||||
enc_password,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
pub fn decrypt(&self, master_pass: &str) -> crate::Result<(String, String)> {
|
||||
let cipher = Cipher::new(master_pass.as_ref(), self.salt.as_ref());
|
||||
let login = String::from_utf8(cipher.decrypt(self.enc_login.as_ref())?)?;
|
||||
let password = String::from_utf8(cipher.decrypt(self.enc_password.as_ref())?)?;
|
||||
Ok((login, password))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, EnumIter, DeriveColumn, Debug)]
|
||||
enum GetNamesQuery {
|
||||
AccountName,
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
/// Gets a list of account names of a user
|
||||
pub async fn get_names(user_id: u64, db: &DatabaseConnection) -> crate::Result<Vec<String>> {
|
||||
Self::find()
|
||||
.select_only()
|
||||
.column_as(Column::Name, GetNamesQuery::AccountName)
|
||||
.filter(Column::UserId.eq(user_id))
|
||||
.into_values::<_, GetNamesQuery>()
|
||||
.all(db)
|
||||
.await
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.2
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use scrypt::{scrypt, Params};
|
||||
use sea_orm::{entity::prelude::*, ActiveValue::Set};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "master_pass")]
|
||||
@ -17,3 +19,23 @@ pub struct Model {
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn from_unencrypted(user_id: u64, password: &str) -> crate::Result<Self> {
|
||||
let mut salt = vec![0; 64];
|
||||
OsRng.fill_bytes(&mut salt);
|
||||
let params = Params::new(
|
||||
Params::RECOMMENDED_LOG_N,
|
||||
Params::RECOMMENDED_R,
|
||||
Params::RECOMMENDED_P,
|
||||
128,
|
||||
)?;
|
||||
let mut password_hash = vec![0; 128];
|
||||
scrypt(password.as_ref(), &salt, ¶ms, &mut password_hash)?;
|
||||
Ok(Self {
|
||||
user_id: Set(user_id),
|
||||
salt: Set(salt),
|
||||
password_hash: Set(password_hash),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
18
src/handlers/add_account.rs
Normal file
18
src/handlers/add_account.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
use crate::entity::account;
|
||||
|
||||
pub async fn add_account(
|
||||
bot: Throttle<Bot>,
|
||||
msg: Message,
|
||||
db: DatabaseConnection,
|
||||
(name, login, password, master_pass): (String, String, String, String),
|
||||
) -> crate::Result<()> {
|
||||
let user_id = msg.from().unwrap().id.0;
|
||||
let account =
|
||||
account::ActiveModel::from_unencrypted(user_id, name, &login, &password, &master_pass)?;
|
||||
account.insert(&db).await?;
|
||||
bot.send_message(msg.chat.id, "Success").await?;
|
||||
Ok(())
|
||||
}
|
6
src/handlers/default.rs
Normal file
6
src/handlers/default.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use teloxide::{adaptors::Throttle, prelude::*};
|
||||
|
||||
pub async fn default(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
||||
bot.send_message(msg.chat.id, "Unknown command").await?;
|
||||
Ok(())
|
||||
}
|
26
src/handlers/get_account.rs
Normal file
26
src/handlers/get_account.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use crate::entity::{account, prelude::Account};
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
|
||||
|
||||
pub async fn get_account(
|
||||
bot: Throttle<Bot>,
|
||||
msg: Message,
|
||||
db: DatabaseConnection,
|
||||
(name, master_pass): (String, String),
|
||||
) -> crate::Result<()> {
|
||||
let account = Account::find()
|
||||
.filter(
|
||||
account::Column::UserId
|
||||
.eq(msg.from().unwrap().id.0)
|
||||
.add(account::Column::Name.eq(&name)),
|
||||
)
|
||||
.one(&db)
|
||||
.await?
|
||||
.unwrap();
|
||||
let (login, password) = account.decrypt(&master_pass)?;
|
||||
let message = format!("Name:\n`{name}`\nLogin:\n`{login}`\nPassword:\n`{password}`");
|
||||
bot.send_message(msg.chat.id, message)
|
||||
.parse_mode(ParseMode::MarkdownV2)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
34
src/handlers/get_accounts.rs
Normal file
34
src/handlers/get_accounts.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use crate::entity::prelude::Account;
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{adaptors::Throttle, prelude::*, types::ParseMode};
|
||||
|
||||
#[derive(Clone, Copy, EnumIter, DeriveColumn, Debug)]
|
||||
enum Query {
|
||||
AccountName,
|
||||
}
|
||||
|
||||
pub async fn get_accounts(
|
||||
bot: Throttle<Bot>,
|
||||
msg: Message,
|
||||
db: DatabaseConnection,
|
||||
) -> crate::Result<()> {
|
||||
let user_id = msg.from().unwrap().id.0;
|
||||
let mut account_names = Account::get_names(user_id, &db).await?.into_iter();
|
||||
let mut result = match account_names.next() {
|
||||
Some(name) => format!("Accounts:\n`{name}`"),
|
||||
None => {
|
||||
bot.send_message(msg.chat.id, "No accounts found").await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
for name in account_names {
|
||||
result.reserve(name.len() + 3);
|
||||
result.push_str("\n`");
|
||||
result.push_str(&name);
|
||||
result.push('\'')
|
||||
}
|
||||
bot.send_message(msg.chat.id, result)
|
||||
.parse_mode(ParseMode::MarkdownV2)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
7
src/handlers/help.rs
Normal file
7
src/handlers/help.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use teloxide::{adaptors::Throttle, prelude::*, utils::command::BotCommands};
|
||||
|
||||
pub async fn help(bot: Throttle<Bot>, msg: Message) -> crate::Result<()> {
|
||||
bot.send_message(msg.chat.id, super::Command::descriptions().to_string())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
56
src/handlers/mod.rs
Normal file
56
src/handlers/mod.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use sea_orm::prelude::*;
|
||||
use teloxide::{
|
||||
adaptors::{throttle::Limits, Throttle},
|
||||
filter_command,
|
||||
prelude::*,
|
||||
utils::command::BotCommands,
|
||||
};
|
||||
|
||||
mod add_account;
|
||||
mod default;
|
||||
mod get_account;
|
||||
mod get_accounts;
|
||||
mod help;
|
||||
|
||||
#[derive(BotCommands, Clone)]
|
||||
#[command(rename_rule = "snake_case")]
|
||||
enum Command {
|
||||
#[command()]
|
||||
Help,
|
||||
#[command(parse_with = "split")]
|
||||
AddAccount(String, String, String, String),
|
||||
#[command(parse_with = "split")]
|
||||
GetAccount(String, String),
|
||||
#[command()]
|
||||
GetAccounts,
|
||||
}
|
||||
|
||||
pub fn get_dispatcher(
|
||||
token: String,
|
||||
db: DatabaseConnection,
|
||||
) -> Dispatcher<Throttle<Bot>, crate::Error, teloxide::dispatching::DefaultKey> {
|
||||
let bot = Bot::new(token).throttle(Limits::default());
|
||||
Dispatcher::builder(
|
||||
bot,
|
||||
Update::filter_message()
|
||||
.branch(
|
||||
filter_command::<Command, _>()
|
||||
.branch(dptree::case![Command::Help].endpoint(help::help))
|
||||
.branch(
|
||||
dptree::case![Command::AddAccount(name, login, password, master_pass)]
|
||||
.endpoint(add_account::add_account),
|
||||
)
|
||||
.branch(
|
||||
dptree::case![Command::GetAccount(name, master_pass)]
|
||||
.endpoint(get_account::get_account),
|
||||
)
|
||||
.branch(
|
||||
dptree::case![Command::GetAccounts].endpoint(get_accounts::get_accounts),
|
||||
),
|
||||
)
|
||||
.branch(dptree::endpoint(default::default)),
|
||||
)
|
||||
.dependencies(dptree::deps![db])
|
||||
.enable_ctrlc_handler()
|
||||
.build()
|
||||
}
|
124
src/main.rs
124
src/main.rs
@ -1,126 +1,22 @@
|
||||
mod entity;
|
||||
mod handlers;
|
||||
|
||||
use entity::{account, prelude::Account};
|
||||
|
||||
use anyhow::Result;
|
||||
use chacha20poly1305::{
|
||||
aead::{rand_core::RngCore, Aead, AeadCore, OsRng},
|
||||
ChaCha20Poly1305, KeyInit,
|
||||
};
|
||||
use anyhow::{Error, Result};
|
||||
use dotenv::dotenv;
|
||||
use pbkdf2::pbkdf2_hmac_array;
|
||||
use sea_orm::{
|
||||
ActiveModelTrait, ActiveValue::Set, ColumnTrait, ConnectOptions, Database, EntityTrait,
|
||||
QueryFilter,
|
||||
};
|
||||
use sha2::Sha256;
|
||||
use handlers::get_dispatcher;
|
||||
use migration::{Migrator, MigratorTrait};
|
||||
use sea_orm::Database;
|
||||
use std::env;
|
||||
use teloxide::{prelude::*, utils::command::BotCommands};
|
||||
|
||||
#[derive(BotCommands, Clone)]
|
||||
#[command(rename_rule = "lowercase")]
|
||||
enum Command {
|
||||
#[command()]
|
||||
Help,
|
||||
#[command(parse_with = "split")]
|
||||
AddAccount(String, String, String, String),
|
||||
#[command(parse_with = "split")]
|
||||
GetAccount(String, String),
|
||||
}
|
||||
|
||||
use Command::*;
|
||||
|
||||
struct Cipher {
|
||||
chacha: ChaCha20Poly1305,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
fn new(password: &[u8], salt: &[u8]) -> Self {
|
||||
let key = pbkdf2_hmac_array::<Sha256, 32>(password, salt, 480000);
|
||||
|
||||
Self {
|
||||
chacha: ChaCha20Poly1305::new(&key.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt(&self, value: &[u8]) -> Result<Vec<u8>> {
|
||||
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
|
||||
let mut result = self.chacha.encrypt(&nonce, value).unwrap();
|
||||
result.extend(nonce);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn decrypt(&self, value: &[u8]) -> Result<Vec<u8>> {
|
||||
let (data, nonce) = value.split_at(value.len() - 12);
|
||||
assert!(nonce.len() == 12);
|
||||
self.chacha
|
||||
.decrypt(nonce.into(), data)
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
||||
async fn answer_command(db: ConnectOptions, bot: Bot, msg: Message, cmd: Command) -> Result<()> {
|
||||
let user_id = msg.from().unwrap().id.0;
|
||||
let db = Database::connect(db).await?;
|
||||
match cmd {
|
||||
Help => {
|
||||
bot.send_message(msg.chat.id, Command::descriptions().to_string())
|
||||
.await?;
|
||||
}
|
||||
AddAccount(name, login, password, master_pass) => {
|
||||
let mut salt = vec![0; 64];
|
||||
OsRng.fill_bytes(&mut salt);
|
||||
let cipher = Cipher::new(master_pass.as_ref(), &salt);
|
||||
let enc_login = Set(cipher.encrypt(login.as_ref())?);
|
||||
let enc_password = Set(cipher.encrypt(password.as_ref())?);
|
||||
let account = account::ActiveModel {
|
||||
name: Set(name),
|
||||
user_id: Set(user_id),
|
||||
salt: Set(salt),
|
||||
enc_login,
|
||||
enc_password,
|
||||
};
|
||||
account.insert(&db).await?;
|
||||
bot.send_message(msg.chat.id, "Success").await?;
|
||||
}
|
||||
GetAccount(name, master_pass) => {
|
||||
let account = Account::find()
|
||||
.filter(
|
||||
account::Column::UserId
|
||||
.eq(user_id)
|
||||
.add(account::Column::Name.eq(&name)),
|
||||
)
|
||||
.one(&db)
|
||||
.await?
|
||||
.unwrap();
|
||||
let cipher = Cipher::new(master_pass.as_ref(), &account.salt);
|
||||
let login = String::from_utf8(cipher.decrypt(&account.enc_login)?)?;
|
||||
let password = String::from_utf8(cipher.decrypt(&account.enc_password)?)?;
|
||||
let message = format!("Account `{name}`\nLogin: `{login}`\nPassword: `{password}`");
|
||||
bot.send_message(msg.chat.id, message).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
async fn main() -> Result<()> {
|
||||
let _ = dotenv();
|
||||
pretty_env_logger::init();
|
||||
|
||||
let token = env::var("TOKEN").unwrap();
|
||||
let database_url = env::var("DATABASE_URL").unwrap();
|
||||
let bot = Bot::new(token);
|
||||
let db = ConnectOptions::new(database_url);
|
||||
Dispatcher::builder(
|
||||
bot,
|
||||
Update::filter_message()
|
||||
.filter_command::<Command>()
|
||||
.endpoint(answer_command),
|
||||
)
|
||||
.dependencies(dptree::deps![db])
|
||||
.enable_ctrlc_handler()
|
||||
.build()
|
||||
.dispatch()
|
||||
.await;
|
||||
let db = Database::connect(database_url).await?;
|
||||
Migrator::up(&db, None).await?;
|
||||
get_dispatcher(token, db).dispatch().await;
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user