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_rule_body_inspect_budget")]
86 pub rule_body_inspect_budget: usize,
87
88 #[serde(default = "default_request_timeout_ms")]
90 pub request_timeout_ms: u64,
91
92 #[serde(default = "default_false")]
94 pub transparent_enabled: bool,
95
96 #[serde(default = "default_true")]
98 pub transparent_require_original_dst: bool,
99
100 #[serde(default = "default_false")]
102 pub transparent_allow_host_fallback: bool,
103
104 #[serde(default = "default_true")]
106 pub transparent_reject_loopback_target: bool,
107
108 #[serde(default = "default_transparent_log_level")]
110 pub transparent_log_level: TransparentLogLevel,
111
112 #[serde(default = "default_quic_mode")]
114 pub quic_mode: QuicMode,
115
116 #[serde(default = "default_false")]
118 pub quic_downgrade_clear_cache: bool,
119
120 #[serde(default)]
121 pub redaction: RedactionPolicy,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
125pub enum TransparentLogLevel {
126 Silent, Info, Debug, Trace, }
131
132#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
133pub enum QuicMode {
134 Downgrade,
136
137 Passthrough,
139
140 #[cfg(feature = "quic_mitm_experimental")]
142 ExperimentalMitm,
143}
144
145fn default_quic_mode() -> QuicMode {
146 QuicMode::Downgrade
147}
148
149impl Default for ProxyPolicy {
150 fn default() -> Self {
151 Self {
152 strict_http_semantics: true,
153 allow_fallback_method: false,
154 allow_fallback_status: false,
155 enable_retry: false,
156 retry_idempotent_only: true,
157 max_retries: 3,
158 sandbox_root: None,
159 max_local_file_bytes: 10 * 1024 * 1024, max_body_size: 10 * 1024 * 1024, rule_body_inspect_budget: 1024 * 1024, request_timeout_ms: 30_000, transparent_enabled: false,
164 transparent_require_original_dst: true,
165 transparent_allow_host_fallback: false,
166 transparent_reject_loopback_target: true,
167 transparent_log_level: TransparentLogLevel::Info,
168 quic_mode: QuicMode::Downgrade,
169 quic_downgrade_clear_cache: false,
170 redaction: RedactionPolicy::default(),
171 }
172 }
173}
174
175impl RedactionPolicy {
176 pub fn apply_patch(&mut self, patch: RedactionPolicyPatch) {
177 if let Some(enabled) = patch.enabled {
178 self.enabled = enabled;
179 }
180 if let Some(names) = patch.sensitive_header_names {
181 self.sensitive_header_names = names;
182 }
183 if let Some(keys) = patch.sensitive_query_keys {
184 self.sensitive_query_keys = keys;
185 }
186 if let Some(redact_bodies) = patch.redact_bodies {
187 self.redact_bodies = redact_bodies;
188 }
189 }
190}
191
192impl ProxyPolicy {
193 pub fn apply_patch(&mut self, patch: ProxyPolicyPatch) {
194 if let Some(redaction_patch) = patch.redaction {
195 self.redaction.apply_patch(redaction_patch);
196 }
197 }
198}
199
200fn default_true() -> bool {
201 true
202}
203fn default_false() -> bool {
204 false
205}
206fn default_max_retries() -> u8 {
207 3
208}
209fn default_max_file_bytes() -> usize {
210 10 * 1024 * 1024
211}
212fn default_max_body_bytes() -> usize {
213 10 * 1024 * 1024
214}
215fn default_rule_body_inspect_budget() -> usize {
216 1024 * 1024 }
218fn default_request_timeout_ms() -> u64 {
219 30_000
220}
221fn default_transparent_log_level() -> TransparentLogLevel {
222 TransparentLogLevel::Info
223}
224fn default_sensitive_header_names() -> Vec<String> {
225 vec![
226 "authorization".to_string(),
227 "proxy-authorization".to_string(),
228 "cookie".to_string(),
229 "set-cookie".to_string(),
230 "x-api-key".to_string(),
231 "x-auth-token".to_string(),
232 ]
233}
234fn default_sensitive_query_keys() -> Vec<String> {
235 vec![
236 "token".to_string(),
237 "access_token".to_string(),
238 "refresh_token".to_string(),
239 "api_key".to_string(),
240 "apikey".to_string(),
241 "password".to_string(),
242 "secret".to_string(),
243 ]
244}