feat: add useful utilities

This commit is contained in:
EETagent 2022-11-11 20:20:48 +01:00
parent ee4d137a7d
commit 693426f041
3 changed files with 144 additions and 41 deletions

41
Cargo.lock generated
View file

@ -409,7 +409,7 @@ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_derive", "clap_derive",
"clap_lex", "clap_lex 0.2.4",
"indexmap", "indexmap",
"once_cell", "once_cell",
"strsim", "strsim",
@ -417,6 +417,20 @@ dependencies = [
"textwrap", "textwrap",
] ]
[[package]]
name = "clap"
version = "4.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eb41c13df48950b20eb4cd0eefa618819469df1bffc49d11e8487c4ba0037e5"
dependencies = [
"atty",
"bitflags",
"clap_lex 0.3.0",
"once_cell",
"strsim",
"termcolor",
]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.2.18" version = "3.2.18"
@ -439,6 +453,15 @@ dependencies = [
"os_str_bytes", "os_str_bytes",
] ]
[[package]]
name = "clap_lex"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
[[package]] [[package]]
name = "codespan-reporting" name = "codespan-reporting"
version = "0.11.1" version = "0.11.1"
@ -1893,6 +1916,18 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "portfolio-recovery"
version = "0.1.0"
dependencies = [
"clap 4.0.23",
"portfolio-core",
"portfolio-entity",
"sea-orm",
"tokio",
"url",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -2339,7 +2374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "882af0d4cd3d6cc2f427d14a48e9f468b37c563b405ea486fd314ba18ca334d0" checksum = "882af0d4cd3d6cc2f427d14a48e9f468b37c563b405ea486fd314ba18ca334d0"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap 3.2.23",
"dotenvy", "dotenvy",
"regex", "regex",
"sea-schema", "sea-schema",
@ -2368,7 +2403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fe6e594b078712e1e797b951b9b56e55d3cfa04aac8ea76eb4bed7c94c5910" checksum = "86fe6e594b078712e1e797b951b9b56e55d3cfa04aac8ea76eb4bed7c94c5910"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"clap", "clap 3.2.23",
"dotenvy", "dotenvy",
"sea-orm", "sea-orm",
"sea-orm-cli", "sea-orm-cli",

View file

@ -9,6 +9,7 @@ url = "^2.3"
clap = { version = "^4.0", features = ["cargo"] } clap = { version = "^4.0", features = ["cargo"] }
portfolio-entity = { path = "../entity" } portfolio-entity = { path = "../entity" }
portfolio-core = { path = "../core" }
[dependencies.tokio] [dependencies.tokio]
version = "^1.21" version = "^1.21"

View file

@ -1,60 +1,127 @@
use std::path::PathBuf; use std::path::PathBuf;
use url::Url; use url::Url;
use clap::{arg, command, value_parser}; use clap::{arg, command, value_parser, Command, ArgAction};
use sea_orm::{Database, DatabaseConnection}; use sea_orm::{Database, DatabaseConnection};
use sea_orm::*;
use ::entity::candidate::Entity as Candidate; use ::entity::candidate::Entity as Candidate;
use ::entity::parent::Entity as Parent; use ::entity::parent::Entity as Parent;
use sea_orm::*;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let clap = command!() let clap = command!()
.arg( .propagate_version(true)
arg!( .subcommand_required(true)
-d --database <URL> "URL to the database or sql file with postgres:// or sqlite://" .arg_required_else_help(true)
) .subcommand(
.alias("url") Command::new("portfolio")
.required(true) .about("Database & Portfolio operations")
.value_parser(value_parser!(Url)), .arg(
arg!(
-d --database <URL> "URL to the database or sql file with postgres:// or sqlite://"
)
.alias("url")
.required(true)
.value_parser(value_parser!(Url)),
)
.arg(
arg!(
-p --portfolio <PATH> "Path to the portfolio root"
)
.required(true)
.value_parser(value_parser!(PathBuf)),
)
.arg(
arg!(
-k --key <KEY> "AGE private key for decryption"
)
.required(true),
)
) )
.arg( .subcommand(
arg!( Command::new("hash")
-p --portfolio <PATH> "Path to the portfolio root" .about("Hash operations")
) .arg(
.required(true) arg!(
.value_parser(value_parser!(PathBuf)), -i --input <INPUT> "Plaintext to hash"
)
.required(true)
),
) )
.arg( .subcommand(
arg!( Command::new("encryption")
-k --key <KEY> "AGE private key for decryption" .about("Encryption operations")
) .arg(
.required(true), arg!(
-d --decrypt ... "Decrypt flag"
)
.action(ArgAction::SetFalse)
.required(false)
)
.arg(
arg!(
-i --input <INPUT> "Plaintext to encrypt/decrypt"
)
.required(true)
)
.arg(
arg!(
-k --key <KEY> "Key for encryption/decryption"
)
.required(true),
)
) )
.get_matches(); .get_matches();
let sqlite_url = clap.get_one::<Url>("database").unwrap(); match clap.subcommand() {
Some(("portfolio", sub_matches)) => {
let sqlite_url = sub_matches.get_one::<Url>("database").unwrap();
println!("Connecting to {:?}", sqlite_url); println!("Connecting to {:?}", sqlite_url);
if sqlite_url.scheme() != "sqlite" && sqlite_url.scheme() != "postgres" { if sqlite_url.scheme() != "sqlite" && sqlite_url.scheme() != "postgres" {
return Err("URL scheme postgres:// or sqlite:// required")?; return Err("URL scheme postgres:// or sqlite:// required")?;
}
let db: DatabaseConnection = Database::connect(sqlite_url.as_str()).await?;
let entries = Candidate::find()
.join_rev(
JoinType::InnerJoin,
Parent::belongs_to(Candidate)
.from(::entity::parent::Column::Application)
.to(::entity::candidate::Column::Application)
.into(),
)
.all(&db)
.await?;
println!("Found {} entries", entries.len());
}
Some(("hash", sub_matches)) => {
let input = sub_matches.get_one::<String>("input").unwrap();
let hash = portfolio_core::crypto::hash_password(input.to_string()).await?;
println!("{}", hash);
}
Some(("encryption", sub_matches)) => {
let decrypt = sub_matches.get_one::<bool>("decrypt").unwrap();
let input = sub_matches.get_one::<String>("input").unwrap();
let key = sub_matches.get_one::<String>("key").unwrap();
let result = if !*decrypt {
portfolio_core::crypto::decrypt_password(input.to_string(), key.to_string()).await?
} else {
portfolio_core::crypto::encrypt_password(input.to_string(), key.to_string()).await?
};
println!("{}", result);
}
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
} }
let db: DatabaseConnection = Database::connect(sqlite_url.as_str()).await?;
let entries = Candidate::find()
.join_rev(
JoinType::InnerJoin,
Parent::belongs_to(Candidate)
.from(::entity::parent::Column::Application)
.to(::entity::candidate::Column::Application)
.into(),
)
.all(&db)
.await?;
Ok(()) Ok(())
} }