Skip to main content
Glama
security_utils.rs4.35 kB
//! Security utilities for path validation and sanitization //! //! This module provides safe path handling to prevent directory traversal //! and other file system security issues. use napi_derive::napi; use std::path::Path; /// Path validation result #[napi(object)] #[derive(Debug, Clone)] pub struct PathValidationResult { /// Whether the path is valid pub is_valid: bool, /// Sanitized path (if valid) pub sanitized_path: Option<String>, /// Error message (if invalid) pub error: Option<String>, } /// Security utilities #[napi] pub struct SecurityUtils; #[napi] impl SecurityUtils { #[napi(constructor)] /// Create a new security utilities instance pub fn new() -> Self { Self } /// Validate and sanitize file path #[napi] pub fn validate_path( &self, path: String, base_path: String, ) -> napi::Result<PathValidationResult> { let path_obj = Path::new(&path); let base = Path::new(&base_path); // Check for null bytes if path.contains('\0') { return Ok(PathValidationResult { is_valid: false, sanitized_path: None, error: Some("Path contains null bytes".to_string()), }); } // Normalize the path let normalized = match path_obj.canonicalize() { Ok(p) => p, Err(_) => { // If the path doesn't exist, try to normalize it manually let mut components = Vec::new(); for component in path_obj.components() { match component { std::path::Component::ParentDir => { components.pop(); } std::path::Component::Normal(c) => { components.push(c.to_string_lossy().to_string()); } std::path::Component::RootDir => { components.clear(); } _ => {} } } let joined = components.join("/"); Path::new(&base_path).join(&joined) } }; // Ensure the path is within the base path if !normalized.starts_with(&base) { return Ok(PathValidationResult { is_valid: false, sanitized_path: None, error: Some("Path traversal detected".to_string()), }); } // Check for dangerous patterns let path_str = normalized.to_string_lossy(); let dangerous_patterns = [ "..", "~", "$", "|", ";", "&", ">", "<", "`", "\\", ]; for pattern in &dangerous_patterns { if path_str.contains(pattern) { return Ok(PathValidationResult { is_valid: false, sanitized_path: None, error: Some(format!("Dangerous pattern '{}' detected", pattern)), }); } } Ok(PathValidationResult { is_valid: true, sanitized_path: Some(normalized.to_string_lossy().to_string()), error: None, }) } /// Sanitize filename by removing dangerous characters #[napi] pub fn sanitize_filename(&self, filename: String) -> napi::Result<String> { let dangerous_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']; let mut sanitized = filename; for ch in &dangerous_chars { sanitized = sanitized.replace(*ch, "_"); } // Remove leading/trailing dots and spaces sanitized = sanitized.trim_matches('.').trim_matches(' ').to_string(); // Ensure the filename is not empty if sanitized.is_empty() { sanitized = "unnamed".to_string(); } Ok(sanitized) } } /// Quick path validation function #[napi] pub fn quick_validate_path(path: String, base_path: String) -> napi::Result<bool> { let utils = SecurityUtils::new(); let result = utils.validate_path(path, base_path)?; Ok(result.is_valid) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/moikas-code/moidvk'

If you have feedback or need assistance with the MCP directory API, please join our Discord server