use strict_path::PathBoundary;
#[cfg(feature = "virtual-path")]
use strict_path::VirtualRoot;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== OS Standard Directory Examples ===\n");
println!("Pattern: dirs::*_dir() -> PathBoundary::try_new_create() -> secure operations\n");
println!("Untrusted Input Validation against OS Config Directory:");
validate_user_config_request()?;
println!();
println!("Application Directories:");
if let Some(config_base) = dirs::config_dir() {
let config_dir: PathBoundary = PathBoundary::try_new_create(config_base.join("myapp"))?;
println!("Config: {}", config_dir.strictpath_display());
let settings = config_dir.strict_join("settings.toml")?;
settings.write(b"theme = 'dark'\nversion = '1.0'")?;
println!(" settings.toml: {}", settings.read_to_string()?);
config_dir.remove_dir_all().ok();
}
if let Some(data_base) = dirs::data_dir() {
let data_dir: PathBoundary = PathBoundary::try_new_create(data_base.join("myapp"))?;
println!("Data: {}", data_dir.strictpath_display());
let database = data_dir.strict_join("app.db")?;
database.write(b"-- SQLite database placeholder")?;
data_dir.remove_dir_all().ok();
}
if let Some(cache_base) = dirs::cache_dir() {
let cache_dir: PathBoundary = PathBoundary::try_new_create(cache_base.join("myapp"))?;
println!("Cache: {}", cache_dir.strictpath_display());
let temp_cache = cache_dir.strict_join("temp.json")?;
temp_cache.write(br#"{"cached_at": "2024-01-01"}"#)?;
cache_dir.remove_dir_all().ok();
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
println!("\nPlatform-Specific Local Directories:");
if let Some(config_local_base) = dirs::config_local_dir() {
let config_local: PathBoundary =
PathBoundary::try_new_create(config_local_base.join("myapp"))?;
println!("Config Local: {}", config_local.strictpath_display());
config_local.remove_dir_all().ok();
}
if let Some(data_local_base) = dirs::data_local_dir() {
let data_local: PathBoundary =
PathBoundary::try_new_create(data_local_base.join("myapp"))?;
println!("Data Local: {}", data_local.strictpath_display());
data_local.remove_dir_all().ok();
}
}
println!("\nUser Directories:");
if let Some(downloads_base) = dirs::download_dir() {
let downloads: PathBoundary = PathBoundary::try_new(downloads_base)?;
println!("Downloads: {}", downloads.strictpath_display());
}
if let Some(documents_base) = dirs::document_dir() {
let documents: PathBoundary = PathBoundary::try_new(documents_base)?;
println!("Documents: {}", documents.strictpath_display());
}
if let Some(pictures_base) = dirs::picture_dir() {
let pictures: PathBoundary = PathBoundary::try_new(pictures_base)?;
println!("Pictures: {}", pictures.strictpath_display());
}
println!("\nMedia Directories:");
if let Some(audio_base) = dirs::audio_dir() {
let audio: PathBoundary = PathBoundary::try_new(audio_base)?;
println!("Audio: {}", audio.strictpath_display());
}
if let Some(videos_base) = dirs::video_dir() {
let videos: PathBoundary = PathBoundary::try_new(videos_base)?;
println!("Videos: {}", videos.strictpath_display());
}
println!("\nSystem Directories:");
if let Some(home_base) = dirs::home_dir() {
let home: PathBoundary = PathBoundary::try_new(home_base)?;
println!("Home: {}", home.strictpath_display());
}
if let Some(desktop_base) = dirs::desktop_dir() {
let desktop: PathBoundary = PathBoundary::try_new(desktop_base)?;
println!("Desktop: {}", desktop.strictpath_display());
}
#[cfg(unix)]
{
println!("\nUnix System Directories:");
if let Some(executables_base) = dirs::executable_dir() {
let executables: PathBoundary = PathBoundary::try_new(executables_base)?;
println!("Executables: {}", executables.strictpath_display());
}
if let Some(runtime_base) = dirs::runtime_dir() {
let runtime: PathBoundary = PathBoundary::try_new(runtime_base)?;
println!("Runtime: {}", runtime.strictpath_display());
}
}
#[cfg(target_os = "linux")]
{
println!("\nLinux-Specific Directories:");
if let Some(state_base) = dirs::state_dir() {
let state_dir: PathBoundary = PathBoundary::try_new_create(state_base.join("myapp"))?;
println!("State: {}", state_dir.strictpath_display());
state_dir.remove_dir_all().ok();
}
}
#[cfg(feature = "virtual-path")]
{
println!("\n=== Virtual Root Example ===");
if let Some(config_base) = dirs::config_dir() {
let vroot: VirtualRoot = VirtualRoot::try_new_create(config_base.join("demo-app"))?;
println!(
"Virtual root at: {}",
vroot.as_unvirtual().strictpath_display()
);
let vconfig = vroot.virtual_join("app.toml")?;
println!("Virtual path: {}", vconfig.virtualpath_display());
vconfig.write(b"name = 'Demo App'\nversion = '1.0'")?;
println!("Content: {}", vconfig.read_to_string()?);
vroot.remove_dir_all().ok();
}
}
println!("\nAll OS directory operations completed successfully!");
println!("\nOne extra line for explicit security:");
println!(" let base = dirs::config_dir().unwrap();");
println!(" let config_dir = PathBoundary::try_new_create(base.join(\"myapp\"))?;");
Ok(())
}
fn validate_user_config_request() -> Result<(), Box<dyn std::error::Error>> {
let Some(config_base) = dirs::config_dir() else {
println!(" (no OS config dir available on this platform, skipping)");
return Ok(());
};
let config_dir: PathBoundary = PathBoundary::try_new_create(config_base.join("myapp-demo"))?;
let external_requests: &[&str] = &[
"preferences.toml",
"../../etc/passwd", "../sibling_app/key", "profiles/default.json", ];
for requested_file in external_requests {
match config_dir.strict_join(requested_file) {
Ok(safe_config_file) => {
safe_config_file.create_parent_dir_all()?;
safe_config_file.write(b"key = value")?;
println!(
" OK '{}' -> {}",
requested_file,
safe_config_file.strictpath_display()
);
}
Err(_) => {
println!(
" BLOCKED '{}' (traversal / escape attempt rejected)",
requested_file
);
}
}
}
config_dir.remove_dir_all().ok();
Ok(())
}