1
use std::fs::File;
2
use std::io::Write as _;
3
use std::path::Path;
4

            
5
use clap::Args;
6
use pgp::{
7
  ArmorOptions,
8
  Deserializable as _,
9
  SignedSecretKey,
10
};
11

            
12
use crate::secrets::context::Context;
13

            
14
use super::KEY_LOCATION_HELP;
15

            
16
#[derive(Debug, Args)]
17
pub struct ExportKey {
18
  #[arg(short, long, help = "The output file")]
19
  output: String,
20

            
21
  /// The location to store the private key
22
  #[arg(short, long, help = KEY_LOCATION_HELP)]
23
  location: Option<String>,
24

            
25
  /// If not provided, the key will be named "default"
26
  #[arg(short, long, help = "The key name")]
27
  name: Option<String>,
28
}
29

            
30
impl ExportKey {
31
  pub fn execute(&self, context: &Context) -> anyhow::Result<()> {
32
    let location: &str = &self.location.clone().unwrap_or_else(|| context.keys_location());
33
    let name: &str = &self.name.clone().unwrap_or_else(|| context.key_name());
34
    let output: &str = &self.output.clone();
35

            
36
    assert!(!location.is_empty(), "Location must be provided");
37
    assert!(!name.is_empty(), "Key name must be provided");
38
    assert!(!output.is_empty(), "Output file must be provided");
39

            
40
    let filename_with_ext: &str = &format!("{name}.key");
41

            
42
    let path = Path::new(location).join(filename_with_ext);
43
    if path.exists() {
44
      // We opt to parse it rather than copy it directly to verify if it is a valid key
45
      let mut secret_key_string = File::open(path)?;
46
      let (signed_secret_key, _) = SignedSecretKey::from_armor_single(&mut secret_key_string)?;
47
      signed_secret_key.verify()?;
48

            
49
      // Save the armored private key to a file
50
      let mut file = File::open(output)?;
51
      signed_secret_key.to_armored_writer(&mut file, ArmorOptions::default())?;
52
      file.flush()?;
53

            
54
      println!("Key {name} exported to {output}.");
55
    } else {
56
      println!("Key {name} does not exist.");
57
    }
58

            
59
    Ok(())
60
  }
61
}