pars_core/pgp/
key_management.rs

1use std::io::Write;
2use std::process::{Command, Stdio};
3
4use anyhow::{anyhow, Result};
5
6use crate::pgp::utils::wait_child_process;
7use crate::pgp::PGPClient;
8
9fn run_gpg_batched_child(executable: &str, args: &[&str], batch_input: &str) -> Result<()> {
10    let mut cmd = Command::new(executable)
11        .args(args)
12        .stdin(Stdio::piped())
13        .stdout(Stdio::null())
14        .stderr(Stdio::piped())
15        .spawn()?;
16    if let Some(mut input) = cmd.stdin.take() {
17        input.write_all(batch_input.as_bytes())?;
18        input.flush()?;
19    } else {
20        return Err(anyhow!("Failed to open stdin for PGP key generation"));
21    }
22    wait_child_process(&mut cmd)
23}
24
25fn run_gpg_inherited_child(executable: &str, args: &[&str]) -> Result<()> {
26    let status = Command::new(executable)
27        .args(args)
28        .stdin(Stdio::inherit())
29        .stdout(Stdio::inherit())
30        .stderr(Stdio::inherit())
31        .status()?;
32    if status.success() {
33        Ok(())
34    } else {
35        Err(anyhow!(format!("Failed to generate PGP key, code {:?}", status)))
36    }
37}
38
39pub fn key_gen_stdin(pgp_exe: &str) -> Result<()> {
40    let gpg_args = ["--gen-key"];
41    run_gpg_inherited_child(pgp_exe, &gpg_args)
42}
43
44pub fn key_edit_stdin(pgp_exe: &str, key_fpr: &str) -> Result<()> {
45    let gpg_args = ["--edit-key", key_fpr];
46    run_gpg_inherited_child(pgp_exe, &gpg_args)
47}
48pub fn key_gen_batch(pgp_exe: &str, batch_input: &str) -> Result<()> {
49    let gpg_args = ["--batch", "--gen-key"];
50    run_gpg_batched_child(pgp_exe, &gpg_args, batch_input)
51}
52
53impl PGPClient {
54    pub fn key_edit_batch(&self, batch_input: &str) -> Result<()> {
55        for key in &self.keys {
56            let gpg_args =
57                ["--batch", "--command-fd", "0", "--status-fd", "1", "--edit-key", &key.key_fpr];
58            run_gpg_batched_child(&self.executable, &gpg_args, batch_input)?;
59        }
60        Ok(())
61    }
62
63    pub fn list_key_fingerprints(&self) -> Result<Vec<String>> {
64        todo!("impl this")
65    }
66
67    pub fn list_all_user_emails(&self) -> Result<Vec<String>> {
68        todo!("impl this")
69    }
70}
71#[cfg(test)]
72mod tests {
73
74    use serial_test::serial;
75
76    use super::*;
77    use crate::util::test_util::{
78        clean_up_test_key, get_test_email, get_test_executable, gpg_key_edit_example_batch,
79        gpg_key_gen_example_batch,
80    };
81
82    // #[test]
83    // #[serial]
84    // #[ignore = "need run interactively"]
85    // fn test_gpg_key_gen_stdin() {
86    //     let executable = get_test_executable();
87    //     let mut pgp_client = PGPClient::new(executable, None, None, None);
88    //     pgp_client.key_gen_stdin().unwrap();
89    // }
90
91    #[test]
92    #[serial]
93    fn pgp_key_gen_batch() {
94        let executable = get_test_executable();
95        key_gen_batch(&executable, &gpg_key_gen_example_batch()).unwrap();
96        let pgp_client = PGPClient::new(executable, &[&get_test_email()]).unwrap();
97        clean_up_test_key(pgp_client.get_executable(), &[&get_test_email()]).unwrap();
98    }
99
100    #[test]
101    #[serial]
102    fn pgp_key_edit_batch() {
103        let executable = get_test_executable();
104        let email = get_test_email();
105        key_gen_batch(&executable, &gpg_key_gen_example_batch()).unwrap();
106        let pgp_client = PGPClient::new(executable, &[&email]).unwrap();
107        pgp_client.key_edit_batch(&gpg_key_edit_example_batch()).unwrap();
108        clean_up_test_key(pgp_client.get_executable(), &[&email]).unwrap();
109    }
110}