1use crate::pkg;
2use anyhow::{Result, anyhow};
3use clap::{ArgGroup, Parser, Subcommand};
4use std::path::Path;
5
6#[derive(Parser, Debug)]
7#[command(long_about = "Manages PGP keys for package signature verification.")]
8pub struct PgpCommand {
9 #[command(subcommand)]
10 pub command: PgpCommands,
11}
12
13#[derive(Subcommand, Debug)]
14pub enum PgpCommands {
15 Add(AddKey),
17 #[command(alias = "rm")]
19 Remove(RemoveKey),
20 #[command(alias = "ls")]
22 List,
23 Search(SearchKey),
25 Show(ShowKey),
27 Verify(VerifySig),
29}
30
31#[derive(Parser, Debug)]
32#[command(group(
33 ArgGroup::new("source")
34 .required(true)
35 .args(["path", "fingerprint", "url"]),
36))]
37pub struct AddKey {
38 #[arg(long)]
40 pub path: Option<String>,
41
42 #[arg(long)]
44 pub fingerprint: Option<String>,
45
46 #[arg(long)]
48 pub url: Option<String>,
49
50 #[arg(long)]
52 pub name: Option<String>,
53}
54
55#[derive(Parser, Debug)]
56#[command(group(
57 ArgGroup::new("key_id")
58 .required(true)
59 .args(["name", "fingerprint"]),
60))]
61pub struct RemoveKey {
62 pub name: Option<String>,
64
65 #[arg(long)]
67 pub fingerprint: Option<String>,
68}
69
70#[derive(Parser, Debug)]
71pub struct SearchKey {
72 #[arg(required = true)]
74 pub term: String,
75}
76
77#[derive(Parser, Debug)]
78pub struct ShowKey {
79 #[arg(required = true)]
81 pub name: String,
82}
83
84#[derive(Parser, Debug)]
85pub struct VerifySig {
86 #[arg(long)]
88 pub file: String,
89
90 #[arg(long)]
92 pub sig: String,
93
94 #[arg(long)]
96 pub key: String,
97}
98
99pub fn run(args: PgpCommand) -> Result<()> {
100 match args.command {
101 PgpCommands::Add(add_args) => {
102 if let Some(path) = add_args.path {
103 pkg::pgp::add_key_from_path(&path, add_args.name.as_deref())?;
104 } else if let Some(fingerprint) = add_args.fingerprint {
105 if let Some(name) = add_args.name {
106 pkg::pgp::add_key_from_fingerprint(&fingerprint, &name)?;
107 } else {
108 return Err(anyhow!(
109 "A name must be provided when adding a key by fingerprint."
110 ));
111 }
112 } else if let Some(url) = add_args.url {
113 let name = if let Some(n) = add_args.name {
114 n
115 } else {
116 Path::new(&url)
117 .file_stem()
118 .and_then(|s| s.to_str())
119 .ok_or(anyhow!("Could not derive name from URL"))?
120 .to_string()
121 };
122 pkg::pgp::add_key_from_url(&url, &name)?;
123 }
124 }
125 PgpCommands::Remove(remove_args) => {
126 if let Some(name) = remove_args.name {
127 pkg::pgp::remove_key_by_name(&name)?;
128 } else if let Some(fingerprint) = remove_args.fingerprint {
129 pkg::pgp::remove_key_by_fingerprint(&fingerprint)?;
130 }
131 }
132 PgpCommands::List => {
133 pkg::pgp::list_keys()?;
134 }
135 PgpCommands::Search(search_args) => {
136 pkg::pgp::search_keys(&search_args.term)?;
137 }
138 PgpCommands::Show(show_args) => {
139 pkg::pgp::show_key(&show_args.name)?;
140 }
141 PgpCommands::Verify(verify_args) => {
142 pkg::pgp::cli_verify_signature(&verify_args.file, &verify_args.sig, &verify_args.key)?;
143 }
144 }
145 Ok(())
146}