Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Features

The strict-path crate provides several optional features that extend functionality while maintaining the core security guarantees. All features are disabled by default to keep the core library lightweight.

Available Features

dirs - OS Standard Directories

Cross-platform access to operating system standard directories following platform conventions (XDG Base Directory on Linux, Known Folder API on Windows, Apple Standard Directories on macOS).

[dependencies]
strict-path = { version = "0.1.0-alpha.1", features = ["dirs"] }

Enables constructors like:

  • PathBoundary::try_new_os_config("MyApp") - Application configuration
  • PathBoundary::try_new_os_data("MyApp") - Application data storage
  • PathBoundary::try_new_os_cache("MyApp") - Application cache
  • PathBoundary::try_new_os_documents() - User documents directory
  • And many more...

→ Full OS Directories Documentation

serde - Serialization Support

Adds Serialize implementations for StrictPath and VirtualPath, plus deserialization helpers for secure path handling in web APIs and configuration files.

[dependencies]
strict-path = { version = "0.1.0-alpha.1", features = ["serde"] }

Enables:

  • Direct serialization: serde_json::to_string(&strict_path)?
  • Context-aware deserialization helpers
  • Integration with web frameworks and config parsers

tempfile - Temporary Directories

RAII temporary directories that are automatically cleaned up when dropped, with each PathBoundary getting a unique temporary directory.

[dependencies]  
strict-path = { version = "0.1.0-alpha.1", features = ["tempfile"] }

Enables:

  • PathBoundary::try_new_temp() - Unique temporary directory
  • PathBoundary::try_new_temp_with_prefix("my-prefix") - Custom prefix
  • Automatic cleanup when the boundary is dropped

app-path - Portable Application Directories

Integration with the app-path crate for discovering application directories relative to the executable with environment variable overrides.

[dependencies]
strict-path = { version = "0.1.0-alpha.1", features = ["app-path"] }

Enables portable application directory discovery for:

  • Configuration directories relative to executable
  • Data directories with environment overrides
  • Cross-platform deployment scenarios

Feature Combinations

Features can be combined as needed:

[dependencies]
strict-path = { 
    version = "0.1.0-alpha.1", 
    features = ["dirs", "serde", "tempfile"] 
}

Design Philosophy

All optional features:

  • Maintain security: Never compromise path boundary enforcement
  • Zero-cost when unused: Features add no overhead if not enabled
  • Composable: Features work together seamlessly
  • Platform-aware: Handle platform differences gracefully
  • Standards-compliant: Follow established conventions and specifications

Migration and Compatibility

Features are additive and backward-compatible. Enabling new features won't break existing code, and the core API remains stable across all feature combinations.

When features are unavailable:

  • Missing feature methods result in compile-time errors (not runtime failures)
  • Documentation clearly indicates feature requirements
  • Examples include feature guards for conditional compilation

API Reference Summary

Core Types Comparison

FeaturePath/PathBufStrictPathVirtualPath
SecurityNone 💥Validates & rejects ✅Clamps any input ✅
Join safetyUnsafe (can escape)Boundary-checkedBoundary-clamped
Boundary guaranteeNoneJailed (cannot escape)Jailed (virtual view)
Input permissivenessAny path (no validation)Only safe pathsAny input (auto-clamped)
Display formatOS pathOS pathVirtual root path
Example: good input"file.txt""file.txt""file.txt""boundary/file.txt""file.txt""/file.txt"
Example: attack input"/etc/passwd"System breach 💥"/etc/passwd"Error"/etc/passwd"/etc/passwd (safe) ✅
Best forKnown-safe pathsSystem boundariesUser interfaces

Integration Examples

Serde Integration

#![allow(unused)]
fn main() {
use strict_path::{PathBoundary, StrictPath};
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct FileRequest {
    filename: String,  // Accept as string first
}

#[derive(Serialize)]  
struct FileResponse {
    path: StrictPath<UserFiles>,  // Serialize safe path
}

async fn handle_upload(req: FileRequest) -> Result<FileResponse, Error> {
    let uploads = PathBoundary::try_new("uploads")?;
    let safe_path = uploads.strict_join(&req.filename)?;  // Validate here
    
    // ... process file ...
    
    Ok(FileResponse { path: safe_path })
}
}

Axum Web Framework

#![allow(unused)]
fn main() {
use axum::{extract::Path, response::Result};
use strict_path::PathBoundary;

struct StaticFiles;

async fn serve_static(Path(filename): Path<String>) -> Result<Vec<u8>> {
    let static_dir = PathBoundary::<StaticFiles>::try_new("./static")?;
    let safe_path = static_dir.strict_join(&filename)?; // Attack = Error
    
    Ok(safe_path.read_bytes()?)
}
}

Configuration with app-path

#![allow(unused)]
fn main() {
use app_path::AppPath;
use strict_path::PathBoundary;

fn load_app_config() -> Result<Config, Box<dyn std::error::Error>> {
    let app_dir = AppPath::new("MyApp").get_app_dir();
    let config_boundary = PathBoundary::try_new_create(app_dir)?;
    let config_file = config_boundary.strict_join("config.toml")?;
    
    Ok(toml::from_str(&config_file.read_to_string()?)?)
}
}

Next Steps