modo_session/config.rs
1use serde::Deserialize;
2
3/// Configuration for the session subsystem.
4///
5/// All fields have sane defaults (see [`Default`]). Deserialises from YAML/TOML
6/// with `#[serde(default)]`, so you only need to specify the fields you want to
7/// override.
8///
9/// # Example (YAML)
10///
11/// ```yaml
12/// session_ttl_secs: 86400
13/// cookie_name: "_sess"
14/// validate_fingerprint: true
15/// touch_interval_secs: 600
16/// max_sessions_per_user: 5
17/// trusted_proxies:
18/// - "10.0.0.0/8"
19/// ```
20#[derive(Debug, Clone, Deserialize)]
21#[serde(default)]
22pub struct SessionConfig {
23 /// Session lifetime in seconds (default: 2 592 000 = 30 days).
24 pub session_ttl_secs: u64,
25 /// Name of the HTTP cookie that carries the session token (default: `"_session"`).
26 pub cookie_name: String,
27 /// Whether to reject sessions whose request fingerprint changed since creation
28 /// (default: `true`). Disabling this reduces hijack protection but allows users
29 /// behind rotating IPs or proxies to keep their session.
30 pub validate_fingerprint: bool,
31 /// Minimum number of seconds between consecutive `touch` (expiry renewal) DB
32 /// writes (default: 300 = 5 minutes).
33 pub touch_interval_secs: u64,
34 /// Maximum number of concurrent active sessions per user before the
35 /// least-recently-used session is evicted (default: 10).
36 pub max_sessions_per_user: usize,
37 /// CIDR ranges of trusted reverse-proxy addresses. When non-empty, the
38 /// `X-Forwarded-For` / `X-Real-IP` headers are only trusted when the TCP
39 /// connection originates from one of these ranges (default: empty = trust
40 /// proxy headers unconditionally).
41 pub trusted_proxies: Vec<String>,
42}
43
44impl Default for SessionConfig {
45 fn default() -> Self {
46 Self {
47 session_ttl_secs: 2_592_000, // 30 days
48 cookie_name: "_session".to_string(),
49 validate_fingerprint: true,
50 touch_interval_secs: 300, // 5 minutes
51 max_sessions_per_user: 10,
52 trusted_proxies: Vec::new(),
53 }
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn default_values() {
63 let config = SessionConfig::default();
64 assert_eq!(config.session_ttl_secs, 2_592_000);
65 assert_eq!(config.cookie_name, "_session");
66 assert!(config.validate_fingerprint);
67 assert_eq!(config.touch_interval_secs, 300);
68 assert_eq!(config.max_sessions_per_user, 10);
69 assert!(config.trusted_proxies.is_empty());
70 }
71
72 #[test]
73 fn partial_yaml_deserialization() {
74 let yaml = r#"
75session_ttl_secs: 3600
76cookie_name: "my_sess"
77"#;
78 let config: SessionConfig = serde_yaml_ng::from_str(yaml).unwrap();
79 assert_eq!(config.session_ttl_secs, 3600);
80 assert_eq!(config.cookie_name, "my_sess");
81 // defaults for omitted fields
82 assert!(config.validate_fingerprint);
83 assert_eq!(config.touch_interval_secs, 300);
84 assert_eq!(config.max_sessions_per_user, 10);
85 }
86}