rust_1password_cli_runner/
lib.rs

1use std::process::Command;
2
3/// This struct defines a secret from the 1Password CLI.
4pub struct OnePasswordSecret {
5    connection_string: String,
6}
7
8impl OnePasswordSecret {
9    /// Creates a new instance of OnePasswordSecret that is connected to the
10    /// given connection_string.
11    ///
12    /// This does not load anything. To access the 1Password CLI tool, you MUST
13    /// use the .load method.
14    pub fn new(connection_string : String) -> OnePasswordSecret {
15        OnePasswordSecret {
16            connection_string
17        }
18    }
19
20    /// Loads the secret behind the connection_string of this OnePasswordSecret.
21    /// It interacts with the 1Password CLI, so that must be installed!
22    ///
23    /// panics:
24    /// if 1Password CLI is not installed!
25    /// if OS is not supported!
26    pub fn load(&self) -> Option<String> {
27        let is_unix = cfg!(target_os = "linux") || cfg!(target_os = "macos");
28
29       if is_unix {
30            self.check_op_cli_installed();
31
32            let secret = Command::new("op")
33                .arg("read")
34                .arg(&self.connection_string)
35                .output();
36
37            if let Ok(secret) = secret {
38                Some(String::from_utf8(secret.stdout).unwrap().trim().to_string())
39            } else {
40                None
41            }
42        } else {
43            panic!("Unsupported OS!")
44        }
45    }
46
47    /// Checks if the 1Password CLI tool has been installed on this computer.
48    ///
49    /// panics:
50    /// If an error occurred
51    fn check_op_cli_installed(&self) {
52        let error = Command::new("op")
53            .arg("--version")
54            .output()
55            .expect("1Password CLI is not installed!")
56            .stderr;
57
58        if !error.is_empty() {
59            panic!("Expected 1Password CLI to be installed! Error: {}",
60                   String::from_utf8(error).unwrap().trim());
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn can_load_dummy_secret() {
71        let connection_string = String::from(
72            "op://DEV-Automated-Testing/rust-1password-cli-runner-test-1234/credential");
73        let secret = OnePasswordSecret::new(connection_string);
74        let secret = secret.load();
75
76        assert_ne!(secret, None);
77
78        let secret = secret.unwrap();
79
80        assert_eq!(secret, String::from("1234"));
81    }
82
83    #[test]
84    fn can_load_empty_secret() {
85        let connection_string = String::from(
86            "op://DEV-Automated-Testing/rust-1password-cli-runner-test-empty/credential");
87        let secret = OnePasswordSecret::new(connection_string);
88        let secret = secret.load();
89
90        assert_ne!(secret, None);
91
92        let secret = secret.unwrap();
93
94        assert_eq!(secret, String::from(""));
95    }
96}