use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io::{self, ErrorKind}, path::Path}; use nix::unistd::{self, Uid, Gid}; /// Writes a file securly to a specified path with given data /// #### Arguments /// * `dir` - The directory of the secure folder /// * `file` - The file name to write /// * `data` - The data to write /// #### Returns /// A ``io::Result<()>`` if the write succeded or failed pub fn write_file(dir: &str, file: &str, data: &str) -> Result<(), io::Error> { fs::create_dir_all(dir)?; set_file_permissions(0, 0, 0o100600, dir)?; let path = path(dir, file); fs::write(&path, data)?; set_file_permissions(0, 0, 0o100600, &path)?; Ok(()) } /// Reads the file secutly to a specified path. If the file has /// been tampered (permissions have been changed), it ignores the /// file. /// #### Arguments /// * `dir` - The directory of the secure folder /// * `file` - The file name to write /// #### Returns /// * `None` - If the files doesnt exist or isnt trusted /// * `Some(String) - If the file is trusted, it returns the file's contents pub fn read_file(dir: &str, file: &str) -> Option { let path = path(dir,file); if !check_file_permissions(0, 0, 0o100600, &path) { return None; } match fs::read_to_string(&path) { Ok(data) => return Some(data), Err(_) => return None }; } /// Sets the permission for a secure file /// #### Arguments /// * `uid` - The user to own the file /// * `gid` - The group to own the file /// * `mode` - The mode permissions of the file /// * `path` - The path of the secure file /// #### Returns /// A ``io::Result<()>`` if the write succeded or failed fn set_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> Result<(), io::Error> { unistd::chown(Path::new(path), Some(Uid::from(uid)), Some(Gid::from(gid)))?; let metadata = fs::metadata(path)?; let mut perms = metadata.permissions(); perms.set_mode(mode); fs::set_permissions(path, perms)?; Ok(()) } /// Checks if the files permissions equals the given parameters /// #### Arguments /// * `uid` - The user to own the file /// * `gid` - The group to own the file /// * `mode` - The mode permissions of the file /// * `path` - The path of the secure file /// #### Returns /// True or false if the files permissions match fn check_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> bool { let metadata = match fs::metadata(path) { Ok(data) => data, Err(e) => { return e.kind() == ErrorKind::NotFound; } }; let perms = metadata.permissions(); return perms.mode() == mode && metadata.st_uid() == uid && metadata.st_gid() == gid; } /// Get the path of a file given a directory and file name fn path(dir: &str, file: &str) -> String { return format!("{}/{}.persist", dir, file); }