bws_web_server/server/
dynamic_tls.rs1use crate::ssl::SslManager;
2use pingora::prelude::*;
3use rustls::ServerConfig as RustlsServerConfig;
4use std::collections::HashMap;
5use std::sync::Arc;
6use tokio::sync::RwLock;
7
8pub struct DynamicTlsHandler {
10 ssl_managers: Arc<RwLock<HashMap<String, Arc<SslManager>>>>,
11 tls_configs: Arc<RwLock<HashMap<String, Arc<RustlsServerConfig>>>>,
12}
13
14impl DynamicTlsHandler {
15 pub fn new(ssl_managers: Arc<RwLock<HashMap<String, Arc<SslManager>>>>) -> Self {
16 Self {
17 ssl_managers,
18 tls_configs: Arc::new(RwLock::new(HashMap::new())),
19 }
20 }
21
22 pub fn is_tls_handshake(data: &[u8]) -> bool {
24 if data.len() < 3 {
25 return false;
26 }
27
28 data[0] == 0x16 && data[1] == 0x03 && (data[2] >= 0x01 && data[2] <= 0x04)
32 }
33
34 pub async fn update_tls_config(
36 &self,
37 domain: &str,
38 ) -> Result<bool, Box<dyn std::error::Error>> {
39 let ssl_managers = self.ssl_managers.read().await;
40
41 if let Some(ssl_manager) = ssl_managers.get(domain) {
42 if ssl_manager.has_certificate(domain).await {
44 log::info!("Certificate available for {domain}, creating TLS config");
45
46 if let Ok(rustls_config) = ssl_manager.get_rustls_config(domain).await {
48 let mut tls_configs = self.tls_configs.write().await;
49 tls_configs.insert(domain.to_string(), Arc::new(rustls_config));
50
51 log::info!("✅ TLS configuration updated for domain: {domain}");
52 log::info!("🔒 HTTPS is now available for https://{domain}");
53 return Ok(true);
54 }
55 }
56 }
57
58 Ok(false)
59 }
60
61 pub async fn has_tls_config(&self, domain: &str) -> bool {
63 let tls_configs = self.tls_configs.read().await;
64 tls_configs.contains_key(domain)
65 }
66
67 pub async fn get_tls_config(&self, domain: &str) -> Option<Arc<RustlsServerConfig>> {
69 let tls_configs = self.tls_configs.read().await;
70 tls_configs.get(domain).cloned()
71 }
72
73 pub fn start_certificate_monitor(&self, domains: Vec<String>) {
75 let ssl_managers = self.ssl_managers.clone();
76 let handler = Self {
77 ssl_managers: ssl_managers.clone(),
78 tls_configs: self.tls_configs.clone(),
79 };
80
81 tokio::spawn(async move {
82 let mut interval = tokio::time::interval(std::time::Duration::from_secs(10));
83
84 loop {
85 interval.tick().await;
86
87 for domain in &domains {
88 if !handler.has_tls_config(domain).await {
89 match handler.update_tls_config(domain).await {
90 Ok(true) => {
91 log::info!("🎉 Dynamic HTTPS upgrade successful for {domain}");
92 log::warn!("Note: Existing HTTP connections on port 443 will continue as HTTP");
93 log::warn!("New connections will automatically use HTTPS");
94 }
95 Ok(false) => {
96 }
98 Err(e) => {
99 log::error!("Failed to update TLS config for {domain}: {e}");
100 }
101 }
102 }
103 }
104 }
105 });
106 }
107}