use std::{
env,
net::{IpAddr, SocketAddr},
path::PathBuf,
};
use auth_lite::{auth, db, server};
use clap::{Parser, Subcommand};
#[derive(Debug, Parser)] struct Cli {
#[arg(short, long, env = "DATABASE_PATH", default_value = "auth.db")]
database: PathBuf,
#[command(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
#[command(alias = "add", arg_required_else_help = true)]
AddUser {
username: String,
},
#[command(alias = "rm", alias = "remove", arg_required_else_help = true)]
RemoveUser {
username: String,
},
#[command(alias = "passwd", arg_required_else_help = true)]
ChangePassword {
username: String,
},
#[command(alias = "ls", alias = "list")]
ListUsers,
Serve {
#[arg(short, long, env = "PORT", default_value = "4000")]
port: u16,
#[arg(short, long, env = "BIND", default_value = "0.0.0.0")]
bind: IpAddr,
},
}
fn setup_tracing() {
if env::var("RUST_LOG").is_err() {
env::set_var("RUST_LOG", "info");
}
tracing_subscriber::fmt::init();
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
setup_tracing();
let cli = Cli::parse();
let pool = db::open(&cli.database).await?;
match cli.command {
Command::AddUser { username } => {
let count = sqlx::query!(
"SELECT count(1) AS count FROM users WHERE username = ?",
username
)
.fetch_one(&pool)
.await?
.count;
if count > 0 {
eprintln!("User {username} already exists");
return Ok(());
}
let password = rpassword::prompt_password("Password: ")?;
auth::create_user(&pool, &username, &password).await?;
}
Command::RemoveUser { username } => {
let count = sqlx::query!(
"SELECT count(1) AS count FROM users WHERE username = ?",
username
)
.fetch_one(&pool)
.await?
.count;
if count == 0 {
eprintln!("User {username} doesn't exist");
return Ok(());
}
auth::remove_user(&pool, &username).await?;
}
Command::ChangePassword { username } => {
let count = sqlx::query!(
"SELECT count(1) AS count FROM users WHERE username = ?",
username
)
.fetch_one(&pool)
.await?
.count;
if count == 0 {
eprintln!("User {username} doesn't exist");
return Ok(());
}
let password = rpassword::prompt_password("Password: ")?;
auth::change_password(&pool, &username, &password).await?;
}
Command::ListUsers => {
let users = sqlx::query!("SELECT username FROM users ORDER BY username")
.fetch_all(&pool)
.await?;
for user in users {
println!("{}", user.username);
}
}
Command::Serve { port, bind } => {
let addr = SocketAddr::from((bind, port));
server::start(addr, pool).await?;
}
}
Ok(())
}