From 6da441fe35ecb86f89e45cbd3f74bcb7915df1ce Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Thu, 16 Apr 2026 21:11:48 +0200 Subject: [PATCH] [Add] TXT record loading --- Cargo.lock | 210 ++++++++++++++++++++++++++++++++--- Cargo.toml | 1 + src/rho/client_connection.rs | 31 ++++++ src/rho/connection.rs | 182 ++++++++++++++++++++++++------ src/rho/iota_connection.rs | 2 +- 5 files changed, 379 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba102a2..0c8a6fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "dotenv", "futures", "hex", + "hickory-resolver", "hkdf", "livekit-api", "livekit-protocol", @@ -264,6 +265,17 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-tungstenite" version = "0.25.1" @@ -485,6 +497,30 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -725,6 +761,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1080,6 +1128,52 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.4", + "ring", + "thiserror 2.0.18", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.4", + "resolv-conf", + "smallvec", + "thiserror 2.0.18", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -1343,6 +1437,19 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ipconfig" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" +dependencies = [ + "socket2 0.6.3", + "widestring", + "windows-registry", + "windows-result", + "windows-sys 0.61.2", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -1452,9 +1559,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libm" @@ -1490,7 +1597,7 @@ dependencies = [ "parking_lot", "pbjson-types", "prost", - "rand 0.9.3", + "rand 0.9.4", "reqwest", "scopeguard", "serde", @@ -1575,6 +1682,23 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "moka" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + [[package]] name = "multimap" version = "0.10.1" @@ -1861,6 +1985,10 @@ name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "opaque-debug" @@ -1870,9 +1998,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.76" +version = "0.10.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +checksum = "bfe4646e360ec77dff7dde40ed3d6c5fee52d156ef4a62f53973d38294dad87f" dependencies = [ "bitflags", "cfg-if", @@ -1902,9 +2030,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.112" +version = "0.9.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +checksum = "ad2f2c0eba47118757e4c6d2bff2838f3e0523380021356e7875e858372ce644" dependencies = [ "cc", "libc", @@ -2129,6 +2257,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + [[package]] name = "potential_utf" version = "0.1.5" @@ -2264,7 +2398,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.3", + "rand 0.9.4", "ring", "rustc-hash", "rustls", @@ -2324,9 +2458,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -2463,6 +2597,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "resolv-conf" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" + [[package]] name = "rfc6979" version = "0.4.0" @@ -2546,9 +2686,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "aws-lc-rs", "log", @@ -2876,6 +3016,12 @@ dependencies = [ "syn", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tempfile" version = "3.27.0" @@ -3133,11 +3279,12 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttp-core" version = "0.1.0" -source = "git+https://git.methanium.net/Tensamin/TTP.git#ff16a5a502ef9886104e1d1d08c22b0ad78e31ce" +source = "git+https://git.methanium.net/Tensamin/TTP.git#0d41631c99501cba52dc1664621756e674a67e96" dependencies = [ "base64 0.22.1", "byteorder", "rand 0.8.5", + "serde_json", "strum", "strum_macros", ] @@ -3145,7 +3292,7 @@ dependencies = [ [[package]] name = "ttp-native" version = "0.1.0" -source = "git+https://git.methanium.net/Tensamin/TTP.git#ff16a5a502ef9886104e1d1d08c22b0ad78e31ce" +source = "git+https://git.methanium.net/Tensamin/TTP.git#0d41631c99501cba52dc1664621756e674a67e96" dependencies = [ "quinn", "rustls", @@ -3431,6 +3578,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + [[package]] name = "winapi" version = "0.3.9" @@ -3459,6 +3612,35 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index c07b798..44c1019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,4 @@ strum_macros = "0.28.0" livekit-api = { version = "0.4.14", features = ["native-tls"] } livekit-protocol = "0.7.1" thiserror = "2.0.18" +hickory-resolver = "0.25.2" diff --git a/src/rho/client_connection.rs b/src/rho/client_connection.rs index 2e9b49c..d442ed7 100644 --- a/src/rho/client_connection.rs +++ b/src/rho/client_connection.rs @@ -133,6 +133,10 @@ impl ClientConnection { self.handle_call_set_anonymous_joining(cv).await; return; } + if cv.is_type(CommunicationType::load_txt_record) { + self.handle_load_txt_record(cv).await; + return; + } if cv.is_type(CommunicationType::get_user_data) { if let Some(anonymous) = { if let Some(user_id) = cv.get_data(DataTypes::user_id).as_number() { @@ -404,6 +408,33 @@ impl ClientConnection { self.send_message(&response_cv).await; } + async fn handle_load_txt_record(self: Arc, cv: CommunicationValue) { + if let Some(path) = cv.get_data(DataTypes::path).as_str() { + if let Ok(builder) = hickory_resolver::Resolver::builder_tokio() { + let resolver = builder.build(); + if let Ok(lookup) = resolver.txt_lookup(path).await { + for record in lookup.iter() { + for txt_data in record.txt_data() { + if let Ok(s) = std::str::from_utf8(txt_data) { + let response = + CommunicationValue::new(CommunicationType::load_txt_record) + .with_id(cv.get_id()) + .add_data( + DataTypes::content, + DataValue::Str(s.to_string()), + ); + self.send_message(&response).await; + return; + } + } + } + } + } + } + self.send_error_response(cv.get_id(), CommunicationType::error) + .await; + } + /// Forward message to Iota async fn forward_to_iota(self: Arc, cv: CommunicationValue) { let sender_user_id = self.get_user_id().await; diff --git a/src/rho/connection.rs b/src/rho/connection.rs index ff03450..0b8a0f6 100755 --- a/src/rho/connection.rs +++ b/src/rho/connection.rs @@ -1,7 +1,7 @@ use rand::{Rng, distributions::Alphanumeric}; use std::{sync::Arc, time::Duration}; use tokio::sync::RwLock; -use ttp_core::{CommunicationType, CommunicationValue, DataTypes, DataValue, util::rand_u64}; +use ttp_core::{CommunicationType, CommunicationValue, DataTypes, DataValue}; use ttp_native::{Receiver, Sender}; use uuid::Uuid; @@ -10,8 +10,8 @@ use crate::{ get_private_key, get_public_key, log_cv_in, log_cv_out, log_err, log_in, log_out, omega::omega_connection::get_omega_connection, rho::{ - client_connection::ClientConnection, iota_connection::IotaConnection, - rho_connection::RhoConnection, rho_manager, + app_connection::AppConnection, client_connection::ClientConnection, + iota_connection::IotaConnection, rho_connection::RhoConnection, rho_manager, }, util::{ crypto_helper::{load_public_key, public_key_to_base64}, @@ -70,14 +70,7 @@ impl GeneralConnection { pub async fn handle(self: Arc) { log_in!(0, PrintType::General, "General connection handler started"); - loop { - let cv = match self.receiver.receive().await { - Ok(v) => v, - Err(_) => { - break; - } - }; - + while let Ok(cv) = self.receiver.receive().await { log_cv_in!(cv); if !*self.identified.read().await { @@ -128,6 +121,60 @@ impl GeneralConnection { return; } + if cv.is_type(CommunicationType::app_identification) { + let app_identifier = cv + .get_data(DataTypes::app_identifier) + .as_str() + .unwrap_or("") + .to_string(); + let app_session_id_str = cv.get_data(DataTypes::app_session).as_str().unwrap_or(""); + let app_session_id = Uuid::parse_str(app_session_id_str).unwrap_or(Uuid::new_v4()); + let pub_key_str = cv + .get_data(DataTypes::app_public_key) + .as_str() + .unwrap_or(""); + let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0); + + *self.id.write().await = user_id as u64; + *self.app_identifier.write().await = Some(app_identifier); + *self.app_session.write().await = Some(app_session_id); + *self.connection_kind.write().await = Some(ConnectionKind::Phi); + + let pub_key = match load_public_key(pub_key_str) { + Some(pk) => pk, + None => return, + }; + *self.pub_key.write().await = Some(pub_key.as_bytes().to_vec()); + + let challenge: String = rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect(); + + *self.challenge.write().await = challenge.clone(); + *self.identified.write().await = true; + + let encrypted_challenge = + SecurePayload::new(challenge.as_bytes(), DataFormat::Raw, get_private_key()) + .unwrap() + .encrypt_x448(pub_key) + .unwrap() + .export(DataFormat::Base64); + + let response = CommunicationValue::new(CommunicationType::app_challange) + .with_id(cv.get_id()) + .add_data( + DataTypes::public_key, + DataValue::Str(public_key_to_base64(&get_public_key())), + ) + .add_data(DataTypes::challenge, DataValue::Str(encrypted_challenge)); + + log_cv_out!(response); + let _ = self.sender.send(&response).await; + return; + } + if !cv.is_type(CommunicationType::identification) { return; } @@ -194,30 +241,53 @@ impl GeneralConnection { *self.id.write().await = *user_id as u64; *self.session_id.write().await = match cv.get_data(DataTypes::session_id) { DataValue::Number(s) => *s as u64, - _ => rand_u64(), + _ => cv.get_sender(), }; - *self.connection_kind.write().await = Some(ConnectionKind::Client); - let get_pub_key_msg = CommunicationValue::new(CommunicationType::get_user_data) - .add_data(DataTypes::user_id, DataValue::Number(*user_id)); + let mut base64_pub = String::new(); - let response_cv = get_omega_connection() - .await_response(&get_pub_key_msg, Some(Duration::from_secs(20))) - .await; + if cv.is_type(CommunicationType::app_identification) { + *self.connection_kind.write().await = Some(ConnectionKind::Phi); - let response_cv = match response_cv { - Ok(r) => r, - Err(_) => { - return; + if let DataValue::Str(app_id) = cv.get_data(DataTypes::app_identifier) { + *self.app_identifier.write().await = Some(app_id.clone()); + } + if let DataValue::Str(app_sess) = cv.get_data(DataTypes::app_session) { + if let Ok(uuid) = uuid::Uuid::parse_str(&app_sess) { + *self.app_session.write().await = Some(uuid); + } } - }; - let base64_pub = response_cv - .get_data(DataTypes::public_key) - .as_str() - .unwrap_or(""); + base64_pub = cv + .get_data(DataTypes::app_public_key) + .as_str() + .unwrap_or("") + .to_string(); + } else { + *self.connection_kind.write().await = Some(ConnectionKind::Client); - let pub_key = match load_public_key(base64_pub) { + let get_pub_key_msg = CommunicationValue::new(CommunicationType::get_user_data) + .add_data(DataTypes::user_id, DataValue::Number(*user_id)); + + let response_cv = get_omega_connection() + .await_response(&get_pub_key_msg, Some(Duration::from_secs(20))) + .await; + + let response_cv = match response_cv { + Ok(r) => r, + Err(_) => { + return; + } + }; + + base64_pub = response_cv + .get_data(DataTypes::public_key) + .as_str() + .unwrap_or("") + .to_string(); + } + + let pub_key = match load_public_key(&base64_pub) { Some(pk) => pk, None => { return; @@ -242,8 +312,15 @@ impl GeneralConnection { .unwrap() .export(DataFormat::Base64); - let response = CommunicationValue::new(CommunicationType::challenge) + let challenge_type = if cv.is_type(CommunicationType::app_identification) { + CommunicationType::app_challange + } else { + CommunicationType::challenge + }; + + let response = CommunicationValue::new(challenge_type) .with_id(cv.get_id()) + .with_receiver(*self.session_id.read().await) .add_data( DataTypes::public_key, DataValue::Str(public_key_to_base64(&get_public_key())), @@ -257,7 +334,9 @@ impl GeneralConnection { async fn handle_challenge_response(self: &Arc, cv: CommunicationValue) { let id = *self.id.read().await as i64; - if !cv.is_type(CommunicationType::challenge_response) { + if !cv.is_type(CommunicationType::challenge_response) + && !cv.is_type(CommunicationType::app_challange_response) + { return; } @@ -402,8 +481,47 @@ impl GeneralConnection { client.start(); } ConnectionKind::Phi => { - let phi = ClientConnection::from_general(self.clone(), id).await; - phi.start(); + let user_id = id as i64; + let mut rho = rho_manager::get_rho_con_for_user(user_id).await; + + if rho.is_none() { + let get_user_msg = CommunicationValue::new(CommunicationType::get_user_data) + .add_data(DataTypes::user_id, DataValue::Number(user_id)); + + if let Ok(user_data_cv) = get_omega_connection() + .await_response(&get_user_msg, Some(Duration::from_secs(20))) + .await + { + if let DataValue::Number(iota_id) = + user_data_cv.get_data(DataTypes::iota_id) + { + if let Some(bound_rho) = + rho_manager::bind_user_to_iota(user_id, *iota_id).await + { + bound_rho.bind_user_id(user_id).await; + rho = Some(bound_rho); + } + } + } + } + + *self.rho_connection.write().await = rho.clone(); + + let app_conn = AppConnection::from_general(self.clone(), id).await; + + if let Some(rho_conn) = rho { + rho_conn.bind_user_id(user_id).await; + rho_conn.add_app_connection(app_conn.clone()).await; + } + + let response = + CommunicationValue::new(CommunicationType::app_identification_response) + .with_id(*self.challenge_cv_id.read().await) + .with_receiver(*self.session_id.read().await); + + let _ = self.sender.send(&response).await; + + app_conn.start(); } } true diff --git a/src/rho/iota_connection.rs b/src/rho/iota_connection.rs index 30363b8..6e899ed 100755 --- a/src/rho/iota_connection.rs +++ b/src/rho/iota_connection.rs @@ -197,7 +197,7 @@ impl IotaConnection { if let Ok(response_cv) = response_cv { if response_cv.is_type(CommunicationType::success) { if let Some(user_id) = cv.get_data(DataTypes::user_id).as_number() { - self.add_user_id(user_id as u64); + self.add_user_id(user_id as u64).await; } } self.send_message(&response_cv).await;