diff options
Diffstat (limited to 'src/config.rs')
| -rw-r--r-- | src/config.rs | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/src/config.rs b/src/config.rs index 720c215..c05c3ae 100644 --- a/src/config.rs +++ b/src/config.rs | |||
| @@ -1,6 +1,62 @@ | |||
| 1 | use std::env; | 1 | use std::env; |
| 2 | use std::io; | ||
| 3 | use std::sync::OnceLock; | ||
| 2 | 4 | ||
| 3 | pub const TEMP_PATH: &str = "/tmp/senator_sperma"; | 5 | static TEMP_PATH: OnceLock<String> = OnceLock::new(); |
| 6 | |||
| 7 | /// Private per-process temp root. Initialized by [`init_temp_dir`] at startup. | ||
| 8 | /// Falls back to the historical path only for code paths that run before init | ||
| 9 | /// (tests). | ||
| 10 | pub fn temp_path() -> &'static str { | ||
| 11 | TEMP_PATH | ||
| 12 | .get() | ||
| 13 | .map(String::as_str) | ||
| 14 | .unwrap_or("/tmp/senator_sperma") | ||
| 15 | } | ||
| 16 | |||
| 17 | /// Create/validate the temp directory with private permissions. | ||
| 18 | /// | ||
| 19 | /// A fixed, predictable path in `/tmp` is a symlink target for any local user. | ||
| 20 | /// Refuse a symlink (or non-directory) and force mode `0700` on the real | ||
| 21 | /// directory before the bot writes anything into it. | ||
| 22 | pub fn init_temp_dir() -> io::Result<()> { | ||
| 23 | let path = env::temp_dir().join("senator_sperma"); | ||
| 24 | match std::fs::symlink_metadata(&path) { | ||
| 25 | Ok(meta) if meta.file_type().is_symlink() => { | ||
| 26 | return Err(io::Error::other(format!( | ||
| 27 | "{} is a symlink; refusing to use it", | ||
| 28 | path.display() | ||
| 29 | ))); | ||
| 30 | } | ||
| 31 | Ok(meta) if !meta.is_dir() => { | ||
| 32 | return Err(io::Error::other(format!( | ||
| 33 | "{} exists and is not a directory", | ||
| 34 | path.display() | ||
| 35 | ))); | ||
| 36 | } | ||
| 37 | Ok(_) => {} | ||
| 38 | Err(e) if e.kind() == io::ErrorKind::NotFound => { | ||
| 39 | let mut builder = std::fs::DirBuilder::new(); | ||
| 40 | #[cfg(unix)] | ||
| 41 | { | ||
| 42 | use std::os::unix::fs::DirBuilderExt; | ||
| 43 | builder.mode(0o700); | ||
| 44 | } | ||
| 45 | builder.create(&path)?; | ||
| 46 | } | ||
| 47 | Err(e) => return Err(e), | ||
| 48 | } | ||
| 49 | #[cfg(unix)] | ||
| 50 | { | ||
| 51 | use std::os::unix::fs::PermissionsExt; | ||
| 52 | std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o700))?; | ||
| 53 | } | ||
| 54 | let encoded = path.to_string_lossy().into_owned(); | ||
| 55 | TEMP_PATH | ||
| 56 | .set(encoded) | ||
| 57 | .map_err(|_| io::Error::other("temp directory already initialized"))?; | ||
| 58 | Ok(()) | ||
| 59 | } | ||
| 4 | 60 | ||
| 5 | #[derive(Debug, Clone)] | 61 | #[derive(Debug, Clone)] |
| 6 | pub struct Config { | 62 | pub struct Config { |
