modified: Cargo.lock

modified:   Cargo.toml
	modified:   src/main.rs
	modified:   src/tor.rs
This commit is contained in:
Michael Wain 2025-03-10 02:10:53 +03:00
parent dc9e45cefc
commit df69b9de10
4 changed files with 47 additions and 37 deletions

1
Cargo.lock generated
View File

@ -25,6 +25,7 @@ dependencies = [
"tor-cell", "tor-cell",
"tor-hsservice", "tor-hsservice",
"tor-proto", "tor-proto",
"tor-rtcompat",
"tower-service", "tower-service",
] ]

View File

@ -16,6 +16,7 @@ tor-cell = "0.28.0"
tor-hsservice = "0.28.0" tor-hsservice = "0.28.0"
tor-proto = { version = "0.28.0", features = ["hs-service", "tokio"] } tor-proto = { version = "0.28.0", features = ["hs-service", "tokio"] }
arti-client = { version = "0.28.0", features = ["tokio", "onion-service-service", "onion-service-client"]} arti-client = { version = "0.28.0", features = ["tokio", "onion-service-service", "onion-service-client"]}
tor-rtcompat = "0.28.0"
futures = "0.3" futures = "0.3"
axum = { version = "0.8.1", features = ["macros"] } axum = { version = "0.8.1", features = ["macros"] }
futures-util = "0.3.30" futures-util = "0.3.30"

View File

@ -9,7 +9,7 @@ mod tor;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
Builder::new() Builder::new()
.filter(None, LevelFilter::Debug) .filter(None, LevelFilter::Info)
.init(); .init();
/* let config = TorClientConfig::default(); /* let config = TorClientConfig::default();

View File

@ -1,6 +1,7 @@
use std::{error::Error, net::TcpListener, time::Duration}; use std::{error::Error, net::TcpListener, time::Duration};
use arti_client::{config::BoolOrAuto, StreamPrefs, TorClient, TorClientConfig}; use arti_client::{config::BoolOrAuto, StreamPrefs, TorClient, TorClientConfig};
use axum::body::Bytes;
use futures::{AsyncReadExt, Stream, StreamExt}; use futures::{AsyncReadExt, Stream, StreamExt};
use log::{error, info}; use log::{error, info};
use tor_hsservice::config::OnionServiceConfigBuilder; use tor_hsservice::config::OnionServiceConfigBuilder;
@ -13,13 +14,14 @@ use axum::{
use axum::routing; use axum::routing;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use futures::io::AsyncWriteExt; use futures::io::AsyncWriteExt;
use tor_rtcompat::PreferredRuntime;
use crate::tor_axum; use crate::tor_axum;
#[debug_handler] #[debug_handler]
async fn test_connection_to_tor(Json(payload): Json<SimpleMessage>) -> (StatusCode, Json<SimpleMessage>) { async fn test_connection_to_tor(payload: Bytes) -> (StatusCode, String) {
info!("Got interesting payload! {}", payload.msg); info!("Got interesting payload! {:#?}", payload);
(StatusCode::OK, Json(SimpleMessage{ msg: "World is hell indeed!".to_string() })) (StatusCode::OK, "World is hell indeed!".to_string())
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -27,6 +29,41 @@ struct SimpleMessage {
msg: String msg: String
} }
struct OnionHttpClient {
tor_client: TorClient<PreferredRuntime>
}
impl OnionHttpClient {
pub async fn request(&self, path: &str, onion_name: String, data: Vec<u8>) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let mut stream_prefs = StreamPrefs::new();
stream_prefs.connect_to_onion_services(BoolOrAuto::Explicit(true));
let mut stream = self.tor_client.connect_with_prefs((onion_name.clone(), 80), &stream_prefs).await?;
let host = onion_name;
// Construct the HTTP request manually
let request = format!(
"POST {} HTTP/1.1\r\nHost: {}\r\nContent-Type: application/octet-stream\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
path, host, data.len()
).as_bytes().to_vec();
let request = [request, data].concat();
stream.write_all(&request).await?;
// Flushing the stream is important; see below!
let _ = stream.flush().await;
let mut buf = [0; 4096];
let n = stream.read(&mut buf).await?;
Ok(String::from_utf8(buf[..n].to_vec()).unwrap())
}
}
pub async fn new_client() -> Result<OnionHttpClient, Box<dyn Error + Send + Sync>> {
let tor_client = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
Ok(OnionHttpClient { tor_client })
}
pub async fn start() -> Result<(), Box<dyn Error>> { pub async fn start() -> Result<(), Box<dyn Error>> {
let tor_client = TorClient::create_bootstrapped(TorClientConfig::default()).await?; let tor_client = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
@ -43,41 +80,12 @@ pub async fn start() -> Result<(), Box<dyn Error>> {
println!("serving at: http://{}", onion_service.onion_name().unwrap()); println!("serving at: http://{}", onion_service.onion_name().unwrap());
let onion_name = onion_service.onion_name().unwrap(); let onion_name = onion_service.onion_name().unwrap();
tokio::spawn(async move { tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(40)).await; tokio::time::sleep(Duration::from_secs(40)).await;
if let Ok(client) = new_client().await {
let mut stream_prefs = StreamPrefs::new(); client.request("/", onion_name.to_string(), [1, 2, 2, 4, 8].to_vec()).await;
stream_prefs.connect_to_onion_services(BoolOrAuto::Explicit(true)); } else {
error!("Error creating new client!");
match tor_client.connect_with_prefs((onion_name.to_string(), 80), &stream_prefs).await {
Ok(mut stream) => {
let host = onion_name.to_string();
let path = "/";
// Construct the HTTP GET request manually
let request = format!(
"POST {} HTTP/1.1\r\nHost: {}\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{}",
path, host, serde_json::to_string(&SimpleMessage { msg: "is world hell?".to_string()}).unwrap()
);
if let Ok(a) = stream
.write_all(request.as_bytes())
.await {
let _ = stream.flush().await;
let mut buf = [0; 4096];
if let Ok(n) = stream.read(&mut buf).await {
info!("Got response!!! {}", String::from_utf8(buf[..n].to_vec()).unwrap());
} else {
error!("No response!!!");
}
// Flushing the stream is important; see below!
} else {
error!("GO NO MONEY");
}
}
Err(err) => error!("Error: {}", err)
} }
}); });