arti/subcommands/
keys.rs
1use std::str::FromStr;
4
5use anyhow::Result;
6
7use arti_client::{InertTorClient, TorClient, TorClientConfig};
8use clap::{ArgMatches, Args, FromArgMatches, Parser, Subcommand};
9use tor_key_forge::KeystoreItemType;
10use tor_keymgr::{KeyMgr, KeyPath, KeystoreEntryResult, KeystoreId, UnrecognizedEntryError};
11use tor_rtcompat::Runtime;
12
13const LINE_LEN: usize = 80;
16
17#[derive(Debug, Parser)]
19pub(crate) enum KeysSubcommands {
20 #[command(subcommand)]
22 Keys(KeysSubcommand),
23}
24
25#[derive(Subcommand, Debug, Clone)]
26pub(crate) enum KeysSubcommand {
27 List(ListArgs),
29
30 ListKeystores,
32}
33
34#[derive(Debug, Clone, Args)]
36pub(crate) struct ListArgs {
37 #[arg(short, long)]
41 keystore_id: Option<String>,
42}
43
44pub(crate) fn run<R: Runtime>(
46 runtime: R,
47 keys_matches: &ArgMatches,
48 config: &TorClientConfig,
49) -> Result<()> {
50 let subcommand =
51 KeysSubcommand::from_arg_matches(keys_matches).expect("Could not parse keys subcommand");
52 let client = TorClient::with_runtime(runtime)
53 .config(config.clone())
54 .create_inert()?;
55
56 match subcommand {
57 KeysSubcommand::List(args) => run_list_keys(&args, &client),
58 KeysSubcommand::ListKeystores => run_list_keystores(&client),
59 }
60}
61
62fn display_entry(path: &KeyPath, ty: &KeystoreItemType, keymgr: &KeyMgr) {
64 match keymgr.describe(path) {
65 Ok(entry) => {
66 println!(" Role: {}", entry.role());
67 println!(" Summary: {}", entry.summary());
68 println!(" KeystoreItemType: {:?}", ty);
69 let extra_info = entry.extra_info();
70 println!(" Extra info:");
71 for (key, value) in extra_info {
72 println!(" - {key}: {value}");
73 }
74 }
75 Err(err) => {
76 println!(" {}", err);
77 }
78 }
79 println!("\n {}\n", "-".repeat(LINE_LEN));
80}
81
82fn display_unrecognized_entry(entry: &UnrecognizedEntryError) {
84 println!(" Unrecognized entry");
85 #[allow(clippy::single_match)]
86 match entry.entry() {
87 tor_keymgr::UnrecognizedEntryId::Path(p) => {
88 println!(" Location: {}", p.to_string_lossy());
89 println!(" Error: {}", entry.error());
90 }
91 other => {
95 panic!("Unhandled enum variant: {:?}", other);
96 }
97 }
98 println!("\n {}\n", "-".repeat(LINE_LEN));
99}
100
101fn run_list_keys(args: &ListArgs, client: &InertTorClient) -> Result<()> {
103 let keymgr = client.keymgr()?;
104 match &args.keystore_id {
109 Some(s) => {
110 let id = KeystoreId::from_str(s)?;
111 let entries = keymgr.list_by_id(&id)?.into_iter().map(|res| match res {
112 Ok((path, ty)) => Ok((path, ty, &id)),
113 Err(unrecognized_entry) => Err(unrecognized_entry),
114 });
115 let empty_err_msg = format!("Currently there are no entries in the keystore {}.", s);
116 display_keystore_entries(entries, keymgr, &empty_err_msg);
117 }
118 None => {
119 let entries = keymgr.list()?.into_iter().map(|res| match res {
120 Ok(entry) => Ok((
121 entry.key_path().to_owned(),
122 entry.key_type().to_owned(),
123 entry.keystore_id(),
124 )),
125 Err(unrecognized_entry) => Err(unrecognized_entry),
126 });
127 display_keystore_entries(
128 entries,
129 keymgr,
130 "Currently there are no entries in any of the keystores.",
131 );
132 }
133 }
134 Ok(())
135}
136
137fn run_list_keystores(client: &InertTorClient) -> Result<()> {
139 let keymgr = client.keymgr()?;
140 let entries = keymgr.list_keystores();
141
142 if entries.is_empty() {
143 println!("Currently there are no keystores available.");
144 } else {
145 println!(" Keystores:\n");
146 for entry in entries {
147 println!(" - {:?}\n", entry.as_ref());
150 }
151 }
152
153 Ok(())
154}
155
156fn display_keystore_entries<'a>(
158 entries: impl std::iter::ExactSizeIterator<
159 Item = KeystoreEntryResult<(KeyPath, KeystoreItemType, &'a KeystoreId)>,
160 >,
161 keymgr: &KeyMgr,
162 empty_err_msg: &str,
163) {
164 if entries.len() == 0 {
165 println!("{}", empty_err_msg);
166 return;
167 }
168 println!(" ===== Keytore entries =====\n\n");
169 for entry in entries {
170 match entry {
171 Ok((path, ty, keystore_id)) => {
172 println!(" Keystore ID: {}", keystore_id.as_ref());
173 display_entry(&path, &ty, keymgr);
174 }
175 Err(entry) => {
176 display_unrecognized_entry(&entry);
177 }
178 }
179 }
180}