From 1ea0b97f6dcc8ac7e9a6474f63d694e089279219 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Sun, 5 Apr 2026 00:03:19 +0200 Subject: [PATCH] ... --- Cargo.lock | 83 ++- Cargo.toml | 2 +- decentralized/src/lib.rs | 2 + .../{local-auth => local_auth}/auth_user.rs | 0 .../{local-auth => local_auth}/local_auth.rs | 2 +- .../src/{local-auth => local_auth}/mod.rs | 0 .../{Cargo.toml => unused-Cargo.toml} | 4 + iota-cli/src/elements/console_card.rs | 28 +- iota-cli/src/elements/elements.rs | 2 +- iota-cli/src/elements/graph_card.rs | 12 +- iota-cli/src/elements/log_card.rs | 29 +- iota-cli/src/input_handler.rs | 4 +- iota-cli/src/screens/terms_checker.rs | 24 +- iota-cli/src/screens/terms_updater.rs | 25 +- iota-cli/src/ui.rs | 2 +- iota-core/src/consent_state.rs | 473 ++++++++++++++++++ iota-core/src/main.rs | 11 + iota-logger/Cargo.toml | 4 + iota-logger/src/lib.rs | 67 +-- iota-state/src/lib.rs | 4 +- iota-storage/Cargo.toml | 4 + iota-storage/src/lib.rs | 4 +- iota-storage/src/users/user_community_util.rs | 2 +- iota-storage/src/users/user_manager.rs | 88 +--- iota-storage/src/users/user_profile.rs | 2 +- iota-storage/src/util/chat_files.rs | 2 +- iota-storage/src/util/config_util.rs | 2 +- iota-storage/src/util/db.rs | 2 +- iota-storage/src/util/mod.rs | 4 - iota-terms/Cargo.toml | 1 + iota-terms/src/doc.rs | 3 +- iota-terms/src/lib.rs | 14 +- iota-terms/src/terms_getter.rs | 2 +- iota-util/Cargo.toml | 12 + iota-util/src/file_util.rs | 26 +- .../src/langu/language_creator.rs | 2 +- .../src/langu/language_manager.rs | 2 +- {iota-cli => iota-util}/src/langu/mod.rs | 0 iota-util/src/lib.rs | 4 + omikron-connector/Cargo.toml | 9 + omikron-connector/src/lib.rs | 1 + omikron-connector/src/omikron_connection.rs | 20 +- omikron-connector/src/ping_pong_task.rs | 5 +- omikron-connector/src/user_ops.rs | 93 ++++ web-ui/Cargo.toml | 5 + web-ui/src/api.rs | 49 +- web-ui/src/server.rs | 20 +- web-ui/src/socket.rs | 0 web-ui/src/web_path_parser.rs | 2 +- 49 files changed, 869 insertions(+), 289 deletions(-) rename decentralized/src/{local-auth => local_auth}/auth_user.rs (100%) rename decentralized/src/{local-auth => local_auth}/local_auth.rs (91%) rename decentralized/src/{local-auth => local_auth}/mod.rs (100%) rename decentralized/{Cargo.toml => unused-Cargo.toml} (88%) create mode 100644 iota-core/src/consent_state.rs rename {iota-cli => iota-util}/src/langu/language_creator.rs (98%) rename {iota-cli => iota-util}/src/langu/language_manager.rs (98%) rename {iota-cli => iota-util}/src/langu/mod.rs (100%) create mode 100644 omikron-connector/src/user_ops.rs create mode 100644 web-ui/src/socket.rs diff --git a/Cargo.lock b/Cargo.lock index d48cc69..a9dcfc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -847,53 +847,6 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" -[[package]] -name = "decentralized" -version = "0.1.0" -dependencies = [ - "actix-web", - "actix-web-actors", - "aes-gcm", - "async-trait", - "base64", - "chrono", - "crossterm", - "dashmap", - "futures", - "futures-util", - "hex", - "hkdf", - "hyper", - "hyper-util", - "json", - "lazy_static", - "once_cell", - "open", - "pnet", - "rand 0.8.5", - "rand_core 0.6.4", - "ratatui", - "reqwest", - "rusqlite", - "rustls", - "rustls-pemfile", - "serde_json", - "sha2", - "strum 0.27.2", - "strum_macros 0.27.2", - "sysinfo", - "tokio", - "tokio-tungstenite", - "ttp-core", - "ttp-native", - "tungstenite", - "uuid", - "walkdir", - "warp", - "x448", - "zip", -] - [[package]] name = "deflate64" version = "0.1.12" @@ -1847,6 +1800,12 @@ dependencies = [ [[package]] name = "iota-logger" version = "0.1.0" +dependencies = [ + "iota-state", + "iota-util", + "ratatui", + "ttp-core", +] [[package]] name = "iota-state" @@ -1868,6 +1827,9 @@ dependencies = [ "base64", "hex", "hkdf", + "iota-logger", + "iota-state", + "iota-util", "json", "once_cell", "rand 0.8.5", @@ -1891,6 +1853,7 @@ name = "iota-terms" version = "0.1.0" dependencies = [ "iota-state", + "iota-util", "json", "reqwest", ] @@ -1899,13 +1862,25 @@ dependencies = [ name = "iota-util" version = "0.1.0" dependencies = [ + "aes-gcm", + "base64", + "hex", + "hkdf", "json", + "once_cell", "pnet", + "rand_core 0.6.4", "ratatui", "reqwest", + "sha2", + "sysinfo", "tokio", "ttp-core", "ttp-native", + "uuid", + "walkdir", + "x448", + "zip", ] [[package]] @@ -2402,12 +2377,21 @@ dependencies = [ name = "omikron-connector" version = "0.1.0" dependencies = [ + "base64", "dashmap", + "hex", + "iota-logger", + "iota-state", + "iota-storage", + "iota-util", "json", + "rand_core 0.6.4", + "sha2", "tokio", "ttp-core", "ttp-native", "uuid", + "x448", ] [[package]] @@ -4403,8 +4387,13 @@ dependencies = [ "hkdf", "hyper", "hyper-util", + "iota-logger", + "iota-state", + "iota-storage", + "iota-util", "json", "lazy_static", + "omikron-connector", "once_cell", "open", "pnet", diff --git a/Cargo.toml b/Cargo.toml index f9744a3..30a7a09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["iota-storage", "iota-terms", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "decentralized", "iota-logger"] +members = ["iota-storage", "iota-terms", "iota-state", "iota-cli", "iota-core", "omikron-connector", "web-server", "web-ui", "iota-logger", "iota-util"] diff --git a/decentralized/src/lib.rs b/decentralized/src/lib.rs index e69de29..e7896d5 100644 --- a/decentralized/src/lib.rs +++ b/decentralized/src/lib.rs @@ -0,0 +1,2 @@ +pub mod communities; +pub mod local_auth; diff --git a/decentralized/src/local-auth/auth_user.rs b/decentralized/src/local_auth/auth_user.rs similarity index 100% rename from decentralized/src/local-auth/auth_user.rs rename to decentralized/src/local_auth/auth_user.rs diff --git a/decentralized/src/local-auth/local_auth.rs b/decentralized/src/local_auth/local_auth.rs similarity index 91% rename from decentralized/src/local-auth/local_auth.rs rename to decentralized/src/local_auth/local_auth.rs index 112ee2b..f9c0fd1 100644 --- a/decentralized/src/local-auth/local_auth.rs +++ b/decentralized/src/local_auth/local_auth.rs @@ -1,6 +1,6 @@ use json::JsonValue; -use crate::util::file_util::load_file; +use iota_iota_util::file_util::load_file; // NOT USED AT MOMENT pub fn is_private_key_valid(user_id: &i64, key_hash: &str) -> bool { let file_contents = load_file("", "users.json"); diff --git a/decentralized/src/local-auth/mod.rs b/decentralized/src/local_auth/mod.rs similarity index 100% rename from decentralized/src/local-auth/mod.rs rename to decentralized/src/local_auth/mod.rs diff --git a/decentralized/Cargo.toml b/decentralized/unused-Cargo.toml similarity index 88% rename from decentralized/Cargo.toml rename to decentralized/unused-Cargo.toml index 9c21cdf..2c9c97c 100644 --- a/decentralized/Cargo.toml +++ b/decentralized/unused-Cargo.toml @@ -6,6 +6,10 @@ edition = "2024" [dependencies] ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } +iota-logger = { path = "../iota-logger" } +iota-util = { path = "../iota-util" } +iota-storage = { path = "../iota-storage" } +iota-state = { path = "../iota-state" } actix-web = { version = "4", features = ["rustls-0_23"] } actix-web-actors = "4" diff --git a/iota-cli/src/elements/console_card.rs b/iota-cli/src/elements/console_card.rs index b189bd4..f7b0c8f 100644 --- a/iota-cli/src/elements/console_card.rs +++ b/iota-cli/src/elements/console_card.rs @@ -1,4 +1,9 @@ use crossterm::event::{KeyCode, KeyEvent}; +use iota_logger::{log, log_command, log_cv}; +use iota_state::{ACTIVE_TASKS, RELOAD, SHUTDOWN}; +use iota_storage::users::{user_manager, user_profile::UserProfile}; +use iota_util::file_util; +use omikron_connector::omikron_connection::OMIKRON_CONNECTION; use ratatui::{ Frame, layout::Rect, @@ -9,19 +14,6 @@ use ratatui::{ use ttp_core::{CommunicationType, CommunicationValue}; use uuid::Uuid; -use crate::{ - ACTIVE_TASKS, RELOAD, SHUTDOWN, - gui::{ - elements::elements::{Element, InteractableElement, JoinableElement}, - interaction_result::InteractionResult, - ui::FPS, - util::borders::draw_block_joins, - }, - log, log_command, log_cv, - omikron::omikron_connection::OMIKRON_CONNECTION, - users::{user_manager, user_profile::UserProfile}, - util::file_util, -}; use std::{ any::Any, sync::{Arc, Mutex}, @@ -29,6 +21,13 @@ use std::{ }; use tokio::time::Instant; +use crate::{ + elements::elements::{Element, InteractableElement, JoinableElement}, + interaction_result::InteractionResult, + ui::FPS, + util::borders::draw_block_joins, +}; + pub struct ConsoleCard { focused: bool, pub title: String, @@ -425,7 +424,8 @@ pub async fn run_command(command: &str) { ping(time).await; } ["user", "add", username] => { - if let (Some(user), Some(_)) = user_manager::create_user(username).await { + if let (Some(user), Some(_)) = omikron_connector::user_ops::create_user(username).await + { log!("Created user {}", user.user_id); } else { log!("Failed to create user"); diff --git a/iota-cli/src/elements/elements.rs b/iota-cli/src/elements/elements.rs index 3429e52..abe9ab9 100644 --- a/iota-cli/src/elements/elements.rs +++ b/iota-cli/src/elements/elements.rs @@ -3,7 +3,7 @@ use std::any::Any; use crossterm::event::KeyEvent; use ratatui::{Frame, layout::Rect, widgets::Borders}; -use crate::gui::{interaction_result::InteractionResult, screens::screens::Screen}; +use crate::{interaction_result::InteractionResult, screens::screens::Screen}; #[allow(unused)] pub trait Element: Send + Sync + Any { diff --git a/iota-cli/src/elements/graph_card.rs b/iota-cli/src/elements/graph_card.rs index d95f937..c7ec2d6 100644 --- a/iota-cli/src/elements/graph_card.rs +++ b/iota-cli/src/elements/graph_card.rs @@ -1,6 +1,7 @@ use std::{any::Any, sync::Arc}; use crossterm::event::KeyEvent; +use iota_state::APP_STATE; use ratatui::{ Frame, layout::Rect, @@ -12,13 +13,10 @@ use ratatui::{ }; use crate::{ - APP_STATE, - gui::{ - elements::elements::{Element, InteractableElement, JoinableElement}, - interaction_result::InteractionResult, - ui::UI, - util::borders::draw_block_joins, - }, + elements::elements::{Element, InteractableElement, JoinableElement}, + interaction_result::InteractionResult, + ui::UI, + util::borders::draw_block_joins, }; pub enum GRAPHS { diff --git a/iota-cli/src/elements/log_card.rs b/iota-cli/src/elements/log_card.rs index e2d4ba1..a0ce8fd 100755 --- a/iota-cli/src/elements/log_card.rs +++ b/iota-cli/src/elements/log_card.rs @@ -1,9 +1,9 @@ -use crate::APP_STATE; -use crate::gui::elements::elements::{Element, InteractableElement, JoinableElement}; -use crate::gui::interaction_result::InteractionResult; -use crate::gui::util::borders::draw_block_joins; -use crate::util::logger::PrintType; +use crate::app_state::APP_STATE; +use crate::elements::elements::{Element, InteractableElement, JoinableElement}; +use crate::interaction_result::InteractionResult; +use crate::util::borders::draw_block_joins; use crossterm::event::{KeyCode, KeyEvent}; +use iota_logger::PrintType; use ratatui::{ Frame, layout::Rect, @@ -90,7 +90,24 @@ impl LogCard { fn get_logs(&self) -> Vec { let state = APP_STATE.lock().unwrap(); - state.get_logs().iter().cloned().collect() + state + .get_logs() + .iter() + .map(|e| UiLogEntry { + timestamp_ms: e.timestamp_ms, + sender: match e.sender.as_str() { + "Call" => PrintType::Call, + "Client" => PrintType::Client, + "Iota" => PrintType::Iota, + "Omikron" => PrintType::Omikron, + "Omega" => PrintType::Omega, + "Command" => PrintType::Command, + _ => PrintType::General, + }, + message: e.message.clone(), + is_error: e.is_error, + }) + .collect() } fn find_split_point(s: &str, max_width: usize) -> usize { diff --git a/iota-cli/src/input_handler.rs b/iota-cli/src/input_handler.rs index 92b899c..524ce2e 100644 --- a/iota-cli/src/input_handler.rs +++ b/iota-cli/src/input_handler.rs @@ -1,6 +1,6 @@ -use crate::ui::{UI, UNIQUE}; -use crate::{RELOAD, SHUTDOWN}; +use crate::ui::UI; use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyModifiers, poll, read}; +use iota_state::{RELOAD, SHUTDOWN, UNIQUE}; use std::sync::Arc; use std::sync::atomic::Ordering; use std::time::Duration; diff --git a/iota-cli/src/screens/terms_checker.rs b/iota-cli/src/screens/terms_checker.rs index 0808ac5..0d64187 100644 --- a/iota-cli/src/screens/terms_checker.rs +++ b/iota-cli/src/screens/terms_checker.rs @@ -2,8 +2,13 @@ use crate::{ interaction_result::InteractionResult, screens::{md_viewer::FileViewer, screens::Screen}, ui::UI, + util::{ + buttons::{checkbox, draw_buttons}, + terms_focus::Focus, + }, }; use crossterm::event::{KeyCode, KeyEvent}; +use iota_terms::{TermsType, get_link, get_terms}; use ratatui::{ Frame, layout::{Alignment, Constraint, Direction, Layout, Rect}, @@ -14,6 +19,13 @@ use ratatui::{ use std::{any::Any, pin::Pin, sync::Arc}; use tokio::sync::oneshot; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UserChoice { + Deny, + AcceptEULA, + AcceptAll, +} + pub struct TermsCheckerScreen { ui: Arc, sender: Option>, @@ -268,9 +280,9 @@ impl Screen for TermsCheckerScreen { } KeyCode::Char('o') | KeyCode::Char('O') => { let terms_type = match self.focus { - Focus::Eula => Some(Type::EULA), - Focus::Tos => Some(Type::TOS), - Focus::Pp => Some(Type::PP), + Focus::Eula => Some(TermsType::EULA), + Focus::Tos => Some(TermsType::TOS), + Focus::Pp => Some(TermsType::PP), _ => None, }; if let Some(terms_type) = terms_type { @@ -288,15 +300,15 @@ impl Screen for TermsCheckerScreen { } KeyCode::Char('l') | KeyCode::Char('L') => match self.focus { Focus::Eula => { - let _ = open::that(get_link(Type::EULA)); + let _ = open::that(get_link(TermsType::EULA)); InteractionResult::Handled } Focus::Tos => { - let _ = open::that(get_link(Type::TOS)); + let _ = open::that(get_link(TermsType::TOS)); InteractionResult::Handled } Focus::Pp => { - let _ = open::that(get_link(Type::PP)); + let _ = open::that(get_link(TermsType::PP)); InteractionResult::Handled } _ => InteractionResult::Unhandled, diff --git a/iota-cli/src/screens/terms_updater.rs b/iota-cli/src/screens/terms_updater.rs index 909da8d..ee91cba 100644 --- a/iota-cli/src/screens/terms_updater.rs +++ b/iota-cli/src/screens/terms_updater.rs @@ -1,9 +1,15 @@ +use crate::screens::terms_checker::UserChoice; use crate::{ interaction_result::InteractionResult, screens::{md_viewer::FileViewer, screens::Screen}, + util::{ + buttons::{checkbox, draw_buttons}, + terms_focus::Focus, + }, }; use chrono::{Local, TimeZone, Utc}; use crossterm::event::{KeyCode, KeyEvent}; +use iota_terms::{Doc, TermsType, get_newest_link, get_terms}; use ratatui::{ Frame, layout::{Alignment, Constraint, Direction, Layout, Rect}, @@ -14,6 +20,13 @@ use ratatui::{ use std::any::Any; use tokio::sync::oneshot; +#[derive(Debug, Clone)] +pub enum UpdateDecision { + NoChange, + Future { newest: Doc }, + Forced(Doc), +} + pub struct TermsUpdaterScreen { sender: Option>, @@ -635,9 +648,9 @@ impl Screen for TermsUpdaterScreen { }, KeyCode::Char('o') | KeyCode::Char('O') => { let terms_type = match self.focus { - Focus::Eula => Some(Type::EULA), - Focus::Tos => Some(Type::TOS), - Focus::Pp => Some(Type::PP), + Focus::Eula => Some(TermsType::EULA), + Focus::Tos => Some(TermsType::TOS), + Focus::Pp => Some(TermsType::PP), _ => None, }; @@ -655,15 +668,15 @@ impl Screen for TermsUpdaterScreen { } KeyCode::Char('l') | KeyCode::Char('L') => match self.focus { Focus::Eula => { - let _ = open::that(get_newest_link(Type::EULA)); + let _ = open::that(get_newest_link(TermsType::EULA)); InteractionResult::Handled } Focus::Tos => { - let _ = open::that(get_newest_link(Type::TOS)); + let _ = open::that(get_newest_link(TermsType::TOS)); InteractionResult::Handled } Focus::Pp => { - let _ = open::that(get_newest_link(Type::PP)); + let _ = open::that(get_newest_link(TermsType::PP)); InteractionResult::Handled } _ => InteractionResult::Unhandled, diff --git a/iota-cli/src/ui.rs b/iota-cli/src/ui.rs index 71e9847..723babe 100644 --- a/iota-cli/src/ui.rs +++ b/iota-cli/src/ui.rs @@ -3,6 +3,7 @@ use crate::{ screens::screens::Screen, }; use crossterm::event::KeyEvent; +use iota_state::{ACTIVE_TASKS, SHUTDOWN, UNIQUE}; use once_cell::sync::Lazy; use ratatui::{Terminal, backend::CrosstermBackend, init}; use std::{ @@ -17,7 +18,6 @@ use std::{ use tokio::{sync::RwLock, time::Instant}; /// UI state and rendering -pub static UNIQUE: AtomicBool = AtomicBool::new(true); pub static FPS: Lazy> = Lazy::new(|| RwLock::new((0.0, 0.0))); diff --git a/iota-core/src/consent_state.rs b/iota-core/src/consent_state.rs new file mode 100644 index 0000000..723c5a7 --- /dev/null +++ b/iota-core/src/consent_state.rs @@ -0,0 +1,473 @@ +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use tokio::sync::oneshot; +use iota_cli::ui::UI; +use iota_cli::screens::terms_checker::{TermsCheckerScreen, UserChoice}; +use iota_cli::screens::terms_updater::{TermsUpdaterScreen, UpdateDecision}; +use iota_terms::{Doc, get_current_docs, get_newest_docs, TermsType as Type}; +use iota_util::file_util::{load_file, save_file}; + + +pub async fn check(ui: Arc) -> (bool, bool) { + let mut state = ConsentState::load_state(); + + if ensure_initial_consent(ui.clone(), &mut state) + .await + .is_err() + { + return (false, false); + } + if ensure_updates(ui, &mut state).await.is_err() { + return (false, false); + }; + + state = state.sanitize(); + state.save_state(); + + (state.accepted_eula, state.accepted_tos && state.accepted_pp) +} + +async fn ensure_initial_consent(ui: Arc, state: &mut ConsentState) -> Result<(), ()> { + if state.accepted_eula { + return Ok(()); + } + + let (tx, rx) = oneshot::channel(); + + ui.set_screen(Box::new(TermsCheckerScreen::new(ui.clone(), Some(tx)))) + .await; + + let result = rx.await.unwrap_or(UserChoice::Deny); + + match result { + UserChoice::AcceptEULA | UserChoice::AcceptAll => { + if let Some((eula, tos, privacy)) = get_current_docs().await { + state.accepted_eula = true; + state.eula = Some(eula); + + if matches!(result, UserChoice::AcceptAll) { + state.accepted_tos = true; + state.accepted_pp = true; + state.tos = Some(tos); + state.privacy = Some(privacy); + } + } + + let _ = &state.save_state(); + Ok(()) + } + UserChoice::Deny => Err(()), + } +} +async fn ensure_updates(ui: Arc, state: &mut ConsentState) -> Result<(), ()> { + let Some((eula_update, tos_update, privacy_update)) = get_updates().await else { + return Ok(()); + }; + + let is_forced = matches!(eula_update, UpdateDecision::Forced(_)) + || matches!(tos_update, UpdateDecision::Forced(_)) + || matches!(privacy_update, UpdateDecision::Forced(_)); + + let (tx, rx) = oneshot::channel(); + + ui.set_screen(Box::new(TermsUpdaterScreen::new( + eula_update.clone(), + tos_update.clone(), + privacy_update.clone(), + Some(tx), + ))) + .await; + + let result = rx.await.unwrap_or(UserChoice::Deny); + + if is_forced { + match result { + UserChoice::AcceptAll => { + state.accepted_eula = true; + state.accepted_tos = true; + state.accepted_pp = true; + } + UserChoice::AcceptEULA => { + state.accepted_eula = true; + } + UserChoice::Deny => return Err(()), + } + } else { + apply_future_updates(state, result, eula_update, tos_update, privacy_update); + } + + state.save_state(); + Ok(()) +} +fn apply_future_updates( + state: &mut ConsentState, + result: UserChoice, + eula_update: UpdateDecision, + tos_update: UpdateDecision, + privacy_update: UpdateDecision, +) { + match result { + UserChoice::AcceptAll => { + if let UpdateDecision::Future { newest } = eula_update { + state.future_eula = Some(newest); + } + if let UpdateDecision::Future { newest } = tos_update { + state.future_tos = Some(newest); + } + if let UpdateDecision::Future { newest } = privacy_update { + state.future_privacy = Some(newest); + } + } + UserChoice::AcceptEULA => { + if let UpdateDecision::Future { newest } = eula_update { + state.future_eula = Some(newest); + } + } + UserChoice::Deny => {} + } +} + +async fn get_updates() -> Option<( + // Ok(None) indicates no update + // Ok(Some) Indicates a future update + // Err indicates a update that has to be accepted before the programm can continue + UpdateDecision, + UpdateDecision, + UpdateDecision, +)> { + if let ( + Some((current_eula, current_tos, current_privacy)), + Some((newest_eula, newest_tos, newest_privacy)), + ) = (get_current_docs().await, get_newest_docs().await) + { + let file = load_file("", "agreements"); + let accepted_state = ConsentState::from_str(&file).sanitize(); + save_file("", "agreements", &accepted_state.to_string()); + + let eula_update: UpdateDecision = if current_eula.equals_some(&accepted_state.eula) { + if current_eula.equals(&newest_eula) { + UpdateDecision::NoChange + } else { + if newest_eula.equals_some(&accepted_state.future_eula) { + UpdateDecision::NoChange + } else { + UpdateDecision::Future { + newest: newest_eula, + } + } + } + } else if newest_eula.equals_some(&accepted_state.eula) { + UpdateDecision::NoChange + } else { + UpdateDecision::Forced(current_eula) + }; + + let tos_update: UpdateDecision = + if !accepted_state.accepted_tos || newest_tos.equals_some(&accepted_state.tos) { + UpdateDecision::NoChange + } else if accepted_state.accepted_tos && current_tos.equals_some(&accepted_state.tos) { + if current_tos.equals(&newest_tos) { + UpdateDecision::NoChange + } else { + if newest_tos.equals_some(&accepted_state.future_tos) { + UpdateDecision::NoChange + } else { + UpdateDecision::Future { newest: newest_tos } + } + } + } else { + UpdateDecision::Forced(current_tos) + }; + + let privacy_update: UpdateDecision = if !accepted_state.accepted_pp + || newest_privacy.equals_some(&accepted_state.privacy) + { + UpdateDecision::NoChange + } else if accepted_state.accepted_pp && current_privacy.equals_some(&accepted_state.privacy) + { + if current_privacy.equals(&newest_privacy) { + UpdateDecision::NoChange + } else { + if newest_privacy.equals_some(&accepted_state.future_privacy) { + UpdateDecision::NoChange + } else { + UpdateDecision::Future { + newest: newest_privacy, + } + } + } + } else { + UpdateDecision::Forced(current_privacy) + }; + match (&eula_update, &tos_update, &privacy_update) { + (&UpdateDecision::NoChange, &UpdateDecision::NoChange, &UpdateDecision::NoChange) => { + None + } + _ => Some((eula_update, tos_update, privacy_update)), + } + } else { + None + } +} + + +#[derive(Debug, Clone)] +pub struct ConsentState { + pub eula: Option, + pub accepted_eula: bool, + pub future_eula: Option, + + pub tos: Option, + pub accepted_tos: bool, + pub future_tos: Option, + + pub privacy: Option, + pub accepted_pp: bool, + pub future_privacy: Option, +} + +impl ConsentState { + fn sanitize(mut self) -> Self { + let current_secs = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + if let Some(future_eula) = self.future_eula.clone() { + if future_eula.get_time() < current_secs { + self.eula = Some(future_eula); + self.future_eula = None; + } + } + if let Some(future_tos) = self.future_tos.clone() { + if future_tos.get_time() < current_secs { + self.tos = Some(future_tos); + self.future_tos = None; + } + } + if let Some(future_privacy) = self.future_privacy.clone() { + if future_privacy.get_time() < current_secs { + self.privacy = Some(future_privacy); + self.future_privacy = None; + } + } + + if !self.accepted_eula { + self.accepted_tos = false; + self.accepted_pp = false; + } + self + } + + pub fn load_state() -> ConsentState { + let file = load_file("", "agreements"); + ConsentState::from_str(&file).sanitize() + } + + pub fn save_state(&self) { + save_file("", "agreements", &self.to_string()); + } + + fn to_string(&self) -> String { + let current_secs = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + let mut file_out: String = format!( + "This file reflects the current consent state used by the application.\ + \nIt may be regenerated or overwritten by the application.\ + \nThis file was last edited by Tensamin at:\ + \nUNIX-SECOND={}", + current_secs + ); + + if let Some(eula) = &self.eula { + file_out.push_str(&format!("\ + \n\"EULA=true\" indicates that you read, understood and accepted Tensamin's End User Licence agreement. You can find our EULA at https://legal.tensamin.net/eula/\ + \nEULA={}\ + \nEULA-VERSION={}\ + \nEULA-HASH={}\ + ", self.accepted_eula, eula.get_version(), eula.get_hash())); + + if self.accepted_tos + && let Some(tos) = &self.tos + { + file_out.push_str(&format!("\ + \n\"Terms-of-Service=true\" indicates that you read, understood and accepted Tensamin's Terms of Service. You can find our Terms of Serivce at https://legal.tensamin.net/tos/\ + \nTerms-of-Service={}\ + \nTerms-of-Service-VERSION={}\ + \nTerms-of-Service-HASH={}\ + ", self.accepted_tos, tos.get_version(), tos.get_hash())); + } + if self.accepted_pp + && let Some(pp) = &self.privacy + { + file_out.push_str(&format!("\ + \n\"Privacy-Policy=true\" indicates that you read, understood and accepted Tensamin's Privacy Policy. You can find our Privacy Policy at https://legal.tensamin.net/privacy/\ + \nPrivacy-Policy={}\ + \nPrivacy-Policy-VERSION={}\ + \nPrivacy-Policy-HASH={}\ + ", self.accepted_pp, pp.get_version(), pp.get_hash())); + } + } else { + file_out.push_str("\ + \n\"EULA=true\" indicates that you read, understood and accepted Tensamin's End User Licence Agreement. You can find Tensamin's EULA at https://legal.tensamin.net/eula/\ + \nEULA=false\ + "); + } + + if let Some(eula) = &self.future_eula { + file_out.push_str(&format!( + "\ + \nFUTURE-EULA-VERSION={}\ + \nFUTURE-EULA-HASH={}\ + \nFUTURE-EULA-TIME={}\ + ", + eula.get_version(), + eula.get_hash(), + eula.get_time() + )); + } + if let Some(tos) = &self.future_tos { + file_out.push_str(&format!( + "\ + \nFUTURE-Terms-of-Service-VERSION={}\ + \nFUTURE-Terms-of-Service-HASH={}\ + \nFUTURE-Terms-of-Service-TIME={}\ + ", + tos.get_version(), + tos.get_hash(), + tos.get_time() + )); + } + if let Some(pp) = &self.future_privacy { + file_out.push_str(&format!( + "\ + \nFUTURE-Privacy-Policy-VERSION={}\ + \nFUTURE-Privacy-Policy-HASH={}\ + \nFUTURE-Privacy-Policy-TIME={}\ + ", + pp.get_version(), + pp.get_hash(), + pp.get_time() + )); + } + + file_out + } + + fn from_str(s: &str) -> Self { + let mut eula = false; + let mut eula_version = String::new(); + let mut eula_hash = String::new(); + let mut pp = false; + let mut pp_version = String::new(); + let mut pp_hash = String::new(); + let mut tos = false; + let mut tos_version = String::new(); + let mut tos_hash = String::new(); + + let mut future_eula_version = String::new(); + let mut future_eula_hash = String::new(); + let mut future_eula_time = String::new(); + + let mut future_tos_version = String::new(); + let mut future_tos_hash = String::new(); + let mut future_tos_time = String::new(); + + let mut future_pp_version = String::new(); + let mut future_pp_hash = String::new(); + let mut future_pp_time = String::new(); + + let mut unix = String::new(); + + for line in s.lines() { + if let Some(v) = line.strip_prefix("EULA=") { + eula = v == "true"; + } else if let Some(v) = line.strip_prefix("EULA-VERSION=") { + eula_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("EULA-HASH=") { + eula_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("Terms-of-Service=") { + tos = v == "true"; + } else if let Some(v) = line.strip_prefix("Terms-of-Service-VERSION=") { + tos_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("Terms-of-Service-HASH=") { + tos_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("Privacy-Policy=") { + pp = v == "true"; + } else if let Some(v) = line.strip_prefix("Privacy-Policy-VERSION=") { + pp_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("Privacy-Policy-HASH=") { + pp_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("UNIX-SECOND=") { + unix = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-EULA-VERSION=") { + future_eula_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-EULA-HASH=") { + future_eula_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-EULA-TIME=") { + future_eula_time = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-VERSION=") { + future_tos_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-HASH=") { + future_tos_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Terms-of-Service-TIME=") { + future_tos_time = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-VERSION=") { + future_pp_version = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-HASH=") { + future_pp_hash = v.to_string(); + } else if let Some(v) = line.strip_prefix("FUTURE-Privacy-Policy-TIME=") { + future_pp_time = v.to_string(); + } + } + let unix: u64 = unix.parse::().unwrap_or(0); + let future_eula_time = future_eula_time.parse::().unwrap_or(0); + let future_tos_time = future_tos_time.parse::().unwrap_or(0); + let future_pp_time = future_pp_time.parse::().unwrap_or(0); + let state = Self { + accepted_eula: eula, + eula: Some(Doc::new(eula_version, eula_hash, Type::EULA, unix)), + accepted_pp: pp, + privacy: Some(Doc::new(pp_version, pp_hash, Type::PP, unix)), + accepted_tos: tos, + tos: Some(Doc::new(tos_version, tos_hash, Type::TOS, unix)), + future_eula: if !future_eula_version.is_empty() { + Some(Doc::new( + future_eula_version, + future_eula_hash, + Type::EULA, + future_eula_time, + )) + } else { + None + }, + future_tos: if !future_tos_version.is_empty() { + Some(Doc::new( + future_tos_version, + future_tos_hash, + Type::TOS, + future_tos_time, + )) + } else { + None + }, + future_privacy: if !future_pp_version.is_empty() { + Some(Doc::new( + future_pp_version, + future_pp_hash, + Type::PP, + future_pp_time, + )) + } else { + None + }, + } + .sanitize(); + + state + } +} diff --git a/iota-core/src/main.rs b/iota-core/src/main.rs index f8f4847..6e4a035 100644 --- a/iota-core/src/main.rs +++ b/iota-core/src/main.rs @@ -1,8 +1,19 @@ +mod consent_state; use pnet::datalink::NetworkInterface; use tokio::time::{Duration, sleep}; use iota_state::{ACTIVE_TASKS, APP_STATE, AppState, RELOAD, SHUTDOWN}; +use iota_cli::screens::main_screen::MainScreen; +use iota_cli::ui::start_tui; +use iota_logger as logger; +use iota_logger::{log, log_t}; +use iota_storage::users::user_manager; +use iota_storage::util::config_util::CONFIG; +use iota_util::file_util::{download_and_extract_zip, has_dir}; +use iota_util::langu::language_creator; +use omikron_connector as omikron; + #[tokio::main(flavor = "multi_thread", worker_threads = 16)] #[allow(unused_must_use, dead_code)] async fn main() { diff --git a/iota-logger/Cargo.toml b/iota-logger/Cargo.toml index a07b745..f03eac3 100644 --- a/iota-logger/Cargo.toml +++ b/iota-logger/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +ratatui = "0.30.0" +ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } +iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } diff --git a/iota-logger/src/lib.rs b/iota-logger/src/lib.rs index a5feb02..8a4b8b0 100644 --- a/iota-logger/src/lib.rs +++ b/iota-logger/src/lib.rs @@ -11,11 +11,8 @@ use std::{ use ratatui::style::Color; use ttp_core::{CommunicationValue, DataTypes, DataValue}; -use crate::{ - APP_STATE, - gui::{elements::log_card::LogEntry, ui::UNIQUE}, - langu::language_manager, -}; +use iota_state::{APP_STATE, UNIQUE, UiLogEntry}; +use iota_util::langu::language_manager; static LOGGER: OnceLock> = OnceLock::new(); @@ -83,7 +80,6 @@ pub fn startup() { }; let timestamp = format_timestamp_inline(msg.timestamp_ms); - let entry = LogEntry::new(msg.kind, resolved_message, msg.is_error); let prefix = if msg.prefix.is_empty() { String::new() @@ -96,13 +92,20 @@ pub fn startup() { "{} {}{}", fixed_box(&msg.timestamp_ms.to_string(), 13), prefix, - entry.message + resolved_message ); let _ = writeln!(file, " {}", timestamp); + let entry = UiLogEntry { + timestamp_ms: msg.timestamp_ms, + sender: format!("{:?}", msg.kind), + message: resolved_message, + is_error: msg.is_error, + }; + let mut state = APP_STATE.lock().unwrap(); - state.push_log(entry.into()); + state.push_log(entry); } }); } @@ -186,8 +189,8 @@ pub fn log_internal(kind: PrintType, prefix: String, is_error: bool, message: St #[macro_export] macro_rules! log_t { ($key:expr) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), false, $key, @@ -196,8 +199,8 @@ macro_rules! log_t { }; ($key:expr, $($arg:expr),+) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), false, $key, @@ -209,8 +212,8 @@ macro_rules! log_t { #[macro_export] macro_rules! log_t_err { ($key:expr) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), true, $key, @@ -219,8 +222,8 @@ macro_rules! log_t_err { }; ($key:expr, $($arg:expr),+) => { - $crate::util::logger::log_internal_translated( - $crate::util::logger::PrintType::General, + $crate::log_internal_translated( + $crate::PrintType::General, "".to_string(), true, $key, @@ -233,8 +236,8 @@ macro_rules! log_t_err { #[macro_export] macro_rules! log_command { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::Command, + $crate::log_internal( + $crate::PrintType::Command, "".to_string(), false, format!($($arg)*) @@ -246,8 +249,8 @@ macro_rules! log_command { #[macro_export] macro_rules! log { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, "".to_string(), false, format!($($arg)*) @@ -259,8 +262,8 @@ macro_rules! log { #[macro_export] macro_rules! log_in { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, ">".to_string(), false, format!($($arg)*) @@ -272,8 +275,8 @@ macro_rules! log_in { #[macro_export] macro_rules! log_out { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, "<".to_string(), false, format!($($arg)*) @@ -285,8 +288,8 @@ macro_rules! log_out { #[macro_export] macro_rules! log_err { ($($arg:tt)*) => { - $crate::util::logger::log_internal( - $crate::util::logger::PrintType::General, + $crate::log_internal( + $crate::PrintType::General, ">>".to_string(), true, format!($($arg)*) @@ -404,29 +407,29 @@ fn format_array(arr: Vec) -> String { #[macro_export] macro_rules! log_cv { ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("", &$cv, Some($kind)) + $crate::log_cv_internal("", &$cv, Some($kind)) }; ($cv:expr) => { - $crate::util::logger::log_cv_internal("", &$cv, None) + $crate::log_cv_internal("", &$cv, None) }; } #[macro_export] macro_rules! log_cv_in { ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("> ", &$cv, Some($kind)) + $crate::log_cv_internal("> ", &$cv, Some($kind)) }; ($cv:expr) => { - $crate::util::logger::log_cv_internal("> ", &$cv, None) + $crate::log_cv_internal("> ", &$cv, None) }; } #[macro_export] macro_rules! log_cv_out { ($kind:expr, $cv:expr) => { - $crate::util::logger::log_cv_internal("< ", &$cv, Some($kind)) + $crate::log_cv_internal("< ", &$cv, Some($kind)) }; ($cv:expr) => { - $crate::util::logger::log_cv_internal("< ", &$cv, None) + $crate::log_cv_internal("< ", &$cv, None) }; } diff --git a/iota-state/src/lib.rs b/iota-state/src/lib.rs index 5d8d351..1e5d1c2 100644 --- a/iota-state/src/lib.rs +++ b/iota-state/src/lib.rs @@ -2,7 +2,7 @@ use dashmap::DashSet; use json::{JsonValue, object}; use once_cell::sync::Lazy; use std::collections::VecDeque; -use std::sync::{Arc, LazyLock, Mutex}; +use std::sync::{Arc, LazyLock, Mutex, atomic::AtomicBool}; use std::thread; use std::time::Duration; use sysinfo::{RefreshKind, System}; @@ -11,6 +11,8 @@ use tokio::sync::RwLock; pub const MAX_POINTS: usize = 1000; pub const MAX_LOGS: usize = 100; +pub static UNIQUE: AtomicBool = AtomicBool::new(true); + #[derive(Clone, Debug)] pub struct UiLogEntry { pub timestamp_ms: u128, diff --git a/iota-storage/Cargo.toml b/iota-storage/Cargo.toml index b62ac11..6bab29e 100644 --- a/iota-storage/Cargo.toml +++ b/iota-storage/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" edition = "2024" [dependencies] +iota-logger = { path = "../iota-logger" } +iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } + ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/iota-storage/src/lib.rs b/iota-storage/src/lib.rs index 778de0f..7f0e8ef 100644 --- a/iota-storage/src/lib.rs +++ b/iota-storage/src/lib.rs @@ -1,2 +1,2 @@ -mod users; -mod util; +pub mod users; +pub mod util; diff --git a/iota-storage/src/users/user_community_util.rs b/iota-storage/src/users/user_community_util.rs index 45b036c..6f01e74 100644 --- a/iota-storage/src/users/user_community_util.rs +++ b/iota-storage/src/users/user_community_util.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::save_file; +use iota_util::file_util::save_file; use json::{self, Array, JsonValue}; use std::fs; use std::path::Path; diff --git a/iota-storage/src/users/user_manager.rs b/iota-storage/src/users/user_manager.rs index bcb5e26..add6ea4 100644 --- a/iota-storage/src/users/user_manager.rs +++ b/iota-storage/src/users/user_manager.rs @@ -1,12 +1,9 @@ -use crate::omikron::omikron_connection::OMIKRON_CONNECTION; use crate::users::user_profile::UserProfile; -use crate::util::crypto_helper::{self, public_key_to_base64}; -use crate::util::file_util::{load_file, save_file}; -use crate::util::logger::PrintType; -use crate::{RELOAD, SHUTDOWN}; -use crate::{log, log_cv}; use base64::{Engine as _, engine::general_purpose::STANDARD}; use hex::{self}; +use iota_logger::{log, log_cv}; +use iota_util::crypto_helper::{self, public_key_to_base64}; +use iota_util::file_util::{load_file, save_file}; use json::JsonValue; use once_cell::sync::Lazy; use rand::Rng; @@ -48,84 +45,7 @@ pub async fn load_from_tu(username: &str) -> Result<(), ()> { Ok(()) } -pub async fn create_user(username: &str) -> (Option, Option) { - let register_cv = CommunicationValue::new(CommunicationType::get_register); - - let conn = OMIKRON_CONNECTION.clone(); - - let response_cv = match conn - .await_response(®ister_cv, Some(Duration::from_secs(20))) - .await - { - Ok(cv) => cv, - Err(_) => return (None, None), - }; - log_cv!(PrintType::Omega, response_cv); - - let user_id = match response_cv.get_data(DataTypes::user_id).as_number() { - Some(id) => id, - None => return (None, None), - }; - let mut buf = [0u8; 56]; - let mut rng = OsRng; - rng.fill_bytes(&mut buf); - let private_key = Secret::from_bytes(&buf).unwrap(); - let public_key = PublicKey::from(&private_key); - - let mut hasher = Sha256::new(); - hasher.update(&STANDARD.encode(&private_key.as_bytes()).as_bytes()); - let result = hasher.finalize(); - let private_key_hash = hex::encode(result); - - let mut bytes = [0u8; 192]; - OsRng.fill(bytes.as_mut()); - let reset_token = STANDARD.encode(&bytes); - - let up = UserProfile::new( - user_id, - username.to_string(), - None, - STANDARD.encode(&public_key.as_bytes()), - private_key_hash, - reset_token.clone(), - ); - - let cv = CommunicationValue::new(CommunicationType::complete_register_user) - .add_data(DataTypes::user_id, DataValue::Number(user_id)) - .add_data(DataTypes::username, DataValue::Str(username.to_string())) - .add_data( - DataTypes::public_key, - DataValue::Str(public_key_to_base64(&public_key)), - ) - .add_data(DataTypes::iota_id, DataValue::Number(user_id)) - .add_data(DataTypes::reset_token, DataValue::Str(reset_token)); - - let response_cv = conn - .await_response(&cv, Some(Duration::from_secs(20))) - .await; - - if let Ok(resp) = response_cv { - log_cv!(PrintType::Omega, resp); - if !resp.is_type(CommunicationType::success) { - return (None, None); - } - } else { - return (None, None); - } - *SHUTDOWN.write().await = true; - *RELOAD.write().await = true; - log!("Created User"); - save_file( - "", - &format!("{}.tu", username), - &format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())), - ); - - USERS.lock().unwrap().push(up.clone()); - save_users(); - (Some(up), Some(STANDARD.encode(&private_key.as_bytes()))) -} - +pub fn add_user(user: UserProfile) { USERS.lock().unwrap().push(user); } pub fn get_user_by_username(username: &str) -> Option { USERS .lock() diff --git a/iota-storage/src/users/user_profile.rs b/iota-storage/src/users/user_profile.rs index 5d60277..ba413ff 100644 --- a/iota-storage/src/users/user_profile.rs +++ b/iota-storage/src/users/user_profile.rs @@ -1,6 +1,6 @@ use std::time::{SystemTime, UNIX_EPOCH}; -use crate::util::file_util::{has_file, load_file, used_dir_space}; +use iota_util::file_util::{has_file, load_file, used_dir_space}; use base64::{Engine as _, engine::general_purpose}; use json::{JsonValue, object}; use rand::Rng; diff --git a/iota-storage/src/util/chat_files.rs b/iota-storage/src/util/chat_files.rs index e54fe29..143aa14 100644 --- a/iota-storage/src/util/chat_files.rs +++ b/iota-storage/src/util/chat_files.rs @@ -1,5 +1,5 @@ -use crate::log; use crate::util::db; +use iota_logger::log; use json::{JsonValue, array, object}; use rusqlite::params; use std::io; diff --git a/iota-storage/src/util/config_util.rs b/iota-storage/src/util/config_util.rs index 6330b59..0ad7827 100644 --- a/iota-storage/src/util/config_util.rs +++ b/iota-storage/src/util/config_util.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::{load_file, save_file}; +use iota_util::file_util::{load_file, save_file}; use json::JsonValue; use once_cell::sync::Lazy; use tokio::sync::RwLock; diff --git a/iota-storage/src/util/db.rs b/iota-storage/src/util/db.rs index 9fb40a0..eb48400 100644 --- a/iota-storage/src/util/db.rs +++ b/iota-storage/src/util/db.rs @@ -5,7 +5,7 @@ //! reuse. The goal is to centralize the "open and initialize" logic and //! provide small convenience helpers used by other util modules. -use crate::util::file_util::get_directory; +use iota_util::file_util::get_directory; use rusqlite::{Connection, Error as RusqliteError}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; diff --git a/iota-storage/src/util/mod.rs b/iota-storage/src/util/mod.rs index 47901f9..dff0d65 100644 --- a/iota-storage/src/util/mod.rs +++ b/iota-storage/src/util/mod.rs @@ -2,8 +2,4 @@ pub mod chat_files; pub mod chats_util; pub mod communities_util; pub mod config_util; -pub mod crypto_helper; -pub mod crypto_util; pub mod db; -pub mod file_util; -pub mod logger; diff --git a/iota-terms/Cargo.toml b/iota-terms/Cargo.toml index 070687c..607dce1 100644 --- a/iota-terms/Cargo.toml +++ b/iota-terms/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } json = "*" reqwest = "0.13.2" diff --git a/iota-terms/src/doc.rs b/iota-terms/src/doc.rs index 2365ba3..0c2e0d2 100644 --- a/iota-terms/src/doc.rs +++ b/iota-terms/src/doc.rs @@ -1,6 +1,7 @@ use json::{JsonValue, object::Object}; -use crate::{terms::terms_getter::Type, util::file_util::load_file}; +use crate::terms_getter::Type; +use iota_util::file_util::load_file; #[derive(Clone, Debug, PartialEq, Eq)] #[allow(unused)] diff --git a/iota-terms/src/lib.rs b/iota-terms/src/lib.rs index b03efc9..4d99cc6 100644 --- a/iota-terms/src/lib.rs +++ b/iota-terms/src/lib.rs @@ -1,2 +1,14 @@ -pub mod doc; + + pub mod terms_getter; + +pub use terms_getter::Type as TermsType; +pub use terms_getter::get_current_docs; +pub use terms_getter::get_link; +pub use terms_getter::get_newest_docs; +pub use terms_getter::get_newest_link; +pub use terms_getter::get_terms; + +pub mod doc; + +pub use doc::Doc; diff --git a/iota-terms/src/terms_getter.rs b/iota-terms/src/terms_getter.rs index a0fa53b..65de9b1 100755 --- a/iota-terms/src/terms_getter.rs +++ b/iota-terms/src/terms_getter.rs @@ -1,6 +1,6 @@ use json::JsonValue::Object; -use crate::terms::doc::Doc; +use crate::doc::Doc; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Type { diff --git a/iota-util/Cargo.toml b/iota-util/Cargo.toml index 369ad84..77ecde1 100644 --- a/iota-util/Cargo.toml +++ b/iota-util/Cargo.toml @@ -13,3 +13,15 @@ pnet = "0.35.0" ratatui = "0.30.0" reqwest = "0.13.2" tokio = { version = "1.50.0", features = ["full"] } +sysinfo = "0.38.3" +uuid = { version = "*", features = ["v4"] } +walkdir = "2.5.0" +zip = "6.0.0" +aes-gcm = "0.10.3" +base64 = "0.22.1" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +sha2 = "0.10.9" +x448 = { version = "*" } +hkdf = "0.12.4" +once_cell = "1.21.3" +hex = "*" diff --git a/iota-util/src/file_util.rs b/iota-util/src/file_util.rs index 2d00718..1326feb 100755 --- a/iota-util/src/file_util.rs +++ b/iota-util/src/file_util.rs @@ -9,7 +9,7 @@ use uuid::Uuid; use walkdir::WalkDir; use zip::ZipArchive; -use crate::log; + #[allow(dead_code)] pub fn delete_directory(path: &str) -> bool { @@ -23,7 +23,7 @@ fn delete_dir_recursive(directory: &Path) -> bool { return false; } if let Err(e) = fs::remove_dir_all(directory) { - log!( + println!( "[IMPORTANT] Couldn't delete directory {}: {}", directory.display(), e, @@ -97,7 +97,7 @@ pub fn load_file(path: &str, name: &str) -> String { if !dir.exists() { if let Err(e) = fs::create_dir_all(&dir) { - log!("[IMPORTANT] Couldn't create directories: {}", e); + println!("[IMPORTANT] Couldn't create directories: {}", e); return String::new(); } return String::new(); @@ -105,7 +105,7 @@ pub fn load_file(path: &str, name: &str) -> String { if !file_path.exists() { if let Err(e) = File::create(&file_path) { - log!("[IMPORTANT] Couldn't create file: {}", e); + println!("[IMPORTANT] Couldn't create file: {}", e); } return String::new(); } @@ -130,13 +130,13 @@ pub fn save_file(path: &str, name: &str, value: &str) { if !dir.exists() { if let Err(e) = fs::create_dir_all(&dir) { - log!("[IMPORTANT] Couldn't create directories: {}", e); + println!("[IMPORTANT] Couldn't create directories: {}", e); return; } } if let Err(e) = fs::write(&file_path, value) { - log!( + println!( "[IMPORTANT] Couldn't write file {}: {}", file_path.display(), e @@ -231,7 +231,7 @@ pub async fn download_zip(url: &str, zip_path: &Path) -> Result<(), Box true, Err(e) => { - log!("Error during ZIP extraction: {}", e); + println!("Error during ZIP extraction: {}", e); false } }; if let Err(e) = tokio::fs::remove_file(&zip_path).await { - log!("Error cleaning up ZIP file {}: {}", zip_path.display(), e); + println!("Error cleaning up ZIP file {}: {}", zip_path.display(), e); } else if successful { - log!("Downloaded and extracted ZIP file successfully."); + println!("Downloaded and extracted ZIP file successfully."); } } diff --git a/iota-cli/src/langu/language_creator.rs b/iota-util/src/langu/language_creator.rs similarity index 98% rename from iota-cli/src/langu/language_creator.rs rename to iota-util/src/langu/language_creator.rs index fc6d1c5..e740e5b 100644 --- a/iota-cli/src/langu/language_creator.rs +++ b/iota-util/src/langu/language_creator.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::save_file; +use crate::file_util::save_file; use json::{self, JsonError, JsonValue}; pub fn create_languages() -> Result<(), JsonError> { diff --git a/iota-cli/src/langu/language_manager.rs b/iota-util/src/langu/language_manager.rs similarity index 98% rename from iota-cli/src/langu/language_manager.rs rename to iota-util/src/langu/language_manager.rs index c903886..0dcfa70 100644 --- a/iota-cli/src/langu/language_manager.rs +++ b/iota-util/src/langu/language_manager.rs @@ -1,4 +1,4 @@ -use crate::util::file_util::{self}; +use crate::file_util::{self}; use json::parse; use once_cell::sync::Lazy; use std::collections::HashMap; diff --git a/iota-cli/src/langu/mod.rs b/iota-util/src/langu/mod.rs similarity index 100% rename from iota-cli/src/langu/mod.rs rename to iota-util/src/langu/mod.rs diff --git a/iota-util/src/lib.rs b/iota-util/src/lib.rs index e69de29..d104f80 100644 --- a/iota-util/src/lib.rs +++ b/iota-util/src/lib.rs @@ -0,0 +1,4 @@ +pub mod crypto_helper; +pub mod crypto_util; +pub mod file_util; +pub mod langu; diff --git a/omikron-connector/Cargo.toml b/omikron-connector/Cargo.toml index 89aa2d4..41f7d55 100644 --- a/omikron-connector/Cargo.toml +++ b/omikron-connector/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" edition = "2024" [dependencies] +iota-logger = { path = "../iota-logger" } +iota-state = { path = "../iota-state" } +iota-storage = { path = "../iota-storage" } +iota-util = { path = "../iota-util" } ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } @@ -11,3 +15,8 @@ dashmap = "6.1.0" json = "*" tokio = { version = "1.50.0", features = ["full"] } uuid = { version = "*", features = ["v4"] } +base64 = "0.22.1" +hex = "*" +rand_core = { version = "0.6", features = ["getrandom", "std"] } +sha2 = "0.10.9" +x448 = { version = "*" } diff --git a/omikron-connector/src/lib.rs b/omikron-connector/src/lib.rs index acb0f59..5d9124d 100644 --- a/omikron-connector/src/lib.rs +++ b/omikron-connector/src/lib.rs @@ -1,2 +1,3 @@ pub mod omikron_connection; pub mod ping_pong_task; +pub mod user_ops; diff --git a/omikron-connector/src/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs index 240da6f..def2cc6 100755 --- a/omikron-connector/src/omikron_connection.rs +++ b/omikron-connector/src/omikron_connection.rs @@ -1,12 +1,14 @@ -use crate::users::contact::Contact; -use crate::util::chat_files::{MessageState, change_message_state}; -use crate::util::chats_util::{get_user, mod_user}; -use crate::util::communities_util::CommunitiesUtil; -use crate::util::crypto_util::{DataFormat, SecurePayload}; -use crate::util::file_util::{get_children, load_file, save_file}; -use crate::util::{chat_files, chats_util}; -use crate::util::{config_util::CONFIG, crypto_helper}; -use crate::{ACTIVE_TASKS, SHUTDOWN, log, log_cv_in, log_cv_out, log_t}; +use iota_storage::users::contact::Contact; +use iota_storage::util::chat_files::{MessageState, change_message_state}; +use iota_storage::util::chats_util::{get_user, mod_user}; +use iota_storage::util::communities_util::CommunitiesUtil; +use iota_util::crypto_util::{DataFormat, SecurePayload}; +use iota_util::file_util::{get_children, load_file, save_file}; +use iota_storage::util::{chat_files, chats_util}; +use iota_storage::util::config_util::CONFIG; +use iota_util::crypto_helper; +use iota_state::{ACTIVE_TASKS, SHUTDOWN}; +use iota_logger::{log, log_cv_in, log_cv_out, log_t}; use dashmap::DashMap; use json::JsonValue; use std::collections::HashMap; diff --git a/omikron-connector/src/ping_pong_task.rs b/omikron-connector/src/ping_pong_task.rs index f1a891f..26bec38 100644 --- a/omikron-connector/src/ping_pong_task.rs +++ b/omikron-connector/src/ping_pong_task.rs @@ -1,5 +1,6 @@ -use crate::omikron::omikron_connection::OmikronConnection; -use crate::{APP_STATE, log}; +use crate::omikron_connection::OmikronConnection; +use iota_state::APP_STATE; +use iota_logger::log; use dashmap::DashMap; use std::sync::LazyLock; use std::time::Instant; diff --git a/omikron-connector/src/user_ops.rs b/omikron-connector/src/user_ops.rs new file mode 100644 index 0000000..1c34670 --- /dev/null +++ b/omikron-connector/src/user_ops.rs @@ -0,0 +1,93 @@ +use base64::{Engine as _, engine::general_purpose::STANDARD}; +use hex; +use iota_logger::{PrintType, log, log_cv}; +use iota_state::{RELOAD, SHUTDOWN}; +use iota_storage::users::user_manager::{add_user, save_users}; +use iota_storage::users::user_profile::UserProfile; +use iota_util::crypto_helper::public_key_to_base64; +use iota_util::file_util::save_file; +use rand_core::{OsRng, RngCore}; +use sha2::{Digest, Sha256}; +use std::time::Duration; +use ttp_core::{CommunicationType, CommunicationValue, DataTypes, DataValue}; +use x448::{PublicKey, Secret}; + +use crate::omikron_connection::OMIKRON_CONNECTION; + +pub async fn create_user(username: &str) -> (Option, Option) { + let register_cv = CommunicationValue::new(CommunicationType::get_register); + + let conn = OMIKRON_CONNECTION.clone(); + + let response_cv = match conn + .await_response(®ister_cv, Some(Duration::from_secs(20))) + .await + { + Ok(cv) => cv, + Err(_) => return (None, None), + }; + log_cv!(PrintType::Omega, response_cv); + + let user_id = match response_cv.get_data(DataTypes::user_id).as_number() { + Some(id) => id, + None => return (None, None), + }; + let mut buf = [0u8; 56]; + let mut rng = OsRng; + rng.fill_bytes(&mut buf); + let private_key = Secret::from_bytes(&buf).unwrap(); + let public_key = PublicKey::from(&private_key); + + let mut hasher = Sha256::new(); + hasher.update(&STANDARD.encode(&private_key.as_bytes()).as_bytes()); + let result = hasher.finalize(); + let private_key_hash = hex::encode(result); + + let mut bytes = [0u8; 192]; + OsRng.fill_bytes(&mut bytes); + let reset_token = STANDARD.encode(&bytes); + + let up = UserProfile::new( + user_id, + username.to_string(), + None, + STANDARD.encode(&public_key.as_bytes()), + private_key_hash, + reset_token.clone(), + ); + + let cv = CommunicationValue::new(CommunicationType::complete_register_user) + .add_data(DataTypes::user_id, DataValue::Number(user_id)) + .add_data(DataTypes::username, DataValue::Str(username.to_string())) + .add_data( + DataTypes::public_key, + DataValue::Str(public_key_to_base64(&public_key)), + ) + .add_data(DataTypes::iota_id, DataValue::Number(user_id)) + .add_data(DataTypes::reset_token, DataValue::Str(reset_token)); + + let response_cv = conn + .await_response(&cv, Some(Duration::from_secs(20))) + .await; + + if let Ok(resp) = response_cv { + log_cv!(PrintType::Omega, resp); + if !resp.is_type(CommunicationType::success) { + return (None, None); + } + } else { + return (None, None); + } + *SHUTDOWN.write().await = true; + *RELOAD.write().await = true; + log!("Created User"); + save_file( + "", + &format!("{}.tu", username), + &format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())), + ); + + add_user(up.clone()); + save_users(); + (Some(up), Some(STANDARD.encode(&private_key.as_bytes()))) +} diff --git a/web-ui/Cargo.toml b/web-ui/Cargo.toml index 4d2ef71..6734582 100644 --- a/web-ui/Cargo.toml +++ b/web-ui/Cargo.toml @@ -4,6 +4,11 @@ version = "0.1.0" edition = "2024" [dependencies] +omikron-connector = { path = "../omikron-connector" } +iota-storage = { path = "../iota-storage" } +iota-state = { path = "../iota-state" } +iota-util = { path = "../iota-util" } +iota-logger = { path = "../iota-logger" } ttp-core = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-core" } ttp-native = { git = "https://github.com/Tensamin/TTP.git", package = "ttp-native" } diff --git a/web-ui/src/api.rs b/web-ui/src/api.rs index f9a87a4..26a0544 100755 --- a/web-ui/src/api.rs +++ b/web-ui/src/api.rs @@ -1,6 +1,6 @@ -use crate::server::server::is_local_network; -use crate::util::config_util::CONFIG; +use crate::server::is_local_network; use actix_web::{HttpRequest, HttpResponse, Responder, web}; +use iota_storage::util::config_util::CONFIG; use serde_json::{Value, json}; use std::net::SocketAddr; use std::sync::Arc; @@ -56,15 +56,15 @@ async fn communities_get(req: HttpRequest, ssl: web::Data) -> impl Respond return forbidden(); } - let communities = crate::communities::community_manager::get_communities().await; + // let communities = decentralized::communities::community_manager::get_communities().await; - let mut list = Vec::new(); + let list: Vec = Vec::new(); - for c in communities { - let val = c.frontend().await; - let s_val: Value = serde_json::to_value(val.to_string()).unwrap(); - list.push(s_val); - } + // for c in communities { + // let val = c.frontend().await.to_string(); + // let s_val: Value = serde_json::from_str(&val).unwrap_or(Value::Null); + // list.push(s_val); + // } HttpResponse::Ok().json(list) } @@ -77,12 +77,13 @@ async fn communities_add( return forbidden(); } - let name = payload["name"].as_str().unwrap_or("").to_string(); - let owner = payload["owner"].as_i64().unwrap_or(0); + // let name = payload["name"].as_str().unwrap_or("").to_string(); + // let owner = payload["owner"].as_i64().unwrap_or(0); - let community = Arc::new(crate::communities::community::Community::create(name, owner).await); + // let community = + // Arc::new(decentralized::communities::community::Community::create(name, owner).await); - crate::communities::community_manager::add_community(community).await; + // decentralized::communities::community_manager::add_community(community).await; success() } @@ -92,13 +93,13 @@ async fn users_get(req: HttpRequest, ssl: web::Data) -> impl Responder { return forbidden(); } - let users = crate::users::user_manager::get_users(); + let users = iota_storage::users::user_manager::get_users(); let list: Vec<_> = users .into_iter() .map(|u| { - let val = u.frontend(); - serde_json::to_value(val.to_string()).unwrap() + let val = u.frontend().to_string(); + serde_json::from_str(&val).unwrap_or(Value::Null) }) .collect(); @@ -116,8 +117,8 @@ async fn users_remove( let uuid = payload.get("uuid").and_then(|v| v.as_i64()).unwrap_or(0); - crate::users::user_manager::remove_user(uuid); - crate::users::user_manager::save_users(); + iota_storage::users::user_manager::remove_user(uuid); + iota_storage::users::user_manager::save_users(); success() } @@ -136,9 +137,9 @@ async fn users_add( _ => return error(), }; - if let (Some(user), Some(_)) = crate::users::user_manager::create_user(username).await { - let val = user.frontend(); - let s_val: Value = serde_json::to_value(val.to_string()).unwrap(); + if let (Some(user), Some(_)) = omikron_connector::user_ops::create_user(username).await { + let val = user.frontend().to_string(); + let s_val: Value = serde_json::from_str(&val).unwrap_or(Value::Null); HttpResponse::Ok().json(s_val) } else { error() @@ -150,7 +151,7 @@ async fn shutdown(req: HttpRequest, ssl: web::Data) -> impl Responder { return forbidden(); } - *crate::SHUTDOWN.write().await = true; + *iota_state::SHUTDOWN.write().await = true; success() } @@ -159,8 +160,8 @@ async fn reload(req: HttpRequest, ssl: web::Data) -> impl Responder { return forbidden(); } - *crate::SHUTDOWN.write().await = true; - *crate::RELOAD.write().await = true; + *iota_state::SHUTDOWN.write().await = true; + *iota_state::RELOAD.write().await = true; success() } diff --git a/web-ui/src/server.rs b/web-ui/src/server.rs index b55a50f..9902fe0 100644 --- a/web-ui/src/server.rs +++ b/web-ui/src/server.rs @@ -1,10 +1,9 @@ -use crate::log; -use crate::server::api::api_config; -use crate::server::web_path_parser; -use crate::util::file_util::load_file_buf; -use crate::{ACTIVE_TASKS, SHUTDOWN}; +use crate::api::api_config; +use crate::web_path_parser; use actix_web::{App, Error, HttpRequest, HttpServer, Responder, dev::ServerHandle, web}; -use actix_web_actors::ws; +use iota_logger::log; +use iota_state::{ACTIVE_TASKS, SHUTDOWN}; +use iota_util::file_util::load_file_buf; use rustls::ServerConfig; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use std::{ @@ -15,13 +14,6 @@ use std::{ time::Duration, }; -async fn ws_handler(req: HttpRequest, stream: web::Payload) -> Result { - let path = req.path().to_string(); - log!("WS connection from {:?}", req.peer_addr()); - let session = WsSession::new(path); - ws::start(session, &req, stream) -} - use tokio::sync::oneshot; pub async fn start(port: u16) -> bool { @@ -36,7 +28,6 @@ pub async fn start(port: u16) -> bool { App::new() .app_data(web::Data::new(true)) .configure(api_config) - .service(web::resource("/ws/{path:.*}").route(web::get().to(ws_handler))) .default_service(web::to(web_path_parser::handle)) }) .bind(("0.0.0.0", port)) @@ -49,7 +40,6 @@ pub async fn start(port: u16) -> bool { App::new() .app_data(web::Data::new(false)) .configure(api_config) - .service(web::resource("/ws/{path:.*}").route(web::get().to(ws_handler))) .default_service(web::to(web_path_parser::handle)) }) .bind(("0.0.0.0", port)) diff --git a/web-ui/src/socket.rs b/web-ui/src/socket.rs new file mode 100644 index 0000000..e69de29 diff --git a/web-ui/src/web_path_parser.rs b/web-ui/src/web_path_parser.rs index a82c8db..2eaf3cf 100755 --- a/web-ui/src/web_path_parser.rs +++ b/web-ui/src/web_path_parser.rs @@ -1,7 +1,7 @@ use actix_web::{HttpRequest, HttpResponse}; use std::path::{Path, PathBuf}; -use crate::util::file_util::load_file_vec; +use iota_util::file_util::load_file_vec; fn codec_for_ext(ext: &str) -> &'static str { match ext {