/ crates / auths-cli / src / core / fs.rs
fs.rs
 1  use anyhow::Result;
 2  use std::path::Path;
 3  
 4  /// Write data to a file with restrictive permissions (0o600 on Unix).
 5  ///
 6  /// Uses atomic temp-file-then-rename to avoid TOCTOU races where the file
 7  /// exists with default permissions before being restricted.
 8  ///
 9  /// Args:
10  /// * `path` - Destination file path.
11  /// * `data` - Bytes to write.
12  pub fn write_sensitive_file(path: &Path, data: impl AsRef<[u8]>) -> Result<()> {
13      #[cfg(unix)]
14      {
15          use std::io::Write;
16          use std::os::unix::fs::PermissionsExt;
17  
18          let parent = path
19              .parent()
20              .ok_or_else(|| anyhow::anyhow!("No parent directory for {:?}", path))?;
21  
22          let mut tmp = tempfile::NamedTempFile::new_in(parent)?;
23          // NamedTempFile creates with 0o600 by default on most systems,
24          // but we set it explicitly via the persisted file permissions.
25          tmp.write_all(data.as_ref())?;
26          tmp.flush()?;
27  
28          let tmp_path = tmp.into_temp_path();
29          std::fs::set_permissions(&tmp_path, std::fs::Permissions::from_mode(0o600))?;
30          tmp_path.persist(path)?;
31  
32          Ok(())
33      }
34  
35      #[cfg(not(unix))]
36      {
37          log::warn!("Restrictive file permissions not enforced on this platform");
38          std::fs::write(path, data)?;
39          Ok(())
40      }
41  }
42  
43  /// Create a directory with restrictive permissions (0o700 on Unix).
44  ///
45  /// Args:
46  /// * `path` - Directory path to create (including parents).
47  pub fn create_restricted_dir(path: &Path) -> Result<()> {
48      #[cfg(unix)]
49      {
50          use std::os::unix::fs::{DirBuilderExt, PermissionsExt};
51          // Create parents with default permissions first
52          if let Some(parent) = path.parent() {
53              std::fs::create_dir_all(parent)?;
54          }
55          std::fs::DirBuilder::new()
56              .mode(0o700)
57              .create(path)
58              .or_else(|e| {
59                  if e.kind() == std::io::ErrorKind::AlreadyExists {
60                      // Tighten permissions on existing directory
61                      std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700))?;
62                      Ok(())
63                  } else {
64                      Err(e.into())
65                  }
66              })
67      }
68  
69      #[cfg(not(unix))]
70      {
71          log::warn!("Restrictive directory permissions not enforced on this platform");
72          std::fs::create_dir_all(path)?;
73          Ok(())
74      }
75  }