1use anyhow::{Context, Result};
2use clap::{Args, Subcommand};
3use dialoguer::{theme::ColorfulTheme, Confirm, Password};
4use p256::ecdsa::SigningKey;
5use rand_core::OsRng;
6use warg_client::keyring::Keyring;
7use warg_client::Config;
8use warg_crypto::signing::PrivateKey;
9
10use super::CommonOptions;
11
12#[derive(Args)]
14pub struct KeyCommand {
15 #[clap(subcommand)]
17 pub command: KeySubcommand,
18}
19
20impl KeyCommand {
21 pub async fn exec(self) -> Result<()> {
23 match self.command {
24 KeySubcommand::New(cmd) => cmd.exec().await,
25 KeySubcommand::Info(cmd) => cmd.exec().await,
26 KeySubcommand::Set(cmd) => cmd.exec().await,
27 KeySubcommand::Delete(cmd) => cmd.exec().await,
28 }
29 }
30}
31
32#[derive(Subcommand)]
34pub enum KeySubcommand {
35 New(KeyNewCommand),
37 Info(KeyInfoCommand),
39 Set(KeySetCommand),
41 Delete(KeyDeleteCommand),
43}
44
45#[derive(Args)]
47pub struct KeyNewCommand {
48 #[clap(flatten)]
50 pub common: CommonOptions,
51}
52
53impl KeyNewCommand {
54 pub async fn exec(self) -> Result<()> {
56 let config = &mut self.common.read_config()?;
57 let key = SigningKey::random(&mut OsRng).into();
58 if let Some(ref reg) = self.common.registry {
59 config.keys.insert(reg.to_string());
60 } else {
61 config.keys.insert("default".to_string());
62 }
63 Keyring::from_config(config)?.set_signing_key(
64 self.common.registry.as_deref(),
65 &key,
66 &mut config.keys,
67 config.home_url.as_deref(),
68 )?;
69 config.write_to_file(&Config::default_config_path()?)?;
70 let public_key = key.public_key();
71 println!("Key ID: {}", public_key.fingerprint());
72 println!("Public Key: {public_key}");
73 Ok(())
74 }
75}
76
77#[derive(Args)]
79pub struct KeyInfoCommand {
80 #[clap(flatten)]
82 pub common: CommonOptions,
83}
84
85impl KeyInfoCommand {
86 pub async fn exec(self) -> Result<()> {
88 let config = &self.common.read_config()?;
89 let private_key = Keyring::from_config(config)?.get_signing_key(
90 self.common.registry.as_deref(),
91 &config.keys,
92 config.home_url.as_deref(),
93 )?;
94 let public_key = private_key.public_key();
95 println!("Key ID: {}", public_key.fingerprint());
96 println!("Public Key: {public_key}");
97 Ok(())
98 }
99}
100
101#[derive(Args)]
103pub struct KeySetCommand {
104 #[clap(flatten)]
106 pub common: CommonOptions,
107}
108
109impl KeySetCommand {
110 pub async fn exec(self) -> Result<()> {
112 let key_str = Password::with_theme(&ColorfulTheme::default())
113 .with_prompt("input signing key (expected format is `<alg>:<base64>`): ")
114 .interact()
115 .context("failed to read signing key")?;
116 let key =
117 PrivateKey::decode(key_str).context("signing key is not in the correct format")?;
118 let config = &mut self.common.read_config()?;
119
120 Keyring::from_config(config)?.set_signing_key(
121 self.common.registry.as_deref(),
122 &key,
123 &mut config.keys,
124 config.home_url.as_deref(),
125 )?;
126 config.write_to_file(&Config::default_config_path()?)?;
127
128 println!("signing key was set successfully");
129
130 Ok(())
131 }
132}
133
134#[derive(Args)]
136pub struct KeyDeleteCommand {
137 #[clap(flatten)]
139 pub common: CommonOptions,
140}
141
142impl KeyDeleteCommand {
143 pub async fn exec(self) -> Result<()> {
145 let config = &mut self.common.read_config()?;
146
147 if Confirm::with_theme(&ColorfulTheme::default())
148 .with_prompt("are you sure you want to delete your signing key")
149 .interact()?
150 {
151 Keyring::from_config(config)?.delete_signing_key(
152 self.common.registry.as_deref(),
153 &config.keys,
154 config.home_url.as_deref(),
155 )?;
156 let keys = &mut config.keys;
157 if let Some(registry_url) = self.common.registry {
158 keys.swap_remove(®istry_url);
159 } else {
160 keys.swap_remove("default");
161 }
162 config.write_to_file(&Config::default_config_path()?)?;
163 println!("signing key was deleted successfully",);
164 } else if let Some(url) = self.common.registry {
165 println!(
166 "skipping deletion of signing key for registry `{url}`",
167 url = url
168 );
169 } else {
170 println!("skipping deletion of signing key");
171 }
172
173 Ok(())
174 }
175}