rush_sync_server/server/
tls.rs

1use crate::core::prelude::*;
2use rcgen::{Certificate, CertificateParams, DistinguishedName};
3use rustls::{Certificate as RustlsCertificate, PrivateKey, ServerConfig};
4use rustls_pemfile::{certs, pkcs8_private_keys};
5use std::fs;
6use std::io::BufReader;
7use std::path::{Path, PathBuf};
8use std::sync::Arc;
9
10#[derive(Debug)]
11pub struct TlsManager {
12    cert_dir: PathBuf,
13    validity_days: u32,
14}
15
16impl TlsManager {
17    pub fn new(cert_dir: &str, validity_days: u32) -> Result<Self> {
18        let exe_path = std::env::current_exe().map_err(AppError::Io)?;
19        let base_dir = exe_path.parent().ok_or_else(|| {
20            AppError::Validation("Cannot determine executable directory".to_string())
21        })?;
22
23        let cert_path = base_dir.join(cert_dir);
24        fs::create_dir_all(&cert_path).map_err(AppError::Io)?;
25
26        Ok(Self {
27            cert_dir: cert_path,
28            validity_days,
29        })
30    }
31
32    pub fn get_rustls_config(&self, server_name: &str, port: u16) -> Result<Arc<ServerConfig>> {
33        let cert_file = self.get_cert_path(server_name, port);
34        let key_file = self.get_key_path(server_name, port);
35
36        // Zertifikat erstellen falls nicht vorhanden
37        if !cert_file.exists() || !key_file.exists() {
38            self.generate_certificate(server_name, port)?;
39        }
40
41        // Zertifikat und Key laden
42        let cert_chain = self.load_certificates(&cert_file)?;
43        let private_key = self.load_private_key(&key_file)?;
44
45        // Rustls Konfiguration erstellen
46        let config = ServerConfig::builder()
47            .with_safe_defaults()
48            .with_no_client_auth()
49            .with_single_cert(cert_chain, private_key)
50            .map_err(|e| AppError::Validation(format!("TLS config error: {}", e)))?;
51
52        Ok(Arc::new(config))
53    }
54
55    fn generate_certificate(&self, server_name: &str, port: u16) -> Result<()> {
56        log::info!("Generating TLS certificate for {}:{}", server_name, port);
57
58        // Subject Alternative Names - Wildcard für Proxy, spezifisch für Server
59        let subject_alt_names = if server_name == "proxy" {
60            vec![
61                "localhost".to_string(),
62                "127.0.0.1".to_string(),
63                "*.localhost".to_string(), // Wildcard für alle Subdomains
64                "proxy.localhost".to_string(),
65            ]
66        } else {
67            vec![
68                "localhost".to_string(),
69                "127.0.0.1".to_string(),
70                format!("{}.localhost", server_name), // spezifische Subdomain
71                format!("{}:{}", server_name, port),
72            ]
73        };
74
75        let mut params = CertificateParams::new(subject_alt_names);
76
77        // Distinguished Name - Korrekte Common Names
78        let mut dn = DistinguishedName::new();
79        dn.push(rcgen::DnType::OrganizationName, "Rush Sync Server");
80
81        let common_name = if server_name == "proxy" {
82            "*.localhost" // Wildcard CN für Proxy
83        } else {
84            &format!("{}.localhost", server_name)
85        };
86
87        dn.push(rcgen::DnType::CommonName, common_name);
88        params.distinguished_name = dn;
89
90        // Rest der Funktion bleibt gleich...
91        params.not_before = time::OffsetDateTime::now_utc() - time::Duration::days(1);
92        params.not_after =
93            time::OffsetDateTime::now_utc() + time::Duration::days(self.validity_days as i64);
94
95        params.key_usages = vec![
96            rcgen::KeyUsagePurpose::DigitalSignature,
97            rcgen::KeyUsagePurpose::KeyEncipherment,
98        ];
99
100        params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ServerAuth];
101
102        // Zertifikat generieren
103        let cert = Certificate::from_params(params)
104            .map_err(|e| AppError::Validation(format!("Certificate generation failed: {}", e)))?;
105
106        let cert_pem = cert.serialize_pem().map_err(|e| {
107            AppError::Validation(format!("Certificate serialization failed: {}", e))
108        })?;
109        let key_pem = cert.serialize_private_key_pem();
110
111        let cert_file = self.get_cert_path(server_name, port);
112        let key_file = self.get_key_path(server_name, port);
113
114        fs::write(&cert_file, cert_pem).map_err(AppError::Io)?;
115        fs::write(&key_file, key_pem).map_err(AppError::Io)?;
116
117        #[cfg(unix)]
118        {
119            use std::os::unix::fs::PermissionsExt;
120            let mut perms = fs::metadata(&key_file).map_err(AppError::Io)?.permissions();
121            perms.set_mode(0o600);
122            fs::set_permissions(&key_file, perms).map_err(AppError::Io)?;
123        }
124
125        log::info!("TLS certificate generated with CN: {}", common_name);
126        log::info!("Certificate: {:?}", cert_file);
127        log::info!("Private Key: {:?}", key_file);
128
129        Ok(())
130    }
131
132    fn load_certificates(&self, path: &Path) -> Result<Vec<RustlsCertificate>> {
133        let cert_file = fs::File::open(path).map_err(AppError::Io)?;
134        let mut reader = BufReader::new(cert_file);
135
136        let cert_chain = certs(&mut reader)
137            .map_err(|e| AppError::Validation(format!("Certificate parsing error: {}", e)))?
138            .into_iter()
139            .map(RustlsCertificate)
140            .collect();
141
142        Ok(cert_chain)
143    }
144
145    fn load_private_key(&self, path: &Path) -> Result<PrivateKey> {
146        let key_file = fs::File::open(path).map_err(AppError::Io)?;
147        let mut reader = BufReader::new(key_file);
148
149        let keys = pkcs8_private_keys(&mut reader)
150            .map_err(|e| AppError::Validation(format!("Private key parsing error: {}", e)))?;
151
152        if keys.is_empty() {
153            return Err(AppError::Validation("No private key found".to_string()));
154        }
155
156        Ok(PrivateKey(keys[0].clone()))
157    }
158
159    fn get_cert_path(&self, server_name: &str, port: u16) -> PathBuf {
160        self.cert_dir.join(format!("{}-{}.cert", server_name, port))
161    }
162
163    fn get_key_path(&self, server_name: &str, port: u16) -> PathBuf {
164        self.cert_dir.join(format!("{}-{}.key", server_name, port))
165    }
166
167    pub fn certificate_exists(&self, server_name: &str, port: u16) -> bool {
168        let cert_file = self.get_cert_path(server_name, port);
169        let key_file = self.get_key_path(server_name, port);
170        cert_file.exists() && key_file.exists()
171    }
172
173    pub fn remove_certificate(&self, server_name: &str, port: u16) -> Result<()> {
174        let cert_file = self.get_cert_path(server_name, port);
175        let key_file = self.get_key_path(server_name, port);
176
177        if cert_file.exists() {
178            fs::remove_file(&cert_file).map_err(AppError::Io)?;
179            log::info!("Removed certificate: {:?}", cert_file);
180        }
181
182        if key_file.exists() {
183            fs::remove_file(&key_file).map_err(AppError::Io)?;
184            log::info!("Removed private key: {:?}", key_file);
185        }
186
187        Ok(())
188    }
189
190    pub fn get_certificate_info(&self, server_name: &str, port: u16) -> Option<CertificateInfo> {
191        let cert_file = self.get_cert_path(server_name, port);
192
193        if !cert_file.exists() {
194            return None;
195        }
196
197        let metadata = fs::metadata(&cert_file).ok()?;
198        let size = metadata.len();
199        let modified = metadata.modified().ok()?;
200
201        Some(CertificateInfo {
202            cert_path: cert_file,
203            key_path: self.get_key_path(server_name, port),
204            file_size: size,
205            created: modified,
206            valid_days: self.validity_days,
207        })
208    }
209
210    pub fn list_certificates(&self) -> Result<Vec<CertificateInfo>> {
211        let mut certificates = Vec::new();
212
213        let entries = fs::read_dir(&self.cert_dir).map_err(AppError::Io)?;
214
215        for entry in entries {
216            let entry = entry.map_err(AppError::Io)?;
217            let path = entry.path();
218
219            if path.extension().and_then(|s| s.to_str()) == Some("cert") {
220                if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
221                    // Parse server-port aus Dateiname
222                    if let Some((server, port_str)) = stem.rsplit_once('-') {
223                        if let Ok(port) = port_str.parse::<u16>() {
224                            if let Some(info) = self.get_certificate_info(server, port) {
225                                certificates.push(info);
226                            }
227                        }
228                    }
229                }
230            }
231        }
232
233        certificates.sort_by(|a, b| b.created.cmp(&a.created));
234        Ok(certificates)
235    }
236
237    pub fn get_production_config(&self, domain: &str) -> Result<Arc<ServerConfig>> {
238        // Prüfen ob bereits Let's Encrypt Zertifikat existiert
239        let cert_file = self.cert_dir.join(format!("{}.fullchain.pem", domain));
240        let key_file = self.cert_dir.join(format!("{}.privkey.pem", domain));
241
242        if cert_file.exists() && key_file.exists() {
243            log::info!("Loading existing Let's Encrypt certificate for {}", domain);
244            let cert_chain = self.load_certificates(&cert_file)?;
245            let private_key = self.load_private_key(&key_file)?;
246
247            let config = ServerConfig::builder()
248                .with_safe_defaults()
249                .with_no_client_auth()
250                .with_single_cert(cert_chain, private_key)
251                .map_err(|e| AppError::Validation(format!("TLS config error: {}", e)))?;
252
253            return Ok(Arc::new(config));
254        }
255
256        log::warn!("No Let's Encrypt certificate found for {}", domain);
257        log::info!("Using self-signed certificate for development");
258
259        // Fallback zu self-signed
260        self.get_rustls_config("proxy", 443)
261    }
262}
263
264#[derive(Debug)]
265pub struct CertificateInfo {
266    pub cert_path: PathBuf,
267    pub key_path: PathBuf,
268    pub file_size: u64,
269    pub created: std::time::SystemTime,
270    pub valid_days: u32,
271}
272
273impl CertificateInfo {
274    pub fn is_expired(&self) -> bool {
275        if let Ok(elapsed) = self.created.elapsed() {
276            elapsed.as_secs() > (self.valid_days as u64 * 24 * 60 * 60)
277        } else {
278            true
279        }
280    }
281
282    pub fn days_until_expiry(&self) -> i64 {
283        if let Ok(elapsed) = self.created.elapsed() {
284            let elapsed_days = elapsed.as_secs() / (24 * 60 * 60);
285            (self.valid_days as i64) - (elapsed_days as i64)
286        } else {
287            0
288        }
289    }
290}