feat(cli): started work on a cli
This commit is contained in:
parent
9fc30d8d0a
commit
8c388e6329
|
@ -245,6 +245,55 @@ dependencies = [
|
|||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is-terminal",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.72"
|
||||
|
@ -290,6 +339,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"libinjection",
|
||||
"log",
|
||||
|
@ -415,6 +465,53 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
|
@ -667,6 +764,12 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.2"
|
||||
|
@ -1344,6 +1447,12 @@ dependencies = [
|
|||
"sqlite3-src",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
|
@ -1527,6 +1636,12 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
|
@ -17,3 +17,4 @@ sha2 = "0.10.2"
|
|||
pbkdf2 = { version = "0.12", features = ["simple"] }
|
||||
env_logger = "0.10"
|
||||
log = "0.4"
|
||||
clap = { version = "4.3.21", features = ["derive"] }
|
||||
|
|
11
README.md
11
README.md
|
@ -57,8 +57,9 @@ Authenticates using an existing account.
|
|||
|
||||
## Arguments
|
||||
|
||||
| Argument | Description |
|
||||
|----------------------------|-----------------------------------------------------------------------------------------|
|
||||
| `-D / --daemon` | Starts the server in daemon mode, to await api requests, etc. |
|
||||
| `-d / --delete <username>` | Deletes the account associated with the specified username. |
|
||||
| `-w / --dir <path>` | Specifies the working dir that will be used. This dir contains stuff like the database. |
|
||||
| Argument | Description |
|
||||
|-----------------------------|-----------------------------------------------------------------------------------------|
|
||||
| `-D / --daemon <port>` | Starts the server in daemon mode, to await api requests on the specified port, etc. |
|
||||
| `-d / --delete <user,user>` | Deletes the account(s) associated with the specified username(s). |
|
||||
| `-l / --list` | Lists all registered accounts |
|
||||
| `-w / --dir <path>` | Specifies the working dir that will be used. This dir contains stuff like the database. |
|
||||
|
|
|
@ -12,14 +12,6 @@ pub struct Backend {
|
|||
db: sqlite::Connection,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Account {
|
||||
id: i64,
|
||||
username: String,
|
||||
salt: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
fn is_sql_injection(string: &String) -> bool {
|
||||
match sqli(string) {
|
||||
Some((is_injection, _)) => is_injection,
|
||||
|
@ -42,21 +34,6 @@ impl Backend {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
fn get_user(&mut self, username: &String) -> Result<Account> {
|
||||
let mut statement = self.db.prepare(format!(
|
||||
"SELECT * FROM Accounts WHERE username='{}';",
|
||||
username
|
||||
))?;
|
||||
statement.next()?;
|
||||
|
||||
Ok(Account {
|
||||
id: statement.read::<i64, _>("id").unwrap(),
|
||||
username: statement.read::<String, _>("username").unwrap(),
|
||||
salt: statement.read::<String, _>("salt").unwrap(),
|
||||
password: statement.read::<String, _>("password").unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register(&mut self, username: &String, password: &String) -> Result<Response> {
|
||||
if is_sql_injection(username) {
|
||||
warn!(
|
||||
|
@ -99,8 +76,15 @@ impl Backend {
|
|||
return Ok(Response::Authenticate(ResponseAuthenticate::UserNotFound));
|
||||
}
|
||||
|
||||
let account = self.get_user(username)?;
|
||||
let hash = PasswordHash::new(&account.password)
|
||||
let mut statement = self.db.prepare(format!(
|
||||
"SELECT * FROM Accounts WHERE username='{}';",
|
||||
username
|
||||
))?;
|
||||
statement.next()?;
|
||||
|
||||
let raw_hash = &statement.read::<String, _>("password").unwrap();
|
||||
|
||||
let hash = PasswordHash::new(raw_hash)
|
||||
.map_err(|_| anyhow::Error::msg("Failed to parse the password hash"))?;
|
||||
|
||||
match Pbkdf2.verify_password(password.as_bytes(), &hash) {
|
||||
|
@ -120,8 +104,17 @@ impl Backend {
|
|||
return Ok(Response::Delete(ResponseDelete::Rejected));
|
||||
}
|
||||
|
||||
println!("<Dummy> Deletion Request: (Username: '{}')", username);
|
||||
println!(" -> Accepted");
|
||||
if !self.user_exists(username)? {
|
||||
warn!("Deletion failed, user `{}` not found", username);
|
||||
return Ok(Response::Delete(ResponseDelete::UserNotFound));
|
||||
}
|
||||
|
||||
self.db.execute(format!(
|
||||
"DELETE FROM Accounts WHERE username='{}';",
|
||||
username
|
||||
))?;
|
||||
|
||||
info!("Deleted `{}`)", username);
|
||||
Ok(Response::Delete(ResponseDelete::Success))
|
||||
}
|
||||
|
||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -3,17 +3,58 @@ mod backend;
|
|||
mod call;
|
||||
|
||||
use anyhow::Result;
|
||||
use call::Call;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Sets the operation directory
|
||||
#[arg(short = 'w', long, value_name = "PATH")]
|
||||
dir: Option<PathBuf>,
|
||||
|
||||
/// Start in daemon / server mode
|
||||
#[arg(short = 'D', long)]
|
||||
daemon: bool,
|
||||
|
||||
/// Delete one or multiple account(s)
|
||||
#[arg(short, long, use_value_delimiter = true, value_delimiter = ',')]
|
||||
deletions: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
env_logger::init();
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||||
let args = Args::parse();
|
||||
|
||||
if let Some(dir) = args.dir {
|
||||
std::env::set_current_dir(dir)?;
|
||||
}
|
||||
|
||||
info!("Starting BaseAuth server v0.1");
|
||||
|
||||
let backend = backend::Backend::new(&std::path::Path::new("db.sqlite"))?;
|
||||
|
||||
let backend = backend::Backend::new(&Path::new("db.sqlite"))?;
|
||||
let tx = call::start_worker(backend).await?;
|
||||
api::start_worker(8080, tx).await?;
|
||||
|
||||
loop {}
|
||||
if let Some(d) = &args.deletions {
|
||||
for username in d.iter() {
|
||||
let (oneshot_tx, oneshot_rx) = oneshot::channel();
|
||||
tx.send((Call::Delete(username.to_string()), oneshot_tx))
|
||||
.await?;
|
||||
|
||||
let _ = oneshot_rx.await??;
|
||||
}
|
||||
}
|
||||
|
||||
if args.daemon {
|
||||
api::start_worker(8080, tx).await?;
|
||||
loop {}
|
||||
} else if args.deletions == None {
|
||||
println!("Nothing to do. run `baseauth --help` for a list of commands");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue