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 max_connections: usize,
19 pub connection_timeout: u64,
21 pub interceptor_timeout_secs: u64,
25 pub upstream_proxy: Option<Proxy>,
28}
29
30impl Default for MitmConfig {
31 fn default() -> Self {
32 Self {
33 ca_storage_path: PathBuf::from(".slinger-mitm"),
34 max_connections: 1000,
35 connection_timeout: 30,
36 interceptor_timeout_secs: 60,
38 upstream_proxy: None,
39 }
40 }
41}
42
43pub struct MitmProxy {
45 config: MitmConfig,
46 cert_manager: Arc<CertificateManager>,
47 interceptor_handler: Arc<RwLock<InterceptorHandler>>,
48}
49
50impl MitmProxy {
51 pub async fn new(config: MitmConfig) -> Result<Self> {
53 let cert_manager = Arc::new(CertificateManager::new(&config.ca_storage_path).await?);
54 let interceptor_handler = Arc::new(RwLock::new(
55 InterceptorHandler::new().with_timeout(config.interceptor_timeout_secs),
56 ));
57
58 Ok(Self {
59 config,
60 cert_manager,
61 interceptor_handler,
62 })
63 }
64
65 pub async fn default() -> Result<Self> {
67 Self::new(MitmConfig::default()).await
68 }
69
70 pub async fn ca_cert_pem(&self) -> Result<String> {
73 self.cert_manager.ca_cert_pem().await
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().await;
113 assert!(ca_pem.is_ok());
114 }
115 }
116}