- Remove custom logging module and init_logging function - Update main.rs to use tracing_subscriber with EnvFilter - Remove log_level from global config structure - Update documentation and tests to use RUST_LOG - Format long lines in config.rs and test files for better readability
165 lines
4.6 KiB
Rust
165 lines
4.6 KiB
Rust
mod common;
|
|
|
|
#[test]
|
|
fn test_per_host_content_isolation() {
|
|
let temp_dir = common::setup_test_environment();
|
|
|
|
// Create different content for each host
|
|
let site1_root = temp_dir.path().join("site1");
|
|
let site2_root = temp_dir.path().join("site2");
|
|
std::fs::create_dir(&site1_root).unwrap();
|
|
std::fs::create_dir(&site2_root).unwrap();
|
|
|
|
// Create different index.gmi files for each site
|
|
std::fs::write(site1_root.join("index.gmi"), "Welcome to Site 1").unwrap();
|
|
std::fs::write(site2_root.join("index.gmi"), "Welcome to Site 2").unwrap();
|
|
|
|
// Create config with two hosts
|
|
let config_path = temp_dir.path().join("config.toml");
|
|
let port = 1965 + (std::process::id() % 1000) as u16; // Use dynamic port
|
|
let config_content = format!(
|
|
r#"
|
|
bind_host = "127.0.0.1"
|
|
port = {}
|
|
|
|
["site1.com"]
|
|
root = "{}"
|
|
cert = "{}"
|
|
key = "{}"
|
|
|
|
["site2.org"]
|
|
root = "{}"
|
|
cert = "{}"
|
|
key = "{}"
|
|
"#,
|
|
port,
|
|
site1_root.display(),
|
|
temp_dir.path().join("cert.pem").display(),
|
|
temp_dir.path().join("key.pem").display(),
|
|
site2_root.display(),
|
|
temp_dir.path().join("cert.pem").display(),
|
|
temp_dir.path().join("key.pem").display()
|
|
);
|
|
std::fs::write(&config_path, config_content).unwrap();
|
|
|
|
// Start server with TLS
|
|
let mut server_process = std::process::Command::new(env!("CARGO_BIN_EXE_pollux"))
|
|
.arg("--config")
|
|
.arg(&config_path)
|
|
.spawn()
|
|
.unwrap();
|
|
|
|
// Wait for server to start
|
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
|
|
|
// Test site1.com serves its content
|
|
let response1 = make_gemini_request("127.0.0.1", port, "gemini://site1.com/");
|
|
assert!(
|
|
response1.starts_with("20"),
|
|
"Expected success for site1.com, got: {}",
|
|
response1
|
|
);
|
|
assert!(
|
|
response1.contains("Welcome to Site 1"),
|
|
"Should serve site1 content, got: {}",
|
|
response1
|
|
);
|
|
|
|
// Test site2.org serves its content
|
|
let response2 = make_gemini_request("127.0.0.1", port, "gemini://site2.org/");
|
|
assert!(
|
|
response2.starts_with("20"),
|
|
"Expected success for site2.org, got: {}",
|
|
response2
|
|
);
|
|
assert!(
|
|
response2.contains("Welcome to Site 2"),
|
|
"Should serve site2 content, got: {}",
|
|
response2
|
|
);
|
|
|
|
server_process.kill().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn test_per_host_path_security() {
|
|
let temp_dir = common::setup_test_environment();
|
|
|
|
// Create directory structure for site1
|
|
let site1_root = temp_dir.path().join("site1");
|
|
std::fs::create_dir(&site1_root).unwrap();
|
|
std::fs::create_dir(site1_root.join("subdir")).unwrap();
|
|
std::fs::write(
|
|
site1_root.join("subdir").join("secret.gmi"),
|
|
"Secret content",
|
|
)
|
|
.unwrap();
|
|
|
|
// Create config
|
|
let config_path = temp_dir.path().join("config.toml");
|
|
let port = 1968 + (std::process::id() % 1000) as u16;
|
|
let cert_path = temp_dir.path().join("cert.pem");
|
|
let key_path = temp_dir.path().join("key.pem");
|
|
|
|
let config_content = format!(
|
|
r#"
|
|
bind_host = "127.0.0.1"
|
|
port = {}
|
|
|
|
["site1.com"]
|
|
root = "{}"
|
|
cert = "{}"
|
|
key = "{}"
|
|
"#,
|
|
port,
|
|
site1_root.display(),
|
|
cert_path.display(),
|
|
key_path.display()
|
|
);
|
|
std::fs::write(&config_path, config_content).unwrap();
|
|
|
|
let mut server_process = std::process::Command::new(env!("CARGO_BIN_EXE_pollux"))
|
|
.arg("--config")
|
|
.arg(&config_path)
|
|
.spawn()
|
|
.unwrap();
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
|
|
|
// Test path traversal attempt should be blocked
|
|
let response = make_gemini_request("127.0.0.1", port, "gemini://site1.com/../../../etc/passwd");
|
|
assert!(
|
|
response.starts_with("51"),
|
|
"Path traversal should be blocked, got: {}",
|
|
response
|
|
);
|
|
|
|
// Test valid subdirectory access should work
|
|
let response = make_gemini_request("127.0.0.1", port, "gemini://site1.com/subdir/secret.gmi");
|
|
assert!(
|
|
response.starts_with("20"),
|
|
"Valid subdirectory access should work, got: {}",
|
|
response
|
|
);
|
|
assert!(
|
|
response.contains("Secret content"),
|
|
"Should serve content from subdirectory, got: {}",
|
|
response
|
|
);
|
|
|
|
server_process.kill().unwrap();
|
|
}
|
|
|
|
fn make_gemini_request(host: &str, port: u16, url: &str) -> String {
|
|
// Use the Python client for TLS requests
|
|
use std::process::Command;
|
|
|
|
let output = Command::new("python3")
|
|
.arg("tests/gemini_test_client.py")
|
|
.arg(url)
|
|
.env("GEMINI_PORT", &port.to_string())
|
|
.env("GEMINI_CONNECT_HOST", host)
|
|
.output()
|
|
.unwrap();
|
|
String::from_utf8(output.stdout).unwrap()
|
|
}
|