From b5640d78e2d2221c3c2b3bf341ac05f5651008be Mon Sep 17 00:00:00 2001 From: joshrmcdaniel <80354972+joshrmcdaniel@users.noreply.github.com> Date: Sun, 17 Aug 2025 09:06:45 -0500 Subject: [PATCH 1/2] generate new cert if exp --- privaxy/src/server/configuration/network.rs | 26 +++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/privaxy/src/server/configuration/network.rs b/privaxy/src/server/configuration/network.rs index 4046c9c4..dc0897a5 100644 --- a/privaxy/src/server/configuration/network.rs +++ b/privaxy/src/server/configuration/network.rs @@ -2,13 +2,13 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use std::str::FromStr; -use std::time::{SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime,UNIX_EPOCH}; use thiserror::Error; use tokio::fs; use super::ConfigurationResult; use openssl::{ - asn1::Asn1Time, + asn1::{Asn1Time, Asn1TimeRef}, bn::{BigNum, MsbOption}, hash::MessageDigest, pkey::{PKey, PKeyRef, Private}, @@ -230,8 +230,26 @@ impl NetworkConfig { ca_cert: X509, ca_key: PKey, ) -> ConfigurationResult { - if let Ok(cert) = self.get_tls_cert().await { - Ok(cert) + if let Ok(mut cert) = self.get_tls_cert().await { + let curtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64; + let current_asn1_time = Asn1Time::from_unix(curtime)?; + let expiry = cert.not_after(); + match current_asn1_time.compare(expiry).unwrap() { + std::cmp::Ordering::Greater | std::cmp::Ordering::Equal => { + let tls_key = self.get_tls_key().await.unwrap(); + if ca_cert.verify(&tls_key).unwrap() { + log::info!("Current TLS certificate has expired, generating new one."); + cert = self.gen_self_signed_tls_cert(ca_cert, ca_key).await.unwrap(); + } + else { + log::warn!("TLS certificate is expired."); + }; + Ok(cert) + } + std::cmp::Ordering::Less => { + Ok(cert) + } + } } else { self.gen_self_signed_tls_cert(ca_cert, ca_key).await } From 82ef7e593e60126ef7ed9ea51196134e395fcbff Mon Sep 17 00:00:00 2001 From: joshrmcdaniel <80354972+joshrmcdaniel@users.noreply.github.com> Date: Sun, 17 Aug 2025 09:09:03 -0500 Subject: [PATCH 2/2] redirect to https --- privaxy/src/server/configuration/network.rs | 29 ++++++++++++--------- privaxy/src/server/lib.rs | 4 +-- privaxy/src/server/web_gui/mod.rs | 23 ++++++++++++---- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/privaxy/src/server/configuration/network.rs b/privaxy/src/server/configuration/network.rs index dc0897a5..dc957995 100644 --- a/privaxy/src/server/configuration/network.rs +++ b/privaxy/src/server/configuration/network.rs @@ -2,7 +2,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use std::str::FromStr; -use std::time::{SystemTime,UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; use thiserror::Error; use tokio::fs; @@ -231,24 +231,27 @@ impl NetworkConfig { ca_key: PKey, ) -> ConfigurationResult { if let Ok(mut cert) = self.get_tls_cert().await { - let curtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64; + let curtime = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as i64; let current_asn1_time = Asn1Time::from_unix(curtime)?; let expiry = cert.not_after(); match current_asn1_time.compare(expiry).unwrap() { std::cmp::Ordering::Greater | std::cmp::Ordering::Equal => { - let tls_key = self.get_tls_key().await.unwrap(); - if ca_cert.verify(&tls_key).unwrap() { - log::info!("Current TLS certificate has expired, generating new one."); - cert = self.gen_self_signed_tls_cert(ca_cert, ca_key).await.unwrap(); - } - else { - log::warn!("TLS certificate is expired."); - }; - Ok(cert) - } - std::cmp::Ordering::Less => { + let tls_key = self.get_tls_key().await.unwrap(); + if ca_cert.verify(&tls_key).unwrap() { + log::info!("Current TLS certificate has expired, generating new one."); + cert = self + .gen_self_signed_tls_cert(ca_cert, ca_key) + .await + .unwrap(); + } else { + log::warn!("TLS certificate is expired."); + }; Ok(cert) } + std::cmp::Ordering::Less => Ok(cert), } } else { self.gen_self_signed_tls_cert(ca_cert, ca_key).await diff --git a/privaxy/src/server/lib.rs b/privaxy/src/server/lib.rs index 21302354..047a37b8 100644 --- a/privaxy/src/server/lib.rs +++ b/privaxy/src/server/lib.rs @@ -19,7 +19,6 @@ use std::time::Duration; use tokio::signal::unix::{signal, SignalKind}; use tokio::sync::broadcast; use tokio::sync::Notify; - pub mod blocker; mod blocker_utils; mod ca; @@ -244,6 +243,7 @@ async fn privaxy_frontend( configuration_save_lock: Arc>, notify_reload: Arc, ) { + let config = read_configuration(&configuration_save_lock).await; let frontend = web_gui::get_frontend( broadcast_tx.clone(), statistics.clone(), @@ -251,10 +251,10 @@ async fn privaxy_frontend( &configuration_updater_tx, &configuration_save_lock, &local_exclusion_store, + config.network.tls, notify_reload.clone(), ); let frontend_server = warp::serve(frontend); - let config = read_configuration(&configuration_save_lock).await; let ip = env_or_config_ip(&config.network).await; let web_api_server_addr = SocketAddr::from((ip, config.network.web_port)); if config.network.tls { diff --git a/privaxy/src/server/web_gui/mod.rs b/privaxy/src/server/web_gui/mod.rs index 053255b4..97cd826b 100644 --- a/privaxy/src/server/web_gui/mod.rs +++ b/privaxy/src/server/web_gui/mod.rs @@ -31,10 +31,10 @@ pub(crate) fn get_frontend( configuration_updater_sender: &Sender, configuration_save_lock: &Arc>, local_exclusions_store: &LocalExclusionStore, + tls: bool, notify_reload: Arc, -) -> BoxedFilter<(impl warp::Reply,)> { +) -> impl Filter + Clone { let static_files_routes = create_static_routes(); - let cors = warp::cors() .allow_any_origin() .allow_methods(vec!["GET", "PUT", "POST", "DELETE"]) @@ -43,7 +43,6 @@ pub(crate) fn get_frontend( http::header::CONTENT_LENGTH, http::header::DATE, ]); - let http_client = reqwest::Client::new(); let api_routes = create_api_routes( @@ -56,8 +55,22 @@ pub(crate) fn get_frontend( http_client, notify_reload, ); - - api_routes.or(static_files_routes).with(cors).boxed() + let routes = api_routes.or(static_files_routes); + let mut headers = warp::http::HeaderMap::new(); + if tls { + headers.insert( + "Strict-Transport-Security", + "max-age=31536000; includeSubDomains".parse().unwrap(), + ); + headers.insert( + "Content-Security-Policy", + "upgrade-insecure-requests".parse().unwrap(), + ); + }; + routes + .with(cors) + .with(warp::reply::with::headers(headers)) + .boxed() } fn create_static_routes() -> BoxedFilter<(impl warp::Reply,)> {