#![allow(unused_imports, dead_code)]
use clap::{Parser, ValueEnum, ArgAction};
use anyhow::Result;
use gen_pass::{PassConfig, PasswordGenerator};
use std::fmt;
#[derive(Parser, Debug)]
#[command(name = "gen_pass", about = "Generate secure passwords", version, author)]
struct Cli {
#[arg(short, long, default_value_t = 16)]
length: usize,
#[arg(long, default_value_t = true, action = ArgAction::Set)]
lowercase: bool,
#[arg(long, default_value_t = true, action = ArgAction::Set)]
uppercase: bool,
#[arg(long, default_value_t = true, action = ArgAction::Set)]
digits: bool,
#[arg(long, default_value_t = true, action = ArgAction::Set)]
symbols: bool,
#[arg(short = 's', long)]
salt: Option<String>,
#[arg(short, long, default_value_t = Output::Plain)]
output: Output,
}
#[derive(Copy, Clone, Debug, ValueEnum, Default)]
enum Output {
#[default]
Plain,
Copy,
}
impl fmt::Display for Output {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Output::Plain => write!(f, "plain"),
Output::Copy => write!(f, "copy"),
}
}
}
#[cfg(not(test))]
fn main() -> Result<()> {
let cli = Cli::parse();
let cfg = PassConfig {
length: cli.length,
use_lowercase: cli.lowercase,
use_uppercase: cli.uppercase,
use_digits: cli.digits,
use_symbols: cli.symbols,
salt: cli.salt,
};
let gen = PasswordGenerator::from_config(&cfg)?;
let password = gen.generate(cfg.length);
match cli.output {
Output::Plain => {
println!("{password}");
}
Output::Copy => {
println!("{password}");
if let Err(e) = copy_to_clipboard(&password) {
eprintln!("Failed to copy to clipboard: {e}");
}
}
}
Ok(())
}
#[cfg(test)]
fn copy_to_clipboard(_text: &str) -> Result<()> {
Ok(())
}
#[cfg(not(test))]
fn copy_to_clipboard(text: &str) -> Result<()> {
if std::env::var("TEST_NO_CLIP").is_ok() {
return Ok(());
}
#[cfg(target_os = "macos")]
{
use std::process::{Command, Stdio};
let mut cmd = Command::new("pbcopy").stdin(Stdio::piped()).spawn()?;
{
use std::io::Write;
cmd.stdin.as_mut().unwrap().write_all(text.as_bytes())?;
}
cmd.wait()?;
return Ok(());
}
#[cfg(target_os = "linux")]
{
use std::process::{Command, Stdio};
let mut cmd = Command::new("xclip").args(["-selection", "clipboard"]).stdin(Stdio::piped()).spawn()?;
{
use std::io::Write;
cmd.stdin.as_mut().unwrap().write_all(text.as_bytes())?;
}
cmd.wait()?;
return Ok(());
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
{
anyhow::bail!("Clipboard copy not supported on this OS");
}
}