Compare commits

...
Author SHA1 Message Date
Jonathan Wanke
39b6351c85 Added allows for unused things. 2026-04-10 00:36:46 +02:00
Jonathan Wanke
77e5072f20 Proper user error handling. 2026-04-10 00:14:41 +02:00
11 changed files with 184 additions and 36 deletions

View file

@ -428,7 +428,7 @@ pub async fn run_command(command: &str) {
{
log!("Created user {}", user.user_id);
} else {
log!("Failed to create user");
log!("User creation: Failed to create user. See errors above.");
}
}
["user", "remove", username] => {
@ -436,7 +436,7 @@ pub async fn run_command(command: &str) {
user_manager::remove_user(user.user_id);
log!("Removed user {}", user.user_id);
} else {
log!("Failed to find user");
log!("User removal: Username doesn't exist");
}
}
["user", "list"] => {
@ -457,7 +457,7 @@ pub async fn run_command(command: &str) {
user_manager::remove_user(user.user_id);
log!("Removed user {}", user.user_id);
} else {
log!("Failed to find user");
log!("User info: Username doesn't exist");
}
}
["reload"] | ["restart"] => {

View file

@ -26,6 +26,7 @@ pub enum UserChoice {
AcceptAll,
}
#[allow(dead_code)] // ui is unused
pub struct TermsCheckerScreen {
ui: Arc<UI>,
sender: Option<oneshot::Sender<UserChoice>>,

View file

@ -9,10 +9,7 @@ use ratatui::{Terminal, backend::CrosstermBackend, init};
use std::{
collections::VecDeque,
io::Stdout,
sync::{
Arc, Mutex,
atomic::{AtomicBool, Ordering},
},
sync::{Arc, Mutex, atomic::Ordering},
time::Duration,
};
use tokio::{sync::RwLock, time::Instant};

View file

@ -15,7 +15,7 @@ use iota_util::file_util::{download_and_extract_zip, has_dir};
use omikron_connector as omikron;
#[tokio::main(flavor = "multi_thread", worker_threads = 16)]
#[allow(unused_must_use, dead_code)]
#[allow(unused_must_use, dead_code, unused_assignments)]
async fn main() {
while *RELOAD.read().await {
*RELOAD.write().await = false;
@ -107,7 +107,9 @@ async fn main() {
sb1 = sb1 + ",";
}
log!("Community IDS: {}", sb1); */
#[allow(unused_variables)] // port is unused
let port = CONFIG.read().await.get_port();
#[allow(unused_variables)] // ip is unused
let mut ip = "0.0.0.0".to_string();
for iface in pnet::datalink::interfaces() {
let iface: NetworkInterface = iface;
@ -115,7 +117,7 @@ async fn main() {
let ipsv = format!("{}", iface.ips[0]);
let ips: &str = ipsv.split('/').next().unwrap_or("");
if format!("{}", ips).starts_with("10.") || format!("{}", ips).starts_with("192.") {
ip = ips.to_string();
ip = ips.to_string(); // Unused assignments.
}
}
}

View file

@ -7,7 +7,6 @@ use anyhow::{Context, Result, anyhow};
use iota_logger::log;
use self_replace::self_replace;
use semver::Version;
use std::fs::File;
use tempfile::NamedTempFile;
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
@ -108,7 +107,6 @@ async fn download_asset(url: &str) -> Result<NamedTempFile> {
}
let tmp = NamedTempFile::new().context("failed to create temp file")?;
let mut out = File::create(tmp.path()).context("failed to open temp file")?;
let bytes = response
.bytes()

View file

@ -79,6 +79,7 @@ impl ConnectionState {
// Omikron Connection (Client-side with auto-reconnect)
// ============================================================================
#[allow(dead_code)] // message_send_times is unused.
pub struct OmikronConnection {
state: Arc<RwLock<ConnectionState>>,
sender: Arc<RwLock<Option<Arc<Sender>>>>,
@ -283,6 +284,7 @@ impl OmikronConnection {
if iota_id == 0 {
log_t!("iota_register_new");
#[allow(unused_variables)] // priv_k is unused
let (pub_k, priv_k) = if let (Some(pk), Some(sk)) = (public_key, private_key) {
(pk, sk)
} else {
@ -426,9 +428,10 @@ impl OmikronConnection {
if cv.is_type(CommunicationType::client_connected) {
let user_id = cv.get_data(DataTypes::user_id).as_number().unwrap_or(0) as i64;
#[allow(unused_variables)] // session_id is unused.
let session_id = cv.get_data(DataTypes::session_id).as_number().unwrap_or(0) as i64;
let mut contacts = chats_util::get_users(user_id);
let contacts = chats_util::get_users(user_id);
let mut contacts_array = Vec::new();
for (i, contact) in contacts.iter().enumerate() {

View file

@ -1,6 +1,5 @@
use crate::omikron_connection::OmikronConnection;
use dashmap::DashMap;
use iota_logger::log;
use iota_state::APP_STATE;
use std::sync::LazyLock;
use std::time::Instant;

View file

@ -1,6 +1,6 @@
use base64::{Engine as _, engine::general_purpose::STANDARD};
use hex;
use iota_logger::{PrintType, log, log_cv};
use iota_logger::{PrintType, log, log_cv, log_t};
use iota_state::{RELOAD, SHUTDOWN};
use iota_storage::users::user_manager::{add_user, save_users};
use iota_storage::users::user_profile::UserProfile;
@ -15,27 +15,36 @@ use x448::{PublicKey, Secret};
use crate::omikron_connection::OMIKRON_CONNECTION;
pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>) {
let register_cv = CommunicationValue::new(CommunicationType::get_register);
let register_communication_value = CommunicationValue::new(CommunicationType::get_register);
let conn = OMIKRON_CONNECTION.clone();
let connection = OMIKRON_CONNECTION.clone();
let response_cv = match conn
.await_response(&register_cv, Some(Duration::from_secs(20)))
let response_communication_value = match connection
.await_response(&register_communication_value, Some(Duration::from_secs(20)))
.await
{
Ok(cv) => cv,
Err(_) => return (None, None),
Ok(communication_value) => communication_value,
Err(e) => {
log_t!("User creation: {}", e);
return (None, None);
}
};
log_cv!(PrintType::Omega, response_cv);
log_cv!(PrintType::Omega, response_communication_value);
let user_id = match response_cv.get_data(DataTypes::user_id).as_number() {
let user_id = match response_communication_value
.get_data(DataTypes::user_id)
.as_number()
{
Some(id) => id,
None => return (None, None),
None => {
log_t!("User creation: Response returned none");
return (None, None);
}
};
let mut buf = [0u8; 56];
let mut buffer = [0u8; 56];
let mut rng = OsRng;
rng.fill_bytes(&mut buf);
let private_key = Secret::from_bytes(&buf).unwrap();
rng.fill_bytes(&mut buffer);
let private_key = Secret::from_bytes(&buffer).unwrap();
let public_key = PublicKey::from(&private_key);
let mut hasher = Sha256::new();
@ -47,7 +56,7 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
OsRng.fill_bytes(&mut bytes);
let reset_token = STANDARD.encode(&bytes);
let up = UserProfile::new(
let user_profile = UserProfile::new(
user_id,
username.to_string(),
None,
@ -56,7 +65,7 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
reset_token.clone(),
);
let cv = CommunicationValue::new(CommunicationType::complete_register_user)
let communication_value = 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(
@ -66,16 +75,17 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
.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)))
let response_communication_value = connection
.await_response(&communication_value, Some(Duration::from_secs(20)))
.await;
if let Ok(resp) = response_cv {
log_cv!(PrintType::Omega, resp);
if !resp.is_type(CommunicationType::success) {
if let Ok(response) = response_communication_value {
log_cv!(PrintType::Omega, response);
if !response.is_type(CommunicationType::success) {
return (None, None);
}
} else {
log_t!("User creation: Response returned none");
return (None, None);
}
*SHUTDOWN.write().await = true;
@ -87,7 +97,10 @@ pub async fn create_user(username: &str) -> (Option<UserProfile>, Option<String>
&format!("{}::{}", user_id, STANDARD.encode(&private_key.as_bytes())),
);
add_user(up.clone());
add_user(user_profile.clone());
save_users();
(Some(up), Some(STANDARD.encode(&private_key.as_bytes())))
(
Some(user_profile),
Some(STANDARD.encode(&private_key.as_bytes())),
)
}

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

135
src/util/auto_update.rs Normal file
View file

@ -0,0 +1,135 @@
/* This file is used for the auto update function for the Iota.
* It connects to the git server from methanium and checks if
* the version has updated inside the cargo.toml file.*/
use anyhow::{Context, Result, anyhow};
use semver::Version;
use serde::Deserialize;
use std::fs::File;
use std::io::copy;
use tempfile::NamedTempFile;
use crate::log; // For logging messages into the iota
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
const API_BASE: &str = "https://git.methanium.net/api/v1";
const OWNER: &str = "Tensamin";
const REPO: &str = "Iota";
#[derive(Debug, Deserialize)]
struct Release {
tag_name: String,
assets: Vec<Asset>,
}
#[derive(Debug, Deserialize)]
struct Asset {
name: String,
browser_download_url: String,
}
async fn latest_release() -> Result<Release> {
let url = format!("{API_BASE}/repos/{OWNER}/{REPO}/releases/latest");
let response = reqwest::get(&url)
.await
.context("failed to query latest release.")?;
if !response.status().is_success() {
return Err(anyhow!("release API returned {}", response.status()));
}
Ok(response
.json()
.await
.context("failed to parse release JSON")?)
}
async fn parse_tag_version(tag: &str) -> Result<Version> {
let normalized = tag.strip_prefix('v').unwrap_or(tag);
Ok(Version::parse(normalized)?)
}
async fn current_version() -> Result<Version> {
Ok(Version::parse(CURRENT_VERSION)?)
}
async fn asset_name_for_current_platform() -> String {
let os = std::env::consts::OS;
let arch = std::env::consts::ARCH;
match (os, arch) {
("linux", "x86_64") => "iota-linux-x86_64".to_string(),
("linux", "aarch64") => "iota-linux-aarch64".to_string(),
("windows", "x86_64") => "iota-windows-x86_64.exe".to_string(),
("macos", "x86_64") => "iota-macos-x86_64".to_string(),
("macos", "aarch64") => "iota-macos-aarch64".to_string(),
_ => panic!("unsupported platform: {os}/{arch}"),
}
}
async fn download_asset(url: &str) -> Result<NamedTempFile> {
let mut response = reqwest::get(url)
.await
.context("failed to download asset")?;
if !response.status().is_success() {
return Err(anyhow!("asset download returned {}", response.status()));
}
let tmp = NamedTempFile::new().context("failed to create temp file")?;
let mut out = File::create(tmp.path()).context("failed to open temp file")?;
let bytes = response
.bytes()
.await
.context("failed to read response bytes")?;
std::fs::write(tmp.path(), &bytes).context("failed to write file")?;
Ok(tmp)
}
async fn check_for_update() -> Result<Option<Release>> {
let current = current_version().await?;
let release = latest_release().await?;
let latest = parse_tag_version(&release.tag_name).await?;
if latest > current {
Ok(Some(release))
} else {
Ok(None)
}
}
async fn perform_update() -> Result<bool> {
let Some(release) = check_for_update().await? else {
return Ok(false);
};
let wanted_asset = asset_name_for_current_platform().await;
let asset = release
.assets
.iter()
.find(|a| a.name == wanted_asset)
.ok_or_else(|| anyhow!("no matching asset found: {}", wanted_asset))?;
log!("Downloading update: {}", asset.name);
let downloaded = download_asset(&asset.browser_download_url).await?;
self_replace::self_replace(downloaded.path())
.context("failed to replace current executable")?;
Ok(true)
}
pub async fn check_update() -> Result<bool> {
if perform_update().await? {
return Ok(true);
} else {
return Ok(false);
}
}

View file

@ -70,7 +70,7 @@ async fn communities_get(req: HttpRequest, ssl: web::Data<bool>) -> impl Respond
async fn communities_add(
req: HttpRequest,
ssl: web::Data<bool>,
payload: web::Json<Value>,
#[allow(unused_variables)] payload: web::Json<Value>,
) -> impl Responder {
if !is_allowed_req(&req, *ssl.get_ref()) {
return forbidden();