Mountain/Binary/Build/
TlsCommands.rs1use std::sync::{Arc, Mutex};
38
39use serde::{Deserialize, Serialize};
40use tauri::{AppHandle, Manager}; use crate::dev_log;
43use super::CertificateManager::{CertificateInfo, CertificateManager};
44
45#[tauri::command]
50pub async fn tls_initialize(app_handle:AppHandle) -> Result<String, String> {
51 dev_log!("security", "TLS certificate manager initializing");
52
53 let state = app_handle
55 .try_state::<Arc<Mutex<CertificateManager>>>()
56 .ok_or("Certificate manager not initialized in app state")?;
57 let cert_manager = state.clone(); let mut manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
60
61 manager
62 .initialize_ca()
63 .await
64 .map_err(|e| format!("Failed to initialize CA: {}", e))?;
65
66 dev_log!("security", "TLS certificate manager initialized");
67 Ok("TLS certificate manager initialized".to_string())
68}
69
70#[tauri::command]
77pub async fn tls_get_ca_cert(app_handle:AppHandle) -> Result<String, String> {
78 dev_log!("security", "getting CA certificate");
79
80 let state = app_handle
81 .try_state::<Arc<Mutex<CertificateManager>>>()
82 .ok_or("Certificate manager not found")?;
83 let cert_manager = state.clone();
84
85 let manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
86 let cert_pem = manager.get_ca_cert_pem().ok_or("CA certificate not initialized")?;
87
88 Ok(String::from_utf8(cert_pem).map_err(|e| format!("Invalid certificate UTF-8: {}", e))?)
89}
90
91#[tauri::command]
99pub async fn tls_get_server_cert_info(
100 app_handle:AppHandle,
101 hostname:String,
102) -> Result<Option<CertificateInfo>, String> {
103 dev_log!("security", "getting server cert info for {}", hostname);
104
105 let state = app_handle
106 .try_state::<Arc<Mutex<CertificateManager>>>()
107 .ok_or("Certificate manager not found")?;
108 let cert_manager = state.clone();
109
110 let manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
111 Ok(manager.get_server_cert_info(&hostname))
112}
113
114#[tauri::command]
122pub async fn tls_renew_certificate(app_handle:AppHandle, hostname:String) -> Result<String, String> {
123 dev_log!("security", "renewing certificate for {}", hostname);
124
125 let state = app_handle
126 .try_state::<Arc<Mutex<CertificateManager>>>()
127 .ok_or("Certificate manager not found")?;
128 let cert_manager = state.clone();
129
130 {
134 let mut manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
135
136 let _result = manager.renew_certificate(&hostname);
137 }
139
140 Ok(format!("Certificate renewed for {}", hostname))
141}
142
143#[tauri::command]
147pub async fn tls_get_all_certs(
148 app_handle:AppHandle,
149) -> Result<std::collections::HashMap<String, CertificateInfo>, String> {
150 dev_log!("security", "getting all server certificates");
151
152 let state = app_handle
153 .try_state::<Arc<Mutex<CertificateManager>>>()
154 .ok_or("Certificate manager not found")?;
155 let cert_manager = state.clone();
156
157 let manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
158 Ok(manager.get_all_certs())
159}
160
161#[tauri::command]
169pub async fn tls_check_cert_status(app_handle:AppHandle, hostname:String) -> Result<CertificateStatus, String> {
170 dev_log!("security", "checking certificate status for {}", hostname);
171
172 let state = app_handle
173 .try_state::<Arc<Mutex<CertificateManager>>>()
174 .ok_or("Certificate manager not found")?;
175 let cert_manager = state.clone();
176
177 let manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
178
179 if let Some(cert_info) = manager.get_server_cert_info(&hostname) {
181 let valid_until = chrono::DateTime::parse_from_rfc3339(&cert_info.valid_until)
183 .map_err(|e| format!("Invalid certificate expiry time: {}", e))?
184 .with_timezone(&chrono::Utc);
185
186 let now = chrono::Utc::now();
187 let days_until_expiry = (valid_until - now).num_days();
188 let needs_renewal = days_until_expiry <= CertificateManager::RENEWAL_THRESHOLD_DAYS;
189
190 Ok(CertificateStatus {
191 exists:true,
192 is_valid:now <= valid_until,
193 days_until_expiry,
194 needs_renewal,
195 valid_until:cert_info.valid_until,
196 })
197 } else {
198 Ok(CertificateStatus {
199 exists:false,
200 is_valid:false,
201 days_until_expiry:0,
202 needs_renewal:true,
203 valid_until:String::new(),
204 })
205 }
206}
207
208#[tauri::command]
219pub async fn tls_generate_cert(app_handle:AppHandle, hostname:String) -> Result<CertificateGenerationResult, String> {
220 dev_log!("security", "generating certificate for {}", hostname);
221
222 let state = app_handle
223 .try_state::<Arc<Mutex<CertificateManager>>>()
224 .ok_or("Certificate manager not found")?;
225
226 let cert_manager = state.clone();
227 let manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
228 let hostname_clone = hostname.clone();
229
230 let _server_config = manager
231 .get_server_cert(&hostname)
232 .await
233 .map_err(|e| format!("Failed to generate certificate: {}", e))?;
234
235 let cert_info:CertificateInfo = manager
237 .get_server_cert_info(&hostname)
238 .ok_or_else(|| "Certificate not found after generation".to_string())?;
239
240 Ok(CertificateGenerationResult {
241 hostname:hostname_clone,
242 success:true,
243 valid_until:cert_info.valid_until,
244 message:format!("Certificate generated successfully for {}", hostname),
245 })
246}
247
248#[tauri::command]
256pub async fn tls_delete_cert(app_handle:AppHandle, hostname:String) -> Result<String, String> {
257 dev_log!("security", "deleting certificate for {}", hostname);
258
259 let state = app_handle
260 .try_state::<Arc<Mutex<CertificateManager>>>()
261 .ok_or("Certificate manager not found")?;
262 let cert_manager = state.clone();
263
264 {
267 let mut manager = cert_manager.lock().map_err(|e| format!("Failed to acquire lock: {}", e))?;
268
269 let _result = manager.renew_certificate(&hostname);
270 }
272
273 Ok(format!("Certificate deleted for {}", hostname))
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct CertificateStatus {
279 pub exists:bool,
281 pub is_valid:bool,
283 pub days_until_expiry:i64,
285 pub needs_renewal:bool,
287 pub valid_until:String,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct CertificateGenerationResult {
294 pub hostname:String,
296 pub success:bool,
298 pub valid_until:String,
300 pub message:String,
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 fn test_certificate_status_serialization() {
310 let status = CertificateStatus {
311 exists:true,
312 is_valid:true,
313 days_until_expiry:30,
314 needs_renewal:true,
315 valid_until:"2025-01-01T00:00:00Z".to_string(),
316 };
317
318 let json = serde_json::to_string(&status).unwrap();
319 assert_eq!(status.exists, true);
320
321 let deserialized:CertificateStatus = serde_json::from_str(&json).unwrap();
322 assert_eq!(deserialized.exists, status.exists);
323 }
324}