sentinelpass_protocol/
paths.rs1use std::path::PathBuf;
4
5pub fn get_config_dir() -> PathBuf {
10 let base = dirs::config_dir()
11 .or_else(dirs::data_dir)
12 .or_else(|| dirs::home_dir().map(|h| h.join(".config")))
13 .unwrap_or_else(|| PathBuf::from("."));
14
15 base.join("PasswordManager")
16}
17
18pub fn default_runtime_dir() -> PathBuf {
25 if cfg!(target_os = "windows") {
26 return get_config_dir().join("runtime");
27 }
28 match std::env::var("XDG_RUNTIME_DIR") {
29 Ok(dir) if !dir.trim().is_empty() => PathBuf::from(dir).join("SentinelPass"),
30 _ => get_config_dir().join("runtime"),
31 }
32}
33
34pub fn default_ipc_socket_path() -> PathBuf {
36 if cfg!(target_os = "windows") {
37 PathBuf::from(r"\\.\pipe\SentinelPass")
39 } else {
40 default_runtime_dir().join("sentinelpass.sock")
41 }
42}
43
44pub fn default_ipc_token_path() -> PathBuf {
46 get_config_dir().join("ipc.token")
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[cfg(unix)]
54 #[test]
55 fn test_default_socket_path_unix() {
56 let path = default_ipc_socket_path();
57 assert!(path.to_string_lossy().ends_with("sentinelpass.sock"));
58 }
59
60 #[cfg(windows)]
61 #[test]
62 fn test_default_socket_path_windows() {
63 let path = default_ipc_socket_path();
64 assert!(path.to_string_lossy().contains("\\\\.\\pipe\\"));
65 }
66
67 static XDG_ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
71
72 #[test]
75 fn test_socket_path_with_xdg_runtime_dir() {
76 let _guard = XDG_ENV_LOCK.lock().unwrap();
77 let custom_runtime = "/tmp/custom_runtime";
78 std::env::set_var("XDG_RUNTIME_DIR", custom_runtime);
79
80 let path = default_ipc_socket_path();
81
82 #[cfg(unix)]
83 {
84 let path_str = path.to_string_lossy();
85 assert!(
86 path_str.contains(custom_runtime) && path_str.contains("SentinelPass"),
87 "default socket must live in the private runtime dir: {path_str}"
88 );
89 }
90
91 #[cfg(windows)]
92 {
93 let _ = path;
95 }
96
97 std::env::remove_var("XDG_RUNTIME_DIR");
98 }
99
100 #[test]
103 fn test_socket_path_without_xdg_runtime_dir_is_not_tmp() {
104 let _guard = XDG_ENV_LOCK.lock().unwrap();
105 std::env::remove_var("XDG_RUNTIME_DIR");
106 let path = default_ipc_socket_path();
107 let path_str = path.to_string_lossy().to_string();
108
109 #[cfg(unix)]
110 assert!(
111 !path_str.starts_with("/tmp/") && !path_str.starts_with("/private/tmp/"),
112 "the /tmp fallback must stay removed: {path_str}"
113 );
114 assert!(
115 path_str.contains("runtime") || path_str.contains("SentinelPass"),
116 "default must use the private runtime dir: {path_str}"
117 );
118 }
119}