Grcov report - generate_key.rs

1

    use std::fs::{

2

      self,

3

      File,

4

    };

5

    use std::io::Write as _;

6

    use std::path::Path;

7

8

    use clap::Args;

9

    use mk_lib::file::ToUtf8;

10

    use pgp::{

11

      ArmorOptions,

12

      KeyType,

13

      SecretKeyParamsBuilder,

14

    };

15

    use rand::thread_rng;

16

17

    use crate::secrets::context::Context;

18

19

    use super::KEY_LOCATION_HELP;

20

21

    #[derive(Debug, Args)]

22

    pub struct GenerateKey {

23

      /// The location to store the private key

24

      #[arg(short, long, help = KEY_LOCATION_HELP)]

25

      location: Option<String>,

26

27

      /// If not provided, the key will be named "default"

28

      /// If the key already exists, it will not be created

29

      #[arg(short, long, help = "The key name")]

30

      name: Option<String>,

31

32

      /// If the key already exists, it will be overwritten

33

      #[arg(short, long, help = "Force overwrite the key")]

34

      force: bool,

35

    }

36

37

    impl GenerateKey {

38

      pub fn execute(&self, context: &Context) -> anyhow::Result<()> {

39

        let location: &str = &self.location.clone().unwrap_or_else(|| context.keys_location());

40

        let name: &str = &self.name.clone().unwrap_or_else(|| context.key_name());

41

        println!("Generating key {} at {}", name, location);

42

43

        assert!(!location.is_empty(), "Location must be provided");

44

        assert!(!name.is_empty(), "Key name must be provided");

45

46

        // Create the directory if it does not exist

47

        let location = Path::new(location);

48

        if !location.exists() {

49

          fs::create_dir_all(location)?;

50

        }

51

52

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

53

        // Check if the file already exists

54

        let file_path = location.join(filename_with_ext);

55

        if file_path.exists() && !self.force {

56

          return Err(anyhow::anyhow!(

57

            "File {} already exists. Aborting.",

58

            file_path.to_utf8()?

59

          ));

60

        }

61

62

        let primary_user_id = format!("Me <{name}@mk.local>");

63

        let mut key_params = SecretKeyParamsBuilder::default();

64

        key_params

65

          .key_type(KeyType::Rsa(2048))

66

          .can_certify(false)

67

          .can_encrypt(true)

68

          .can_sign(true)

69

          .primary_user_id(primary_user_id);

70

        let private_key_params = key_params.build()?;

71

        let private_key = private_key_params.generate(thread_rng())?;

72

73

        // Use the private key to sign itself and put empty password

74

        let signed_private_key = private_key.sign(&mut thread_rng(), String::new)?;

75

76

        // Save the armored private key to a file

77

        let mut file = File::create(file_path.clone())?;

78

        signed_private_key.to_armored_writer(&mut file, ArmorOptions::default())?;

79

        file.flush()?;

80

        println!("Key saved to {}", file_path.to_utf8()?);

81

82

        Ok(())

83

      }

84

    }