use crate::{repository::CliOpenRepo, status_err, Application, RUSTIC_APP};
use std::path::PathBuf;
use abscissa_core::{Command, Runnable, Shutdown};
use anyhow::Result;
use dialoguer::Password;
use log::info;
use rustic_core::{CommandInput, KeyOptions, RepositoryOptions};
#[derive(clap::Parser, Command, Debug)]
pub(super) struct KeyCmd {
#[clap(subcommand)]
cmd: KeySubCmd,
}
#[derive(clap::Subcommand, Debug, Runnable)]
enum KeySubCmd {
Add(AddCmd),
}
#[derive(clap::Parser, Debug)]
pub(crate) struct AddCmd {
#[clap(long)]
pub(crate) new_password: Option<String>,
#[clap(long)]
pub(crate) new_password_file: Option<PathBuf>,
#[clap(long)]
pub(crate) new_password_command: Option<CommandInput>,
#[clap(flatten)]
pub(crate) key_opts: KeyOptions,
}
impl Runnable for KeyCmd {
fn run(&self) {
self.cmd.run();
}
}
impl Runnable for AddCmd {
fn run(&self) {
if let Err(err) = RUSTIC_APP
.config()
.repository
.run_open(|repo| self.inner_run(repo))
{
status_err!("{}", err);
RUSTIC_APP.shutdown(Shutdown::Crash);
};
}
}
impl AddCmd {
fn inner_run(&self, repo: CliOpenRepo) -> Result<()> {
let mut pass_opts = RepositoryOptions::default();
pass_opts.password = self.new_password.clone();
pass_opts.password_file = self.new_password_file.clone();
pass_opts.password_command = self.new_password_command.clone();
let pass = pass_opts
.evaluate_password()
.map_err(Into::into)
.transpose()
.unwrap_or_else(|| -> Result<_> {
Ok(Password::new()
.with_prompt("enter password for new key")
.allow_empty_password(true)
.with_confirmation("confirm password", "passwords do not match")
.interact()?)
})?;
let id = repo.add_key(&pass, &self.key_opts)?;
info!("key {id} successfully added.");
Ok(())
}
}