1use crate::ca::CertificateManager;
4use crate::error::Result;
5use crate::interceptor::InterceptorHandler;
6use crate::server::ProxyServer;
7use slinger::Proxy;
8use std::path::PathBuf;
9use std::sync::Arc;
10use tokio::sync::RwLock;
11
12#[derive(Clone)]
14pub struct MitmConfig {
15 pub ca_storage_path: PathBuf,
17 pub enable_https_interception: bool,
19 pub max_connections: usize,
21 pub connection_timeout: u64,
23 pub upstream_proxy: Option<Proxy>,
26}
27
28impl Default for MitmConfig {
29 fn default() -> Self {
30 Self {
31 ca_storage_path: PathBuf::from(".slinger-mitm"),
32 enable_https_interception: true,
33 max_connections: 1000,
34 connection_timeout: 30,
35 upstream_proxy: None,
36 }
37 }
38}
39
40pub struct MitmProxy {
42 config: MitmConfig,
43 cert_manager: Arc<CertificateManager>,
44 interceptor_handler: Arc<RwLock<InterceptorHandler>>,
45}
46
47impl MitmProxy {
48 pub async fn new(config: MitmConfig) -> Result<Self> {
50 let cert_manager = Arc::new(CertificateManager::new(&config.ca_storage_path).await?);
51 let interceptor_handler = Arc::new(RwLock::new(InterceptorHandler::new()));
52
53 Ok(Self {
54 config,
55 cert_manager,
56 interceptor_handler,
57 })
58 }
59
60 pub async fn default() -> Result<Self> {
62 Self::new(MitmConfig::default()).await
63 }
64
65 pub fn ca_cert_pem(&self) -> Result<String> {
69 self.cert_manager.ca_cert_pem()
70 }
71
72 pub fn ca_cert_path(&self) -> PathBuf {
74 self.cert_manager.ca_cert_path()
75 }
76
77 pub fn interceptor_handler(&self) -> Arc<RwLock<InterceptorHandler>> {
79 self.interceptor_handler.clone()
80 }
81
82 pub async fn start(&self, addr: &str) -> Result<()> {
84 let server = ProxyServer::new(
85 self.config.clone(),
86 self.cert_manager.clone(),
87 self.interceptor_handler.clone(),
88 )?;
89 server.run(addr).await
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[tokio::test]
98 async fn test_mitm_proxy_creation() {
99 let config = MitmConfig {
100 ca_storage_path: PathBuf::from("/tmp/test-mitm-ca"),
101 ..Default::default()
102 };
103
104 let proxy = MitmProxy::new(config).await;
105 assert!(proxy.is_ok());
106
107 if let Ok(p) = proxy {
108 let ca_pem = p.ca_cert_pem();
109 assert!(ca_pem.is_ok());
110 }
111 }
112}