use crate::pkg;
use anyhow::{Result, anyhow};
use clap::{ArgGroup, Parser, Subcommand};
use std::path::Path;
#[derive(Parser, Debug)]
#[command(long_about = "Manages PGP keys for package signature verification.")]
pub struct PgpCommand {
#[command(subcommand)]
pub command: PgpCommands,
}
#[derive(Subcommand, Debug)]
pub enum PgpCommands {
Add(AddKey),
#[command(alias = "rm")]
Remove(RemoveKey),
#[command(alias = "ls")]
List,
Search(SearchKey),
Show(ShowKey),
Verify(VerifySig),
}
#[derive(Parser, Debug)]
#[command(group(
ArgGroup::new("source")
.required(true)
.args(["path", "fingerprint", "url"]),
))]
pub struct AddKey {
#[arg(long)]
pub path: Option<String>,
#[arg(long)]
pub fingerprint: Option<String>,
#[arg(long)]
pub url: Option<String>,
#[arg(long)]
pub name: Option<String>,
}
#[derive(Parser, Debug)]
#[command(group(
ArgGroup::new("key_id")
.required(true)
.args(["name", "fingerprint"]),
))]
pub struct RemoveKey {
pub name: Option<String>,
#[arg(long)]
pub fingerprint: Option<String>,
}
#[derive(Parser, Debug)]
pub struct SearchKey {
#[arg(required = true)]
pub term: String,
}
#[derive(Parser, Debug)]
pub struct ShowKey {
#[arg(required = true)]
pub name: String,
}
#[derive(Parser, Debug)]
pub struct VerifySig {
#[arg(long)]
pub file: String,
#[arg(long)]
pub sig: String,
#[arg(long)]
pub key: String,
}
pub fn run(args: PgpCommand) -> Result<()> {
match args.command {
PgpCommands::Add(add_args) => {
if let Some(path) = add_args.path {
pkg::pgp::add_key_from_path(&path, add_args.name.as_deref(), false)?;
} else if let Some(fingerprint) = add_args.fingerprint {
if let Some(name) = add_args.name {
pkg::pgp::add_key_from_fingerprint(&fingerprint, &name, false)?;
} else {
return Err(anyhow!(
"A name must be provided when adding a key by fingerprint."
));
}
} else if let Some(url) = add_args.url {
let name = if let Some(n) = add_args.name {
n
} else {
Path::new(&url)
.file_stem()
.and_then(|s| s.to_str())
.ok_or(anyhow!("Could not derive name from URL"))?
.to_string()
};
pkg::pgp::add_key_from_url(&url, &name, false)?;
}
}
PgpCommands::Remove(remove_args) => {
if let Some(name) = remove_args.name {
pkg::pgp::remove_key_by_name(&name)?;
} else if let Some(fingerprint) = remove_args.fingerprint {
pkg::pgp::remove_key_by_fingerprint(&fingerprint)?;
}
}
PgpCommands::List => {
pkg::pgp::list_keys()?;
}
PgpCommands::Search(search_args) => {
pkg::pgp::search_keys(&search_args.term)?;
}
PgpCommands::Show(show_args) => {
pkg::pgp::show_key(&show_args.name)?;
}
PgpCommands::Verify(verify_args) => {
pkg::pgp::cli_verify_signature(&verify_args.file, &verify_args.sig, &verify_args.key)?;
}
}
Ok(())
}