use std::path::PathBuf;
use std::str::FromStr;
use clap::Args;
use crate::cli::ENV_PATH_SEP;
use crate::error::{Result, YageError};
use crate::{
decrypt_yaml, encrypt_yaml, get_yaml_recipients, load_identities, load_recipients, read_yaml,
write_yaml,
};
#[derive(Args, Debug)]
#[command(alias = "recrypt")]
pub struct ReEncryptArgs {
#[clap(short, long)]
pub in_place: bool,
#[clap(short = 'e', long)]
pub keep_recipients: bool,
#[clap(short, long = "key", value_name = "KEY", env = "YAGE_KEY", value_delimiter = ',')]
pub keys: Vec<String>,
#[clap(
short = 'K',
long = "key-file",
value_name = "FILE",
env = "YAGE_KEY_FILE",
value_delimiter = ENV_PATH_SEP,
)]
pub key_files: Vec<PathBuf>,
#[clap(
short,
long = "recipient",
value_name = "RECIPIENT",
env = "YAGE_RECIPIENT",
value_delimiter = ','
)]
pub recipients: Vec<String>,
#[clap(
short = 'R',
long = "recipient-file",
value_name = "FILE",
env = "YAGE_RECIPIENT_FILE",
value_delimiter = ENV_PATH_SEP,
)]
pub recipient_files: Vec<PathBuf>,
#[clap(short = 'd', long = "remove-recipient", value_name = "RECIPIENT")]
pub remove_recipients: Vec<String>,
#[clap(short = 'D', long = "remove-recipient-file", value_name = "FILE")]
pub remove_recipient_files: Vec<PathBuf>,
#[clap(short, long, default_value = "-", value_name = "FILE")]
pub output: PathBuf,
#[arg()]
pub files: Vec<PathBuf>,
}
pub fn re_encrypt(args: &ReEncryptArgs) -> Result<i32> {
if args.in_place && args.files.contains(&PathBuf::from_str("-").unwrap()) {
return Err(YageError::InPlaceStdin);
}
if !args.in_place && args.files.len() != 1 {
return Err(YageError::InvalidNumberOfInputFiles);
}
let identities = load_identities(&args.keys, &args.key_files)?;
let arg_recipients = load_recipients(&args.recipients, &args.recipient_files)?;
let remove_recipients = load_recipients(&args.remove_recipients, &args.remove_recipient_files)?;
for file in &args.files {
let input_data = read_yaml(file)?;
let decrypted_data = decrypt_yaml(&input_data, &identities)?;
let yaml_recipients =
if args.keep_recipients { get_yaml_recipients(&input_data)? } else { vec![] };
let mut recipients = [arg_recipients.clone(), yaml_recipients].concat();
recipients.sort_by_cached_key(|r| r.to_string());
recipients.dedup();
recipients.retain(|r| !remove_recipients.contains(r));
debug!("{file:?} recipients: {recipients:?}");
let output_data = encrypt_yaml(&decrypted_data, &recipients)?;
write_yaml(if args.in_place { file } else { &args.output }, &output_data)?;
}
Ok(0)
}