use anyhow::Result;
use bc_components::KeyDerivationMethod;
use clap::Args;
use crate::{ASKPASS_HELP, ASKPASS_LONG_HELP, read_password};
#[derive(Debug, Clone, Copy, clap::ValueEnum, Default)]
pub enum PasswordMethod {
#[default]
Argon2id,
PBKDF2,
Scrypt,
}
impl From<PasswordMethod> for KeyDerivationMethod {
fn from(method: PasswordMethod) -> Self {
match method {
PasswordMethod::Argon2id => KeyDerivationMethod::Argon2id,
PasswordMethod::PBKDF2 => KeyDerivationMethod::PBKDF2,
PasswordMethod::Scrypt => KeyDerivationMethod::Scrypt,
}
}
}
#[derive(Debug, Args)]
#[group(skip)]
pub struct ReadPasswordArgs {
#[arg(long, num_args(0..=1), value_name = "PASSWORD")]
pub password: Option<Option<String>>,
#[arg(long, requires = "password", help = ASKPASS_HELP, long_help = ASKPASS_LONG_HELP)]
pub askpass: bool,
}
impl ReadPasswordArgs {
pub fn read_password(&self, prompt: &str) -> Result<Option<String>> {
match &self.password {
Some(password_arg) => {
let password = read_password(
prompt,
password_arg.as_deref(),
self.askpass,
)?;
Ok(Some(password))
}
None => Ok(None),
}
}
#[allow(dead_code)]
pub fn has_password(&self) -> bool { self.password.is_some() }
}
#[derive(Debug, Args)]
#[group(skip)]
pub struct WritePasswordArgs {
#[arg(long = "encrypt-password", num_args(0..=1), value_name = "PASSWORD")]
pub encrypt_password: Option<Option<String>>,
#[arg(long = "encrypt-askpass", requires = "encrypt_password", help = ASKPASS_HELP, long_help = ASKPASS_LONG_HELP)]
pub encrypt_askpass: bool,
#[arg(
long = "encrypt-method",
value_enum,
default_value_t = PasswordMethod::Argon2id,
requires = "encrypt_password"
)]
pub encrypt_method: PasswordMethod,
}
impl WritePasswordArgs {
pub fn read_password(&self, prompt: &str) -> Result<String> {
read_password(
prompt,
self.encrypt_password.as_ref().and_then(|p| p.as_deref()),
self.encrypt_askpass,
)
}
#[allow(dead_code)]
pub fn has_password(&self) -> bool { self.encrypt_password.is_some() }
pub fn method(&self) -> KeyDerivationMethod { self.encrypt_method.into() }
}
#[derive(Debug, Args)]
#[group(skip)]
pub struct ReadWritePasswordArgs {
#[command(flatten)]
pub read: ReadPasswordArgs,
#[command(flatten)]
pub write: WritePasswordArgs,
}
impl ReadWritePasswordArgs {
#[allow(dead_code)]
pub fn read_password(&self) -> Result<Option<String>> {
self.read.read_password("Decryption password:")
}
#[allow(dead_code)]
pub fn read_encrypt_password(&self) -> Result<String> {
self.write.read_password("Encryption password:")
}
#[allow(dead_code)]
pub fn has_read_password(&self) -> bool { self.read.has_password() }
#[allow(dead_code)]
pub fn has_write_password(&self) -> bool { self.write.has_password() }
#[allow(dead_code)]
pub fn encrypt_method(&self) -> KeyDerivationMethod { self.write.method() }
}