1use std::path::Path;
7
8use anyhow::{Result, anyhow};
9use clap::{ArgGroup, Parser, Subcommand};
10
11use crate::pkg;
12
13#[derive(Parser, Debug)]
15#[command(long_about = "Manages PGP keys for package signature verification.")]
16pub struct PgpCommand {
17 #[command(subcommand)]
19 pub command: PgpCommands
20}
21
22#[derive(Subcommand, Debug)]
24pub enum PgpCommands {
25 Add(AddKey),
27 #[command(alias = "rm")]
29 Remove(RemoveKey),
30 #[command(alias = "ls")]
32 List,
33 Search(SearchKey),
35 Show(ShowKey),
37 Verify(VerifySig)
39}
40
41#[derive(Parser, Debug)]
43#[command(group(
44 ArgGroup::new("source")
45 .required(true)
46 .args(["path", "fingerprint", "url"]),
47))]
48pub struct AddKey {
49 #[arg(long)]
51 pub path: Option<String>,
52
53 #[arg(long)]
55 pub fingerprint: Option<String>,
56
57 #[arg(long)]
59 pub url: Option<String>,
60
61 #[arg(long)]
64 pub name: Option<String>
65}
66
67#[derive(Parser, Debug)]
69#[command(group(
70 ArgGroup::new("key_id")
71 .required(true)
72 .args(["name", "fingerprint"]),
73))]
74pub struct RemoveKey {
75 pub name: Option<String>,
77
78 #[arg(long)]
80 pub fingerprint: Option<String>
81}
82
83#[derive(Parser, Debug)]
85pub struct SearchKey {
86 #[arg(required = true)]
88 pub term: String
89}
90
91#[derive(Parser, Debug)]
93pub struct ShowKey {
94 #[arg(required = true)]
96 pub name: String
97}
98
99#[derive(Parser, Debug)]
101pub struct VerifySig {
102 #[arg(long)]
104 pub file: String,
105
106 #[arg(long)]
108 pub sig: String,
109
110 #[arg(long)]
112 pub key: String
113}
114
115pub fn run(args: PgpCommand) -> Result<()> {
121 match args.command {
122 PgpCommands::Add(add_args) => {
123 if let Some(path) = add_args.path {
124 pkg::pgp::add_key_from_path(
125 &path,
126 add_args.name.as_deref(),
127 false
128 )?;
129 } else if let Some(fingerprint) = add_args.fingerprint {
130 if let Some(name) = add_args.name {
131 pkg::pgp::add_key_from_fingerprint(
132 &fingerprint,
133 &name,
134 false
135 )?;
136 } else {
137 return Err(anyhow!(
138 "A name must be provided when adding a key by \
139 fingerprint."
140 ));
141 }
142 } else if let Some(url) = add_args.url {
143 let name = if let Some(n) = add_args.name {
144 n
145 } else {
146 Path::new(&url)
147 .file_stem()
148 .and_then(|s| s.to_str())
149 .ok_or(anyhow!("Could not derive name from URL"))?
150 .to_string()
151 };
152 pkg::pgp::add_key_from_url(&url, &name, false)?;
153 }
154 }
155 PgpCommands::Remove(remove_args) => {
156 if let Some(name) = remove_args.name {
157 pkg::pgp::remove_key_by_name(&name)?;
158 } else if let Some(fingerprint) = remove_args.fingerprint {
159 pkg::pgp::remove_key_by_fingerprint(&fingerprint)?;
160 }
161 }
162 PgpCommands::List => {
163 pkg::pgp::list_keys()?;
164 }
165 PgpCommands::Search(search_args) => {
166 pkg::pgp::search_keys(&search_args.term)?;
167 }
168 PgpCommands::Show(show_args) => {
169 pkg::pgp::show_key(&show_args.name)?;
170 }
171 PgpCommands::Verify(verify_args) => {
172 pkg::pgp::cli_verify_signature(
173 &verify_args.file,
174 &verify_args.sig,
175 &verify_args.key
176 )?;
177 }
178 }
179 Ok(())
180}