1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5pub struct RedactionPolicy {
6 #[serde(default = "default_false")]
7 pub enabled: bool,
8 #[serde(default = "default_sensitive_header_names")]
9 pub sensitive_header_names: Vec<String>,
10 #[serde(default = "default_sensitive_query_keys")]
11 pub sensitive_query_keys: Vec<String>,
12 #[serde(default = "default_false")]
13 pub redact_bodies: bool,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
17pub struct RedactionPolicyPatch {
18 #[serde(default)]
19 pub enabled: Option<bool>,
20 #[serde(default)]
21 pub sensitive_header_names: Option<Vec<String>>,
22 #[serde(default)]
23 pub sensitive_query_keys: Option<Vec<String>>,
24 #[serde(default)]
25 pub redact_bodies: Option<bool>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
29pub struct ProxyPolicyPatch {
30 #[serde(default)]
31 pub redaction: Option<RedactionPolicyPatch>,
32}
33
34impl Default for RedactionPolicy {
35 fn default() -> Self {
36 Self {
37 enabled: false,
38 sensitive_header_names: default_sensitive_header_names(),
39 sensitive_query_keys: default_sensitive_query_keys(),
40 redact_bodies: false,
41 }
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct ProxyPolicy {
47 #[serde(default = "default_true")]
49 pub strict_http_semantics: bool,
50
51 #[serde(default = "default_false")]
53 pub allow_fallback_method: bool,
54
55 #[serde(default = "default_false")]
57 pub allow_fallback_status: bool,
58
59 #[serde(default = "default_false")]
61 pub enable_retry: bool,
62
63 #[serde(default = "default_true")]
65 pub retry_idempotent_only: bool,
66
67 #[serde(default = "default_max_retries")]
69 pub max_retries: u8,
70
71 pub sandbox_root: Option<PathBuf>,
73
74 #[serde(default = "default_max_file_bytes")]
76 pub max_local_file_bytes: usize,
77
78 #[serde(default = "default_max_body_bytes")]
80 pub max_body_size: usize,
81
82 #[serde(default = "default_request_timeout_ms")]
84 pub request_timeout_ms: u64,
85
86 #[serde(default = "default_false")]
88 pub transparent_enabled: bool,
89
90 #[serde(default = "default_true")]
92 pub transparent_require_original_dst: bool,
93
94 #[serde(default = "default_false")]
96 pub transparent_allow_host_fallback: bool,
97
98 #[serde(default = "default_true")]
100 pub transparent_reject_loopback_target: bool,
101
102 #[serde(default = "default_transparent_log_level")]
104 pub transparent_log_level: TransparentLogLevel,
105
106 #[serde(default = "default_quic_mode")]
108 pub quic_mode: QuicMode,
109
110 #[serde(default = "default_false")]
112 pub quic_downgrade_clear_cache: bool,
113
114 #[serde(default)]
115 pub redaction: RedactionPolicy,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
119pub enum TransparentLogLevel {
120 Silent, Info, Debug, Trace, }
125
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
127pub enum QuicMode {
128 Downgrade,
130
131 Passthrough,
133
134 #[cfg(feature = "quic_mitm_experimental")]
136 ExperimentalMitm,
137}
138
139fn default_quic_mode() -> QuicMode {
140 QuicMode::Downgrade
141}
142
143impl Default for ProxyPolicy {
144 fn default() -> Self {
145 Self {
146 strict_http_semantics: true,
147 allow_fallback_method: false,
148 allow_fallback_status: false,
149 enable_retry: false,
150 retry_idempotent_only: true,
151 max_retries: 3,
152 sandbox_root: None,
153 max_local_file_bytes: 10 * 1024 * 1024, max_body_size: 10 * 1024 * 1024, request_timeout_ms: 30_000, transparent_enabled: false,
157 transparent_require_original_dst: true,
158 transparent_allow_host_fallback: false,
159 transparent_reject_loopback_target: true,
160 transparent_log_level: TransparentLogLevel::Info,
161 quic_mode: QuicMode::Downgrade,
162 quic_downgrade_clear_cache: false,
163 redaction: RedactionPolicy::default(),
164 }
165 }
166}
167
168impl RedactionPolicy {
169 pub fn apply_patch(&mut self, patch: RedactionPolicyPatch) {
170 if let Some(enabled) = patch.enabled {
171 self.enabled = enabled;
172 }
173 if let Some(names) = patch.sensitive_header_names {
174 self.sensitive_header_names = names;
175 }
176 if let Some(keys) = patch.sensitive_query_keys {
177 self.sensitive_query_keys = keys;
178 }
179 if let Some(redact_bodies) = patch.redact_bodies {
180 self.redact_bodies = redact_bodies;
181 }
182 }
183}
184
185impl ProxyPolicy {
186 pub fn apply_patch(&mut self, patch: ProxyPolicyPatch) {
187 if let Some(redaction_patch) = patch.redaction {
188 self.redaction.apply_patch(redaction_patch);
189 }
190 }
191}
192
193fn default_true() -> bool { true }
194fn default_false() -> bool { false }
195fn default_max_retries() -> u8 { 3 }
196fn default_max_file_bytes() -> usize { 10 * 1024 * 1024 }
197fn default_max_body_bytes() -> usize { 10 * 1024 * 1024 }
198fn default_request_timeout_ms() -> u64 { 30_000 }
199fn default_transparent_log_level() -> TransparentLogLevel { TransparentLogLevel::Info }
200fn default_sensitive_header_names() -> Vec<String> {
201 vec![
202 "authorization".to_string(),
203 "proxy-authorization".to_string(),
204 "cookie".to_string(),
205 "set-cookie".to_string(),
206 "x-api-key".to_string(),
207 "x-auth-token".to_string(),
208 ]
209}
210fn default_sensitive_query_keys() -> Vec<String> {
211 vec![
212 "token".to_string(),
213 "access_token".to_string(),
214 "refresh_token".to_string(),
215 "api_key".to_string(),
216 "apikey".to_string(),
217 "password".to_string(),
218 "secret".to_string(),
219 ]
220}