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 enable_tcp_interception: bool,
22 pub max_connections: usize,
24 pub connection_timeout: u64,
26 pub upstream_proxy: Option<Proxy>,
29}
30
31impl Default for MitmConfig {
32 fn default() -> Self {
33 Self {
34 ca_storage_path: PathBuf::from(".slinger-mitm"),
35 enable_https_interception: true,
36 enable_tcp_interception: false,
37 max_connections: 1000,
38 connection_timeout: 30,
39 upstream_proxy: None,
40 }
41 }
42}
43
44pub struct MitmProxy {
46 config: MitmConfig,
47 cert_manager: Arc<CertificateManager>,
48 interceptor_handler: Arc<RwLock<InterceptorHandler>>,
49}
50
51impl MitmProxy {
52 pub async fn new(config: MitmConfig) -> Result<Self> {
54 let cert_manager = Arc::new(CertificateManager::new(&config.ca_storage_path).await?);
55 let interceptor_handler = Arc::new(RwLock::new(InterceptorHandler::new()));
56
57 Ok(Self {
58 config,
59 cert_manager,
60 interceptor_handler,
61 })
62 }
63
64 pub async fn default() -> Result<Self> {
66 Self::new(MitmConfig::default()).await
67 }
68
69 pub fn ca_cert_pem(&self) -> Result<String> {
73 self.cert_manager.ca_cert_pem()
74 }
75
76 pub fn ca_cert_path(&self) -> PathBuf {
78 self.cert_manager.ca_cert_path()
79 }
80
81 pub fn interceptor_handler(&self) -> Arc<RwLock<InterceptorHandler>> {
83 self.interceptor_handler.clone()
84 }
85
86 pub async fn start(&self, addr: &str) -> Result<()> {
88 let server = ProxyServer::new(
89 self.config.clone(),
90 self.cert_manager.clone(),
91 self.interceptor_handler.clone(),
92 )?;
93 server.run(addr).await
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[tokio::test]
102 async fn test_mitm_proxy_creation() {
103 let config = MitmConfig {
104 ca_storage_path: PathBuf::from("/tmp/test-mitm-ca"),
105 ..Default::default()
106 };
107
108 let proxy = MitmProxy::new(config).await;
109 assert!(proxy.is_ok());
110
111 if let Ok(p) = proxy {
112 let ca_pem = p.ca_cert_pem();
113 assert!(ca_pem.is_ok());
114 }
115 }
116}