use crate::env_vars;
use std::env;
use tracing::{debug, info};
use wisegate_core::ConfigProvider;
#[derive(Clone, Debug)]
pub struct StartupConfig {
pub listen_port: u16,
pub forward_port: u16,
pub bind_address: String,
pub verbose: bool,
pub quiet: bool,
}
pub fn print_startup_info(startup_config: &StartupConfig, config: &impl ConfigProvider) {
if startup_config.quiet {
return;
}
let rate_config = config.rate_limit_config();
let proxy_config = config.proxy_config();
let allowed_proxy_ips = config.allowed_proxy_ips();
info!(
version = env!("CARGO_PKG_VERSION"),
listen_port = startup_config.listen_port,
forward_port = startup_config.forward_port,
bind_address = %startup_config.bind_address,
"WiseGate starting"
);
info!(
max_requests = rate_config.max_requests,
window_secs = rate_config.window_duration.as_secs(),
"Rate limiting configured"
);
info!(
timeout_secs = proxy_config.timeout.as_secs(),
max_body_mb = proxy_config.max_body_size_mb(),
"Proxy configured"
);
let mode = if allowed_proxy_ips.is_some() {
"strict"
} else {
"permissive"
};
let trusted_proxies = allowed_proxy_ips.map(|ips| ips.len()).unwrap_or(0);
info!(
mode = mode,
trusted_proxies = trusted_proxies,
blocked_ips = config.blocked_ips().len(),
blocked_methods = config.blocked_methods().len(),
blocked_patterns = config.blocked_patterns().len(),
"Security configured"
);
let basic_auth_enabled = config.is_basic_auth_enabled();
let bearer_auth_enabled = config.is_bearer_auth_enabled();
if basic_auth_enabled || bearer_auth_enabled {
info!(
basic_auth = basic_auth_enabled,
basic_auth_users = config.auth_credentials().len(),
bearer_token = bearer_auth_enabled,
realm = config.auth_realm(),
"Authentication configured"
);
} else {
debug!("Authentication disabled (no credentials or bearer token configured)");
}
if startup_config.verbose {
print_env_config();
}
}
fn print_env_config() {
for &var_name in env_vars::all_env_vars() {
match env::var(var_name) {
Ok(value) => {
let display_value = mask_sensitive_value(var_name, &value);
debug!(name = var_name, value = %display_value, "Environment variable");
}
Err(_) => {
debug!(name = var_name, value = "[NOT SET]", "Environment variable");
}
}
}
}
fn mask_sensitive_value(var_name: &str, value: &str) -> String {
let upper = var_name.to_uppercase();
if upper.contains("IP")
|| upper.contains("PROXY")
|| upper.contains("AUTH")
|| upper.contains("TOKEN")
|| upper.contains("BEARER")
|| upper.contains("PASSWORD")
|| upper.contains("SECRET")
{
"[CONFIGURED]".to_string()
} else {
value.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mask_sensitive_value_with_ip() {
assert_eq!(
mask_sensitive_value("BLOCKED_IPS", "192.168.1.1"),
"[CONFIGURED]"
);
assert_eq!(
mask_sensitive_value("TRUSTED_PROXY_IPS", "10.0.0.1"),
"[CONFIGURED]"
);
assert_eq!(
mask_sensitive_value("CC_REVERSE_PROXY_IPS", "172.16.0.1"),
"[CONFIGURED]"
);
}
#[test]
fn test_mask_sensitive_value_with_proxy() {
assert_eq!(
mask_sensitive_value("PROXY_ALLOWLIST", "10.0.0.1"),
"[CONFIGURED]"
);
assert_eq!(
mask_sensitive_value("TRUSTED_PROXY_IPS_VAR", "CUSTOM_VAR"),
"[CONFIGURED]"
);
}
#[test]
fn test_mask_sensitive_value_with_auth() {
assert_eq!(
mask_sensitive_value("CC_HTTP_BASIC_AUTH", "admin:secret"),
"[CONFIGURED]"
);
assert_eq!(
mask_sensitive_value("CC_HTTP_BASIC_AUTH_REALM", "MyRealm"),
"[CONFIGURED]"
);
}
#[test]
fn test_mask_sensitive_value_with_token() {
assert_eq!(
mask_sensitive_value("CC_BEARER_TOKEN", "my-secret-token"),
"[CONFIGURED]"
);
}
#[test]
fn test_mask_sensitive_value_non_sensitive() {
assert_eq!(mask_sensitive_value("RATE_LIMIT_REQUESTS", "100"), "100");
assert_eq!(mask_sensitive_value("MAX_BODY_SIZE_MB", "50"), "50");
assert_eq!(
mask_sensitive_value("BLOCKED_METHODS", "TRACE,CONNECT"),
"TRACE,CONNECT"
);
assert_eq!(
mask_sensitive_value("BLOCKED_PATTERNS", ".php,.env"),
".php,.env"
);
}
}