use std::sync::Arc;
use async_trait::async_trait;
use parking_lot::Mutex;
use product_os_configuration::{Configuration, Network, NetworkProxyCertificateAuthorityFiles, TunnelType};
use product_os_capabilities::{RegistryService, Service};
use product_os_security::certificates::Certificates;
use product_os_security::RandomGeneratorTemplate;
use product_os_utilities::ProductOSError;
use crate::mitm::certificate_authority::RcgenAuthority;
use crate::mitm::{HttpHandler, ProxyBuilder};
use crate::mitm::rustls::crypto::CryptoProvider;
use crate::proxy_middleware::DefaultAsyncMiddleware;
mod mitm;
mod proxy_middleware;
pub use crate::proxy_middleware::ProxyMiddleware;
pub struct Proxy {
key: String,
config: product_os_configuration::NetworkProxy,
vpn_config: Option<product_os_configuration::VPN>,
middleware: Option<ProxyMiddleware>
}
impl Proxy {
pub fn new(mut config: product_os_configuration::NetworkProxy) -> Self {
let mut random_generator = product_os_security::RandomGenerator::new(None);
let key = random_generator.get_random_string(10);
if config.network.port == 0 {
config.network.port = u16::try_from(random_generator.get_random_usize(1025, 65535)).unwrap()
};
if config.network.insecure_port == 0 {
config.network.insecure_port = u16::try_from(random_generator.get_random_usize(1025, 65535)).unwrap()
};
Self {
key,
config,
vpn_config: None,
middleware: None
}
}
pub fn set_middleware(&mut self, middleware: Option<ProxyMiddleware>) {
self.middleware = middleware;
}
pub fn set_vpn_config(&mut self, vpn_config: Option<product_os_configuration::VPN>) {
self.vpn_config = vpn_config;
}
pub async fn run(&mut self) {
let mut config = product_os_configuration::Configuration::new();
config.network = Network {
protocol: if self.config.network.secure { "https".to_string() } else { "http".to_string() },
secure: self.config.network.secure.to_owned(),
host: self.config.network.host.to_owned(),
port: self.config.network.port,
listen_all_interfaces: self.config.network.listen_all_interfaces,
allow_insecure: self.config.network.allow_insecure,
insecure_port: self.config.network.insecure_port,
insecure_use_different_port: false,
insecure_force_secure: false
};
let cert_config = self.config.certificate_authority.clone().unwrap();
let (cert_file, key_file) = match cert_config.files {
None => panic!("No certificate authority certs provided"),
Some(files) => {
(files.cert_file, files.key_file)
}
};
let certificates = product_os_security::certificates::Certificates::new_from_file(cert_file, key_file, None);
let socket_address = Configuration::get_socket_address(self.config.network.host.as_str(), self.config.network.port, self.config.network.listen_all_interfaces);
let mut proxy_builder = mitm::Proxy::https_builder()
.use_address(socket_address)
.use_certificate_authority(certificates)
.use_compression(self.config.compression.to_owned())
.use_rustls_client({
match mitm::rustls::crypto::ring::default_provider().install_default() {
Ok(_) => {
let crypto_provider = mitm::rustls::crypto::ring::default_provider();
crypto_provider
}
Err(e) => panic!("Problem establishing crypto default provider: {:?}", e)
}
})
.use_http_handler({
self.middleware.to_owned().unwrap_or_else(|| ProxyMiddleware::new(Arc::new(DefaultAsyncMiddleware::new())))
});
match self.config.custom_requester {
true => { proxy_builder = proxy_builder.use_custom_requester(product_os_request::ProductOSRequestClient::new()); }
false => {}
};
if self.config.enable_tunnel {
match self.config.tunnel_settings.tunnel_type {
TunnelType::Tor => {
#[cfg(feature = "tor")]
{
tracing::info!("Enabling Tor");
proxy_builder = match proxy_builder.use_tor_client().await {
Ok(proxy_builder) => { proxy_builder }
Err(e) => panic!("Problem starting proxy with Tor: {:?}", e)
}
}
}
TunnelType::Vpn => {
#[cfg(feature = "vpn")]
{
match &self.vpn_config {
None => {}
Some(vpn_conf) => {
proxy_builder = proxy_builder.use_vpn_client(vpn_conf.to_owned());
}
}
}
}
};
}
let proxy = match proxy_builder.build() {
Ok(proxy) => proxy,
Err(e) => panic!("Unable to build proxy: {:?}", e)
};
let port = self.config.network.port;
tracing::info!("Starting SSL Proxy server on port: {}", port);
tokio::spawn(async move {
match proxy.start().await {
Ok(_) => {
tracing::info!("SSL Proxy server started successfully on port: {}", port);
}
Err(e) => { tracing::info!("SSL Proxy server starting error: {:?}", e); }
}
});
}
pub fn get_config(&self) -> &product_os_configuration::NetworkProxy {
&self.config
}
pub fn get_port(&self) -> u16 {
self.config.network.port
}
pub fn generate_certificate_authority(cert_path: Option<(String, String)>) -> Certificates {
match cert_path {
None => Certificates::new(None, None, None, None, None),
Some((cert_file, key_file)) => Certificates::new_from_file(cert_file, key_file, None)
}
}
}
#[async_trait]
impl Service for Proxy {
async fn register(&self, service: Arc<dyn Service>) -> RegistryService {
panic!("Immutable proxy not allowed to be registered")
}
async fn register_mut(&self, service: Arc<Mutex<dyn Service>>) -> RegistryService {
RegistryService {
identifier: "Proxy".to_string(),
key: self.key.to_owned(),
kind: "Proxy".to_string(),
active: false,
enabled: false,
created_at: Default::default(),
updated_at: Default::default(),
service: None,
service_mut: Some(service)
}
}
fn identifier(&self) -> String {
"Proxy".to_string()
}
fn key(&self) -> String {
self.key.to_owned()
}
fn is_enabled(&self) -> bool {
todo!()
}
fn is_active(&self) -> bool {
todo!()
}
async fn status(&self) -> Result<(), ()> {
tokio::spawn(async move {
});
Ok(())
}
async fn init_service(&self) -> Result<(), ()> {
todo!()
}
async fn start(&self) -> Result<(), ()> {
panic!("Proxy must be mutable")
}
async fn stop(&self) -> Result<(), ()> {
todo!()
}
async fn restart(&self) -> Result<(), ()> {
todo!()
}
async fn init_service_mut(&mut self) -> Result<(), ()> {
todo!()
}
async fn start_mut(&mut self) -> Result<(), ()> {
self.run().await;
Ok(())
}
async fn stop_mut(&mut self) -> Result<(), ()> {
todo!()
}
async fn restart_mut(&mut self) -> Result<(), ()> {
todo!()
}
}