mod commands;
mod pwsmanager;
mod passgen;
mod securecrypto;
mod configtool;
mod xotp;
use clap::{Parser, Args};
use serde::{Serialize, Deserialize};
use crate::passgen::Capitalization;
#[derive(Debug, Parser)]
#[command(name = "rpawomaster")]
#[command(author, version, about = "A secure password manager written in Rust", long_about = None)]
enum Cli {
Init {
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
import: Option<String>,
},
Gen {
#[command(subcommand)]
subcommand: GenSubcommand,
},
Add {
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
},
Update {
#[arg(short, long)]
all: Option<bool>,
#[arg(short, long)]
passwordname: Option<String>,
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
},
Delete {
passwordname: String,
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
},
List {
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
},
Search {
text: String,
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
#[arg(short, long)]
exact: Option<bool>,
},
Testpass(TestpassArgs),
Vaults {
#[arg(short, long)]
user: Option<String>,
},
Crypt {
#[command(subcommand)]
subcommand: CryptSubcommand,
},
Export {
user: String,
#[arg(short, long)]
path: Option<String>,
#[arg(short, long)]
vault: Option<String>,
},
Xotp {
#[command(subcommand)]
subcommand: XotpSubcommand,
}
}
#[derive(Debug, Parser)]
enum XotpSubcommand {
Add {
#[arg(short, long)]
name: String,
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
#[arg(short, long)]
secret: String,
},
List {
#[arg(short, long)]
user: Option<String>,
#[arg(short, long)]
vault: Option<String>,
},
}
#[derive(Debug, Parser)]
enum GenSubcommand {
Random(GenRandomArgs),
Memorable(GenMemorableArgs),
}
#[derive(Debug, Parser)]
enum CryptSubcommand {
En {
#[arg(short, long)]
password: Option<String>,
#[arg(short, long)]
source: String,
#[arg(short, long)]
target: String,
},
De {
#[arg(short, long)]
password: Option<String>,
#[arg(short, long)]
source: String,
#[arg(short, long)]
target: String,
},
}
#[derive(Debug, Parser)]
struct GenRandomArgs {
#[arg(short, long, default_value_t = 12)]
length: usize,
#[arg(long, default_value_t = false)]
no_uppercase: bool,
#[arg(long, default_value_t = false)]
no_lowercase: bool,
#[arg(long, default_value_t = false)]
no_numbers: bool,
#[arg(long, default_value_t = false)]
no_special: bool,
#[arg(short = 's', long, default_value_t = false)]
url_safe: bool,
#[arg(short = 'c', long, default_value_t = false)]
avoid_confusion: bool,
}
#[derive(Debug, Parser)]
struct GenMemorableArgs {
#[arg(short, long, default_value_t = 4)]
words: usize,
#[arg(short, long, default_value_t = '-')]
separator: char,
#[arg(short, long, default_value_t = false)]
include_numbers: bool,
#[arg(short, long, default_value_t = Capitalization::CamelCase)]
capitalization: Capitalization,
}
#[derive(Debug, Args, Serialize, Deserialize)]
struct TestpassArgs {
password: String,
#[arg(short = 's', long, default_value_t = false)]
check_url_safe: bool,
#[arg(short = 'c', long, default_value_t = false)]
check_confusion: bool,
}
fn main() -> Result<(), String> {
let cli = Cli::parse();
match cli {
Cli::Init { user, import } => {
if let Some(import_path) = import {
let vault_path = configtool::prompt_input("Enter vault path (default: config path): ")?;
let vault_path = if vault_path.is_empty() {
configtool::get_config_dir()?.to_string_lossy().to_string()
} else {
vault_path
};
commands::import::import_passvaults(import_path, vault_path).map_err(|e| e.to_string())
} else {
commands::init::interactive_init(user)
}
},
Cli::Gen { subcommand } => match subcommand {
GenSubcommand::Random(args) => {
commands::password_gen::generate_random(
args.length,
args.no_uppercase,
args.no_lowercase,
args.no_numbers,
args.no_special,
args.url_safe,
args.avoid_confusion,
)
},
GenSubcommand::Memorable(args) => {
commands::password_gen::generate_memorable(
args.words,
args.separator,
args.include_numbers,
args.capitalization,
)
}
},
Cli::Add { user, vault } => {
commands::add::add_password_interactive(user, vault)
},
Cli::Update { all, passwordname, user, vault } => {
commands::update::update_password(all, passwordname, user, vault)
},
Cli::Delete { passwordname, user, vault } => {
commands::delete::delete_password(passwordname, user, vault)
},
Cli::List { user, vault } => {
commands::list::list_passwords(user, vault)
},
Cli::Search { text, user, vault, exact } => {
commands::search::search_passwords(text, user, vault, exact)
},
Cli::Testpass(args) => {
commands::testpass::test_password(args.password, args.check_url_safe, args.check_confusion)
},
Cli::Vaults { user } => {
commands::vaults::list_vaults(user)
},
Cli::Crypt { subcommand } => match subcommand {
CryptSubcommand::En { password, source, target } => {
commands::crypt::encrypt_path(password, source, target)
},
CryptSubcommand::De { password, source, target } => {
commands::crypt::decrypt_path(password, source, target)
}
},
Cli::Export { user, path , vault } => {
commands::export::export_vault(user, path, vault)
},
Cli::Xotp { subcommand } => {
match subcommand {
XotpSubcommand::Add { name, user, vault, secret } => {
commands::xotp::add_otp(name, user, vault, secret)
},
XotpSubcommand::List { user, vault } => {
commands::xotp::list_otps(user, vault)
},
}
},
}
}