hashiverse_server_lib/server/
passphrase.rs1use std::fs;
16use secrecy::SecretString;
17
18pub const DEFAULT_PASSPHRASE_PATHS: &[&str] = &[
21 "/run/secrets/hashiverse_passphrase",
22 "/run/secrets/HASHIVERSE_PASSPHRASE",
23 "/mnt/secrets/hashiverse_passphrase",
24 "/mnt/secrets/HASHIVERSE_PASSPHRASE",
25 "/etc/secrets/hashiverse_passphrase",
26 "/etc/secrets/HASHIVERSE_PASSPHRASE",
27 "./.hashiverse_passphrase",
28 "./.HASHIVERSE_PASSPHRASE",
29];
30
31pub fn get_passphrase(passphrase_path: Option<String>) -> anyhow::Result<SecretString> {
32 fn get_passphrase_from_file_if_exists(path: &str) -> Option<SecretString> {
33 let contents = fs::read_to_string(path);
34 match contents {
35 Ok(contents) => Some(SecretString::new(Box::from(contents))),
36 Err(_) => None
37 }
38 }
39
40 if let Some(passphrase_path) = passphrase_path {
42 let passphrase = get_passphrase_from_file_if_exists(&passphrase_path);
43 match passphrase {
44 Some(passphrase) => return Ok(passphrase),
45 None => anyhow::bail!("no passphrase found at {}", passphrase_path)
46 }
47 }
48
49 for default_passphrase_path in DEFAULT_PASSPHRASE_PATHS {
51 if let Some(passphrase) = get_passphrase_from_file_if_exists(default_passphrase_path) { return Ok(passphrase); }
52 }
53
54 if let Ok(passphrase) = std::env::var("HASHIVERSE_PASSPHRASE") { return Ok(SecretString::new(Box::from(passphrase))); }
56
57 anyhow::bail!("no passphrase found - please (at worst) set the HASHIVERSE_PASSPHRASE environment variable to something memorable");
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use secrecy::ExposeSecret;
65
66 #[test]
68 fn default_passphrase_paths_have_no_stray_whitespace() {
69 for default_passphrase_path in DEFAULT_PASSPHRASE_PATHS {
70 assert_eq!(default_passphrase_path.trim(), *default_passphrase_path, "whitespace in {:?}", default_passphrase_path);
71 assert!(default_passphrase_path.starts_with('/') || default_passphrase_path.starts_with("./"), "not a path: {:?}", default_passphrase_path);
72 }
73 }
74
75 #[test]
76 fn explicit_passphrase_path_is_read() {
77 let (_temp_dir, temp_dir_path) = hashiverse_lib::tools::tools::get_temp_dir().unwrap();
78 let passphrase_path = std::path::Path::new(&temp_dir_path).join("passphrase");
79 fs::write(&passphrase_path, "correct horse").unwrap();
80 let passphrase = get_passphrase(Some(passphrase_path.to_string_lossy().into_owned())).unwrap();
81 assert_eq!(passphrase.expose_secret(), "correct horse");
82 }
83
84 #[test]
85 fn missing_explicit_passphrase_path_is_an_error() {
86 let (_temp_dir, temp_dir_path) = hashiverse_lib::tools::tools::get_temp_dir().unwrap();
87 let passphrase_path = std::path::Path::new(&temp_dir_path).join("does-not-exist");
88 assert!(get_passphrase(Some(passphrase_path.to_string_lossy().into_owned())).is_err());
89 }
90}