1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize)]
4#[serde(default)]
5pub struct Config {
6 pub storage: StorageConfig,
7 pub search: SearchConfig,
8 pub validation: ValidationConfig,
9 pub privacy: PrivacyConfig,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(default)]
14pub struct StorageConfig {
15 pub retention_days: u32,
16 pub vacuum_interval_secs: u64,
17 pub max_db_size_mb: u64,
18 pub busy_timeout_ms: u32,
19 pub cache_size_kb: u32,
20 pub dedup_window_secs: u64,
21 pub encryption_enabled: bool,
22}
23
24impl Default for StorageConfig {
25 fn default() -> Self {
26 Self {
27 retention_days: 90,
28 vacuum_interval_secs: 604800,
29 max_db_size_mb: 500,
30 busy_timeout_ms: 5000,
31 cache_size_kb: 2048,
32 dedup_window_secs: 900,
33 encryption_enabled: false,
34 }
35 }
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(default)]
40pub struct SearchConfig {
41 pub default_limit: u32,
42 pub max_limit: u32,
43}
44
45impl Default for SearchConfig {
46 fn default() -> Self {
47 Self {
48 default_limit: 10,
49 max_limit: 50,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(default)]
56pub struct ValidationConfig {
57 pub max_key_length: usize,
58 pub max_value_length: usize,
59 pub max_tags: usize,
60 pub max_tag_length: usize,
61}
62
63impl Default for ValidationConfig {
64 fn default() -> Self {
65 Self {
66 max_key_length: 256,
67 max_value_length: 2000,
68 max_tags: 20,
69 max_tag_length: 64,
70 }
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75#[serde(default)]
76pub struct PrivacyConfig {
77 pub secret_patterns: Vec<String>,
78 pub extra_patterns: Vec<String>,
79 pub replace_defaults: bool,
80 pub file_deny_list: Vec<String>,
81}
82
83impl Default for PrivacyConfig {
84 fn default() -> Self {
85 Self {
86 secret_patterns: default_secret_patterns(),
87 extra_patterns: Vec::new(),
88 replace_defaults: false,
89 file_deny_list: vec![
90 ".env".into(),
91 ".env.*".into(),
92 "*.pem".into(),
93 "*.key".into(),
94 "*.p12".into(),
95 "*.pfx".into(),
96 "id_rsa".into(),
97 "id_ed25519".into(),
98 "id_ecdsa".into(),
99 "*.secret".into(),
100 "credentials.json".into(),
101 ],
102 }
103 }
104}
105
106pub fn default_secret_patterns() -> Vec<String> {
107 vec![
108 r"AKIA[0-9A-Z]{16}".into(),
109 r"-----BEGIN [A-Z ]*PRIVATE KEY-----".into(),
110 r"(?i)(api[_-]?key|token|secret|password)\s*[:=]\s*\S+".into(),
111 r"(?i)mongodb(\+srv)?://[^\s]+".into(),
112 r"(?i)postgres(ql)?://[^\s]+".into(),
113 r"(?i)mysql://[^\s]+".into(),
114 r"(?i)redis://[^\s]+".into(),
115 r"ghp_[a-zA-Z0-9]{36}".into(),
116 r"sk-[a-zA-Z0-9]{48}".into(),
117 r"xoxb-[0-9]+-[0-9]+-[a-zA-Z0-9]+".into(),
118 ]
119}