mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-23 02:40:11 +00:00
fix: expand tilde in file path validation for SSH keys and TLS certs
`validate_file_path` now expands leading `~` to the user's home directory before checking file existence, so paths like `~/.ssh/id_rsa` work on macOS and Linux. Also fixes error messages that incorrectly said "Database file".
This commit is contained in:
@@ -1,5 +1,28 @@
|
||||
use std::path::Path;
|
||||
|
||||
fn expand_tilde(path: &str) -> String {
|
||||
if !path.starts_with('~') {
|
||||
return path.to_string();
|
||||
}
|
||||
if path.len() == 1 {
|
||||
// path is "~"
|
||||
return home_dir().unwrap_or_else(|| path.to_string());
|
||||
}
|
||||
if path.as_bytes().get(1) == Some(&b'/') {
|
||||
// path is "~/..."
|
||||
return match home_dir() {
|
||||
Some(home) => home + &path[1..],
|
||||
None => path.to_string(),
|
||||
};
|
||||
}
|
||||
// "~user" or "~something-without-slash" — not a home-dir expansion
|
||||
path.to_string()
|
||||
}
|
||||
|
||||
fn home_dir() -> Option<String> {
|
||||
std::env::var("HOME").or_else(|_| std::env::var("USERPROFILE")).ok()
|
||||
}
|
||||
|
||||
/// Validates a file path for database connections.
|
||||
///
|
||||
/// Performs comprehensive checks including:
|
||||
@@ -22,30 +45,31 @@ where
|
||||
{
|
||||
// Check if path is empty
|
||||
if path.is_empty() {
|
||||
return Err("Database file path cannot be empty".to_string());
|
||||
return Err("File path cannot be empty".to_string());
|
||||
}
|
||||
|
||||
// Check if path contains invalid characters
|
||||
if path.contains('\0') {
|
||||
return Err("Database file path contains null characters".to_string());
|
||||
return Err("File path contains null characters".to_string());
|
||||
}
|
||||
|
||||
let path_obj = Path::new(path);
|
||||
let expanded = expand_tilde(path);
|
||||
let path_obj = Path::new(&expanded);
|
||||
|
||||
// For non-network paths, perform file system checks
|
||||
if !is_network_path(path) {
|
||||
if !path_obj.exists() {
|
||||
return Err(format!("Database file does not exist: {}", path));
|
||||
return Err(format!("File does not exist: {}", path));
|
||||
}
|
||||
|
||||
// Check if path is actually a file, not a directory
|
||||
if path_obj.is_dir() {
|
||||
return Err(format!("Database file path is a directory, not a file: {}", path));
|
||||
return Err(format!("File path is a directory, not a file: {}", path));
|
||||
}
|
||||
|
||||
// Check if path is a valid file
|
||||
if !path_obj.is_file() {
|
||||
return Err(format!("Database file path is not a valid file: {}", path));
|
||||
return Err(format!("File path is not a valid file: {}", path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +110,43 @@ mod tests {
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("does not exist"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tilde_expands_to_home() {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
if home.is_empty() {
|
||||
return; // skip if no HOME
|
||||
}
|
||||
let result = validate_file_path(&format!("{}/.bashrc", home), is_network_path_test);
|
||||
// $HOME/.bashrc may or may not exist, but the path shouldn't contain literal ~
|
||||
// We just verify no error mentioning tilde
|
||||
if let Err(e) = &result {
|
||||
assert!(!e.contains('~'), "Error should not contain literal tilde: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tilde_only() {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
if home.is_empty() {
|
||||
return;
|
||||
}
|
||||
let result = validate_file_path("~", |_| true); // treat as network to skip fs check
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_tilde_unchanged() {
|
||||
let result = validate_file_path("/absolute/path", is_network_path_test);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("/absolute/path"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tilde_without_slash_not_expanded() {
|
||||
// ~user form is not expanded, treated literally
|
||||
let result = validate_file_path("~nonexistentuser", is_network_path_test);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains('~'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user