Skip to main content

backbone_core/config/
security_config.rs

1//! Security configuration
2//!
3//! Defines CORS, CSRF, and security headers settings.
4
5use serde::{Deserialize, Serialize};
6
7fn default_true() -> bool { true }
8
9/// Security configuration
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct SecurityConfig {
12    /// Enable CORS
13    #[serde(default = "default_true")]
14    pub cors_enabled: bool,
15    /// Allowed CORS origins
16    #[serde(default = "default_cors_origins")]
17    pub cors_origins: Vec<String>,
18    /// Allowed CORS methods
19    #[serde(default = "default_cors_methods")]
20    pub cors_methods: Vec<String>,
21    /// Allowed CORS headers
22    #[serde(default = "default_cors_headers")]
23    pub cors_headers: Vec<String>,
24    /// CSRF configuration
25    #[serde(default)]
26    pub csrf: Option<CsrfConfig>,
27    /// Security headers configuration
28    #[serde(default)]
29    pub headers: Option<SecurityHeadersConfig>,
30}
31
32fn default_cors_origins() -> Vec<String> { vec!["http://localhost:3000".to_string()] }
33fn default_cors_methods() -> Vec<String> {
34    vec!["GET".to_string(), "POST".to_string(), "PUT".to_string(), "DELETE".to_string(), "PATCH".to_string(), "OPTIONS".to_string()]
35}
36fn default_cors_headers() -> Vec<String> {
37    vec!["Content-Type".to_string(), "Authorization".to_string()]
38}
39
40impl Default for SecurityConfig {
41    fn default() -> Self {
42        Self {
43            cors_enabled: true,
44            cors_origins: default_cors_origins(),
45            cors_methods: default_cors_methods(),
46            cors_headers: default_cors_headers(),
47            csrf: None,
48            headers: Some(SecurityHeadersConfig::default()),
49        }
50    }
51}
52
53/// CSRF configuration
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct CsrfConfig {
56    /// Enable CSRF protection
57    #[serde(default = "default_true")]
58    pub enabled: bool,
59    /// CSRF token length
60    #[serde(default = "default_csrf_token_length")]
61    pub token_length: u32,
62    /// Token expiration in seconds
63    #[serde(default = "default_csrf_expires")]
64    pub expires_in: u64,
65}
66
67fn default_csrf_token_length() -> u32 { 32 }
68fn default_csrf_expires() -> u64 { 3600 }
69
70impl Default for CsrfConfig {
71    fn default() -> Self {
72        Self {
73            enabled: true,
74            token_length: default_csrf_token_length(),
75            expires_in: default_csrf_expires(),
76        }
77    }
78}
79
80/// Security headers configuration
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct SecurityHeadersConfig {
83    /// X-Frame-Options header
84    #[serde(default = "default_x_frame_options")]
85    pub x_frame_options: Option<String>,
86    /// X-Content-Type-Options header
87    #[serde(default = "default_x_content_type_options")]
88    pub x_content_type_options: Option<String>,
89    /// X-XSS-Protection header
90    #[serde(default = "default_x_xss_protection")]
91    pub x_xss_protection: Option<String>,
92    /// Strict-Transport-Security header
93    #[serde(default = "default_hsts")]
94    pub strict_transport_security: Option<String>,
95}
96
97fn default_x_frame_options() -> Option<String> { Some("DENY".to_string()) }
98fn default_x_content_type_options() -> Option<String> { Some("nosniff".to_string()) }
99fn default_x_xss_protection() -> Option<String> { Some("1; mode=block".to_string()) }
100fn default_hsts() -> Option<String> { Some("max-age=31536000; includeSubDomains".to_string()) }
101
102impl Default for SecurityHeadersConfig {
103    fn default() -> Self {
104        Self {
105            x_frame_options: default_x_frame_options(),
106            x_content_type_options: default_x_content_type_options(),
107            x_xss_protection: default_x_xss_protection(),
108            strict_transport_security: default_hsts(),
109        }
110    }
111}