//! Creating files and directories this server alone can read. //! //! Everything the server writes outside the repo goes through here: the //! config (token hashes, hosts, sessions), the TLS private keys, and the //! session directories holding whole transcripts. One module owns the //! modes so "owner-only" is a property that can be checked in one place //! rather than re-argued at every `create`. use std::fs::File; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; use std::path::Path; use anyhow::{Context, Result}; /// Creates `dir` and its parents, owner-accessible only. pub fn create_dir(dir: &Path) -> Result<()> { std::fs::DirBuilder::new() .recursive(true) .mode(0o700) .create(dir) .with_context(|| format!("create {}", dir.display()))?; // Set explicitly as well: `mode` applies only when the directory is // created, so one that already existed -- made by hand, or by a // version that didn't do this -- would otherwise keep whatever // permissions it had while holding secrets. std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700)) .with_context(|| format!("restrict {}", dir.display())) } /// Opens `path` for writing, truncating it, owner-readable only from the /// moment it exists rather than by a `chmod` afterwards. pub fn create_file(path: &Path) -> Result { std::fs::OpenOptions::new() .write(true) .create(true) .truncate(true) .mode(0o600) .open(path) .with_context(|| format!("write {}", path.display())) } /// Writes `contents` to `path`, owner-readable only. pub fn write_file(path: &Path, contents: &[u8]) -> Result<()> { use std::io::Write; create_file(path)? .write_all(contents) .with_context(|| format!("write {}", path.display())) }