From 8c5346563b2de344b00b8041eaa1fda1ce087210 Mon Sep 17 00:00:00 2001 From: M Alghazwi Date: Tue, 28 Oct 2025 09:24:30 +0300 Subject: [PATCH] impl get-request tests --- Cargo.toml | 8 ++++++ src/get_request_tests.rs | 46 ++++++++++++++++++++++++++++++ src/lib.rs | 17 ++--------- src/tor_client_builder.rs | 31 ++++++++++++++++++++ src/ureq_builder.rs | 60 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 src/get_request_tests.rs create mode 100644 src/tor_client_builder.rs create mode 100644 src/ureq_builder.rs diff --git a/Cargo.toml b/Cargo.toml index edbcc53..9565bf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,14 @@ [package] name = "tor-experiments" +authors = ["M.A. Alghazwi."] version = "0.1.0" edition = "2024" +license = "MIT OR Apache-2.0" +keywords = ["tor", "privacy", "anonymity"] [dependencies] +anyhow = "1.0.75" +arti-client = { version = "0.35", features = ["full"] } +arti-ureq = "0.35" +tor-circmgr = "0.35" +tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util"] } diff --git a/src/get_request_tests.rs b/src/get_request_tests.rs new file mode 100644 index 0000000..abdeefe --- /dev/null +++ b/src/get_request_tests.rs @@ -0,0 +1,46 @@ +#[cfg(test)] +mod tests { + use anyhow::Result; + use crate::ureq_builder::*; + use arti_ureq::ureq::Agent; + use crate::tor_client_builder::{choose_tls_provider, make_tor_client}; + const TEST_URL: &str = "https://check.torproject.org/api/ip"; + const TEST_ONION: &str = "http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion"; + + /// Builds all components + fn builds_ureq_agent() -> Result { + let tls = choose_tls_provider(); + let tor = make_tor_client()?; + let connector = make_connector(tor, tls)?; + let agent = make_ureq_agent(connector, tls)?; + Ok(agent) + } + + /// Test: send get request to url over Tor. + /// This test may take a little while on the first run + #[test] + fn fetches_url_over_tor() -> Result<()> { + let agent = builds_ureq_agent()?; + + let body = fetch_with_agent(&agent, TEST_URL)?; + //sanity check: + assert!(!body.trim().is_empty(), "empty body from {}", TEST_URL); + Ok(()) + } + + // /// Test: send get request to .onion over Tor. + // /// This test may take a little while on the first run + // #[test] + // fn fetches_onion_over_tor() -> Result<()> { + // let tls = choose_tls_provider(); + // let tor = make_tor_client()?; + // let connector = make_connector(tor, tls)?; + // let agent = make_ureq_agent(connector, tls)?; + // + // let body = fetch_with_agent(&agent, TEST_ONION)?; + // //sanity check: + // assert!(!body.trim().is_empty(), "empty body from {}", TEST_ONION); + // eprintln!("Response: {}", body); + // Ok(()) + // } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b93cf3f..35a9b05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,3 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +pub mod ureq_builder; +pub mod get_request_tests; +pub mod tor_client_builder; \ No newline at end of file diff --git a/src/tor_client_builder.rs b/src/tor_client_builder.rs new file mode 100644 index 0000000..dcaf788 --- /dev/null +++ b/src/tor_client_builder.rs @@ -0,0 +1,31 @@ +use anyhow::Context; +use arti_ureq::ureq; + +/// Create a Tor client +pub fn make_tor_client() -> anyhow::Result> { + let rt = arti_ureq::tor_rtcompat::PreferredRuntime::create() + .context("Failed to create runtime.")?; + + let tor_client = arti_client::TorClient::with_runtime(rt) + .config(make_tor_client_config()) + .create_unbootstrapped() + .context("Error creating Tor Client.")?; + + // let tor_client = arti_client::TorClient::builder() + // .bootstrap_behavior(BootstrapBehavior::OnDemand) + // .create_unbootstrapped()?; + + Ok(tor_client) +} + +/// Build a default Tor client config. +/// For our purposes, we can use the default now. +pub fn make_tor_client_config() -> arti_client::config::TorClientConfig { + let config = arti_client::config::TorClientConfig::default(); + config +} + +/// returns TLS provider to use, default for now +pub fn choose_tls_provider() -> ureq::tls::TlsProvider { + arti_ureq::get_default_tls_provider() +} diff --git a/src/ureq_builder.rs b/src/ureq_builder.rs new file mode 100644 index 0000000..90ffe69 --- /dev/null +++ b/src/ureq_builder.rs @@ -0,0 +1,60 @@ +use anyhow::{Context, Result}; +use arti_ureq::ureq; +use arti_ureq::ureq::tls::RootCerts; + +/// Build a Connector from the Tor client and chosen TLS provider. +/// This is a ureq connector, and here we are giving it out already created tor client + tls +pub fn make_connector( + tor_client: arti_client::TorClient, + tls_provider: ureq::tls::TlsProvider, +) -> Result> { + let builder = arti_ureq::Connector::::builder() + .context("Failed to create ConnectorBuilder")? + .tor_client(tor_client) + .tls_provider(tls_provider); + + Ok(builder.build().context("Failed to build Connector")?) +} + +/// Build a `ureq::Agent` +pub fn make_ureq_agent( + connector: arti_ureq::Connector, + tls_provider: ureq::tls::TlsProvider, +) -> Result { + // Build ureq TLS config + let ureq_tls_config = ureq::tls::TlsConfig::builder() + .root_certs(RootCerts::PlatformVerifier) + .provider(tls_provider) + .build(); + + // Build ureq config. + let ureq_config = ureq::config::Config::builder() + .user_agent("arti-ureq-custom-user-agent") + .tls_config(ureq_tls_config) + .build(); + + connector + .agent_with_ureq_config(ureq_config) + .context("Failed to create ureq agent.") +} + +/// Fetch a URL via the provided ureq agent, returning the body as String. +pub fn fetch_with_agent(agent: &ureq::Agent, url: &str) -> Result { + println!("[+] Making request to: {}", url); + + let mut request = agent + .get(url) + .call() + .context("Failed to make request.")?; + + println!("[+] Response status: {}", request.status()); + + let response = request + .body_mut() + .read_to_string() + .context("Failed to read body.")?; + + println!("Response: {response}"); + + Ok(response) +} \ No newline at end of file