[Updt] Mtp 0.3.0
This commit is contained in:
parent
e1dd86ec02
commit
ad8555bc6e
45 changed files with 2019 additions and 1441 deletions
|
|
@ -5,23 +5,11 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
mtp = { git = "https://git.methanium.net/Methanium/mtp.git" }
|
||||
iota-logger = { path = "../iota-logger" }
|
||||
iota-util = { path = "../iota-util" }
|
||||
iota-storage = { path = "../iota-storage" }
|
||||
iota-state = { path = "../iota-state" }
|
||||
iota-auth = { path = "../iota-auth" }
|
||||
|
||||
actix-web = { version = "4", features = ["rustls-0_23"] }
|
||||
actix-web-actors = "4"
|
||||
aes-gcm = "0.10.3"
|
||||
async-trait = "0.1.89"
|
||||
base64 = "0.22.1"
|
||||
chrono = "0.4.43"
|
||||
crossterm = "*"
|
||||
dashmap = "6.1.0"
|
||||
futures = "*"
|
||||
futures-util = "*"
|
||||
hex = "*"
|
||||
hkdf = "0.12.4"
|
||||
hyper = { version = "1.8.1", features = [
|
||||
"capi",
|
||||
|
|
@ -34,27 +22,12 @@ hyper = { version = "1.8.1", features = [
|
|||
] }
|
||||
hyper-util = { version = "*" }
|
||||
json = "*"
|
||||
lazy_static = "1.5.0"
|
||||
once_cell = "1.21.3"
|
||||
open = "5.3.3"
|
||||
pnet = "0.35.0"
|
||||
rand = "0.8"
|
||||
rand_core = { version = "0.6", features = ["getrandom", "std"] }
|
||||
ratatui = "0.30.0"
|
||||
reqwest = "0.13.2"
|
||||
rusqlite = "0.40.0"
|
||||
rustls = { version = "0.23.37", features = ["aws-lc-rs"] }
|
||||
rustls-pemfile = "2.2.0"
|
||||
serde_json = "1.0.149"
|
||||
sha2 = "0.11.0"
|
||||
strum = "0.28.0"
|
||||
strum_macros = "0.28.0"
|
||||
sysinfo = "0.39.0"
|
||||
tokio = { version = "1.50.0", features = ["full"] }
|
||||
tokio-tungstenite = { version = "*", features = ["native-tls"] }
|
||||
tungstenite = "*"
|
||||
uuid = { version = "*", features = ["v4"] }
|
||||
walkdir = "2.5.0"
|
||||
warp = "*"
|
||||
x448 = { version = "*" }
|
||||
zip = "6.0.0"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use crate::auth::auth_user::AuthUser;
|
|||
use crate::communities::community::Community;
|
||||
use crate::communities::interactables::interactable::Interactable;
|
||||
use crate::users::user_manager::get_user;
|
||||
use iota_util::mtp_compat::CommunicationValueCompat;
|
||||
use aes_gcm::{Aes256Gcm, KeyInit, Nonce, aead::Aead};
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||
use futures::SinkExt;
|
||||
|
|
@ -22,6 +21,20 @@ use tungstenite::Message;
|
|||
use tungstenite::Utf8Bytes;
|
||||
use uuid::Uuid;
|
||||
use x448::PublicKey;
|
||||
|
||||
trait CommunicationResponseExt {
|
||||
fn with_request_id(self, request: &CommunicationValue) -> Self;
|
||||
}
|
||||
|
||||
impl CommunicationResponseExt for CommunicationValue {
|
||||
fn with_request_id(mut self, request: &CommunicationValue) -> Self {
|
||||
self = self.without_id();
|
||||
if let Some(id) = request.id() {
|
||||
self = self.with_id(id);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
pub struct CommunityConnection {
|
||||
pub sender: Arc<RwLock<SplitSink<WebSocketStream<TokioIo<Upgraded>>, Message>>>,
|
||||
pub receiver: Arc<RwLock<SplitStream<WebSocketStream<TokioIo<Upgraded>>>>>,
|
||||
|
|
@ -115,7 +128,7 @@ impl CommunityConnection {
|
|||
.unwrap_or(0);
|
||||
|
||||
let Some(user) = get_user(user_id) else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidUserId)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidUserId)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
|
@ -145,7 +158,7 @@ impl CommunityConnection {
|
|||
let user_public_key_bytes = match STANDARD.decode(&user.public_key) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidUserId)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidUserId)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -154,14 +167,14 @@ impl CommunityConnection {
|
|||
let user_pub_key: PublicKey = match PublicKey::from_bytes(&user_public_key_bytes) {
|
||||
Some(key) => key,
|
||||
__ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidUserId)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidUserId)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let Some(community) = self.community.read().await.clone() else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
|
@ -172,7 +185,7 @@ impl CommunityConnection {
|
|||
let shared_secret = match community_private_key.to_diffie_hellman(&user_pub_key) {
|
||||
Some(secret) => secret,
|
||||
_ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -194,7 +207,7 @@ impl CommunityConnection {
|
|||
let encrypted_challenge = match cipher.encrypt(nonce, challenge_str.as_bytes()) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -209,7 +222,7 @@ impl CommunityConnection {
|
|||
STANDARD.encode(community_public_key.as_bytes()),
|
||||
)
|
||||
.add_data_str(DataType::Challenge, STANDARD.encode(&encrypted_out))
|
||||
.with_id(cv.get_id());
|
||||
.with_request_id(&cv);
|
||||
|
||||
self.send_message(&response).await;
|
||||
}
|
||||
|
|
@ -217,7 +230,7 @@ impl CommunityConnection {
|
|||
let client_challenge_response_b64 = match cv.get_data(DataType::Challenge) {
|
||||
Some(data) => data.to_string(),
|
||||
_ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidData)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidData)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -226,38 +239,38 @@ impl CommunityConnection {
|
|||
let challenge_response_bytes = match STANDARD.decode(&client_challenge_response_b64) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidData)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidData)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if challenge_response_bytes.len() < 12 {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidData)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidData)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(user) = self.auth.read().await.clone() else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(user_pub_bytes) = STANDARD.decode(&user.public_key).ok() else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidData)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidData)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(user_pub_key) = PublicKey::from_bytes(&user_pub_bytes) else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidPublicKey)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidPublicKey)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(community) = self.community.read().await.clone() else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
|
@ -267,7 +280,7 @@ impl CommunityConnection {
|
|||
let shared_secret = match community_private_key.to_diffie_hellman(&user_pub_key) {
|
||||
Some(secret) => secret,
|
||||
_ => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -291,7 +304,7 @@ impl CommunityConnection {
|
|||
let decrypted_bytes = match cipher.decrypt(nonce, ciphertext) {
|
||||
Ok(pt) => pt,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidChallenge)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidChallenge)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -300,7 +313,7 @@ impl CommunityConnection {
|
|||
let client_response = match String::from_utf8(decrypted_bytes) {
|
||||
Ok(str) => str,
|
||||
Err(_) => {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidData)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidData)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -309,7 +322,7 @@ impl CommunityConnection {
|
|||
let expected_challenge = self.challenge.read().await.clone();
|
||||
|
||||
if client_response != expected_challenge {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidChallenge)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidChallenge)
|
||||
.await;
|
||||
self.close().await;
|
||||
return;
|
||||
|
|
@ -321,7 +334,7 @@ impl CommunityConnection {
|
|||
}
|
||||
|
||||
let Some(community) = self.community.read().await.clone() else {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInternal)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInternal)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
|
@ -329,7 +342,7 @@ impl CommunityConnection {
|
|||
|
||||
let user_id = self.get_user_id().await;
|
||||
if user_id == 0 {
|
||||
self.send_error_response(&cv.get_id(), CommunicationType::ErrorInvalidUserId)
|
||||
self.send_error_response(&cv, CommunicationType::ErrorInvalidUserId)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
|
@ -348,13 +361,17 @@ impl CommunityConnection {
|
|||
}
|
||||
c
|
||||
})
|
||||
.with_id(cv.get_id());
|
||||
.with_request_id(&cv);
|
||||
|
||||
self.send_message(&response).await;
|
||||
}
|
||||
|
||||
async fn send_error_response(&self, message_id: &Uuid, error_type: CommunicationType) {
|
||||
let error = CommunicationValue::new(error_type).with_id(*message_id);
|
||||
async fn send_error_response(
|
||||
&self,
|
||||
request: &CommunicationValue,
|
||||
error_type: CommunicationType,
|
||||
) {
|
||||
let error = CommunicationValue::new(error_type).with_request_id(request);
|
||||
self.send_message(&error).await;
|
||||
}
|
||||
pub async fn close(&self) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
};
|
||||
use async_trait::async_trait;
|
||||
use json::{JsonValue, array, object};
|
||||
use iota_util::mtp_compat::{CommunicationValueCompat, OptionalDataValueExt};
|
||||
use iota_util::mtp_compat::{OptionalDataValueExt, RequiredCommunicationFields};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -31,6 +31,10 @@ impl TextChat {
|
|||
}
|
||||
}
|
||||
pub fn add_message(&self, send_time: u128, sender: i64, message: &str) {
|
||||
let Ok(send_time) = i64::try_from(send_time) else {
|
||||
log!("Message timestamp exceeds local storage range");
|
||||
return;
|
||||
};
|
||||
let user_dir = &format!(
|
||||
"communities/{}/interactables/{}/{}",
|
||||
self.get_community().get_name(),
|
||||
|
|
@ -74,7 +78,7 @@ impl TextChat {
|
|||
}
|
||||
|
||||
let json_obj = object! {
|
||||
"timestamp" => send_time as i64,
|
||||
"timestamp" => send_time,
|
||||
"content" => message,
|
||||
"sender" => sender.to_string(),
|
||||
};
|
||||
|
|
@ -202,7 +206,7 @@ impl Interactable for TextChat {
|
|||
let mut payload = JsonValue::new_object();
|
||||
payload["messages"] = messages;
|
||||
return CommunicationValue::new(CommunicationType::Function)
|
||||
.with_id(cv.get_id())
|
||||
.with_request_id(&cv)
|
||||
.add_data_str(DataType::Name, self.name.clone())
|
||||
.add_data_str(DataType::Path, self.path.clone())
|
||||
.add_data_str(DataType::Result, "message_chunk".to_string())
|
||||
|
|
@ -210,19 +214,28 @@ impl Interactable for TextChat {
|
|||
}
|
||||
if cv.get_data(DataType::Function).unwrap().as_str().unwrap() == "send_message" {
|
||||
let message = payload["message"].as_str().unwrap();
|
||||
let sender = match cv.require_sender() {
|
||||
Ok(sender) => sender,
|
||||
Err(_) => return CommunicationValue::new(CommunicationType::ErrorInvalidData)
|
||||
.with_request_id(&cv),
|
||||
};
|
||||
let milliseconds_timestamp: u128 = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis();
|
||||
self.add_message(milliseconds_timestamp, cv.get_sender(), message);
|
||||
let Ok(sender) = i64::try_from(sender) else {
|
||||
return CommunicationValue::new(CommunicationType::ErrorInvalidData)
|
||||
.with_request_id(&cv);
|
||||
};
|
||||
self.add_message(milliseconds_timestamp, sender, message);
|
||||
|
||||
let mut distribution_payload = JsonValue::new_object();
|
||||
distribution_payload["message"] = JsonValue::String(message.to_string());
|
||||
distribution_payload["sender_id"] = JsonValue::String(cv.get_sender().to_string());
|
||||
distribution_payload["sender_id"] = JsonValue::String(sender.to_string());
|
||||
distribution_payload["send_time"] =
|
||||
JsonValue::String(milliseconds_timestamp.to_string());
|
||||
let distribution = CommunicationValue::new(CommunicationType::Update)
|
||||
.with_id(cv.get_id())
|
||||
.with_request_id(&cv)
|
||||
.add_data_str(DataType::Name, self.name.clone())
|
||||
.add_data_str(DataType::Path, self.path.clone())
|
||||
.add_data_str(DataType::Result, "message_live".to_string())
|
||||
|
|
@ -238,13 +251,13 @@ impl Interactable for TextChat {
|
|||
}
|
||||
}
|
||||
return CommunicationValue::new(CommunicationType::Function)
|
||||
.with_id(cv.get_id())
|
||||
.with_request_id(&cv)
|
||||
.add_data_str(DataType::Name, self.name.clone())
|
||||
.add_data_str(DataType::Path, self.path.clone())
|
||||
.add_data_str(DataType::Result, "message_received".to_string())
|
||||
.add_data(DataType::Payload, JsonValue::new_object());
|
||||
}
|
||||
CommunicationValue::new(CommunicationType::ErrorInternal).with_id(cv.get_id())
|
||||
CommunicationValue::new(CommunicationType::ErrorInternal).with_request_id(&cv)
|
||||
}
|
||||
fn to_json(&self) -> JsonValue {
|
||||
JsonValue::new_object()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::communities::{community::Community, interactables::interactable::Interactable};
|
||||
use async_trait::async_trait;
|
||||
use json::JsonValue;
|
||||
use iota_util::mtp_compat::{CommunicationValueCompat, OptionalDataValueExt};
|
||||
use iota_util::mtp_compat::OptionalDataValueExt;
|
||||
use std::sync::Arc;
|
||||
use std::{any::Any, sync::RwLock};
|
||||
use uuid::Uuid;
|
||||
|
|
@ -131,7 +131,7 @@ impl Interactable for VoiceChat {
|
|||
response_payload["send_time"] = JsonValue::String(send_time.to_string());
|
||||
|
||||
return CommunicationValue::new(CommunicationType::Function)
|
||||
.with_id(cv.get_id())
|
||||
.with_request_id(&cv)
|
||||
.add_data_str(DataType::Name, self.name.clone())
|
||||
.add_data_str(DataType::Path, self.path.clone())
|
||||
.add_data_str(DataType::Result, "getting_call".to_string())
|
||||
|
|
@ -159,13 +159,13 @@ impl Interactable for VoiceChat {
|
|||
response_payload["streaming"] = JsonValue::Boolean(streaming);
|
||||
|
||||
return CommunicationValue::new(CommunicationType::Update)
|
||||
.with_id(cv.get_id())
|
||||
.with_request_id(&cv)
|
||||
.add_data_str(DataType::Name, self.name.clone())
|
||||
.add_data_str(DataType::Path, self.path.clone())
|
||||
.add_data_str(DataType::Result, "user_changed".to_string())
|
||||
.add_data(DataType::Payload, response_payload);
|
||||
}
|
||||
CommunicationValue::new(CommunicationType::ErrorInternal).with_id(cv.get_id())
|
||||
CommunicationValue::new(CommunicationType::ErrorInternal).with_request_id(&cv)
|
||||
}
|
||||
|
||||
fn to_json(&self) -> JsonValue {
|
||||
|
|
|
|||
Loading…
Reference in a new issue