From 91e167940ca299c228c9de973487b1978d2e550d Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 01:33:11 +0100 Subject: config: harden the shared temp directory --- src/config.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'src/config.rs') 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 @@ use std::env; +use std::io; +use std::sync::OnceLock; -pub const TEMP_PATH: &str = "/tmp/senator_sperma"; +static TEMP_PATH: OnceLock = OnceLock::new(); + +/// Private per-process temp root. Initialized by [`init_temp_dir`] at startup. +/// Falls back to the historical path only for code paths that run before init +/// (tests). +pub fn temp_path() -> &'static str { + TEMP_PATH + .get() + .map(String::as_str) + .unwrap_or("/tmp/senator_sperma") +} + +/// Create/validate the temp directory with private permissions. +/// +/// A fixed, predictable path in `/tmp` is a symlink target for any local user. +/// Refuse a symlink (or non-directory) and force mode `0700` on the real +/// directory before the bot writes anything into it. +pub fn init_temp_dir() -> io::Result<()> { + let path = env::temp_dir().join("senator_sperma"); + match std::fs::symlink_metadata(&path) { + Ok(meta) if meta.file_type().is_symlink() => { + return Err(io::Error::other(format!( + "{} is a symlink; refusing to use it", + path.display() + ))); + } + Ok(meta) if !meta.is_dir() => { + return Err(io::Error::other(format!( + "{} exists and is not a directory", + path.display() + ))); + } + Ok(_) => {} + Err(e) if e.kind() == io::ErrorKind::NotFound => { + let mut builder = std::fs::DirBuilder::new(); + #[cfg(unix)] + { + use std::os::unix::fs::DirBuilderExt; + builder.mode(0o700); + } + builder.create(&path)?; + } + Err(e) => return Err(e), + } + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o700))?; + } + let encoded = path.to_string_lossy().into_owned(); + TEMP_PATH + .set(encoded) + .map_err(|_| io::Error::other("temp directory already initialized"))?; + Ok(()) +} #[derive(Debug, Clone)] pub struct Config { -- cgit v1.2.3