diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5a17589..6d8efeb 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -18,11 +18,17 @@ tauri-build = { version = "1.0.0-rc.8", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.0.0-rc.9", features = ["api-all"] } + +# Access to the Windows Registry. +registry = "1.2.1" +# Program opener. opener = "0.5.0" + +# Dependencies for the HTTP(S) proxy. hudsucker = "0.17.2" -tracing = "0.1.34" -tokio-rustls = "0.23.4" -tokio-tungstenite = "0.17.1" +tracing = "0.1.21" +tokio-rustls = "0.23.0" +tokio-tungstenite = "0.17.0" rustls-pemfile = "1.0.0" reqwest = { version = "0.11.3", features = ["stream"] } futures-util = "0.3.14" diff --git a/src-tauri/resources/ca-certificate.pem b/src-tauri/resources/ca-certificate.pem new file mode 100644 index 0000000..7e98962 --- /dev/null +++ b/src-tauri/resources/ca-certificate.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIJAMdLw5xpuf6yMA0GCSqGSIb3DQEBCwUAMGYxHTAbBgNV +BAMMFEh1ZHN1Y2tlciBJbmR1c3RyaWVzMR0wGwYDVQQKDBRIdWRzdWNrZXIgSW5k +dXN0cmllczELMAkGA1UEBgwCVVMxCzAJBgNVBAgMAk5ZMQwwCgYDVQQHDANOWUMw +IBcNNzUwMTAxMDAwMDAwWhgPNDA5NjAxMDEwMDAwMDBaMGYxHTAbBgNVBAMMFEh1 +ZHN1Y2tlciBJbmR1c3RyaWVzMR0wGwYDVQQKDBRIdWRzdWNrZXIgSW5kdXN0cmll +czELMAkGA1UEBgwCVVMxCzAJBgNVBAgMAk5ZMQwwCgYDVQQHDANOWUMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaHrZ9VUL7SKqgJdeG/dciikuummsr +Ds4Cn+p01J5mURQ/bq62EU5IiWFsM0LgwkO0UlTGE9gU+U1w1GeDxlDeVqcwitx+ +sPjup59ybC2l/iNihETjrLuFUaZVFH/eqdXqNgiRf1fBHV/RD27BlPN6OPo8Z6qT +fuRlVAUbpj+IViIkdQtmymgCJDrQabtnnwpPqZA0MQFnsAvmelOrWyTX1ASjzFAl +WWq7JDvFsrYcqPeMv8QaN/teESFN5pMSNDbvYm2guwcRu4jVL75hMezqm6StXe5p +CbbZOKPHLGqtRUAHnUFHEV1khOEz5HhOsC6m0DvWvKf5QiUvqcYFYxFZAgMBAAGj +QjBAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUsv65aZzDS8dPy3NWpXkAOKf0 +2rMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVnXJDTCCcV/c +79IidGy3Hh/st+4e2A6R3YueE01Rwo340Asp9Tp3IewDQcF3oRosgDp/i9daRrxv +c2q76CNmo57qUSjbdyu4o5SDqj7lmr263YgM4ZnVOQR9CaWwCL21C65tpgHa8Grm +hNil9REdnpM7br4H0yeX2nFjOYI8sUguxNle3ojTFLl0sWXZIPJE/koEaaHGSJD1 +XR72llJbbExYbTzaEV3uw7sJsuwldMC/QL+oWm/Jnwc2WfLTl3HjLOaK9r/smF/E +RtYk5yo7J6pMALrIP7SPHpFooez5JHn2ucP42HcUwOXmrDIOUt6gJQ4w8DBE46Bo +oMKSHK2k0g== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src-tauri/resources/private-key.pem b/src-tauri/resources/private-key.pem new file mode 100644 index 0000000..1456230 --- /dev/null +++ b/src-tauri/resources/private-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCaHrZ9VUL7SKqg +JdeG/dciikuummsrDs4Cn+p01J5mURQ/bq62EU5IiWFsM0LgwkO0UlTGE9gU+U1w +1GeDxlDeVqcwitx+sPjup59ybC2l/iNihETjrLuFUaZVFH/eqdXqNgiRf1fBHV/R +D27BlPN6OPo8Z6qTfuRlVAUbpj+IViIkdQtmymgCJDrQabtnnwpPqZA0MQFnsAvm +elOrWyTX1ASjzFAlWWq7JDvFsrYcqPeMv8QaN/teESFN5pMSNDbvYm2guwcRu4jV +L75hMezqm6StXe5pCbbZOKPHLGqtRUAHnUFHEV1khOEz5HhOsC6m0DvWvKf5QiUv +qcYFYxFZAgMBAAECggEARsXZyV4w3xG0gMw/19aTR2I4dNqmYeRvh9cFpFbK0nNj +F+nswuDZkQe9PCGiEXJEAvdXxInyTVdaT3jKfEHCewdRyUHLFUaRWY6R8spof/Rf +LWtN8zsr9YHUHvfF7GsTN3VOo/nVQ3IIwQkUNEMBN9wYVUrJkufPXBSkL9k9DY7B +uoUghTbpj2nZhSQYRWyAkbc5CcpJzuBDhSE8m2X+0ZMuoW91rOw+G2OLlBwiIOFg +PHPiS0wAMyKycmDnCwm4NDu8BK/I6ucORfFlCyroh63riz/BzJo6FFrzRTd70pHG +2VwAo+58LkRYkJjW7gJZ0XzoAxEKntsIYf8r25jzXQKBgQDHq8BOTDGkEtUPR8PE +ICKUFck3fHRlI39Sv2P2JBoPgGP9zy2xyycV/Uc3+tbNnmkUrTFPIWTQSorb0i4R +fhg/3Jqtm2NUb1lrLo9oEDEqRgCSLbLYO1zLFD42s7dW7DOEr+q/54pcAh/xVrDB +L4CSnuWpkGB5PiuTugaJB8TOAwKBgQDFmUUMosNxofUFE5HNYX3+N0rMNX4XgXG7 ++TS36XJrKo7PQMTnqD5VUr7Iii/1Ncmr/dANSTUzRErkTjm9gbHllakDqy0rTweB +EtskWoN2s45g+i7xocMVNSkLWDd03NzyMM6riArRz2hkWeTSkJLn+AmFm+q+cFHj +yL+6Nx+CcwKBgQCgT4tE0fQBMYWSkSHic5KPprY5MFkbYta1Dyko1G+ABqtBenfL +ibpF82ac0W5pBEiF60/tongYq+C1ARkvvjel/m7J+DpV7liyr11ARc/TiwSmWL6A +0Zh9DDGvJbeLuHTckYk+rp3tpV8UG3AqiwMFtUHbVCnA7mN6Zh8dIfmnFQKBgH0q +66xnZfqTJwxCKze4LAFesQjOUcM+AfeakqR1Qj9URAZQ9unvjxypP6T0tBBWNBu4 +uZPQ7dw9xFr+mmDKyQ+vT9K9Ge23L/+5HAvZMjF86BHSKO5zE4pZlFhVVzu1tFfO +RvwtPv1Mrsnyj5o6bnR2kEGMVJSxvY3W2mxxAoq1AoGAT2sgBDO0CFydMsrxZPno +YYu8LfNefE2KuVFcoLxiseRK/OHOzw7RtSOa0ZW0omXnawwMEje+LavYCO2GerdT +cwJvbfFUqX1F3FqnbyE7vOFkQnzDboLZuw7kY8JeqEdP34CniG1bX4o3Ni2FrAb/ +01/t/macxPNVtcpvKsABzJY= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index b6a08fc..e6d1306 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,28 +1,55 @@ #![cfg_attr( - all(not(debug_assertions), target_os = "windows"), - windows_subsystem = "windows" +all(not(debug_assertions), target_os = "windows"), +windows_subsystem = "windows" )] +use tracing::log::error; +use opener; + mod proxy; -use tauri::{ - command -}; -use opener; +/** + * Application shutdown handler. + */ +async fn shutdown_signal() { + +} fn main() { tauri::Builder::default() - .invoke_handler(tauri::generate_handler![run_program]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .invoke_handler(tauri::generate_handler![run_program]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} + +#[tauri::command] +async fn connect() { + // Create a proxy instance. + let proxy_server = proxy::create_proxy().await; + + // Create the proxy & listen for errors. + let result = proxy_server.start(shutdown_signal()).await; + if result { + error!("Unable to start proxy"); + } + + // Change proxy settings. + proxy::connect_to_proxy(); +} + +#[tauri::command] +fn disconnect() { + // Change proxy settings. + proxy::disconnect_from_proxy(); +} + +#[tauri::command] +fn test() { + println!("test"); } #[tauri::command] fn run_program(path: String) { + // Open the program from the specified path. opener::open(path.clone()); -} - -#[tauri::command] -fn connect() { - } \ No newline at end of file diff --git a/src-tauri/src/proxy.rs b/src-tauri/src/proxy.rs index 4277c09..6092bd8 100644 --- a/src-tauri/src/proxy.rs +++ b/src-tauri/src/proxy.rs @@ -7,15 +7,92 @@ use hudsucker::{ async_trait::async_trait, certificate_authority::RcgenAuthority, hyper::{Body, Request, Response}, - *, + tungstenite::Message, + tungstenite::protocol::WebSocketContext, + http::HttpsConnector, + * }; use std::net::SocketAddr; -use tracing::*; -use tokio_tungstenite::tungstenite::Message; +use hudsucker::hyper::client::HttpConnector; +use registry::{Hive, Data, Security}; +use rustls_pemfile as pemfile; + +#[derive(Clone)] +struct ProxyHandler; + +#[async_trait] +impl HttpHandler for ProxyHandler { + async fn handle_request(&mut self, + context: &HttpContext, + request: Request + ) -> RequestOrResponse { + println!("{:?}", request.uri().path()); + RequestOrResponse::Request(request) + } + + async fn handle_response(&mut self, + context: &HttpContext, + response: Response + ) -> Response { response } +} /** * Starts an HTTP(S) proxy server. */ -async fn start_proxy() { +pub(crate) async fn create_proxy() -> Proxy { + // Get the certificate and private key. + let mut private_key_bytes: &[u8] = include_bytes!("../resources/private-key.pem"); + let mut ca_cert_bytes: &[u8] = include_bytes!("../resources/ca-certificate.pem"); + // Parse the private key and certificate. + let private_key = rustls::PrivateKey( + pemfile::pkcs8_private_keys(&mut private_key_bytes) + .expect("Failed to parse private key") + .remove(0), + ); + + let ca_cert = rustls::Certificate( + pemfile::certs(&mut ca_cert_bytes) + .expect("Failed to parse CA certificate") + .remove(0), + ); + + // Create the certificate authority. + let authority = RcgenAuthority::new(private_key, ca_cert, 1_000) + .expect("Failed to create Certificate Authority"); + + // Create an instance of the proxy. + return ProxyBuilder::new() + .with_addr(SocketAddr::from([127, 0, 0, 1], 8080)) + .with_rustls_client() + .with_ca(authority) + .with_http_handler(ProxyHandler) + .build(); +} + +/** + * Connects to the local HTTP(S) proxy server. + */ +pub(crate) fn connect_to_proxy() { + if cfg!(target_os = "windows") { + // Fetch the 'Internet Settings' registry key. + let settings = Hive::CurrentUser.open(r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", Security::Write); + + // Set registry values. + settings.set_value("ProxyServer", &Data::String("http=127.0.0.1:8080;https=127.0.0.1:8080;ftp=127.0.0.1:8080".parse().unwrap())); + settings.set_value("ProxyEnable", &Data::U32(1)); + } +} + +/** + * Disconnects from the local HTTP(S) proxy server. + */ +pub(crate) fn disconnect_from_proxy() { + if cfg!(target_os = "windows") { + // Fetch the 'Internet Settings' registry key. + let settings = Hive::CurrentUser.open(r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", Security::Write); + + // Set registry values. + settings.set_value("ProxyEnable", &Data::U32(0)); + } } \ No newline at end of file