product-os-proxy 0.0.17

Product OS : Proxy builds on the work of hudsucker, taking it to the next level with a man-in-the-middle proxy server that can tunnel traffic through a VPN utilising Product OS : VPN.
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);

        // Define the proxy port if set to zero
        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,
            // internal_proxy: None,

            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
    }

    // Setup certificates
    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!()
    }
}