Skip to main content

wisegate_core/
default_config.rs

1//! Ready-to-use configuration for library consumers.
2//!
3//! [`DefaultConfig`] implements every configuration trait
4//! ([`RateLimitingProvider`], [`ProxyProvider`], [`FilteringProvider`],
5//! [`ConnectionProvider`], [`AuthenticationProvider`]) with the same defaults
6//! the CLI uses. Tweak its public fields to customize behaviour without
7//! defining a fresh struct or implementing each trait by hand.
8//!
9//! # Example
10//!
11//! ```
12//! use std::sync::Arc;
13//! use std::time::Duration;
14//! use wisegate_core::{DefaultConfig, RateLimiter};
15//!
16//! let mut config = DefaultConfig::default();
17//! config.rate_limit.max_requests = 200;
18//! config.rate_limit.window_duration = Duration::from_secs(30);
19//! config.blocked_methods = vec!["TRACE".into(), "CONNECT".into()];
20//!
21//! let _limiter = RateLimiter::new();
22//! let _shared_config = Arc::new(config);
23//! ```
24
25use crate::auth::Credentials;
26use crate::defaults;
27use crate::types::{
28    AuthenticationProvider, ConnectionProvider, FilteringProvider, ProxyConfig, ProxyProvider,
29    RateLimitCleanupConfig, RateLimitConfig, RateLimitingProvider,
30};
31
32/// Configuration backed by plain fields — pre-populated with WiseGate's defaults.
33///
34/// Use this when you want to drop wisegate-core into an application without
35/// designing your own configuration plumbing. Mutate the fields directly,
36/// then pass the struct (often wrapped in an `Arc`) to
37/// [`request_handler::handle_request`](crate::request_handler::handle_request).
38#[derive(Debug, Clone)]
39pub struct DefaultConfig {
40    /// Rate limit policy applied per client IP.
41    pub rate_limit: RateLimitConfig,
42    /// Rate limiter housekeeping policy.
43    pub cleanup: RateLimitCleanupConfig,
44    /// Upstream proxy behaviour (timeout, body size cap).
45    pub proxy: ProxyConfig,
46    /// Trusted proxy IPs. `Some` activates strict mode; `None` is permissive.
47    pub allowed_proxy_ips: Option<Vec<String>>,
48    /// Treat a loopback TCP peer as a trusted proxy in strict mode.
49    pub trust_loopback_proxy: bool,
50    /// Client IPs that should be rejected with 403.
51    pub blocked_ips: Vec<String>,
52    /// HTTP methods that should be rejected with 405.
53    pub blocked_methods: Vec<String>,
54    /// URL substrings that should be rejected with 404.
55    pub blocked_patterns: Vec<String>,
56    /// Hard cap on concurrent connections; `0` disables the limit.
57    pub max_connections: usize,
58    /// Basic Auth credential set (empty disables Basic Auth).
59    pub auth_credentials: Credentials,
60    /// Realm advertised in `WWW-Authenticate`.
61    pub auth_realm: String,
62    /// Bearer token (`None` or empty disables bearer auth).
63    pub bearer_token: Option<String>,
64    /// Forward the `Authorization` header to the upstream after wisegate auth.
65    pub forward_authorization_header: bool,
66}
67
68impl Default for DefaultConfig {
69    fn default() -> Self {
70        Self {
71            rate_limit: RateLimitConfig {
72                max_requests: defaults::RATE_LIMIT_REQUESTS,
73                window_duration: defaults::RATE_LIMIT_WINDOW,
74            },
75            cleanup: RateLimitCleanupConfig {
76                threshold: defaults::RATE_LIMIT_CLEANUP_THRESHOLD,
77                interval: defaults::RATE_LIMIT_CLEANUP_INTERVAL,
78            },
79            proxy: ProxyConfig {
80                timeout: defaults::PROXY_TIMEOUT,
81                max_body_size: defaults::MAX_BODY_SIZE,
82            },
83            allowed_proxy_ips: None,
84            trust_loopback_proxy: false,
85            blocked_ips: Vec::new(),
86            blocked_methods: Vec::new(),
87            blocked_patterns: Vec::new(),
88            max_connections: defaults::MAX_CONNECTIONS,
89            auth_credentials: Credentials::new(),
90            auth_realm: defaults::AUTH_REALM.to_string(),
91            bearer_token: None,
92            forward_authorization_header: false,
93        }
94    }
95}
96
97impl RateLimitingProvider for DefaultConfig {
98    fn rate_limit_config(&self) -> &RateLimitConfig {
99        &self.rate_limit
100    }
101    fn rate_limit_cleanup_config(&self) -> &RateLimitCleanupConfig {
102        &self.cleanup
103    }
104}
105
106impl ProxyProvider for DefaultConfig {
107    fn proxy_config(&self) -> &ProxyConfig {
108        &self.proxy
109    }
110    fn allowed_proxy_ips(&self) -> Option<&[String]> {
111        self.allowed_proxy_ips.as_deref()
112    }
113    fn trust_loopback_proxy(&self) -> bool {
114        self.trust_loopback_proxy
115    }
116}
117
118impl FilteringProvider for DefaultConfig {
119    fn blocked_ips(&self) -> &[String] {
120        &self.blocked_ips
121    }
122    fn blocked_methods(&self) -> &[String] {
123        &self.blocked_methods
124    }
125    fn blocked_patterns(&self) -> &[String] {
126        &self.blocked_patterns
127    }
128}
129
130impl ConnectionProvider for DefaultConfig {
131    fn max_connections(&self) -> usize {
132        self.max_connections
133    }
134}
135
136impl AuthenticationProvider for DefaultConfig {
137    fn auth_credentials(&self) -> &Credentials {
138        &self.auth_credentials
139    }
140    fn auth_realm(&self) -> &str {
141        &self.auth_realm
142    }
143    fn bearer_token(&self) -> Option<&str> {
144        self.bearer_token.as_deref()
145    }
146    fn forward_authorization_header(&self) -> bool {
147        self.forward_authorization_header
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154    use crate::types::ConfigProvider;
155
156    fn assert_is_config_provider<T: ConfigProvider>(_: &T) {}
157
158    #[test]
159    fn default_config_implements_config_provider() {
160        let config = DefaultConfig::default();
161        assert_is_config_provider(&config);
162    }
163
164    #[test]
165    fn default_values_match_cli_defaults() {
166        let config = DefaultConfig::default();
167        assert_eq!(
168            config.rate_limit.max_requests,
169            defaults::RATE_LIMIT_REQUESTS
170        );
171        assert_eq!(config.max_connections, defaults::MAX_CONNECTIONS);
172        assert!(config.allowed_proxy_ips.is_none());
173        assert!(!config.trust_loopback_proxy);
174        assert!(!config.forward_authorization_header);
175    }
176}